← Commit list

b803dc9f20

Stefan Eissing
Stefan Eissing
2026-03-06
SUCCESS Duration: 274s

Subject

async-ares: blocking resolve timeout handling, better

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/asyn-ares.c+48 -45
@@ -368,6 +368,32 @@ out:
return result;
}
+static timediff_t async_ares_poll_timeout(struct async_ares_ctx *ares,
+ timediff_t timeout_ms)
+{
+ struct timeval *ares_calced, time_buf, max_timeout;
+ int itimeout_ms;
+
+#if TIMEDIFF_T_MAX > INT_MAX
+ itimeout_ms = (timeout_ms > INT_MAX) ? INT_MAX :
+ ((timeout_ms < 0) ? -1 : (int)timeout_ms);
+#else
+ itimeout_ms = (int)timeout_ms;
+#endif
+ max_timeout.tv_sec = itimeout_ms / 1000;
+ max_timeout.tv_usec = (itimeout_ms % 1000) * 1000;
+
+ /* c-ares tells us the shortest timeout of any operation on channel */
+ ares_calced = ares_timeout(ares->channel, &max_timeout, &time_buf);
+ /* use the timeout period ares returned to us above if less than one
+ second is left, otherwise use 1000ms to make sure the progress callback
+ gets called frequent enough */
+ if(!ares_calced->tv_sec)
+ return (timediff_t)(ares_calced->tv_usec / 1000);
+ else
+ return 1000;
+}
+
/*
* Curl_async_await()
*
@@ -383,67 +409,44 @@ CURLcode Curl_async_await(struct Curl_easy *data,
struct Curl_dns_entry **dns)
{
struct async_ares_ctx *ares = &data->state.async.ares;
+ struct curltime start = *Curl_pgrs_now(data);
CURLcode result = CURLE_OK;
- timediff_t timeout_ms;
DEBUGASSERT(dns);
*dns = NULL; /* clear on entry */
- timeout_ms = Curl_timeleft_ms(data);
- if(timeout_ms < 0) {
- /* already expired! */
- connclose(data->conn, "Timed out before name resolve started");
- return CURLE_OPERATION_TIMEDOUT;
- }
- if(!timeout_ms)
- timeout_ms = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve */
-
- /* Wait for the name resolve query to complete. */
+ /* Wait for the name resolve query to complete or time out. */
while(!result) {
- struct timeval *real_timeout, time_buf, max_timeout;
- int itimeout_ms;
- timediff_t call_timeout_ms;
-
-#if TIMEDIFF_T_MAX > INT_MAX
- itimeout_ms = (timeout_ms > INT_MAX) ? INT_MAX : (int)timeout_ms;
-#else
- itimeout_ms = (int)timeout_ms;
-#endif
-
- max_timeout.tv_sec = itimeout_ms / 1000;
- max_timeout.tv_usec = (itimeout_ms % 1000) * 1000;
+ timediff_t timeout_ms;
- real_timeout = ares_timeout(ares->channel, &max_timeout, &time_buf);
+ timeout_ms = Curl_timeleft_ms(data);
+ if(!timeout_ms) { /* no applicable timeout from `data`*/
+ timediff_t elapsed_ms = curlx_ptimediff_ms(Curl_pgrs_now(data), &start);
+ if(elapsed_ms < (CURL_TIMEOUT_RESOLVE * 1000))
+ timeout_ms = (CURL_TIMEOUT_RESOLVE * 1000) - elapsed_ms;
+ else
+ timeout_ms = -1;
+ }
- /* use the timeout period ares returned to us above if less than one
- second is left, otherwise use 1000ms to make sure the progress callback
- gets called frequent enough */
- if(!real_timeout->tv_sec)
- call_timeout_ms = (timediff_t)(real_timeout->tv_usec / 1000);
- else
- call_timeout_ms = 1000;
+ if(timeout_ms < 0) {
+ result = CURLE_OPERATION_TIMEDOUT;
+ break;
+ }
- if(Curl_ares_perform(ares->channel, call_timeout_ms) < 0)
- return CURLE_UNRECOVERABLE_POLL;
+ if(Curl_ares_perform(ares->channel,
+ async_ares_poll_timeout(ares, timeout_ms)) < 0) {
+ result = CURLE_UNRECOVERABLE_POLL;
+ break;
+ }
result = Curl_async_is_resolved(data, dns);
if(result || data->state.async.done)
break;
- if(Curl_pgrsUpdate(data))
+ if(Curl_pgrsUpdate(data)) {
result = CURLE_ABORTED_BY_CALLBACK;
- else {
- struct curltime now = curlx_now(); /* update in loop */
- timediff_t elapsed_ms = curlx_ptimediff_ms(&now, Curl_pgrs_now(data));
- if(elapsed_ms <= 0)
- timeout_ms -= 1; /* always deduct at least 1 */
- else if(elapsed_ms > timeout_ms)
- timeout_ms = -1;
- else
- timeout_ms -= elapsed_ms;
+ break;
}
- if(timeout_ms < 0)
- result = CURLE_OPERATION_TIMEDOUT;
}
/* Operation complete, if the lookup was successful we now have the entry