Fixed signed/unsigned convertion errors in Salford-C.
[platform/upstream/curl.git] / lib / select.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2005, 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 #ifdef HAVE_POLL_FINE
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   do {
96     r = poll(pfd, num, timeout_ms);
97   } while((r == -1) && (errno == EINTR));
98
99   if (r < 0)
100     return -1;
101   if (r == 0)
102     return 0;
103
104   ret = 0;
105   num = 0;
106   if (readfd != CURL_SOCKET_BAD) {
107     if (pfd[num].revents & (POLLIN|POLLHUP))
108       ret |= CSELECT_IN;
109     if (pfd[num].revents & POLLERR)
110       ret |= CSELECT_ERR;
111     num++;
112   }
113   if (writefd != CURL_SOCKET_BAD) {
114     if (pfd[num].revents & POLLOUT)
115       ret |= CSELECT_OUT;
116     if (pfd[num].revents & POLLERR)
117       ret |= CSELECT_ERR;
118   }
119
120   return ret;
121 #else
122   struct timeval timeout;
123   fd_set fds_read;
124   fd_set fds_write;
125   fd_set fds_err;
126   curl_socket_t maxfd;
127   int r;
128   int ret;
129
130   timeout.tv_sec = timeout_ms / 1000;
131   timeout.tv_usec = (timeout_ms % 1000) * 1000;
132
133   FD_ZERO(&fds_err);
134   maxfd = (curl_socket_t)-1;
135
136   FD_ZERO(&fds_read);
137   if (readfd != CURL_SOCKET_BAD) {
138     VERIFY_SOCK(readfd);
139     FD_SET(readfd, &fds_read);
140     FD_SET(readfd, &fds_err);
141     maxfd = readfd;
142   }
143
144   FD_ZERO(&fds_write);
145   if (writefd != CURL_SOCKET_BAD) {
146     VERIFY_SOCK(writefd);
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((int)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 = (curl_socket_t)-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((int)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 }
264
265 #ifdef TPF
266 /*
267  * This is a replacement for select() on the TPF platform.
268  * It is used whenever libcurl calls select().
269  * The call below to tpf_process_signals() is required because
270  * TPF's select calls are not signal interruptible.
271  *
272  * Return values are the same as select's.
273  */
274 int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
275                        fd_set* excepts, struct timeval* tv)
276 {
277    int rc;
278
279    rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
280    tpf_process_signals();
281    return(rc);
282 }
283 #endif /* TPF */