Discussion:
curl multi pipelining and CURLOPT_CONNECTTIMEOUT
Török Edwin
2013-01-24 15:46:17 UTC
Permalink
Hi,

I am using the curl multi interface and I see a lot of timeouts on slowish links (all fine on fast links of course).
I have concluded that CURLOPT_CONNECTTIMEOUT sets not only the timeout for connect(), but also the timeout
for starting to receive a reply for a pipelined request.

Due to how pipelining works this means that all N-1 pipelined requests must finish during the CONNECTTIMEOUT
of the Nth request, otherwise all N (and later) requests are considered as timed out.
Is this intended behaviour?

I would've expected CURLOPT_CONNECTTIMEOUT to set only the timeout for connect(). For pipelined connections
as long as _any_ easy handle is receiving data on that connection I don't want the 'connect' timeout
of other pipelined requests to trigger. Is there a way to do that without modifying curl?

Alternatively I could queue up all requests that would go to the same host and only add the easy handle
to a multi handle when previous request is finished, but it'd be nice if curl could do this itself.

Note: I'm actually interested in persistent connections only, not necesarely pipelining (that is just a nice addition),
but in the multi interface I don't see a way to request that only: it is either both (MOPT_PIPELINING on), or neith
(MOPT_PIPELINING off, separate connections).

Here is how I encountered this issue:
rc = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 60);
...
rc2 = curl_multi_setopt(x->multi, CURLMOPT_PIPELINING, 1);
....

If I add lots of easy handles to the multi handle (lets say 10 requests to same host each with a 1MB reply)
then the last requests tends to timeout with an error on a slowish link:
Timeout was reached, Operation timed out after 60009 milliseconds with 0 out of 0 bytes received

At first I thought there is some other timeout option that I'm not setting, but setting this didn't help
(its the default value anyway):
rc = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 0);

Changing CURLOPT_CONNECCTIMEOUT to 10s will cause all the multi pipelined transfers to time out after ~10000 ms, so that
supports my original idea that CONNECTTIMEOUT influences timeout for pipelined requests.

Best regards,
--Edwin
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Daniel Stenberg
2013-01-29 08:29:48 UTC
Permalink
Post by Török Edwin
I am using the curl multi interface and I see a lot of timeouts on slowish
links (all fine on fast links of course). I have concluded that
CURLOPT_CONNECTTIMEOUT sets not only the timeout for connect(), but also the
timeout for starting to receive a reply for a pipelined request.
If that's so, then it is a bug. You didn't mention what libcurl version you're
using.

This said, Linus Nielsen Feltzing has a pretty massive HTTP pipelining patch
pending to get merged at some point after the 7.29.0 release so I'm reluctant
to fix anything pipeline-related until then. Possibly we should ask Linus how
to get his latest tree so that we can start trying out your problem on that
already now.
Post by Török Edwin
Note: I'm actually interested in persistent connections only, not necesarely
pipelining (that is just a nice addition), but in the multi interface I
don't see a way to request that only: it is either both (MOPT_PIPELINING
on), or neith (MOPT_PIPELINING off, separate connections).
Without pipelining it can't re-use the connections if you do multiple requests
in parallel. Without pipelining you need to issue the requests in a serial
manner if you want them to re-use connections.

Again, the pending work from Linus will allow some more customizibility in
this area as well.
--
/ daniel.haxx.se
Török Edwin
2013-01-29 09:47:21 UTC
Permalink
I am using the curl multi interface and I see a lot of timeouts on slowish links (all fine on fast links of course). I have concluded that CURLOPT_CONNECTTIMEOUT sets not only the timeout for
connect(), but also the timeout for starting to receive a reply for a pipelined request.
If that's so, then it is a bug. You didn't mention what libcurl version you're using.
7.28.0 from Debian. But it reproduces with 7.28.1 too.

See attached testcase:
$ ./curltest
CURL version: libcurl/7.28.1 OpenSSL/1.0.1c zlib/1.2.7
....
* Operation timed out after 5000 milliseconds with 0 out of 0 bytes received
Result: Timeout was reached
* Operation timed out after 5000 milliseconds with 0 out of 0 bytes received
* Operation timed out after 5000 milliseconds with 0 out of 0 bytes received
* Operation timed out after 5000 milliseconds with 0 out of 0 bytes received
* Operation timed out after 5000 milliseconds with 0 out of 0 bytes received
* Operation timed out after 5000 milliseconds with 0 out of 0 bytes received
Result: Timeout was reached
...
OK: 1, Failed: 7


If you remove CURLMOPT_PIPELINING from the testcase it works:
Result: No error
OK: 8, Failed: 0
This said, Linus Nielsen Feltzing has a pretty massive HTTP pipelining patch pending to get merged at some point after the 7.29.0 release so I'm reluctant to fix anything pipeline-related until then.
Possibly we should ask Linus how to get his latest tree so that we can start trying out your problem on that already now.
Note: I'm actually interested in persistent connections only, not necesarely pipelining (that is just a nice addition), but in the multi interface I don't see a way to request that only: it is
either both (MOPT_PIPELINING on), or neith (MOPT_PIPELINING off, separate connections).
Without pipelining it can't re-use the connections if you do multiple requests in parallel. Without pipelining you need to issue the requests in a serial manner if you want them to re-use connections.
Yes, I think that is what I'll do (add easy handle to multi only when previous finished for the same host).
Again, the pending work from Linus will allow some more customizibility in this area as well.
Looking forward to try that out.

Thanks,
--Edwin
Daniel Stenberg
2013-02-04 21:17:57 UTC
Permalink
Post by Török Edwin
Post by Török Edwin
I am using the curl multi interface and I see a lot of timeouts on slowish
links (all fine on fast links of course). I have concluded that
CURLOPT_CONNECTTIMEOUT sets not only the timeout for connect(), but also
the timeout for starting to receive a reply for a pipelined request.
If that's so, then it is a bug. You didn't mention what libcurl version you're using.
7.28.0 from Debian. But it reproduces with 7.28.1 too.
Seems to be a (current) bug indeed.

Would you be able to provide a recipe that we can use to repeat the problem?
Like source code for a stand-alone app that shows it happening or similar.
--
/ daniel.haxx.se
Török Edwin
2013-02-04 21:31:48 UTC
Permalink
Post by Daniel Stenberg
Post by Török Edwin
I am using the curl multi interface and I see a lot of timeouts on slowish links (all fine on fast links of course). I have concluded that CURLOPT_CONNECTTIMEOUT sets not only the timeout for
connect(), but also the timeout for starting to receive a reply for a pipelined request.
If that's so, then it is a bug. You didn't mention what libcurl version you're using.
7.28.0 from Debian. But it reproduces with 7.28.1 too.
Seems to be a (current) bug indeed.
Would you be able to provide a recipe that we can use to repeat the problem? Like source code for a stand-alone app that shows it happening or similar.
I've sent a testcase last week, did it get lost?
http://curl.haxx.se/mail/lib-2013-01/att-0341/curltest.c

It should be fairly self-contained, just edit it and set CURLMOPT_PIPELINING to 1L to see it fail, and to 0L to see it work.

Here it is attached again, let me know if the testcase doesn't reproduce the problem for you, or if you need additional info.

Usage:
$ gcc curltest.c -lcurl -o curltest
$ ./curltest
...
OK: 1, Failed: 7

Best regards,
--Edwin
Daniel Stenberg
2013-02-04 21:50:26 UTC
Permalink
Post by Török Edwin
Post by Daniel Stenberg
Would you be able to provide a recipe that we can use to repeat the
problem? Like source code for a stand-alone app that shows it happening or
similar.
I've sent a testcase last week, did it get lost?
http://curl.haxx.se/mail/lib-2013-01/att-0341/curltest.c
It should be fairly self-contained, just edit it and set CURLMOPT_PIPELINING
to 1L to see it fail, and to 0L to see it work.
Oh sorry, I missed/forgot that. Thanks! I'll need to postpone any work on it
until after the pending release though...
--
/ daniel.haxx.se
Loading...