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 ==================================================================================
22 ***************************************************************************
25 * Abstract: This module contains functions to make the connection using
26 * a transport block which has been given a transport (tcp) family
30 * Author: E. Scott Daniels
32 * Mod: 08 Mar 2007 - conversion of sorts to support ipv6
33 * 17 Apr 2020 - Add safe connect capabilities
34 ******************************************************************************
36 #include <netinet/tcp.h>
39 #include "sitransport.h"
41 // ---------------- internal functions ----------------------------------------------
44 Attempts a connection to addr, and ensures that the linux even port
45 connect bug does not establish the connection back to our process.
46 If we detect this, then we abort the connection and return -1. 0
47 returned on a good connection.
49 If we are hit with the even port connection bug we have no choice but
50 to abort the connection which will CLOSE the caller's FD. This may
51 not be expected in some situations, and when we do the errno is set to
52 EBADFD to indicate this. We ensure that this state is returned ONLY
53 if the failure results in a closed fd which the caller will need to reopen.
55 int safe_connect( int fd, struct sockaddr* addr, int alen ) {
57 char caddr[255]; // work buffer for get sock name (v6 addr ~28 bytes, so this is plenty)
58 int calen; // len of the connect generated address
60 if( (state = CONNECT( fd, addr, alen )) != 0 ) {
61 if( errno == EBADFD ) { // ensure we return bad fd ONLY if we abort later
67 if( PARANOID_CHECKS ) {
68 if( alen > sizeof( caddr ) ) { // shouldn't happen, but be safe
69 fprintf( stderr, "safe_connect: address buffer for connect exceeds work space %d > %lu\n", alen, sizeof( caddr ) );
75 calen = alen; // we assume a bound address will have the same type, and thus len, as the connect to addr
76 if( getsockname( fd, (struct sockaddr *) &caddr, &calen ) == 0 ) {
77 if( calen != alen || memcmp( addr, &caddr, calen ) != 0 ) { // addresses differ, so it's good
89 Accept a file descriptor and add it to the map.
91 extern void SImap_fd( struct ginfo_blk *gptr, int fd, struct tp_blk* tpptr ) {
93 gptr->tp_map[fd] = tpptr;
95 rmr_vlog( RMR_VL_WARN, "fd on connected session is out of range: %d\n", fd );
100 Creates a connection to the target endpoint using the address in the
101 buffer provided. The address may be one of three forms:
106 On success the open file descriptor is returned; else -1 is returned. Errno
107 will be left set by the underlying connect() call.
109 To avoid the even port connect bug in the linux connect() systeem call,
110 we will use safe_connect() if indicated during the connection prep
113 extern int SIconnect( struct ginfo_blk *gptr, char *abuf ) {
115 struct tp_blk *tpptr; // pointer to new block
116 struct sockaddr *taddr; // convenience pointer to addr of target
117 int alen = 0; // len of address struct
118 int fd = SI_ERROR; // file descriptor to return to caller
122 if( PARANOID_CHECKS ) {
127 if( gptr->magicnum != MAGICNUM ) { // no cookie -- no connection
132 tpptr = SIconn_prep( gptr, TCP_DEVICE, abuf, 0 ); // create tp struct, and socket. get peer address 0 == any family that suits the addr
133 if( tpptr != NULL ) {
134 taddr = tpptr->paddr;
137 if( gptr->tcp_flags & SI_TF_QUICK ) {
138 optvalrlen = sizeof(optvalr);
139 GETSOCKOPT( tpptr->fd, IPPROTO_TCP, TCP_SYNCNT, (void *)&optvalr, &optvalrlen) ;
141 SETSOCKOPT( tpptr->fd, IPPROTO_TCP, TCP_SYNCNT, (void *)&optvalw, sizeof( optvalw) ) ;
144 if( tpptr->flags & TPF_SAFEC ) {
145 if( safe_connect( tpptr->fd, taddr, tpptr->palen ) != 0 ) { // fd closed on failure
149 if( CONNECT( tpptr->fd, taddr, tpptr->palen ) != 0 ) {
150 CLOSE( tpptr->fd ); // clean up fd and tp_block
155 if( tpptr->fd >= 0 ) { // connect ok
156 if( gptr->tcp_flags & SI_TF_QUICK ) {
157 SETSOCKOPT( tpptr->fd, IPPROTO_TCP, TCP_SYNCNT, (void *)&optvalr, sizeof( optvalr) ) ;
160 tpptr->flags |= TPF_SESSION; // indicate we have a session here
161 tpptr->next = gptr->tplist; // add block to the list
162 if( tpptr->next != NULL ) {
163 tpptr->next->prev = tpptr; // if there - point back at new
166 gptr->tplist = tpptr; // point at new head
167 fd = tpptr->fd; // save for return value
168 SImap_fd( gptr, fd, tpptr );
170 SItrash( TP_BLK, tpptr ); // free the trasnsport block