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