summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/select.c')
-rw-r--r--libs/libcurl/src/select.c133
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 */