xref: /curl/lib/select.c (revision f81f351b)
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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 https://curl.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  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #include <limits.h>
28 
29 #ifdef HAVE_SYS_SELECT_H
30 #include <sys/select.h>
31 #elif defined(HAVE_UNISTD_H)
32 #include <unistd.h>
33 #endif
34 
35 #if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
36 #error "We cannot compile without select() or poll() support."
37 #endif
38 
39 #ifdef MSDOS
40 #include <dos.h>  /* delay() */
41 #endif
42 
43 #include <curl/curl.h>
44 
45 #include "urldata.h"
46 #include "connect.h"
47 #include "select.h"
48 #include "timediff.h"
49 #include "warnless.h"
50 /* The last 3 #include files should be in this order */
51 #include "curl_printf.h"
52 #include "curl_memory.h"
53 #include "memdebug.h"
54 
55 /*
56  * Internal function used for waiting a specific amount of ms
57  * in Curl_socket_check() and Curl_poll() when no file descriptor
58  * is provided to wait on, just being used to delay execution.
59  * Winsock select() and poll() timeout mechanisms need a valid
60  * socket descriptor in a not null file descriptor set to work.
61  * Waiting indefinitely with this function is not allowed, a
62  * zero or negative timeout value will return immediately.
63  * Timeout resolution, accuracy, as well as maximum supported
64  * value is system dependent, neither factor is a critical issue
65  * for the intended use of this function in the library.
66  *
67  * Return values:
68  *   -1 = system call error, or invalid timeout value
69  *    0 = specified timeout has elapsed, or interrupted
70  */
Curl_wait_ms(timediff_t timeout_ms)71 int Curl_wait_ms(timediff_t timeout_ms)
72 {
73   int r = 0;
74 
75   if(!timeout_ms)
76     return 0;
77   if(timeout_ms < 0) {
78     SET_SOCKERRNO(EINVAL);
79     return -1;
80   }
81 #if defined(MSDOS)
82   delay(timeout_ms);
83 #elif defined(_WIN32)
84   /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
85 #if TIMEDIFF_T_MAX >= ULONG_MAX
86   if(timeout_ms >= ULONG_MAX)
87     timeout_ms = ULONG_MAX-1;
88     /* do not use ULONG_MAX, because that is equal to INFINITE */
89 #endif
90   Sleep((ULONG)timeout_ms);
91 #else
92 #if defined(HAVE_POLL_FINE)
93   /* prevent overflow, timeout_ms is typecast to int. */
94 #if TIMEDIFF_T_MAX > INT_MAX
95   if(timeout_ms > INT_MAX)
96     timeout_ms = INT_MAX;
97 #endif
98   r = poll(NULL, 0, (int)timeout_ms);
99 #else
100   {
101     struct timeval pending_tv;
102     r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms));
103   }
104 #endif /* HAVE_POLL_FINE */
105 #endif /* USE_WINSOCK */
106   if(r) {
107     if((r == -1) && (SOCKERRNO == EINTR))
108       /* make EINTR from select or poll not a "lethal" error */
109       r = 0;
110     else
111       r = -1;
112   }
113   return r;
114 }
115 
116 #ifndef HAVE_POLL_FINE
117 /*
118  * This is a wrapper around select() to aid in Windows compatibility.
119  * A negative timeout value makes this function wait indefinitely,
120  * unless no valid file descriptor is given, when this happens the
121  * negative timeout is ignored and the function times out immediately.
122  *
123  * Return values:
124  *   -1 = system call error or fd >= FD_SETSIZE
125  *    0 = timeout
126  *    N = number of signalled file descriptors
127  */
our_select(curl_socket_t maxfd,fd_set * fds_read,fd_set * fds_write,fd_set * fds_err,timediff_t timeout_ms)128 static int our_select(curl_socket_t maxfd,   /* highest socket number */
129                       fd_set *fds_read,      /* sockets ready for reading */
130                       fd_set *fds_write,     /* sockets ready for writing */
131                       fd_set *fds_err,       /* sockets with errors */
132                       timediff_t timeout_ms) /* milliseconds to wait */
133 {
134   struct timeval pending_tv;
135   struct timeval *ptimeout;
136 
137 #ifdef USE_WINSOCK
138   /* Winsock select() cannot handle zero events. See the comment below. */
139   if((!fds_read || fds_read->fd_count == 0) &&
140      (!fds_write || fds_write->fd_count == 0) &&
141      (!fds_err || fds_err->fd_count == 0)) {
142     /* no sockets, just wait */
143     return Curl_wait_ms(timeout_ms);
144   }
145 #endif
146 
147   ptimeout = curlx_mstotv(&pending_tv, timeout_ms);
148 
149 #ifdef USE_WINSOCK
150   /* Winsock select() must not be called with an fd_set that contains zero
151     fd flags, or it will return WSAEINVAL. But, it also cannot be called
152     with no fd_sets at all!  From the documentation:
153 
154     Any two of the parameters, readfds, writefds, or exceptfds, can be
155     given as null. At least one must be non-null, and any non-null
156     descriptor set must contain at least one handle to a socket.
157 
158     It is unclear why Winsock does not just handle this for us instead of
159     calling this an error. Luckily, with Winsock, we can _also_ ask how
160     many bits are set on an fd_set. So, let's just check it beforehand.
161   */
162   return select((int)maxfd + 1,
163                 fds_read && fds_read->fd_count ? fds_read : NULL,
164                 fds_write && fds_write->fd_count ? fds_write : NULL,
165                 fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
166 #else
167   return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
168 #endif
169 }
170 
171 #endif
172 
173 /*
174  * Wait for read or write events on a set of file descriptors. It uses poll()
175  * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
176  * otherwise select() is used. An error is returned if select() is being used
177  * and a file descriptor is too large for FD_SETSIZE.
178  *
179  * A negative timeout value makes this function wait indefinitely,
180  * unless no valid file descriptor is given, when this happens the
181  * negative timeout is ignored and the function times out immediately.
182  *
183  * Return values:
184  *   -1 = system call error or fd >= FD_SETSIZE
185  *    0 = timeout
186  *    [bitmask] = action as described below
187  *
188  * CURL_CSELECT_IN - first socket is readable
189  * CURL_CSELECT_IN2 - second socket is readable
190  * CURL_CSELECT_OUT - write socket is writable
191  * CURL_CSELECT_ERR - an error condition occurred
192  */
Curl_socket_check(curl_socket_t readfd0,curl_socket_t readfd1,curl_socket_t writefd,timediff_t timeout_ms)193 int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
194                       curl_socket_t readfd1,
195                       curl_socket_t writefd, /* socket to write to */
196                       timediff_t timeout_ms) /* milliseconds to wait */
197 {
198   struct pollfd pfd[3];
199   int num;
200   int r;
201 
202   if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
203      (writefd == CURL_SOCKET_BAD)) {
204     /* no sockets, just wait */
205     return Curl_wait_ms(timeout_ms);
206   }
207 
208   /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
209      time in this function does not need to be measured. This happens
210      when function is called with a zero timeout or a negative timeout
211      value indicating a blocking call should be performed. */
212 
213   num = 0;
214   if(readfd0 != CURL_SOCKET_BAD) {
215     pfd[num].fd = readfd0;
216     pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
217     pfd[num].revents = 0;
218     num++;
219   }
220   if(readfd1 != CURL_SOCKET_BAD) {
221     pfd[num].fd = readfd1;
222     pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
223     pfd[num].revents = 0;
224     num++;
225   }
226   if(writefd != CURL_SOCKET_BAD) {
227     pfd[num].fd = writefd;
228     pfd[num].events = POLLWRNORM|POLLOUT|POLLPRI;
229     pfd[num].revents = 0;
230     num++;
231   }
232 
233   r = Curl_poll(pfd, (unsigned int)num, timeout_ms);
234   if(r <= 0)
235     return r;
236 
237   r = 0;
238   num = 0;
239   if(readfd0 != CURL_SOCKET_BAD) {
240     if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
241       r |= CURL_CSELECT_IN;
242     if(pfd[num].revents & (POLLPRI|POLLNVAL))
243       r |= CURL_CSELECT_ERR;
244     num++;
245   }
246   if(readfd1 != CURL_SOCKET_BAD) {
247     if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
248       r |= CURL_CSELECT_IN2;
249     if(pfd[num].revents & (POLLPRI|POLLNVAL))
250       r |= CURL_CSELECT_ERR;
251     num++;
252   }
253   if(writefd != CURL_SOCKET_BAD) {
254     if(pfd[num].revents & (POLLWRNORM|POLLOUT))
255       r |= CURL_CSELECT_OUT;
256     if(pfd[num].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL))
257       r |= CURL_CSELECT_ERR;
258   }
259 
260   return r;
261 }
262 
263 /*
264  * This is a wrapper around poll(). If poll() does not exist, then
265  * select() is used instead. An error is returned if select() is
266  * being used and a file descriptor is too large for FD_SETSIZE.
267  * A negative timeout value makes this function wait indefinitely,
268  * unless no valid file descriptor is given, when this happens the
269  * negative timeout is ignored and the function times out immediately.
270  *
271  * Return values:
272  *   -1 = system call error or fd >= FD_SETSIZE
273  *    0 = timeout
274  *    N = number of structures with non zero revent fields
275  */
Curl_poll(struct pollfd ufds[],unsigned int nfds,timediff_t timeout_ms)276 int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
277 {
278 #ifdef HAVE_POLL_FINE
279   int pending_ms;
280 #else
281   fd_set fds_read;
282   fd_set fds_write;
283   fd_set fds_err;
284   curl_socket_t maxfd;
285 #endif
286   bool fds_none = TRUE;
287   unsigned int i;
288   int r;
289 
290   if(ufds) {
291     for(i = 0; i < nfds; i++) {
292       if(ufds[i].fd != CURL_SOCKET_BAD) {
293         fds_none = FALSE;
294         break;
295       }
296     }
297   }
298   if(fds_none) {
299     /* no sockets, just wait */
300     return Curl_wait_ms(timeout_ms);
301   }
302 
303   /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
304      time in this function does not need to be measured. This happens
305      when function is called with a zero timeout or a negative timeout
306      value indicating a blocking call should be performed. */
307 
308 #ifdef HAVE_POLL_FINE
309 
310   /* prevent overflow, timeout_ms is typecast to int. */
311 #if TIMEDIFF_T_MAX > INT_MAX
312   if(timeout_ms > INT_MAX)
313     timeout_ms = INT_MAX;
314 #endif
315   if(timeout_ms > 0)
316     pending_ms = (int)timeout_ms;
317   else if(timeout_ms < 0)
318     pending_ms = -1;
319   else
320     pending_ms = 0;
321   r = poll(ufds, nfds, pending_ms);
322   if(r <= 0) {
323     if((r == -1) && (SOCKERRNO == EINTR))
324       /* make EINTR from select or poll not a "lethal" error */
325       r = 0;
326     return r;
327   }
328 
329   for(i = 0; i < nfds; i++) {
330     if(ufds[i].fd == CURL_SOCKET_BAD)
331       continue;
332     if(ufds[i].revents & POLLHUP)
333       ufds[i].revents |= POLLIN;
334     if(ufds[i].revents & POLLERR)
335       ufds[i].revents |= POLLIN|POLLOUT;
336   }
337 
338 #else  /* HAVE_POLL_FINE */
339 
340   FD_ZERO(&fds_read);
341   FD_ZERO(&fds_write);
342   FD_ZERO(&fds_err);
343   maxfd = (curl_socket_t)-1;
344 
345   for(i = 0; i < nfds; i++) {
346     ufds[i].revents = 0;
347     if(ufds[i].fd == CURL_SOCKET_BAD)
348       continue;
349     VERIFY_SOCK(ufds[i].fd);
350     if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
351                          POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
352       if(ufds[i].fd > maxfd)
353         maxfd = ufds[i].fd;
354       if(ufds[i].events & (POLLRDNORM|POLLIN))
355         FD_SET(ufds[i].fd, &fds_read);
356       if(ufds[i].events & (POLLWRNORM|POLLOUT))
357         FD_SET(ufds[i].fd, &fds_write);
358       if(ufds[i].events & (POLLRDBAND|POLLPRI))
359         FD_SET(ufds[i].fd, &fds_err);
360     }
361   }
362 
363   /*
364      Note also that Winsock ignores the first argument, so we do not worry
365      about the fact that maxfd is computed incorrectly with Winsock (since
366      curl_socket_t is unsigned in such cases and thus -1 is the largest
367      value).
368   */
369   r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
370   if(r <= 0) {
371     if((r == -1) && (SOCKERRNO == EINTR))
372       /* make EINTR from select or poll not a "lethal" error */
373       r = 0;
374     return r;
375   }
376 
377   r = 0;
378   for(i = 0; i < nfds; i++) {
379     ufds[i].revents = 0;
380     if(ufds[i].fd == CURL_SOCKET_BAD)
381       continue;
382     if(FD_ISSET(ufds[i].fd, &fds_read)) {
383       if(ufds[i].events & POLLRDNORM)
384         ufds[i].revents |= POLLRDNORM;
385       if(ufds[i].events & POLLIN)
386         ufds[i].revents |= POLLIN;
387     }
388     if(FD_ISSET(ufds[i].fd, &fds_write)) {
389       if(ufds[i].events & POLLWRNORM)
390         ufds[i].revents |= POLLWRNORM;
391       if(ufds[i].events & POLLOUT)
392         ufds[i].revents |= POLLOUT;
393     }
394     if(FD_ISSET(ufds[i].fd, &fds_err)) {
395       if(ufds[i].events & POLLRDBAND)
396         ufds[i].revents |= POLLRDBAND;
397       if(ufds[i].events & POLLPRI)
398         ufds[i].revents |= POLLPRI;
399     }
400     if(ufds[i].revents)
401       r++;
402   }
403 
404 #endif  /* HAVE_POLL_FINE */
405 
406   return r;
407 }
408 
Curl_pollfds_init(struct curl_pollfds * cpfds,struct pollfd * static_pfds,unsigned int static_count)409 void Curl_pollfds_init(struct curl_pollfds *cpfds,
410                        struct pollfd *static_pfds,
411                        unsigned int static_count)
412 {
413   DEBUGASSERT(cpfds);
414   memset(cpfds, 0, sizeof(*cpfds));
415   if(static_pfds && static_count) {
416     cpfds->pfds = static_pfds;
417     cpfds->count = static_count;
418   }
419 }
420 
Curl_pollfds_cleanup(struct curl_pollfds * cpfds)421 void Curl_pollfds_cleanup(struct curl_pollfds *cpfds)
422 {
423   DEBUGASSERT(cpfds);
424   if(cpfds->allocated_pfds) {
425     free(cpfds->pfds);
426   }
427   memset(cpfds, 0, sizeof(*cpfds));
428 }
429 
cpfds_increase(struct curl_pollfds * cpfds,unsigned int inc)430 static CURLcode cpfds_increase(struct curl_pollfds *cpfds, unsigned int inc)
431 {
432   struct pollfd *new_fds;
433   unsigned int new_count = cpfds->count + inc;
434 
435   new_fds = calloc(new_count, sizeof(struct pollfd));
436   if(!new_fds)
437     return CURLE_OUT_OF_MEMORY;
438 
439   memcpy(new_fds, cpfds->pfds, cpfds->count * sizeof(struct pollfd));
440   if(cpfds->allocated_pfds)
441     free(cpfds->pfds);
442   cpfds->pfds = new_fds;
443   cpfds->count = new_count;
444   cpfds->allocated_pfds = TRUE;
445   return CURLE_OK;
446 }
447 
cpfds_add_sock(struct curl_pollfds * cpfds,curl_socket_t sock,short events,bool fold)448 static CURLcode cpfds_add_sock(struct curl_pollfds *cpfds,
449                                curl_socket_t sock, short events, bool fold)
450 {
451   int i;
452 
453   if(fold && cpfds->n <= INT_MAX) {
454     for(i = (int)cpfds->n - 1; i >= 0; --i) {
455       if(sock == cpfds->pfds[i].fd) {
456         cpfds->pfds[i].events |= events;
457         return CURLE_OK;
458       }
459     }
460   }
461   /* not folded, add new entry */
462   if(cpfds->n >= cpfds->count) {
463     if(cpfds_increase(cpfds, 100))
464       return CURLE_OUT_OF_MEMORY;
465   }
466   cpfds->pfds[cpfds->n].fd = sock;
467   cpfds->pfds[cpfds->n].events = events;
468   ++cpfds->n;
469   return CURLE_OK;
470 }
471 
Curl_pollfds_add_sock(struct curl_pollfds * cpfds,curl_socket_t sock,short events)472 CURLcode Curl_pollfds_add_sock(struct curl_pollfds *cpfds,
473                                curl_socket_t sock, short events)
474 {
475   return cpfds_add_sock(cpfds, sock, events, FALSE);
476 }
477 
Curl_pollfds_add_ps(struct curl_pollfds * cpfds,struct easy_pollset * ps)478 CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
479                              struct easy_pollset *ps)
480 {
481   size_t i;
482 
483   DEBUGASSERT(cpfds);
484   DEBUGASSERT(ps);
485   for(i = 0; i < ps->num; i++) {
486     short events = 0;
487     if(ps->actions[i] & CURL_POLL_IN)
488       events |= POLLIN;
489     if(ps->actions[i] & CURL_POLL_OUT)
490       events |= POLLOUT;
491     if(events) {
492       if(cpfds_add_sock(cpfds, ps->sockets[i], events, TRUE))
493         return CURLE_OUT_OF_MEMORY;
494     }
495   }
496   return CURLE_OK;
497 }
498 
Curl_waitfds_init(struct curl_waitfds * cwfds,struct curl_waitfd * static_wfds,unsigned int static_count)499 void Curl_waitfds_init(struct curl_waitfds *cwfds,
500                        struct curl_waitfd *static_wfds,
501                        unsigned int static_count)
502 {
503   DEBUGASSERT(cwfds);
504   DEBUGASSERT(static_wfds);
505   memset(cwfds, 0, sizeof(*cwfds));
506   cwfds->wfds = static_wfds;
507   cwfds->count = static_count;
508 }
509 
cwfds_add_sock(struct curl_waitfds * cwfds,curl_socket_t sock,short events)510 static CURLcode cwfds_add_sock(struct curl_waitfds *cwfds,
511                                curl_socket_t sock, short events)
512 {
513   int i;
514 
515   if(cwfds->n <= INT_MAX) {
516     for(i = (int)cwfds->n - 1; i >= 0; --i) {
517       if(sock == cwfds->wfds[i].fd) {
518         cwfds->wfds[i].events |= events;
519         return CURLE_OK;
520       }
521     }
522   }
523   /* not folded, add new entry */
524   if(cwfds->n >= cwfds->count)
525     return CURLE_OUT_OF_MEMORY;
526   cwfds->wfds[cwfds->n].fd = sock;
527   cwfds->wfds[cwfds->n].events = events;
528   ++cwfds->n;
529   return CURLE_OK;
530 }
531 
Curl_waitfds_add_ps(struct curl_waitfds * cwfds,struct easy_pollset * ps)532 CURLcode Curl_waitfds_add_ps(struct curl_waitfds *cwfds,
533                              struct easy_pollset *ps)
534 {
535   size_t i;
536 
537   DEBUGASSERT(cwfds);
538   DEBUGASSERT(ps);
539   for(i = 0; i < ps->num; i++) {
540     short events = 0;
541     if(ps->actions[i] & CURL_POLL_IN)
542       events |= CURL_WAIT_POLLIN;
543     if(ps->actions[i] & CURL_POLL_OUT)
544       events |= CURL_WAIT_POLLOUT;
545     if(events) {
546       if(cwfds_add_sock(cwfds, ps->sockets[i], events))
547         return CURLE_OUT_OF_MEMORY;
548     }
549   }
550   return CURLE_OK;
551 }
552