On 11/13/2014 1:59 PM, Daniel Stenberg wrote:
On Thu, 13 Nov 2014, JOHAN LANTZ wrote:
However moving to the multi examples, I do not manage to download
anything. There are no errors for the api calls setting things up but
I always end up at this print: printf("select() returns error, this
is badness\n");
I guess that is when maxfd is -1 and there are no file descriptors to
wait for?
Yeah. On Windows select() will return -1 and winsock error code
WSAEINVAL in that case. The documentation for Windows' select() [1] says:
"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."
Their remarks for the WSAEINVAL error code isn't as encompassing but
that's what happens. So it won't sleep via select() unless you use a
dummy socket. You could instead call Windows' Sleep(). Its resolution
isn't that granular but I think it's fine for this. The documentation
for curl_multi_fdset() [2] says the recommended time is 100ms at least:
"When libcurl returns -1 in max_fd, it is because libcurl currently does
something that isn't possible for your application to monitor with a
socket and unfortunately you can then not know exactly when the current
action is completed using select(). You then need to wait a while before
you proceed and call curl_multi_perform anyway. How long to wait? We
suggest 100 milliseconds at least, but you may want to test it out in
your own particular conditions to find a suitable value."
I have attached a patch which fixes the multi examples for use on
Windows by sleeping 100ms whenever curl_multi_fdset() doesn't set any
file descriptors. I also added a check on its return value because why
not. Alternatively if you want to get closer to what select() would do
use a dummy socket or something like Sleep((DWORD)(timeout.tv_sec * 1000
+ timeout.tv_usec / 1000)) assuming you have a valid timeval.
Also- The examples are inconsistent on whether or not they notify of
select error.
[1]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms740141.aspx
[2]: http://curl.haxx.se/libcurl/c/curl_multi_fdset.html
From 966f7e8a63c5aba662ab47292e51a8a04ec3f9e7 Mon Sep 17 00:00:00 2001
From: Jay Satiro <[email protected]>
Date: Fri, 14 Nov 2014 03:59:46 -0500
Subject: [PATCH] examples: Don't call select() to sleep on windows
Windows does not support using select() for sleeping without a dummy
socket. Instead use Windows' Sleep() and sleep for 100ms which is the
minimum suggested value in the curl_multi_fdset() doc.
Prior to this change the multi examples would exit prematurely since
select() would error instead of sleeping when called without an fd.
Reported on the mailing list by Johan Lantz:
http://curl.haxx.se/mail/lib-2014-11/0221.html
---
docs/examples/fopen.c | 31 ++++++++++++++++++++++++-------
docs/examples/imap-multi.c | 34 ++++++++++++++++++++++++++--------
docs/examples/multi-app.c | 31 ++++++++++++++++++++++++-------
docs/examples/multi-debugcallback.c | 31 ++++++++++++++++++++++++-------
docs/examples/multi-double.c | 31 ++++++++++++++++++++++++-------
docs/examples/multi-post.c | 31 ++++++++++++++++++++++++-------
docs/examples/multi-single.c | 31 ++++++++++++++++++++++++-------
docs/examples/pop3-multi.c | 34 ++++++++++++++++++++++++++--------
docs/examples/smtp-multi.c | 34 ++++++++++++++++++++++++++--------
9 files changed, 222 insertions(+), 66 deletions(-)
diff --git a/docs/examples/fopen.c b/docs/examples/fopen.c
index 6fe5c0f..c26c0de 100644
--- a/docs/examples/fopen.c
+++ b/docs/examples/fopen.c
@@ -128,6 +128,7 @@ static int fill_buffer(URL_FILE *file, size_t want)
fd_set fdexcep;
struct timeval timeout;
int rc;
+ CURLMcode mc; /* curl_multi_fdset() return code */
/* only attempt to fill buffer if transactions still running and buffer
* doesnt exceed required size already
@@ -158,15 +159,31 @@ static int fill_buffer(URL_FILE *file, size_t want)
}
/* get file descriptors from the transfers */
- curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially
- in case of (maxfd == -1), we call select(0, ...), which is basically
- equal to sleep. */
+ if(mc != CURLM_OK)
+ {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) we call
+ select(0, ...), which is basically equal to sleeping the timeout. On
+ Windows we can't sleep via select without a dummy socket and instead
+ we Sleep() for 100ms which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+#ifdef _WIN32
+ if(maxfd == -1) {
+ Sleep(100);
+ rc = 0;
+ }
+ else
+#endif
+ {
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
switch(rc) {
case -1:
diff --git a/docs/examples/imap-multi.c b/docs/examples/imap-multi.c
index 601205a..c8c67ff 100644
--- a/docs/examples/imap-multi.c
+++ b/docs/examples/imap-multi.c
@@ -88,6 +88,7 @@ int main(void)
fd_set fdexcep;
int maxfd = -1;
int rc;
+ CURLMcode mc; /* curl_multi_fdset() return code */
long curl_timeo = -1;
@@ -109,15 +110,32 @@ int main(void)
timeout.tv_usec = (curl_timeo % 1000) * 1000;
}
- /* Get file descriptors from the transfers */
- curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
+ /* get file descriptors from the transfers */
+ mc = curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially in
- case of (maxfd == -1), we call select(0, ...), which is basically equal
- to sleep. */
- rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
+ if(mc != CURLM_OK)
+ {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
+
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) we call
+ select(0, ...), which is basically equal to sleeping the timeout. On
+ Windows we can't sleep via select without a dummy socket and instead
+ we Sleep() for 100ms which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+#ifdef _WIN32
+ if(maxfd == -1) {
+ Sleep(100);
+ rc = 0;
+ }
+ else
+#endif
+ {
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
if(tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
fprintf(stderr,
diff --git a/docs/examples/multi-app.c b/docs/examples/multi-app.c
index a5f71c5..bf0f11a 100644
--- a/docs/examples/multi-app.c
+++ b/docs/examples/multi-app.c
@@ -73,6 +73,7 @@ int main(void)
do {
struct timeval timeout;
int rc; /* select() return code */
+ CURLMcode mc; /* curl_multi_fdset() return code */
fd_set fdread;
fd_set fdwrite;
@@ -99,15 +100,31 @@ int main(void)
}
/* get file descriptors from the transfers */
- curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially in
- case of (maxfd == -1), we call select(0, ...), which is basically equal
- to sleep. */
+ if(mc != CURLM_OK)
+ {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) we call
+ select(0, ...), which is basically equal to sleeping the timeout. On
+ Windows we can't sleep via select without a dummy socket and instead
+ we Sleep() for 100ms which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+#ifdef _WIN32
+ if(maxfd == -1) {
+ Sleep(100);
+ rc = 0;
+ }
+ else
+#endif
+ {
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
switch(rc) {
case -1:
diff --git a/docs/examples/multi-debugcallback.c
b/docs/examples/multi-debugcallback.c
index 8eedcee..31dec54 100644
--- a/docs/examples/multi-debugcallback.c
+++ b/docs/examples/multi-debugcallback.c
@@ -147,6 +147,7 @@ int main(void)
do {
struct timeval timeout;
int rc; /* select() return code */
+ CURLMcode mc; /* curl_multi_fdset() return code */
fd_set fdread;
fd_set fdwrite;
@@ -173,15 +174,31 @@ int main(void)
}
/* get file descriptors from the transfers */
- curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially in
- case of (maxfd == -1), we call select(0, ...), which is basically equal
- to sleep. */
+ if(mc != CURLM_OK)
+ {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) we call
+ select(0, ...), which is basically equal to sleeping the timeout. On
+ Windows we can't sleep via select without a dummy socket and instead
+ we Sleep() for 100ms which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+#ifdef _WIN32
+ if(maxfd == -1) {
+ Sleep(100);
+ rc = 0;
+ }
+ else
+#endif
+ {
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
switch(rc) {
case -1:
diff --git a/docs/examples/multi-double.c b/docs/examples/multi-double.c
index 91422e6..df0922a 100644
--- a/docs/examples/multi-double.c
+++ b/docs/examples/multi-double.c
@@ -62,6 +62,7 @@ int main(void)
do {
struct timeval timeout;
int rc; /* select() return code */
+ CURLMcode mc; /* curl_multi_fdset() return code */
fd_set fdread;
fd_set fdwrite;
@@ -88,15 +89,31 @@ int main(void)
}
/* get file descriptors from the transfers */
- curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially in
- case of (maxfd == -1), we call select(0, ...), which is basically equal
- to sleep. */
+ if(mc != CURLM_OK)
+ {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) we call
+ select(0, ...), which is basically equal to sleeping the timeout. On
+ Windows we can't sleep via select without a dummy socket and instead
+ we Sleep() for 100ms which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+#ifdef _WIN32
+ if(maxfd == -1) {
+ Sleep(100);
+ rc = 0;
+ }
+ else
+#endif
+ {
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
switch(rc) {
case -1:
diff --git a/docs/examples/multi-post.c b/docs/examples/multi-post.c
index 965a2c3..a6cc868 100644
--- a/docs/examples/multi-post.c
+++ b/docs/examples/multi-post.c
@@ -83,6 +83,7 @@ int main(void)
do {
struct timeval timeout;
int rc; /* select() return code */
+ CURLMcode mc; /* curl_multi_fdset() return code */
fd_set fdread;
fd_set fdwrite;
@@ -109,15 +110,31 @@ int main(void)
}
/* get file descriptors from the transfers */
- curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially
in
- case of (maxfd == -1), we call select(0, ...), which is basically
equal
- to sleep. */
+ if(mc != CURLM_OK)
+ {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) we call
+ select(0, ...), which is basically equal to sleeping the timeout. On
+ Windows we can't sleep via select without a dummy socket and instead
+ we Sleep() for 100ms which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+#ifdef _WIN32
+ if(maxfd == -1) {
+ Sleep(100);
+ rc = 0;
+ }
+ else
+#endif
+ {
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
switch(rc) {
case -1:
diff --git a/docs/examples/multi-single.c b/docs/examples/multi-single.c
index 37a01cd..3d80c65 100644
--- a/docs/examples/multi-single.c
+++ b/docs/examples/multi-single.c
@@ -60,6 +60,7 @@ int main(void)
do {
struct timeval timeout;
int rc; /* select() return code */
+ CURLMcode mc; /* curl_multi_fdset() return code */
fd_set fdread;
fd_set fdwrite;
@@ -86,15 +87,31 @@ int main(void)
}
/* get file descriptors from the transfers */
- curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
+ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially in
- case of (maxfd == -1), we call select(0, ...), which is basically equal
- to sleep. */
+ if(mc != CURLM_OK)
+ {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) we call
+ select(0, ...), which is basically equal to sleeping the timeout. On
+ Windows we can't sleep via select without a dummy socket and instead
+ we Sleep() for 100ms which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+#ifdef _WIN32
+ if(maxfd == -1) {
+ Sleep(100);
+ rc = 0;
+ }
+ else
+#endif
+ {
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
switch(rc) {
case -1:
diff --git a/docs/examples/pop3-multi.c b/docs/examples/pop3-multi.c
index d14d115..42142f9 100644
--- a/docs/examples/pop3-multi.c
+++ b/docs/examples/pop3-multi.c
@@ -88,6 +88,7 @@ int main(void)
fd_set fdexcep;
int maxfd = -1;
int rc;
+ CURLMcode mc; /* curl_multi_fdset() return code */
long curl_timeo = -1;
@@ -109,15 +110,32 @@ int main(void)
timeout.tv_usec = (curl_timeo % 1000) * 1000;
}
- /* Get file descriptors from the transfers */
- curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
+ /* get file descriptors from the transfers */
+ mc = curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially in
- case of (maxfd == -1), we call select(0, ...), which is basically equal
- to sleep. */
- rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
+ if(mc != CURLM_OK)
+ {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
+
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) we call
+ select(0, ...), which is basically equal to sleeping the timeout. On
+ Windows we can't sleep via select without a dummy socket and instead
+ we Sleep() for 100ms which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+#ifdef _WIN32
+ if(maxfd == -1) {
+ Sleep(100);
+ rc = 0;
+ }
+ else
+#endif
+ {
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
if(tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
fprintf(stderr,
diff --git a/docs/examples/smtp-multi.c b/docs/examples/smtp-multi.c
index 7f3d333..998f69e 100644
--- a/docs/examples/smtp-multi.c
+++ b/docs/examples/smtp-multi.c
@@ -155,6 +155,7 @@ int main(void)
fd_set fdexcep;
int maxfd = -1;
int rc;
+ CURLMcode mc; /* curl_multi_fdset() return code */
long curl_timeo = -1;
@@ -176,15 +177,32 @@ int main(void)
timeout.tv_usec = (curl_timeo % 1000) * 1000;
}
- /* Get file descriptors from the transfers */
- curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
+ /* get file descriptors from the transfers */
+ mc = curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);
- /* In a real-world program you OF COURSE check the return code of the
- function calls. On success, the value of maxfd is guaranteed to be
- greater or equal than -1. We call select(maxfd + 1, ...), specially in
- case of (maxfd == -1), we call select(0, ...), which is basically equal
- to sleep. */
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ if(mc != CURLM_OK)
+ {
+ fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
+ break;
+ }
+
+ /* On success the value of maxfd is guaranteed to be >= -1. We call
+ select(maxfd + 1, ...); specially in case of (maxfd == -1) we call
+ select(0, ...), which is basically equal to sleeping the timeout. On
+ Windows we can't sleep via select without a dummy socket and instead
+ we Sleep() for 100ms which is the minimum suggested value in the
+ curl_multi_fdset() doc. */
+
+#ifdef _WIN32
+ if(maxfd == -1) {
+ Sleep(100);
+ rc = 0;
+ }
+ else
+#endif
+ {
+ rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+ }
if(tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
fprintf(stderr,
--
1.9.4.msysgit.2
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html