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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16