Re-enable RMR libary's module tests
[ric-plt/lib/rmr.git] / src / rmr / si / src / si95 / siestablish.c
1 // vim: noet sw=4 ts=4:
2 /*
3 ==================================================================================
4     Copyright (c) 2020 Nokia
5     Copyright (c) 2020 AT&T Intellectual Property.
6
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
10
11        http://www.apache.org/licenses/LICENSE-2.0
12
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 ==================================================================================
19 */
20
21
22 /*
23 *-----------------------------------------------------------------------------------
24 *
25 * Mnemonic:             SIestablish
26 * Abstract:i    Prep functions that set up a socket for listening or making a
27 *                               connection.
28 * Date:                 26 March 1995
29 * Author:               E. Scott Daniels
30 *
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
34 *                                                               functions.
35 *-----------------------------------------------------------------------------------
36 */
37
38
39 #include "sisetup.h"       //  include the necessary setup stuff
40 #include "sitransport.h"
41 #include <errno.h>
42 #include <netinet/tcp.h>
43
44 #ifndef SO_REUSEPORT
45 #define SO_REUSEPORT 0
46 #endif
47
48 /*
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.
54
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)
58
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
64
65         Returns a transport struct which is the main context for the listener.
66 */
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
70         int optval = 0;
71         int alen = 0;
72         int status = SI_OK;          //  processing status
73         int protocol;                //  protocol for socket call
74
75         tptr = (struct tp_blk *) SInew( TP_BLK );     // transport info
76
77         if( tptr != NULL ) {
78                 addr = NULL;
79
80                 if( type == UDP_DEVICE ) {
81                         tptr->type = SOCK_DGRAM;
82                         protocol = IPPROTO_UDP;
83                 } else {
84                         tptr->type = SOCK_STREAM;
85                         protocol = IPPROTO_TCP;
86                 }
87
88                 alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr );  //  family == 0 for type that suits the address passed in
89                 if( alen <= 0 ) {
90                         if( addr != NULL ) {
91                                 free( addr );           // not needed, but scanners complain if we don't overtly do this
92                         }
93                         free( tptr );
94                         return NULL;
95                 }
96
97                 tptr->family = addr->sa_family;
98
99                 if( (tptr->fd = SOCKET( tptr->family, tptr->type, protocol )) >= SI_OK ) {
100                         optval = 1;
101                         if( SO_REUSEPORT ) {
102                                 SETSOCKOPT(tptr->fd, SOL_SOCKET, SO_REUSEPORT, (char *)&optval, sizeof( optval) ) ;
103                         }
104
105                         status = BIND( tptr->fd, (struct sockaddr *) addr, alen );
106                         if( status == SI_OK ) {
107                                 tptr->addr = addr;                      //  save address
108                         } else {
109                                 fprintf( stderr, "<ERR> siestablish: bind failed: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) );
110                                 close( tptr->fd );
111                         }
112                 } else {
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 ) );
115                 }
116
117                 if( status != SI_OK ) {                         //  socket or bind call failed - clean up stuff
118                         fprintf( stderr, "<ERR> siestablish: bad state -- returning nil pointer\n" );
119                         free( addr );
120                         SItrash( TP_BLK, tptr );        //  free the trasnsport block
121                         tptr = NULL;                            //  set to return nothing
122                 }
123         }
124
125         return tptr;
126 }
127
128 /*
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
134         use safe_connect().
135 */
136 static int need_smartc( char* abuf ) {
137         char*   tok;
138         int             state = 1;
139         int             v;
140
141         if( (tok = strchr( abuf, ':')) != NULL ) {
142                 v = atoi( tok+1 );
143                 if( v < 32767  || v % 2 != 0 ) {
144                         state = 0;
145                 }
146         }
147
148         return state;
149 }
150
151 /*
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.
160 */
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
166         int optval = 0;
167         int alen = 0;
168
169         tptr = (struct tp_blk *) SInew( TP_BLK );     //  new transport info block
170
171         if( tptr != NULL )
172         {
173                 addr = NULL;
174
175                 switch( type )                  //  things specifc to tcp or udp
176                 {
177                         case UDP_DEVICE:
178                                 tptr->type = SOCK_DGRAM;
179                                 protocol = IPPROTO_UDP;
180                                 break;
181
182                         case TCP_DEVICE:
183                         default:
184                                 tptr->type = SOCK_STREAM;
185                                 protocol = IPPROTO_TCP;
186                 }
187
188                 alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr );  //  family == 0 for type that suits the address passed in
189                 if( alen <= 0 ) {
190                         if( addr != NULL ) {            // not needed, but scanners complain if we don't overtly do this
191                                 free( addr );
192                         }
193                         free( tptr );
194                         return NULL;
195                 }
196
197                 tptr->family = addr->sa_family;
198                 tptr->palen = alen;
199
200                 if( (tptr->fd = SOCKET( tptr->family, tptr->type, protocol )) >= SI_OK ) {
201                         optval = 1;
202
203                         if( gptr->tcp_flags & SI_TF_NODELAY ) {
204                                 optval = 1;
205                         } else {
206                                 optval = 0;
207                         }
208                         SETSOCKOPT( tptr->fd, SOL_TCP, TCP_NODELAY, (void *)&optval, sizeof( optval) ) ;
209
210                         if( gptr->tcp_flags & SI_TF_FASTACK ) {
211                                 optval = 1;
212                         } else {
213                                 optval = 0;
214                         }
215                         SETSOCKOPT( tptr->fd, SOL_TCP, TCP_QUICKACK, (void *)&optval, sizeof( optval) ) ;
216
217                         tptr->paddr = addr;                             // tuck the remote peer address away
218                         if( need_smartc( abuf ) ) {
219                                 tptr->flags |= TPF_SAFEC;
220                         }
221                 } else {
222                         free( addr );
223                         SItrash( TP_BLK, tptr );                // free the trasnsport block
224                         tptr = NULL;                                    // we'll return nil
225                 }
226         }
227
228         return tptr;
229 }