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