errrno can by freak accident become EINTR on DOS or
[platform/upstream/curl.git] / lib / select.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, 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 #ifdef WIN32
54 #define VALID_SOCK(s) (1)  /* Win-sockets are not in range [0..FD_SETSIZE> */
55 #else
56 #define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
57 #endif
58
59 /*
60  * This is an internal function used for waiting for read or write
61  * events on single file descriptors.  It attempts to replace select()
62  * in order to avoid limits with FD_SETSIZE.
63  *
64  * Return values:
65  *   -1 = system call error
66  *    0 = timeout
67  *    CSELECT_IN | CSELECT_OUT | CSELECT_ERR
68  */
69 int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
70 {
71 #ifdef HAVE_POLL_FINE
72   struct pollfd pfd[2];
73   int num;
74   int r;
75   int ret;
76
77   num = 0;
78   if (readfd != CURL_SOCKET_BAD) {
79     pfd[num].fd = readfd;
80     pfd[num].events = POLLIN;
81     num++;
82   }
83   if (writefd != CURL_SOCKET_BAD) {
84     pfd[num].fd = writefd;
85     pfd[num].events = POLLOUT;
86     num++;
87   }
88
89   do {
90     r = poll(pfd, num, timeout_ms);
91   } while((r == -1) && (errno == EINTR));
92
93   if (r < 0)
94     return -1;
95   if (r == 0)
96     return 0;
97
98   ret = 0;
99   num = 0;
100   if (readfd != CURL_SOCKET_BAD) {
101     if (pfd[num].revents & POLLIN)
102       ret |= CSELECT_IN;
103     if (pfd[num].revents & POLLERR)
104       ret |= CSELECT_ERR;
105     num++;
106   }
107   if (writefd != CURL_SOCKET_BAD) {
108     if (pfd[num].revents & POLLOUT)
109       ret |= CSELECT_OUT;
110     if (pfd[num].revents & POLLERR)
111       ret |= CSELECT_ERR;
112   }
113
114   return ret;
115 #else
116   struct timeval timeout;
117   fd_set fds_read;
118   fd_set fds_write;
119   fd_set fds_err;
120   curl_socket_t maxfd;
121   int r;
122   int ret;
123
124   timeout.tv_sec = timeout_ms / 1000;
125   timeout.tv_usec = (timeout_ms % 1000) * 1000;
126
127   FD_ZERO(&fds_err);
128   maxfd = -1;
129
130   FD_ZERO(&fds_read);
131   if (readfd != CURL_SOCKET_BAD) {
132     if (!VALID_SOCK(readfd)) {
133       errno = EINVAL;
134       return -1;
135     }
136     FD_SET(readfd, &fds_read);
137     FD_SET(readfd, &fds_err);
138     maxfd = readfd;
139   }
140
141   FD_ZERO(&fds_write);
142   if (writefd != CURL_SOCKET_BAD) {
143     if (!VALID_SOCK(writefd)) {
144       errno = EINVAL;
145       return -1;
146     }
147     FD_SET(writefd, &fds_write);
148     FD_SET(writefd, &fds_err);
149     if (writefd > maxfd)
150       maxfd = writefd;
151   }
152
153   do {
154     r = select(maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout);
155   } while((r == -1) && (Curl_ourerrno() == EINTR));
156
157   if (r < 0)
158     return -1;
159   if (r == 0)
160     return 0;
161
162   ret = 0;
163   if (readfd != CURL_SOCKET_BAD) {
164     if (FD_ISSET(readfd, &fds_read))
165       ret |= CSELECT_IN;
166     if (FD_ISSET(readfd, &fds_err))
167       ret |= CSELECT_ERR;
168   }
169   if (writefd != CURL_SOCKET_BAD) {
170     if (FD_ISSET(writefd, &fds_write))
171       ret |= CSELECT_OUT;
172     if (FD_ISSET(writefd, &fds_err))
173       ret |= CSELECT_ERR;
174   }
175
176   return ret;
177 #endif
178 }
179
180 /*
181  * This is a wrapper around poll().  If poll() does not exist, then
182  * select() is used instead.  An error is returned if select() is
183  * being used and a file descriptor too large for FD_SETSIZE.
184  *
185  * Return values:
186  *   -1 = system call error or fd >= FD_SETSIZE
187  *    0 = timeout
188  *    1 = number of structures with non zero revent fields
189  */
190 int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
191 {
192   int r;
193 #ifdef HAVE_POLL_FINE
194   do {
195     r = poll(ufds, nfds, timeout_ms);
196   } while((r == -1) && (errno == EINTR));
197 #else
198   struct timeval timeout;
199   struct timeval *ptimeout;
200   fd_set fds_read;
201   fd_set fds_write;
202   fd_set fds_err;
203   curl_socket_t maxfd;
204   unsigned int i;
205
206   FD_ZERO(&fds_read);
207   FD_ZERO(&fds_write);
208   FD_ZERO(&fds_err);
209   maxfd = -1;
210
211   for (i = 0; i < nfds; i++) {
212     if (ufds[i].fd == CURL_SOCKET_BAD)
213       continue;
214 #ifndef WIN32  /* This is harmless and wrong on Win32 */
215     if (ufds[i].fd >= FD_SETSIZE) {
216       errno = EINVAL;
217       return -1;
218     }
219 #endif
220     if (ufds[i].fd > maxfd)
221       maxfd = ufds[i].fd;
222     if (ufds[i].events & POLLIN)
223       FD_SET(ufds[i].fd, &fds_read);
224     if (ufds[i].events & POLLOUT)
225       FD_SET(ufds[i].fd, &fds_write);
226     if (ufds[i].events & POLLERR)
227       FD_SET(ufds[i].fd, &fds_err);
228   }
229
230   if (timeout_ms < 0) {
231     ptimeout = NULL;      /* wait forever */
232   } else {
233     timeout.tv_sec = timeout_ms / 1000;
234     timeout.tv_usec = (timeout_ms % 1000) * 1000;
235     ptimeout = &timeout;
236   }
237
238   do {
239     r = select(maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
240   } while((r == -1) && (Curl_ourerrno() == EINTR));
241
242   if (r < 0)
243     return -1;
244   if (r == 0)
245     return 0;
246
247   r = 0;
248   for (i = 0; i < nfds; i++) {
249     ufds[i].revents = 0;
250     if (ufds[i].fd == CURL_SOCKET_BAD)
251       continue;
252     if (FD_ISSET(ufds[i].fd, &fds_read))
253       ufds[i].revents |= POLLIN;
254     if (FD_ISSET(ufds[i].fd, &fds_write))
255       ufds[i].revents |= POLLOUT;
256     if (FD_ISSET(ufds[i].fd, &fds_err))
257       ufds[i].revents |= POLLERR;
258     if (ufds[i].revents != 0)
259       r++;
260   }
261 #endif
262   return r;
263 }