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