Address multi-threading issues in SI95
[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( struct ginfo_blk *gptr, 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         char buf[256];               //  buffer to build request address in 
73         int optval = 0;
74         int alen = 0;
75
76         tptr = (struct tp_blk *) SInew( TP_BLK );     //  new transport info block 
77
78         if( tptr != NULL )
79         {
80                 addr = NULL;
81
82                 switch( type )                  //  things specifc to tcp or udp 
83                 {
84                         case UDP_DEVICE:
85                                 tptr->type = SOCK_DGRAM;
86                                 protocol = IPPROTO_UDP;
87                                 break;
88
89                         case TCP_DEVICE:
90                         default:
91                                 tptr->type = SOCK_STREAM;
92                                 protocol = IPPROTO_TCP;
93                 }
94
95                 alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr );  //  family == 0 for type that suits the address passed in 
96                 if( alen <= 0 ) {
97                         return NULL;
98                 }
99
100                 tptr->family = addr->sa_family;
101
102                 if( (tptr->fd = SOCKET( tptr->family, tptr->type, protocol )) >= SI_OK ) {
103                         optval = 1;
104                         if( SO_REUSEPORT ) {
105                                 SETSOCKOPT(tptr->fd, SOL_SOCKET, SO_REUSEPORT, (char *)&optval, sizeof( optval) ) ;
106                         }
107
108                         status = BIND( tptr->fd, (struct sockaddr *) addr, alen );
109                         if( status == SI_OK ) {
110                                 tptr->addr = addr;              //  save address 
111                         } else {
112                                 fprintf( stderr, ">>>>> siestablish: bind failed: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) );
113                                 close( tptr->fd );
114                         }
115                 } else {
116                         status = ! SI_OK;                       //  force bad return later 
117                         fprintf( stderr, ">>>>> siestablish: socket not esablished: fam=%d type=%d pro=%d %s\n", tptr->family, tptr->type, protocol, strerror( errno ) );
118                 }
119
120                 if( status != SI_OK ) {                         //  socket or bind call failed - clean up stuff 
121                         fprintf( stderr, ">>>>> siestablish: bad state -- returning nil pointer\n" );
122                         free( addr );
123                         SItrash( TP_BLK, tptr );        //  free the trasnsport block 
124                         tptr = NULL;                    //  set to return nothing 
125                 }
126         }
127
128         return tptr;
129 }
130
131 /*
132         Prep a socket to use to connect to a listener.
133         Establish a transport block and target address in prep to connect.
134         Type is the SI constant UDP_DEVICE or TCP_DEVICE. The abuf pointer
135         should point to either a name:port or IP:port string. Family should
136         be 0 to select the family best suited to the address provided, or
137         any (v4 or v6) if the address is a name. If a perticular type is
138         desired family should be either AF_INET or AF_INET6.  Using a
139         family of 0 (AF_ANY) is usually the best choice.
140 */
141 extern struct tp_blk *SIconn_prep( struct ginfo_blk *gptr, int type, char *abuf, int family ) {
142         struct tp_blk *tptr;         //  pointer at new tp block 
143         struct sockaddr *addr;          //  IP address we are requesting 
144         int protocol;                //  protocol for socket call 
145         char buf[256];               //  buffer to build request address in 
146         int optval = 0;
147         int alen = 0;
148
149         tptr = (struct tp_blk *) SInew( TP_BLK );     //  new transport info block 
150
151         if( tptr != NULL )
152         {
153                 addr = NULL;
154
155                 switch( type )                  //  things specifc to tcp or udp 
156                 {
157                         case UDP_DEVICE:
158                                 tptr->type = SOCK_DGRAM;
159                                 protocol = IPPROTO_UDP;
160                                 break;
161
162                         case TCP_DEVICE:
163                         default:
164                                 tptr->type = SOCK_STREAM;
165                                 protocol = IPPROTO_TCP;
166                 }
167
168                 alen = SIgenaddr( abuf, protocol, family, tptr->type, &addr );  //  family == 0 for type that suits the address passed in 
169                 if( alen <= 0 )
170                 {
171                         //fprintf( stderr, ">>>>> siconn_prep: error generating an address struct for %s(abuf) %d(proto) %d(type): %s\n",
172                         //      abuf, protocol, tptr->type, strerror( errno ) );
173                         return NULL;
174                 }
175
176                 tptr->family = addr->sa_family;
177                 tptr->palen = alen;
178
179                 if( (tptr->fd = SOCKET( tptr->family, tptr->type, protocol )) >= SI_OK ) {
180                         optval = 1;
181
182                         if( SO_REUSEPORT ) {
183                                 SETSOCKOPT( tptr->fd, SOL_SOCKET, SO_REUSEPORT, (char *)&optval, sizeof( optval) );
184                         }
185
186                         if( gptr->tcp_flags & SI_TF_NODELAY ) {
187                                 optval = 1;
188                         } else {
189                                 optval = 0;
190                         }
191                         //fprintf( stderr, ">>>>> conn_prep: setting no delay = %d\n", optval );
192                         SETSOCKOPT( tptr->fd, SOL_TCP, TCP_NODELAY, (void *)&optval, sizeof( optval) ) ;
193
194                         if( gptr->tcp_flags & SI_TF_FASTACK ) {
195                                 optval = 1;
196                         } else {
197                                 optval = 0;
198                         }
199                         //fprintf( stderr, ">>>>> conn_prep: setting quick ack = %d\n", optval );
200                         SETSOCKOPT( tptr->fd, SOL_TCP, TCP_QUICKACK, (void *)&optval, sizeof( optval) ) ;
201
202                         tptr->paddr = addr;                             // tuck the remote peer address away
203                 } else {
204                         //fprintf( stderr, ">>>>> conn_prep: bad socket create: %s\n", strerror( errno ) );
205                         free( addr );
206                         SItrash( TP_BLK, tptr );        //  free the trasnsport block 
207                         tptr = NULL;                                    // we'll return nil
208                 }
209         }
210
211         return tptr;
212 }