Marcin Konicki provided two configure fixes and a source fix to make curl
[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 #ifdef HAVE_SYS_TYPES_H
27 #include <sys/types.h>
28 #endif
29 #ifdef HAVE_SYS_SELECT_H
30 #include <sys/select.h>
31 #endif
32 #ifdef HAVE_SYS_TIME_H
33 #include <sys/time.h>
34 #endif
35
36 #ifndef HAVE_SELECT
37 #error "We can't compile without select() support!"
38 #endif
39
40 #include "select.h"
41
42 #ifdef __BEOS__
43 /* BeOS has FD_SET defined in socket.h */
44 #include <socket.h>
45 #endif
46
47 #ifdef WIN32
48 #define VALID_SOCK(s) (1)  /* Win-sockets are not in range [0..FD_SETSIZE> */
49 #else
50 #define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
51 #endif
52
53 /*
54  * This is an internal function used for waiting for read or write
55  * events on single file descriptors.  It attempts to replace select()
56  * in order to avoid limits with FD_SETSIZE.
57  *
58  * Return values:
59  *   -1 = system call error
60  *    0 = timeout
61  *    CSELECT_IN | CSELECT_OUT | CSELECT_ERR
62  */
63 int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
64 {
65 #ifdef HAVE_POLL_FINE
66   struct pollfd pfd[2];
67   int num;
68   int r;
69   int ret;
70
71   num = 0;
72   if (readfd != CURL_SOCKET_BAD) {
73     pfd[num].fd = readfd;
74     pfd[num].events = POLLIN;
75     num++;
76   }
77   if (writefd != CURL_SOCKET_BAD) {
78     pfd[num].fd = writefd;
79     pfd[num].events = POLLOUT;
80     num++;
81   }
82
83   r = poll(pfd, num, timeout_ms);
84
85   if (r < 0)
86     return -1;
87   if (r == 0)
88     return 0;
89
90   ret = 0;
91   num = 0;
92   if (readfd != CURL_SOCKET_BAD) {
93     if (pfd[num].revents & POLLIN)
94       ret |= CSELECT_IN;
95     if (pfd[num].revents & POLLERR)
96       ret |= CSELECT_ERR;
97     num++;
98   }
99   if (writefd != CURL_SOCKET_BAD) {
100     if (pfd[num].revents & POLLOUT)
101       ret |= CSELECT_OUT;
102     if (pfd[num].revents & POLLERR)
103       ret |= CSELECT_ERR;
104   }
105
106   return ret;
107 #else
108   struct timeval timeout;
109   fd_set fds_read;
110   fd_set fds_write;
111   fd_set fds_err;
112   curl_socket_t maxfd;
113   int r;
114   int ret;
115
116   timeout.tv_sec = timeout_ms / 1000;
117   timeout.tv_usec = (timeout_ms % 1000) * 1000;
118
119   FD_ZERO(&fds_err);
120   maxfd = -1;
121
122   FD_ZERO(&fds_read);
123   if (readfd != CURL_SOCKET_BAD) {
124     if (!VALID_SOCK(readfd)) {
125       errno = EINVAL;
126       return -1;
127     }
128     FD_SET(readfd, &fds_read);
129     FD_SET(readfd, &fds_err);
130     maxfd = readfd;
131   }
132
133   FD_ZERO(&fds_write);
134   if (writefd != CURL_SOCKET_BAD) {
135     if (!VALID_SOCK(writefd)) {
136       errno = EINVAL;
137       return -1;
138     }
139     FD_SET(writefd, &fds_write);
140     FD_SET(writefd, &fds_err);
141     if (writefd > maxfd)
142       maxfd = writefd;
143   }
144
145   r = select(maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout);
146
147   if (r < 0)
148     return -1;
149   if (r == 0)
150     return 0;
151
152   ret = 0;
153   if (readfd != CURL_SOCKET_BAD) {
154     if (FD_ISSET(readfd, &fds_read))
155       ret |= CSELECT_IN;
156     if (FD_ISSET(readfd, &fds_err))
157       ret |= CSELECT_ERR;
158   }
159   if (writefd != CURL_SOCKET_BAD) {
160     if (FD_ISSET(writefd, &fds_write))
161       ret |= CSELECT_OUT;
162     if (FD_ISSET(writefd, &fds_err))
163       ret |= CSELECT_ERR;
164   }
165
166   return ret;
167 #endif
168 }
169
170 /*
171  * This is a wrapper around poll().  If poll() does not exist, then
172  * select() is used instead.  An error is returned if select() is
173  * being used and a file descriptor too large for FD_SETSIZE.
174  *
175  * Return values:
176  *   -1 = system call error or fd >= FD_SETSIZE
177  *    0 = timeout
178  *    1 = number of structures with non zero revent fields
179  */
180 int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
181 {
182 #ifdef HAVE_POLL_FINE
183     return poll(ufds, nfds, timeout_ms);
184 #else
185   struct timeval timeout;
186   struct timeval *ptimeout;
187   fd_set fds_read;
188   fd_set fds_write;
189   fd_set fds_err;
190   curl_socket_t maxfd;
191   int r;
192   unsigned int i;
193
194   FD_ZERO(&fds_read);
195   FD_ZERO(&fds_write);
196   FD_ZERO(&fds_err);
197   maxfd = -1;
198
199   for (i = 0; i < nfds; i++) {
200     if (ufds[i].fd == CURL_SOCKET_BAD)
201       continue;
202 #ifndef WIN32  /* This is harmless and wrong on Win32 */
203     if (ufds[i].fd >= FD_SETSIZE) {
204       errno = EINVAL;
205       return -1;
206     }
207 #endif
208     if (ufds[i].fd > maxfd)
209       maxfd = ufds[i].fd;
210     if (ufds[i].events & POLLIN)
211       FD_SET(ufds[i].fd, &fds_read);
212     if (ufds[i].events & POLLOUT)
213       FD_SET(ufds[i].fd, &fds_write);
214     if (ufds[i].events & POLLERR)
215       FD_SET(ufds[i].fd, &fds_err);
216   }
217
218   if (timeout_ms < 0) {
219     ptimeout = NULL;      /* wait forever */
220   } else {
221     timeout.tv_sec = timeout_ms / 1000;
222     timeout.tv_usec = (timeout_ms % 1000) * 1000;
223     ptimeout = &timeout;
224   }
225
226   r = select(maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
227
228   if (r < 0)
229     return -1;
230   if (r == 0)
231     return 0;
232
233   r = 0;
234   for (i = 0; i < nfds; i++) {
235     ufds[i].revents = 0;
236     if (ufds[i].fd == CURL_SOCKET_BAD)
237       continue;
238     if (FD_ISSET(ufds[i].fd, &fds_read))
239       ufds[i].revents |= POLLIN;
240     if (FD_ISSET(ufds[i].fd, &fds_write))
241       ufds[i].revents |= POLLOUT;
242     if (FD_ISSET(ufds[i].fd, &fds_err))
243       ufds[i].revents |= POLLERR;
244     if (ufds[i].revents != 0)
245       r++;
246   }
247
248   return r;
249 #endif
250 }