diff options
Diffstat (limited to 'libs/libcurl/src/select.c')
-rw-r--r-- | libs/libcurl/src/select.c | 133 |
1 files changed, 100 insertions, 33 deletions
diff --git a/libs/libcurl/src/select.c b/libs/libcurl/src/select.c index db7fb6d43c..28390a4a6a 100644 --- a/libs/libcurl/src/select.c +++ b/libs/libcurl/src/select.c @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -39,6 +39,10 @@ #include <dos.h> /* delay() */ #endif +#ifdef __VXWORKS__ +#include <strings.h> /* bzero() in FD_SET */ +#endif + #include <curl/curl.h> #include "urldata.h" @@ -47,15 +51,14 @@ #include "warnless.h" /* Convenience local macros */ - -#define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) +#define ELAPSED_MS() (int)Curl_timediff(Curl_now(), initial_tv) int Curl_ack_eintr = 0; -#define error_not_EINTR (Curl_ack_eintr || error != EINTR) +#define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR) /* * Internal function used for waiting a specific amount of ms - * in Curl_socket_ready() and Curl_poll() when no file descriptor + * in Curl_socket_check() and Curl_poll() when no file descriptor * is provided to wait on, just being used to delay execution. * WinSock select() and poll() timeout mechanisms need a valid * socket descriptor in a not null file descriptor set to work. @@ -75,7 +78,7 @@ int Curl_wait_ms(int timeout_ms) #ifndef HAVE_POLL_FINE struct timeval pending_tv; #endif - struct timeval initial_tv; + struct curltime initial_tv; int pending_ms; int error; #endif @@ -93,7 +96,7 @@ int Curl_wait_ms(int timeout_ms) Sleep(timeout_ms); #else pending_ms = timeout_ms; - initial_tv = curlx_tvnow(); + initial_tv = Curl_now(); do { #if defined(HAVE_POLL_FINE) r = poll(NULL, 0, pending_ms); @@ -105,11 +108,13 @@ int Curl_wait_ms(int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; - pending_ms = timeout_ms - elapsed_ms; - if(pending_ms <= 0) + pending_ms = timeout_ms - ELAPSED_MS(); + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ break; + } } while(r == -1); #endif /* USE_WINSOCK */ if(r) @@ -124,7 +129,7 @@ int Curl_wait_ms(int timeout_ms) * and a file descriptor is too large for FD_SETSIZE. * * A negative timeout value makes this function wait indefinitely, - * unles no valid file descriptor is given, when this happens the + * unless no valid file descriptor is given, when this happens the * negative timeout is ignored and the function times out immediately. * * Return values: @@ -140,7 +145,7 @@ int Curl_wait_ms(int timeout_ms) int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ curl_socket_t readfd1, curl_socket_t writefd, /* socket to write to */ - long timeout_ms) /* milliseconds to wait */ + time_t timeout_ms) /* milliseconds to wait */ { #ifdef HAVE_POLL_FINE struct pollfd pfd[3]; @@ -153,12 +158,18 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ fd_set fds_err; curl_socket_t maxfd; #endif - struct timeval initial_tv = {0,0}; + struct curltime initial_tv = {0, 0}; int pending_ms = 0; int error; int r; int ret; +#if SIZEOF_TIME_T != SIZEOF_INT + /* wrap-around precaution */ + if(timeout_ms >= INT_MAX) + timeout_ms = INT_MAX; +#endif + if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { /* no sockets, just wait */ @@ -166,14 +177,14 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ return r; } - /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed + /* Avoid initial timestamp, avoid Curl_now() call, when elapsed time in this function does not need to be measured. This happens when function is called with a zero timeout or a negative timeout value indicating a blocking call should be performed. */ if(timeout_ms > 0) { pending_ms = (int)timeout_ms; - initial_tv = curlx_tvnow(); + initial_tv = Curl_now(); } #ifdef HAVE_POLL_FINE @@ -207,10 +218,10 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - elapsed_ms); + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -288,14 +299,44 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ pending_tv.tv_sec = 0; pending_tv.tv_usec = 0; } + + /* WinSock select() must not be called with an fd_set that contains zero + fd flags, or it will return WSAEINVAL. But, it also can't be called + with no fd_sets at all! From the documentation: + + Any two of the parameters, readfds, writefds, or exceptfds, can be + given as null. At least one must be non-null, and any non-null + descriptor set must contain at least one handle to a socket. + + We know that we have at least one bit set in at least two fd_sets in + this case, but we may have no bits set in either fds_read or fd_write, + so check for that and handle it. Luckily, with WinSock, we can _also_ + ask how many bits are set on an fd_set. + + It is unclear why WinSock doesn't just handle this for us instead of + calling this an error. + + Note also that WinSock ignores the first argument, so we don't worry + about the fact that maxfd is computed incorrectly with WinSock (since + curl_socket_t is unsigned in such cases and thus -1 is the largest + value). + */ +#ifdef USE_WINSOCK + r = select((int)maxfd + 1, + fds_read.fd_count ? &fds_read : NULL, + fds_write.fd_count ? &fds_write : NULL, + &fds_err, ptimeout); +#else r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); +#endif + if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -339,7 +380,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ * select() is used instead. An error is returned if select() is * being used and a file descriptor is too large for FD_SETSIZE. * A negative timeout value makes this function wait indefinitely, - * unles no valid file descriptor is given, when this happens the + * unless no valid file descriptor is given, when this happens the * negative timeout is ignored and the function times out immediately. * * Return values: @@ -357,7 +398,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) fd_set fds_err; curl_socket_t maxfd; #endif - struct timeval initial_tv = {0,0}; + struct curltime initial_tv = {0, 0}; bool fds_none = TRUE; unsigned int i; int pending_ms = 0; @@ -377,14 +418,14 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) return r; } - /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed + /* Avoid initial timestamp, avoid Curl_now() call, when elapsed time in this function does not need to be measured. This happens when function is called with a zero timeout or a negative timeout value indicating a blocking call should be performed. */ if(timeout_ms > 0) { pending_ms = timeout_ms; - initial_tv = curlx_tvnow(); + initial_tv = Curl_now(); } #ifdef HAVE_POLL_FINE @@ -398,12 +439,14 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; - if(pending_ms <= 0) + pending_ms = (int)(timeout_ms - ELAPSED_MS()); + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ break; + } } } while(r == -1); @@ -446,6 +489,16 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) } } +#ifdef USE_WINSOCK + /* WinSock select() can't handle zero events. See the comment about this in + Curl_check_socket(). */ + if(fds_read.fd_count == 0 && fds_write.fd_count == 0 + && fds_err.fd_count == 0) { + r = Curl_wait_ms(timeout_ms); + return r; + } +#endif + ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; do { @@ -457,16 +510,30 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) pending_tv.tv_sec = 0; pending_tv.tv_usec = 0; } + +#ifdef USE_WINSOCK + r = select((int)maxfd + 1, + /* WinSock select() can't handle fd_sets with zero bits set, so + don't give it such arguments. See the comment about this in + Curl_check_socket(). + */ + fds_read.fd_count ? &fds_read : NULL, + fds_write.fd_count ? &fds_write : NULL, + fds_err.fd_count ? &fds_err : NULL, ptimeout); +#else r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); +#endif if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; - if(pending_ms <= 0) + pending_ms = timeout_ms - ELAPSED_MS(); + if(pending_ms <= 0) { + r = 0; /* Simulate a "call timed out" case */ break; + } } } while(r == -1); @@ -504,13 +571,13 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) * * Return values are the same as select's. */ -int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, - fd_set* excepts, struct timeval* tv) +int tpf_select_libcurl(int maxfds, fd_set *reads, fd_set *writes, + fd_set *excepts, struct timeval *tv) { int rc; rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv); tpf_process_signals(); - return(rc); + return rc; } #endif /* TPF */ |