Cygwin 1.5.21 needs this hack to pass test 160.
[platform/upstream/curl.git] / lib / select.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id$
22  ***************************************************************************/
23
24 #include "setup.h"
25
26 #include <errno.h>
27
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 #ifdef HAVE_SYS_SELECT_H
32 #include <sys/select.h>
33 #endif
34 #ifdef HAVE_SYS_TIME_H
35 #include <sys/time.h>
36 #endif
37
38 #ifndef HAVE_SELECT
39 #error "We can't compile without select() support!"
40 #endif
41
42 #ifdef __BEOS__
43 /* BeOS has FD_SET defined in socket.h */
44 #include <socket.h>
45 #endif
46
47 #include <curl/curl.h>
48
49 #include "urldata.h"
50 #include "connect.h"
51 #include "select.h"
52
53 #if defined(WIN32) || defined(TPF)
54 #define VERIFY_SOCK(x)  /* sockets are not in range [0..FD_SETSIZE] */
55 #else
56 #define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
57 #define VERIFY_SOCK(x) do { \
58   if(!VALID_SOCK(x)) { \
59     errno = EINVAL; \
60     return -1; \
61   } \
62 } while(0)
63 #endif
64
65 /*
66  * This is an internal function used for waiting for read or write
67  * events on single file descriptors.  It attempts to replace select()
68  * in order to avoid limits with FD_SETSIZE.
69  *
70  * Return values:
71  *   -1 = system call error
72  *    0 = timeout
73  *    CSELECT_IN | CSELECT_OUT | CSELECT_ERR
74  */
75 int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
76 {
77 #if defined(HAVE_POLL_FINE) || defined(CURL_HAVE_WSAPOLL)
78   struct pollfd pfd[2];
79   int num;
80   int r;
81   int ret;
82
83   num = 0;
84   if (readfd != CURL_SOCKET_BAD) {
85     pfd[num].fd = readfd;
86     pfd[num].events = POLLIN;
87     num++;
88   }
89   if (writefd != CURL_SOCKET_BAD) {
90     pfd[num].fd = writefd;
91     pfd[num].events = POLLOUT;
92     num++;
93   }
94
95 #ifdef HAVE_POLL_FINE
96   do {
97     r = poll(pfd, num, timeout_ms);
98   } while((r == -1) && (errno == EINTR));
99 #else
100   r = WSAPoll(pfd, num, timeout_ms);
101 #endif
102
103   if (r < 0)
104     return -1;
105   if (r == 0)
106     return 0;
107
108   ret = 0;
109   num = 0;
110   if (readfd != CURL_SOCKET_BAD) {
111     if (pfd[num].revents & (POLLIN|POLLHUP))
112       ret |= CSELECT_IN;
113     if (pfd[num].revents & POLLERR) {
114 #ifdef __CYGWIN__ 
115       /* Cygwin 1.5.21 needs this hack to pass test 160 */
116       if (errno == EINPROGRESS)
117         ret |= CSELECT_IN;
118       else
119 #endif
120         ret |= CSELECT_ERR;
121     }
122     num++;
123   }
124   if (writefd != CURL_SOCKET_BAD) {
125     if (pfd[num].revents & POLLOUT)
126       ret |= CSELECT_OUT;
127     if (pfd[num].revents & POLLERR)
128       ret |= CSELECT_ERR;
129   }
130
131   return ret;
132 #else
133   struct timeval timeout;
134   fd_set fds_read;
135   fd_set fds_write;
136   fd_set fds_err;
137   curl_socket_t maxfd;
138   int r;
139   int ret;
140
141   timeout.tv_sec = timeout_ms / 1000;
142   timeout.tv_usec = (timeout_ms % 1000) * 1000;
143
144   FD_ZERO(&fds_err);
145   maxfd = (curl_socket_t)-1;
146
147   FD_ZERO(&fds_read);
148   if (readfd != CURL_SOCKET_BAD) {
149     VERIFY_SOCK(readfd);
150     FD_SET(readfd, &fds_read);
151     FD_SET(readfd, &fds_err);
152     maxfd = readfd;
153   }
154
155   FD_ZERO(&fds_write);
156   if (writefd != CURL_SOCKET_BAD) {
157     VERIFY_SOCK(writefd);
158     FD_SET(writefd, &fds_write);
159     FD_SET(writefd, &fds_err);
160     if (writefd > maxfd)
161       maxfd = writefd;
162   }
163
164   do {
165     r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout);
166   } while((r == -1) && (Curl_sockerrno() == EINTR));
167
168   if (r < 0)
169     return -1;
170   if (r == 0)
171     return 0;
172
173   ret = 0;
174   if (readfd != CURL_SOCKET_BAD) {
175     if (FD_ISSET(readfd, &fds_read))
176       ret |= CSELECT_IN;
177     if (FD_ISSET(readfd, &fds_err))
178       ret |= CSELECT_ERR;
179   }
180   if (writefd != CURL_SOCKET_BAD) {
181     if (FD_ISSET(writefd, &fds_write))
182       ret |= CSELECT_OUT;
183     if (FD_ISSET(writefd, &fds_err))
184       ret |= CSELECT_ERR;
185   }
186
187   return ret;
188 #endif
189 }
190
191 /*
192  * This is a wrapper around poll().  If poll() does not exist, then
193  * select() is used instead.  An error is returned if select() is
194  * being used and a file descriptor too large for FD_SETSIZE.
195  *
196  * Return values:
197  *   -1 = system call error or fd >= FD_SETSIZE
198  *    0 = timeout
199  *    1 = number of structures with non zero revent fields
200  */
201 int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
202 {
203   int r;
204 #ifdef HAVE_POLL_FINE
205   do {
206     r = poll(ufds, nfds, timeout_ms);
207   } while((r == -1) && (errno == EINTR));
208 #elif defined(CURL_HAVE_WSAPOLL)
209   r = WSAPoll(ufds, nfds, timeout_ms);
210 #else
211   struct timeval timeout;
212   struct timeval *ptimeout;
213   fd_set fds_read;
214   fd_set fds_write;
215   fd_set fds_err;
216   curl_socket_t maxfd;
217   unsigned int i;
218
219   FD_ZERO(&fds_read);
220   FD_ZERO(&fds_write);
221   FD_ZERO(&fds_err);
222   maxfd = (curl_socket_t)-1;
223
224   for (i = 0; i < nfds; i++) {
225     if (ufds[i].fd == CURL_SOCKET_BAD)
226       continue;
227 #ifndef WIN32  /* This is harmless and wrong on Win32 */
228     if (ufds[i].fd >= FD_SETSIZE) {
229       errno = EINVAL;
230       return -1;
231     }
232 #endif
233     if (ufds[i].fd > maxfd)
234       maxfd = ufds[i].fd;
235     if (ufds[i].events & POLLIN)
236       FD_SET(ufds[i].fd, &fds_read);
237     if (ufds[i].events & POLLOUT)
238       FD_SET(ufds[i].fd, &fds_write);
239     if (ufds[i].events & POLLERR)
240       FD_SET(ufds[i].fd, &fds_err);
241   }
242
243   if (timeout_ms < 0) {
244     ptimeout = NULL;      /* wait forever */
245   } else {
246     timeout.tv_sec = timeout_ms / 1000;
247     timeout.tv_usec = (timeout_ms % 1000) * 1000;
248     ptimeout = &timeout;
249   }
250
251   do {
252     r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
253   } while((r == -1) && (Curl_sockerrno() == EINTR));
254
255   if (r < 0)
256     return -1;
257   if (r == 0)
258     return 0;
259
260   r = 0;
261   for (i = 0; i < nfds; i++) {
262     ufds[i].revents = 0;
263     if (ufds[i].fd == CURL_SOCKET_BAD)
264       continue;
265     if (FD_ISSET(ufds[i].fd, &fds_read))
266       ufds[i].revents |= POLLIN;
267     if (FD_ISSET(ufds[i].fd, &fds_write))
268       ufds[i].revents |= POLLOUT;
269     if (FD_ISSET(ufds[i].fd, &fds_err))
270       ufds[i].revents |= POLLERR;
271     if (ufds[i].revents != 0)
272       r++;
273   }
274 #endif
275   return r;
276 }
277
278 #ifdef TPF
279 /*
280  * This is a replacement for select() on the TPF platform.
281  * It is used whenever libcurl calls select().
282  * The call below to tpf_process_signals() is required because
283  * TPF's select calls are not signal interruptible.
284  *
285  * Return values are the same as select's.
286  */
287 int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
288                        fd_set* excepts, struct timeval* tv)
289 {
290    int rc;
291
292    rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
293    tpf_process_signals();
294    return(rc);
295 }
296 #endif /* TPF */