More changes for scan corrections and unit test coverage
[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         int status = SI_OK;          //  processing status
70         struct sockaddr *addr;          //  IP address we are requesting
71         int protocol;                //  protocol for socket call
72         int optval = 0;
73         int alen = 0;
74
75         tptr = (struct tp_blk *) SInew( TP_BLK );     //  new transport info block
76
77         if( tptr != NULL )
78         {
79                 addr = NULL;
80
81                 switch( type )                  //  things specifc to tcp or udp
82                 {
83                         case UDP_DEVICE:
84                                 tptr->type = SOCK_DGRAM;
85                                 protocol = IPPROTO_UDP;
86                                 break;
87
88                         case TCP_DEVICE:
89                         default:
90                                 tptr->type = SOCK_STREAM;
91                                 protocol = IPPROTO_TCP;
92                 }
93
94                 alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr );  //  family == 0 for type that suits the address passed in
95                 if( alen <= 0 ) {
96                         if( addr != NULL ) {
97                                 free( addr );           // not needed, but scanners complain if we don't overtly do this
98                         }
99                         return NULL;
100                 }
101
102                 tptr->family = addr->sa_family;
103
104                 if( (tptr->fd = SOCKET( tptr->family, tptr->type, protocol )) >= SI_OK ) {
105                         optval = 1;
106                         if( SO_REUSEPORT ) {
107                                 SETSOCKOPT(tptr->fd, SOL_SOCKET, SO_REUSEPORT, (char *)&optval, sizeof( optval) ) ;
108                         }
109
110                         status = BIND( tptr->fd, (struct sockaddr *) addr, alen );
111                         if( status == SI_OK ) {
112                                 tptr->addr = addr;                      //  save address
113                         } else {
114                                 fprintf( stderr, "<ERR> siestablish: bind failed: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) );
115                                 close( tptr->fd );
116                         }
117                 } else {
118                         status = ! SI_OK;                               //  force bad return later
119                         fprintf( stderr, "<ERR> siestablish: socket not esablished: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) );
120                 }
121
122                 if( status != SI_OK ) {                         //  socket or bind call failed - clean up stuff
123                         fprintf( stderr, "<ERR> siestablish: bad state -- returning nil pointer\n" );
124                         free( addr );
125                         SItrash( TP_BLK, tptr );        //  free the trasnsport block
126                         tptr = NULL;                            //  set to return nothing
127                 }
128         }
129
130         return tptr;
131 }
132
133 /*
134         Look at the address and determine if the connect attempt to this address must
135         use safe_connect() rather than the system connect() call. On linux, a smart
136         connect is needed if the target port is >32K and is even. This makes the assumption
137         that the local port rage floor is 32K; we could read something in /proc, but
138         at this point won't bother.  Returns true if we determine that it is best to
139         use safe_connect().
140 */
141 static int need_smartc( char* abuf ) {
142         char*   tok;
143         int             state = 1;
144         int             v;
145
146         if( (tok = strchr( abuf, ':')) != NULL ) {
147                 v = atoi( tok+1 );
148                 if( v < 32767  || v % 2 != 0 ) {
149                         state = 0;
150                 }
151         }
152
153         return state;
154 }
155
156 /*
157         Prep a socket to use to connect to a listener.
158         Establish a transport block and target address in prep to connect.
159         Type is the SI constant UDP_DEVICE or TCP_DEVICE. The abuf pointer
160         should point to either a name:port or IP:port string. Family should
161         be 0 to select the family best suited to the address provided, or
162         any (v4 or v6) if the address is a name. If a perticular type is
163         desired family should be either AF_INET or AF_INET6.  Using a
164         family of 0 (AF_ANY) is usually the best choice.
165 */
166 extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf, int family ) {
167         struct tp_blk *tptr;         //  pointer at new tp block
168         struct sockaddr *addr;          //  IP address we are requesting
169         int protocol;                //  protocol for socket call
170         char buf[256];               //  buffer to build request address in
171         int optval = 0;
172         int alen = 0;
173
174         tptr = (struct tp_blk *) SInew( TP_BLK );     //  new transport info block
175
176         if( tptr != NULL )
177         {
178                 addr = NULL;
179
180                 switch( type )                  //  things specifc to tcp or udp
181                 {
182                         case UDP_DEVICE:
183                                 tptr->type = SOCK_DGRAM;
184                                 protocol = IPPROTO_UDP;
185                                 break;
186
187                         case TCP_DEVICE:
188                         default:
189                                 tptr->type = SOCK_STREAM;
190                                 protocol = IPPROTO_TCP;
191                 }
192
193                 alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr );  //  family == 0 for type that suits the address passed in
194                 if( alen <= 0 ) {
195                         if( addr != NULL ) {            // not needed, but scanners complain if we don't overtly do this
196                                 free( addr );
197                         }
198                         return NULL;
199                 }
200
201                 tptr->family = addr->sa_family;
202                 tptr->palen = alen;
203
204                 if( (tptr->fd = SOCKET( tptr->family, tptr->type, protocol )) >= SI_OK ) {
205                         optval = 1;
206
207                         if( gptr->tcp_flags & SI_TF_NODELAY ) {
208                                 optval = 1;
209                         } else {
210                                 optval = 0;
211                         }
212                         SETSOCKOPT( tptr->fd, SOL_TCP, TCP_NODELAY, (void *)&optval, sizeof( optval) ) ;
213
214                         if( gptr->tcp_flags & SI_TF_FASTACK ) {
215                                 optval = 1;
216                         } else {
217                                 optval = 0;
218                         }
219                         SETSOCKOPT( tptr->fd, SOL_TCP, TCP_QUICKACK, (void *)&optval, sizeof( optval) ) ;
220
221                         tptr->paddr = addr;                             // tuck the remote peer address away
222                         if( need_smartc( abuf ) ) {
223                                 tptr->flags |= TPF_SAFEC;
224                         }
225                 } else {
226                         free( addr );
227                         SItrash( TP_BLK, tptr );                // free the trasnsport block
228                         tptr = NULL;                                    // we'll return nil
229                 }
230         }
231
232         return tptr;
233 }