I found that 7.29 and 7.30 libcurl versions have partly broken CONNECTTIMEOUT_MS functionality. These versions do not respect subseconds and use full-second resolution for timeouts even if compiled against c-ares.
OS: CentOS 6.3 x86_64
Broken: curl 7.30.0 (x86_64-unknown-linux-gnu) libcurl/7.30.0 OpenSSL/1.0.0 zlib/1.2.3 c-ares/1.9.1 libidn/1.18 libssh2/1.4.3 (the same goes for 7.29)
Good: curl 7.28.1 (x86_64-unknown-linux-gnu) libcurl/7.28.1 OpenSSL/1.0.0 zlib/1.2.3 c-ares/1.9.1 libidn/1.18 libssh2/1.4.3
Configuration options are exactly the same.
Simple php script to reproduce this:
::php
Trace for 7.28.1 (the good one):
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("8.9.8.9")}, 16) = -1 EINPROGRESS (Operation now in progress)
clock_gettime(CLOCK_MONOTONIC, {681218, 818857874}) = 0
clock_gettime(CLOCK_MONOTONIC, {681218, 819188128}) = 0
poll([{fd=3, events=POLLOUT|POLLWRNORM}], 1, 39) = 0 (Timeout)
Trace for 7.30.0 (the bad one):
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
clock_gettime(CLOCK_MONOTONIC, {681540, 350585044}) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("8.9.8.9")}, 16) = -1 EINPROGRESS (Operation now in progress)
clock_gettime(CLOCK_MONOTONIC, {681540, 351323315}) = 0
clock_gettime(CLOCK_MONOTONIC, {681540, 351379339}) = 0
clock_gettime(CLOCK_MONOTONIC, {681540, 351437113}) = 0
clock_gettime(CLOCK_MONOTONIC, {681540, 351493897}) = 0
poll([{fd=3, events=POLLOUT|POLLWRNORM}], 1, 0) = 0 (Timeout)
clock_gettime(CLOCK_MONOTONIC, {681540, 351618878}) = 0
clock_gettime(CLOCK_MONOTONIC, {681540, 351676111}) = 0
poll([{fd=3, events=POLLOUT}], 1, 1000) = 0 (Timeout)
Let me know if you need any additional info.
Thanks.
Works for me. I just tried the latest dev version (I have no reason to beleive it works any differently than 7.30.0 in this aspect) and it worked fine:
$ time ./debugit
curl_easy_perform() failed: Timeout was reached
I attached my test program. My libcurl has version set:
curl 7.31.0-DEV (x86_64-unknown-linux-gnu) libcurl/7.31.0-DEV OpenSSL/1.0.1e zlib/1.2.8 c-ares/1.10.1-DEV libidn/1.25 libssh2/1.4.4_DEV librtmp/2.3
So, please help us repeat your claim!
Hi Daniel,
I forgot to mention 1 important part... The host:port you are trying to connect to must be completely unreachable from your network. Pick any unreachable external host (better outside of your network to prevent any ICMP replies from your router) which will timeout your request. It works fine if host refuses the connection or send any reply back. I can reproduce the same behavior for DNS resolvers connections. Probably it can be OS related, but CentOS / RedHat are de facto enterprise standard, so I'll appreciate any clues.
Libcurl 7.28.1 is the latest version which handles such timeouts properly.
Sure, here is the output:
Latest daily build:
curl -V
curl 7.31.0-20130522 (x86_64-unknown-linux-gnu) libcurl/7.31.0-20130522 OpenSSL/1.0.0 zlib/1.2.3 c-ares/1.9.1 libidn/1.18 libssh2/1.4.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz
./debugit
curl_easy_perform() failed: Timeout was reached
But if you try to connect to any host within your network which will refuse the connection really fast or send any reply back it will just work:
./debugit
curl_easy_perform() failed: Timeout was reached
curl -V
curl 7.30.0 (x86_64-unknown-linux-gnu) libcurl/7.30.0 OpenSSL/1.0.0 zlib/1.2.3 c-ares/1.9.1 libidn/1.18 libssh2/1.4.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz
time ./debugit
curl_easy_perform() failed: Timeout was reached
real 0m1.026s
user 0m0.010s
sys 0m0.015s
and for 7.28.1 (which works):
curl -V
curl 7.28.1 (x86_64-unknown-linux-gnu) libcurl/7.28.1 OpenSSL/1.0.0 zlib/1.2.3 c-ares/1.9.1 libidn/1.18 libssh2/1.4.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz
time ./debugit
curl_easy_perform() failed: Couldn't connect to server
real 0m0.024s
user 0m0.006s
sys 0m0.016s
The interesting part is that there is no "* Connection timed out after XX milliseconds" message generated but the timeout mechanism works as it should.
Thanks.
and the other thing I just noticed.. in 7.28.1 error message is different for this particular case.
it just says: Couldn't connect to server and not "Timeout was reached". But as you can see from strace I provided it respects CONNECTIONTIMEOUT_MS value: poll([{fd=3, events=POLLOUT|POLLWRNORM}], 1, 39) = 0 (Timeout). In my initial example timeout was set to '40' ms
yeps, with an unreachable IP it seems to happen for me as well. Should give me something to debug...
Thanks for the report. I believe I fixed this problem just now with this commit: https://github.com/bagder/curl/commit/29bf0598aad58d9da5dd8c5358f5175dae49026d
Please give it a go and tell us how it works for you!