1 // vim: noet sw=4 ts=4:
3 ==================================================================================
4 Copyright (c) 2020 Nokia
5 Copyright (c) 2020 AT&T Intellectual Property.
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
11 http://www.apache.org/licenses/LICENSE-2.0
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18 ==================================================================================
23 *-----------------------------------------------------------------------------------
25 * Mnemonic: SIestablish
26 * Abstract:i Prep functions that set up a socket for listening or making a
29 * Author: E. Scott Daniels
31 * Modified: 19 Apr 1995 - To keep returned address of the port.
32 * 08 Mar 2007 - conversion for ipv6.
33 * 12 Oct 2020 - split into connect prep and listen prep
35 *-----------------------------------------------------------------------------------
39 #include "sisetup.h" // include the necessary setup stuff
40 #include "sitransport.h"
42 #include <netinet/tcp.h>
45 #define SO_REUSEPORT 0
49 Prep a socket for "listening."
50 This routine will open a socket and bind an address to it in
51 preparation for listening for connections or inbound UDP
52 datagrams. A file descriptor for the socket is captured and all
53 related information is placed into a transport provider (tp) block.
55 Type is the SI constant UDP_DEVICE or TCP_DEVICE
56 abuf points to the address that is to be bound to the socket.
57 Family is one of the AF_* constants (AF_ANY, AF_INET or AF_INET6)
59 The address should be one of these forms:
60 [::1]:port v6 localhost device (loop back)
61 localhost:port v4 or 6 loopback depending on /etc/hosts
62 0.0.0.0:port any interface
63 addr:port an address assigned to one of the devices
65 Returns a transport struct which is the main context for the listener.
67 extern struct tp_blk *SIlisten_prep( int type, char* abuf, int family ) {
68 struct tp_blk *tptr; // pointer at new tp block
69 struct sockaddr *addr; // IP address we are requesting
72 int status = SI_OK; // processing status
73 int protocol; // protocol for socket call
75 tptr = (struct tp_blk *) SInew( TP_BLK ); // transport info
80 if( type == UDP_DEVICE ) {
81 tptr->type = SOCK_DGRAM;
82 protocol = IPPROTO_UDP;
84 tptr->type = SOCK_STREAM;
85 protocol = IPPROTO_TCP;
88 alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr ); // family == 0 for type that suits the address passed in
91 free( addr ); // not needed, but scanners complain if we don't overtly do this
97 tptr->family = addr->sa_family;
99 if( (tptr->fd = SOCKET( tptr->family, tptr->type, protocol )) >= SI_OK ) {
102 SETSOCKOPT(tptr->fd, SOL_SOCKET, SO_REUSEPORT, (char *)&optval, sizeof( optval) ) ;
105 status = BIND( tptr->fd, (struct sockaddr *) addr, alen );
106 if( status == SI_OK ) {
107 tptr->addr = addr; // save address
109 fprintf( stderr, "<ERR> siestablish: bind failed: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) );
113 status = ! SI_OK; // force bad return later
114 fprintf( stderr, "<ERR> siestablish: socket not esablished: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) );
117 if( status != SI_OK ) { // socket or bind call failed - clean up stuff
118 fprintf( stderr, "<ERR> siestablish: bad state -- returning nil pointer\n" );
120 SItrash( TP_BLK, tptr ); // free the trasnsport block
121 tptr = NULL; // set to return nothing
129 Look at the address and determine if the connect attempt to this address must
130 use safe_connect() rather than the system connect() call. On linux, a smart
131 connect is needed if the target port is >32K and is even. This makes the assumption
132 that the local port rage floor is 32K; we could read something in /proc, but
133 at this point won't bother. Returns true if we determine that it is best to
136 static int need_smartc( char* abuf ) {
141 if( (tok = strchr( abuf, ':')) != NULL ) {
143 if( v < 32767 || v % 2 != 0 ) {
152 Prep a socket to use to connect to a listener.
153 Establish a transport block and target address in prep to connect.
154 Type is the SI constant UDP_DEVICE or TCP_DEVICE. The abuf pointer
155 should point to either a name:port or IP:port string. Family should
156 be 0 to select the family best suited to the address provided, or
157 any (v4 or v6) if the address is a name. If a perticular type is
158 desired family should be either AF_INET or AF_INET6. Using a
159 family of 0 (AF_ANY) is usually the best choice.
161 extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf, int family ) {
162 struct tp_blk *tptr; // pointer at new tp block
163 struct sockaddr *addr; // IP address we are requesting
164 int protocol; // protocol for socket call
165 char buf[256]; // buffer to build request address in
169 tptr = (struct tp_blk *) SInew( TP_BLK ); // new transport info block
175 switch( type ) // things specifc to tcp or udp
178 tptr->type = SOCK_DGRAM;
179 protocol = IPPROTO_UDP;
184 tptr->type = SOCK_STREAM;
185 protocol = IPPROTO_TCP;
188 alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr ); // family == 0 for type that suits the address passed in
190 if( addr != NULL ) { // not needed, but scanners complain if we don't overtly do this
197 tptr->family = addr->sa_family;
200 if( (tptr->fd = SOCKET( tptr->family, tptr->type, protocol )) >= SI_OK ) {
203 if( gptr->tcp_flags & SI_TF_NODELAY ) {
208 SETSOCKOPT( tptr->fd, SOL_TCP, TCP_NODELAY, (void *)&optval, sizeof( optval) ) ;
210 if( gptr->tcp_flags & SI_TF_FASTACK ) {
215 SETSOCKOPT( tptr->fd, SOL_TCP, TCP_QUICKACK, (void *)&optval, sizeof( optval) ) ;
217 if( gptr->tcp_flags & SI_TF_QUICK ) {
219 SETSOCKOPT( tptr->fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval, sizeof( optval) ) ;
221 SETSOCKOPT( tptr->fd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&optval, sizeof( optval) ) ;
223 SETSOCKOPT( tptr->fd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&optval, sizeof( optval) ) ;
225 SETSOCKOPT( tptr->fd, IPPROTO_TCP, TCP_KEEPCNT, (void *)&optval, sizeof( optval) ) ;
228 tptr->paddr = addr; // tuck the remote peer address away
229 if( need_smartc( abuf ) ) {
230 tptr->flags |= TPF_SAFEC;
234 SItrash( TP_BLK, tptr ); // free the trasnsport block
235 tptr = NULL; // we'll return nil