1*c2c66affSColin Finck #include "syshdrs.h"
2*c2c66affSColin Finck 
3*c2c66affSColin Finck #ifndef NO_SIGNALS
4*c2c66affSColin Finck extern volatile Sjmp_buf gNetTimeoutJmp;
5*c2c66affSColin Finck extern volatile Sjmp_buf gPipeJmp;
6*c2c66affSColin Finck #endif
7*c2c66affSColin Finck 
8*c2c66affSColin Finck int
SConnect(int sfd,const struct sockaddr_in * const addr,int tlen)9*c2c66affSColin Finck SConnect(int sfd, const struct sockaddr_in *const addr, int tlen)
10*c2c66affSColin Finck {
11*c2c66affSColin Finck #ifndef NO_SIGNALS
12*c2c66affSColin Finck 	int result;
13*c2c66affSColin Finck 	vsio_sigproc_t sigalrm;
14*c2c66affSColin Finck 
15*c2c66affSColin Finck 	if (SSetjmp(gNetTimeoutJmp) != 0) {
16*c2c66affSColin Finck 		alarm(0);
17*c2c66affSColin Finck 		(void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
18*c2c66affSColin Finck 		errno = ETIMEDOUT;
19*c2c66affSColin Finck 		return (kTimeoutErr);
20*c2c66affSColin Finck 	}
21*c2c66affSColin Finck 
22*c2c66affSColin Finck 	sigalrm = (vsio_sigproc_t) SSignal(SIGALRM, SIOHandler);
23*c2c66affSColin Finck 	alarm((unsigned int) tlen);
24*c2c66affSColin Finck 
25*c2c66affSColin Finck 	errno = 0;
26*c2c66affSColin Finck 	do {
27*c2c66affSColin Finck 		result = connect(sfd, (struct sockaddr *) addr,
28*c2c66affSColin Finck 			(int) sizeof(struct sockaddr_in));
29*c2c66affSColin Finck 	} while ((result < 0) && (errno == EINTR));
30*c2c66affSColin Finck 
31*c2c66affSColin Finck 	alarm(0);
32*c2c66affSColin Finck 	(void) SSignal(SIGALRM, (sio_sigproc_t) sigalrm);
33*c2c66affSColin Finck 	return (result);
34*c2c66affSColin Finck #else	/* NO_SIGNALS */
35*c2c66affSColin Finck 	unsigned long opt;
36*c2c66affSColin Finck 	fd_set ss, xx;
37*c2c66affSColin Finck 	struct timeval tv;
38*c2c66affSColin Finck 	int result;
39*c2c66affSColin Finck 	int cErrno;
40*c2c66affSColin Finck #if defined(WIN32) || defined(_WINDOWS)
41*c2c66affSColin Finck 	int wsaErrno;
42*c2c66affSColin Finck 	int soerr, soerrsize;
43*c2c66affSColin Finck #else
44*c2c66affSColin Finck 	int optval;
45*c2c66affSColin Finck 	int optlen;
46*c2c66affSColin Finck #endif
47*c2c66affSColin Finck 
48*c2c66affSColin Finck 	errno = 0;
49*c2c66affSColin Finck 	if (tlen <= 0) {
50*c2c66affSColin Finck 		do {
51*c2c66affSColin Finck 			result = connect(sfd, (struct sockaddr *) addr,
52*c2c66affSColin Finck 				(int) sizeof(struct sockaddr_in));
53*c2c66affSColin Finck 			SETERRNO
54*c2c66affSColin Finck 		} while ((result < 0) && (errno == EINTR));
55*c2c66affSColin Finck 		return (result);
56*c2c66affSColin Finck 	}
57*c2c66affSColin Finck 
58*c2c66affSColin Finck #ifdef FIONBIO
59*c2c66affSColin Finck 	opt = 1;
60*c2c66affSColin Finck 	if (ioctlsocket(sfd, FIONBIO, &opt) != 0) {
61*c2c66affSColin Finck 		SETERRNO
62*c2c66affSColin Finck 		return (-1);
63*c2c66affSColin Finck 	}
64*c2c66affSColin Finck #else
65*c2c66affSColin Finck 	if (fcntl(sfd, F_GETFL, &opt) < 0) {
66*c2c66affSColin Finck 		SETERRNO
67*c2c66affSColin Finck 		return (-1);
68*c2c66affSColin Finck 	} else if (fcntl(sfd, F_SETFL, opt | O_NONBLOCK) < 0) {
69*c2c66affSColin Finck 		SETERRNO
70*c2c66affSColin Finck 		return (-1);
71*c2c66affSColin Finck 	}
72*c2c66affSColin Finck #endif
73*c2c66affSColin Finck 
74*c2c66affSColin Finck 	errno = 0;
75*c2c66affSColin Finck 	result = connect(sfd, (struct sockaddr *) addr,
76*c2c66affSColin Finck 			(int) sizeof(struct sockaddr_in));
77*c2c66affSColin Finck 	if (result == 0)
78*c2c66affSColin Finck 		return 0;	/* Already?!? */
79*c2c66affSColin Finck 
80*c2c66affSColin Finck 	if ((result < 0)
81*c2c66affSColin Finck #if defined(WIN32) || defined(_WINDOWS)
82*c2c66affSColin Finck 		&& ((wsaErrno = WSAGetLastError()) != WSAEWOULDBLOCK)
83*c2c66affSColin Finck 		&& (wsaErrno != WSAEINPROGRESS)
84*c2c66affSColin Finck #else
85*c2c66affSColin Finck 		&& (errno != EWOULDBLOCK) && (errno != EINPROGRESS)
86*c2c66affSColin Finck #endif
87*c2c66affSColin Finck 		) {
88*c2c66affSColin Finck 		SETERRNO
89*c2c66affSColin Finck 		shutdown(sfd, 2);
90*c2c66affSColin Finck 		return (-1);
91*c2c66affSColin Finck 	}
92*c2c66affSColin Finck 	cErrno = errno;
93*c2c66affSColin Finck 
94*c2c66affSColin Finck 	forever {
95*c2c66affSColin Finck #if defined(WIN32) || defined(_WINDOWS)
96*c2c66affSColin Finck 		WSASetLastError(0);
97*c2c66affSColin Finck #endif
98*c2c66affSColin Finck 		FD_ZERO(&ss);
99*c2c66affSColin Finck 		FD_SET(sfd, &ss);
100*c2c66affSColin Finck 		xx = ss;
101*c2c66affSColin Finck 		tv.tv_sec = tlen;
102*c2c66affSColin Finck 		tv.tv_usec = 0;
103*c2c66affSColin Finck 		result = select(sfd + 1, NULL, SELECT_TYPE_ARG234 &ss, SELECT_TYPE_ARG234 &xx, SELECT_TYPE_ARG5 &tv);
104*c2c66affSColin Finck 		if (result == 1) {
105*c2c66affSColin Finck 			/* ready */
106*c2c66affSColin Finck 			break;
107*c2c66affSColin Finck 		} else if (result == 0) {
108*c2c66affSColin Finck 			/* timeout */
109*c2c66affSColin Finck 			errno = ETIMEDOUT;
110*c2c66affSColin Finck 			SETWSATIMEOUTERR
111*c2c66affSColin Finck 			/* Don't bother turning off FIONBIO */
112*c2c66affSColin Finck 			return (kTimeoutErr);
113*c2c66affSColin Finck 		} else if (errno != EINTR) {
114*c2c66affSColin Finck 			/* Don't bother turning off FIONBIO */
115*c2c66affSColin Finck 			SETERRNO
116*c2c66affSColin Finck 			return (-1);
117*c2c66affSColin Finck 		}
118*c2c66affSColin Finck 	}
119*c2c66affSColin Finck 
120*c2c66affSColin Finck 	/* Supposedly once the select() returns with a writable
121*c2c66affSColin Finck 	 * descriptor, it is connected and we don't need to
122*c2c66affSColin Finck 	 * recall connect().  When select() returns an exception,
123*c2c66affSColin Finck 	 * the connection failed -- we can get the connect error
124*c2c66affSColin Finck 	 * doing a write on the socket which will err out.
125*c2c66affSColin Finck 	 */
126*c2c66affSColin Finck 
127*c2c66affSColin Finck 	if (FD_ISSET(sfd, &xx)) {
128*c2c66affSColin Finck #if defined(WIN32) || defined(_WINDOWS)
129*c2c66affSColin Finck 		errno = 0;
130*c2c66affSColin Finck 		soerr = 0;
131*c2c66affSColin Finck 		soerrsize = sizeof(soerr);
132*c2c66affSColin Finck 		result = getsockopt(sfd, SOL_SOCKET, SO_ERROR, (char *) &soerr, &soerrsize);
133*c2c66affSColin Finck 		if ((result >= 0) && (soerr != 0)) {
134*c2c66affSColin Finck 			errno = soerr;
135*c2c66affSColin Finck 		} else {
136*c2c66affSColin Finck 			errno = 0;
137*c2c66affSColin Finck 			(void) send(sfd, "\0", 1, 0);
138*c2c66affSColin Finck 			SETERRNO
139*c2c66affSColin Finck 		}
140*c2c66affSColin Finck #else
141*c2c66affSColin Finck 		errno = 0;
142*c2c66affSColin Finck 		(void) send(sfd, "\0", 1, 0);
143*c2c66affSColin Finck #endif
144*c2c66affSColin Finck 		result = errno;
145*c2c66affSColin Finck 		shutdown(sfd, 2);
146*c2c66affSColin Finck 		errno = result;
147*c2c66affSColin Finck 		return (-1);
148*c2c66affSColin Finck 	}
149*c2c66affSColin Finck 
150*c2c66affSColin Finck #if defined(WIN32) || defined(_WINDOWS)
151*c2c66affSColin Finck #else
152*c2c66affSColin Finck 	if (cErrno == EINPROGRESS) {
153*c2c66affSColin Finck 		/*
154*c2c66affSColin Finck 		 * [from Linux connect(2) page]
155*c2c66affSColin Finck 		 *
156*c2c66affSColin Finck 		 * EINPROGRESS
157*c2c66affSColin Finck 		 *
158*c2c66affSColin Finck 		 * The socket is non-blocking and the connection can�
159*c2c66affSColin Finck 		 * not  be  completed immediately.  It is possible to
160*c2c66affSColin Finck 		 * select(2) or poll(2) for completion  by  selecting
161*c2c66affSColin Finck 		 * the  socket  for  writing.  After select indicates
162*c2c66affSColin Finck 		 * writability,  use  getsockopt(2)   to   read   the
163*c2c66affSColin Finck 		 * SO_ERROR  option  at level SOL_SOCKET to determine
164*c2c66affSColin Finck 		 * whether connect completed  successfully  (SO_ERROR
165*c2c66affSColin Finck 		 * is zero) or unsuccessfully (SO_ERROR is one of the
166*c2c66affSColin Finck 		 * usual error codes  listed  above,  explaining  the
167*c2c66affSColin Finck 		 * reason for the failure).
168*c2c66affSColin Finck 	         */
169*c2c66affSColin Finck 		optval = 0;
170*c2c66affSColin Finck 		optlen = sizeof(optval);
171*c2c66affSColin Finck 		if (getsockopt(sfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == 0) {
172*c2c66affSColin Finck 			errno = optval;
173*c2c66affSColin Finck 			if (errno != 0)
174*c2c66affSColin Finck 				return (-1);
175*c2c66affSColin Finck 		}
176*c2c66affSColin Finck 	}
177*c2c66affSColin Finck #endif
178*c2c66affSColin Finck 
179*c2c66affSColin Finck #ifdef FIONBIO
180*c2c66affSColin Finck 	opt = 0;
181*c2c66affSColin Finck 	if (ioctlsocket(sfd, FIONBIO, &opt) != 0) {
182*c2c66affSColin Finck 		SETERRNO
183*c2c66affSColin Finck 		shutdown(sfd, 2);
184*c2c66affSColin Finck 		return (-1);
185*c2c66affSColin Finck 	}
186*c2c66affSColin Finck #else
187*c2c66affSColin Finck 	if (fcntl(sfd, F_SETFL, opt) < 0) {
188*c2c66affSColin Finck 		SETERRNO
189*c2c66affSColin Finck 		shutdown(sfd, 2);
190*c2c66affSColin Finck 		return (-1);
191*c2c66affSColin Finck 	}
192*c2c66affSColin Finck #endif
193*c2c66affSColin Finck 
194*c2c66affSColin Finck 	return (0);
195*c2c66affSColin Finck #endif	/* NO_SIGNALS */
196*c2c66affSColin Finck }	/* SConnect */
197