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 ******************************************************************************
37 #include "sitransport.h"
39 // ---------------- internal functions ----------------------------------------------
42 Attempts a connection to addr, and ensures that the linux even port
43 connect bug does not establish the connection back to our process.
44 If we detect this, then we abort the connection and return -1. 0
45 returned on a good connection.
47 If we are hit with the even port connection bug we have no choice but
48 to abort the connection which will CLOSE the caller's FD. This may
49 not be expected in some situations, and when we do the errno is set to
50 EBADFD to indicate this. We ensure that this state is returned ONLY
51 if the failure results in a closed fd which the caller will need to reopen.
53 int safe_connect( int fd, struct sockaddr* addr, int alen ) {
55 char caddr[255]; // work buffer for get sock name (v6 addr ~28 bytes, so this is plenty)
56 int calen; // len of the connect generated address
58 if( (state = CONNECT( fd, addr, alen )) != 0 ) {
59 if( errno == EBADFD ) { // ensure we return bad fd ONLY if we abort later
65 if( PARANOID_CHECKS ) {
66 if( alen > sizeof( caddr ) ) { // shouldn't happen, but be safe
67 fprintf( stderr, "safe_connect: address buffer for connect exceeds work space %d > %lu\n", alen, sizeof( caddr ) );
73 calen = alen; // we assume a bound address will have the same type, and thus len, as the connect to addr
74 if( getsockname( fd, (struct sockaddr *) &caddr, &calen ) == 0 ) {
75 if( calen != alen || memcmp( addr, &caddr, calen ) != 0 ) { // addresses differ, so it's good
87 Accept a file descriptor and add it to the map.
89 extern void SImap_fd( struct ginfo_blk *gptr, int fd, struct tp_blk* tpptr ) {
91 gptr->tp_map[fd] = tpptr;
93 rmr_vlog( RMR_VL_WARN, "fd on connected session is out of range: %d\n", fd );
98 Creates a connection to the target endpoint using the address in the
99 buffer provided. The address may be one of three forms:
104 On success the open file descriptor is returned; else -1 is returned. Errno
105 will be left set by the underlying connect() call.
107 To avoid the even port connect bug in the linux connect() systeem call,
108 we will use safe_connect() if indicated during the connection prep
111 extern int SIconnect( struct ginfo_blk *gptr, char *abuf ) {
113 struct tp_blk *tpptr; // pointer to new block
114 struct sockaddr *taddr; // convenience pointer to addr of target
115 int alen = 0; // len of address struct
116 int fd = SI_ERROR; // file descriptor to return to caller
118 if( PARANOID_CHECKS ) {
123 if( gptr->magicnum != MAGICNUM ) { // no cookie -- no connection
128 tpptr = SIconn_prep( gptr, TCP_DEVICE, abuf, 0 ); // create tp struct, and socket. get peer address 0 == any family that suits the addr
129 if( tpptr != NULL ) {
130 taddr = tpptr->paddr;
132 if( tpptr->flags & TPF_SAFEC ) {
133 if( safe_connect( tpptr->fd, taddr, tpptr->palen ) != 0 ) { // fd closed on failure
137 if( CONNECT( tpptr->fd, taddr, tpptr->palen ) != 0 ) {
138 CLOSE( tpptr->fd ); // clean up fd and tp_block
143 if( tpptr->fd >= 0 ) { // connect ok
144 tpptr->flags |= TPF_SESSION; // indicate we have a session here
145 tpptr->next = gptr->tplist; // add block to the list
146 if( tpptr->next != NULL ) {
147 tpptr->next->prev = tpptr; // if there - point back at new
150 gptr->tplist = tpptr; // point at new head
151 fd = tpptr->fd; // save for return value
152 SImap_fd( gptr, fd, tpptr );
154 SItrash( TP_BLK, tpptr ); // free the trasnsport block