multi: handle timeouts on DNS servers by checking for new sockets

If the first name server is not available, the multi interface does
not invoke the socket_cb when the DNS request to the first name server
timesout.  Ensure that the list of sockets are always updated after
calling Curl_resolver_is_resolved.

This bug can be reproduced if Curl is complied with --enable_ares and
your code uses the multi socket interfaces and the
CURLMOPT_SOCKETFUNCTION option.  To test try:
  iptables -I INPUT \
           -s $(sed -n -e '/name/{s/.* //p;q}' /etc/resolv.conf)/32 \
           -j REJECT
and then run a program which uses the multi-interface.
This commit is contained in:
Jason Glasgow 2011-11-30 15:23:44 -05:00 committed by Daniel Stenberg
parent 83350c9cc4
commit adc88ca203
2 changed files with 13 additions and 9 deletions

View File

@ -227,18 +227,19 @@ int Curl_resolver_getsock(struct connectdata *conn,
struct timeval maxtime;
struct timeval timebuf;
struct timeval *timeout;
long milli;
int max = ares_getsock((ares_channel)conn->data->state.resolver,
(ares_socket_t *)socks, numsocks);
maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
maxtime.tv_usec = 0;
timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
&timebuf);
Curl_expire(conn->data,
(timeout->tv_sec * 1000) + (timeout->tv_usec/1000));
milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
if(milli == 0)
milli += 10;
Curl_expire(conn->data, milli);
return max;
}

View File

@ -1085,12 +1085,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* check if we have the name resolved by now */
easy->result = Curl_resolver_is_resolved(easy->easy_conn, &dns);
if(dns) {
/* Update sockets here. Mainly because the socket(s) may have been
closed and the application thus needs to be told, even if it is
likely that the same socket(s) will again be used further down. */
singlesocket(multi, easy);
/* Update sockets here, because the socket(s) may have been
closed and the application thus needs to be told, even if it
is likely that the same socket(s) will again be used further
down. If the name has not yet been resolved, it is likely
that new sockets have been opened in an attempt to contact
another resolver. */
singlesocket(multi, easy);
if(dns) {
/* Perform the next step in the connection phase, and then move on
to the WAITCONNECT state */
easy->result = Curl_async_resolved(easy->easy_conn,