VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/select.c@ 86643

Last change on this file since 86643 was 85671, checked in by vboxsync, 4 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

  • Property svn:eol-style set to native
File size: 15.6 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2017, Daniel Stenberg, <[email protected]>, 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)Curl_timediff(Curl_now(), initial_tv)
55
56int Curl_ack_eintr = 0;
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 */
75int 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#endif
84 int r = 0;
85
86 if(!timeout_ms)
87 return 0;
88 if(timeout_ms < 0) {
89 SET_SOCKERRNO(EINVAL);
90 return -1;
91 }
92#if defined(MSDOS)
93 delay(timeout_ms);
94#elif defined(USE_WINSOCK)
95 Sleep(timeout_ms);
96#else
97 pending_ms = timeout_ms;
98 initial_tv = Curl_now();
99 do {
100 int error;
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 */
145int 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 r;
164 int ret;
165
166#if SIZEOF_TIME_T != SIZEOF_INT
167 /* wrap-around precaution */
168 if(timeout_ms >= INT_MAX)
169 timeout_ms = INT_MAX;
170#endif
171
172 if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
173 (writefd == CURL_SOCKET_BAD)) {
174 /* no sockets, just wait */
175 r = Curl_wait_ms((int)timeout_ms);
176 return r;
177 }
178
179 /* Avoid initial timestamp, avoid Curl_now() call, when elapsed
180 time in this function does not need to be measured. This happens
181 when function is called with a zero timeout or a negative timeout
182 value indicating a blocking call should be performed. */
183
184 if(timeout_ms > 0) {
185 pending_ms = (int)timeout_ms;
186 initial_tv = Curl_now();
187 }
188
189#ifdef HAVE_POLL_FINE
190
191 num = 0;
192 if(readfd0 != CURL_SOCKET_BAD) {
193 pfd[num].fd = readfd0;
194 pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
195 pfd[num].revents = 0;
196 num++;
197 }
198 if(readfd1 != CURL_SOCKET_BAD) {
199 pfd[num].fd = readfd1;
200 pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
201 pfd[num].revents = 0;
202 num++;
203 }
204 if(writefd != CURL_SOCKET_BAD) {
205 pfd[num].fd = writefd;
206 pfd[num].events = POLLWRNORM|POLLOUT;
207 pfd[num].revents = 0;
208 num++;
209 }
210
211 do {
212 int error;
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 int error;
295 if(timeout_ms > 0) {
296 pending_tv.tv_sec = pending_ms / 1000;
297 pending_tv.tv_usec = (pending_ms % 1000) * 1000;
298 }
299 else if(!timeout_ms) {
300 pending_tv.tv_sec = 0;
301 pending_tv.tv_usec = 0;
302 }
303
304 /* WinSock select() must not be called with an fd_set that contains zero
305 fd flags, or it will return WSAEINVAL. But, it also can't be called
306 with no fd_sets at all! From the documentation:
307
308 Any two of the parameters, readfds, writefds, or exceptfds, can be
309 given as null. At least one must be non-null, and any non-null
310 descriptor set must contain at least one handle to a socket.
311
312 We know that we have at least one bit set in at least two fd_sets in
313 this case, but we may have no bits set in either fds_read or fd_write,
314 so check for that and handle it. Luckily, with WinSock, we can _also_
315 ask how many bits are set on an fd_set.
316
317 It is unclear why WinSock doesn't just handle this for us instead of
318 calling this an error.
319
320 Note also that WinSock ignores the first argument, so we don't worry
321 about the fact that maxfd is computed incorrectly with WinSock (since
322 curl_socket_t is unsigned in such cases and thus -1 is the largest
323 value).
324 */
325#ifdef USE_WINSOCK
326 r = select((int)maxfd + 1,
327 fds_read.fd_count ? &fds_read : NULL,
328 fds_write.fd_count ? &fds_write : NULL,
329 &fds_err, ptimeout);
330#else
331 r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
332#endif
333
334 if(r != -1)
335 break;
336 error = SOCKERRNO;
337 if(error && ERROR_NOT_EINTR(error))
338 break;
339 if(timeout_ms > 0) {
340 pending_ms = (int)(timeout_ms - ELAPSED_MS());
341 if(pending_ms <= 0) {
342 r = 0; /* Simulate a "call timed out" case */
343 break;
344 }
345 }
346 } while(r == -1);
347
348 if(r < 0)
349 return -1;
350 if(r == 0)
351 return 0;
352
353 ret = 0;
354 if(readfd0 != CURL_SOCKET_BAD) {
355 if(FD_ISSET(readfd0, &fds_read))
356 ret |= CURL_CSELECT_IN;
357 if(FD_ISSET(readfd0, &fds_err))
358 ret |= CURL_CSELECT_ERR;
359 }
360 if(readfd1 != CURL_SOCKET_BAD) {
361 if(FD_ISSET(readfd1, &fds_read))
362 ret |= CURL_CSELECT_IN2;
363 if(FD_ISSET(readfd1, &fds_err))
364 ret |= CURL_CSELECT_ERR;
365 }
366 if(writefd != CURL_SOCKET_BAD) {
367 if(FD_ISSET(writefd, &fds_write))
368 ret |= CURL_CSELECT_OUT;
369 if(FD_ISSET(writefd, &fds_err))
370 ret |= CURL_CSELECT_ERR;
371 }
372
373 return ret;
374
375#endif /* HAVE_POLL_FINE */
376
377}
378
379/*
380 * This is a wrapper around poll(). If poll() does not exist, then
381 * select() is used instead. An error is returned if select() is
382 * being used and a file descriptor is too large for FD_SETSIZE.
383 * A negative timeout value makes this function wait indefinitely,
384 * unless no valid file descriptor is given, when this happens the
385 * negative timeout is ignored and the function times out immediately.
386 *
387 * Return values:
388 * -1 = system call error or fd >= FD_SETSIZE
389 * 0 = timeout
390 * N = number of structures with non zero revent fields
391 */
392int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
393{
394#ifndef HAVE_POLL_FINE
395 struct timeval pending_tv;
396 struct timeval *ptimeout;
397 fd_set fds_read;
398 fd_set fds_write;
399 fd_set fds_err;
400 curl_socket_t maxfd;
401#endif
402 struct curltime initial_tv = {0, 0};
403 bool fds_none = TRUE;
404 unsigned int i;
405 int pending_ms = 0;
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 Curl_now() 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 = Curl_now();
429 }
430
431#ifdef HAVE_POLL_FINE
432
433 do {
434 int error;
435 if(timeout_ms < 0)
436 pending_ms = -1;
437 else if(!timeout_ms)
438 pending_ms = 0;
439 r = poll(ufds, nfds, pending_ms);
440 if(r != -1)
441 break;
442 error = SOCKERRNO;
443 if(error && ERROR_NOT_EINTR(error))
444 break;
445 if(timeout_ms > 0) {
446 pending_ms = (int)(timeout_ms - ELAPSED_MS());
447 if(pending_ms <= 0) {
448 r = 0; /* Simulate a "call timed out" case */
449 break;
450 }
451 }
452 } while(r == -1);
453
454 if(r < 0)
455 return -1;
456 if(r == 0)
457 return 0;
458
459 for(i = 0; i < nfds; i++) {
460 if(ufds[i].fd == CURL_SOCKET_BAD)
461 continue;
462 if(ufds[i].revents & POLLHUP)
463 ufds[i].revents |= POLLIN;
464 if(ufds[i].revents & POLLERR)
465 ufds[i].revents |= (POLLIN|POLLOUT);
466 }
467
468#else /* HAVE_POLL_FINE */
469
470 FD_ZERO(&fds_read);
471 FD_ZERO(&fds_write);
472 FD_ZERO(&fds_err);
473 maxfd = (curl_socket_t)-1;
474
475 for(i = 0; i < nfds; i++) {
476 ufds[i].revents = 0;
477 if(ufds[i].fd == CURL_SOCKET_BAD)
478 continue;
479 VERIFY_SOCK(ufds[i].fd);
480 if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
481 POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
482 if(ufds[i].fd > maxfd)
483 maxfd = ufds[i].fd;
484 if(ufds[i].events & (POLLRDNORM|POLLIN))
485 FD_SET(ufds[i].fd, &fds_read);
486 if(ufds[i].events & (POLLWRNORM|POLLOUT))
487 FD_SET(ufds[i].fd, &fds_write);
488 if(ufds[i].events & (POLLRDBAND|POLLPRI))
489 FD_SET(ufds[i].fd, &fds_err);
490 }
491 }
492
493#ifdef USE_WINSOCK
494 /* WinSock select() can't handle zero events. See the comment about this in
495 Curl_check_socket(). */
496 if(fds_read.fd_count == 0 && fds_write.fd_count == 0
497 && fds_err.fd_count == 0) {
498 r = Curl_wait_ms(timeout_ms);
499 return r;
500 }
501#endif
502
503 ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
504
505 do {
506 int error;
507 if(timeout_ms > 0) {
508 pending_tv.tv_sec = pending_ms / 1000;
509 pending_tv.tv_usec = (pending_ms % 1000) * 1000;
510 }
511 else if(!timeout_ms) {
512 pending_tv.tv_sec = 0;
513 pending_tv.tv_usec = 0;
514 }
515
516#ifdef USE_WINSOCK
517 r = select((int)maxfd + 1,
518 /* WinSock select() can't handle fd_sets with zero bits set, so
519 don't give it such arguments. See the comment about this in
520 Curl_check_socket().
521 */
522 fds_read.fd_count ? &fds_read : NULL,
523 fds_write.fd_count ? &fds_write : NULL,
524 fds_err.fd_count ? &fds_err : NULL, ptimeout);
525#else
526 r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
527#endif
528 if(r != -1)
529 break;
530 error = SOCKERRNO;
531 if(error && ERROR_NOT_EINTR(error))
532 break;
533 if(timeout_ms > 0) {
534 pending_ms = timeout_ms - ELAPSED_MS();
535 if(pending_ms <= 0) {
536 r = 0; /* Simulate a "call timed out" case */
537 break;
538 }
539 }
540 } while(r == -1);
541
542 if(r < 0)
543 return -1;
544 if(r == 0)
545 return 0;
546
547 r = 0;
548 for(i = 0; i < nfds; i++) {
549 ufds[i].revents = 0;
550 if(ufds[i].fd == CURL_SOCKET_BAD)
551 continue;
552 if(FD_ISSET(ufds[i].fd, &fds_read))
553 ufds[i].revents |= POLLIN;
554 if(FD_ISSET(ufds[i].fd, &fds_write))
555 ufds[i].revents |= POLLOUT;
556 if(FD_ISSET(ufds[i].fd, &fds_err))
557 ufds[i].revents |= POLLPRI;
558 if(ufds[i].revents != 0)
559 r++;
560 }
561
562#endif /* HAVE_POLL_FINE */
563
564 return r;
565}
566
567#ifdef TPF
568/*
569 * This is a replacement for select() on the TPF platform.
570 * It is used whenever libcurl calls select().
571 * The call below to tpf_process_signals() is required because
572 * TPF's select calls are not signal interruptible.
573 *
574 * Return values are the same as select's.
575 */
576int tpf_select_libcurl(int maxfds, fd_set *reads, fd_set *writes,
577 fd_set *excepts, struct timeval *tv)
578{
579 int rc;
580
581 rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
582 tpf_process_signals();
583 return rc;
584}
585#endif /* TPF */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette