mirror of
https://github.com/curl/curl.git
synced 2024-11-21 01:16:58 +08:00
quic: make eyeballers connect retries stop at weird replies
- when a connect immediately goes into DRAINING state, do not attempt retries in the QUIC connection filter. Instead, return CURLE_WEIRD_SERVER_REPLY - When eyeballing, interpret CURLE_WEIRD_SERVER_REPLY as an inconclusive answer. When all addresses have been attempted, rewind the address list once on an inconclusive answer. - refs #11832 where connects were retried indefinitely until the overall timeout fired Closes #12400
This commit is contained in:
parent
e7112a726b
commit
247defa753
@ -351,6 +351,7 @@ void Curl_conncontrol(struct connectdata *conn,
|
||||
*/
|
||||
struct eyeballer {
|
||||
const char *name;
|
||||
const struct Curl_addrinfo *first; /* complete address list, not owned */
|
||||
const struct Curl_addrinfo *addr; /* List of addresses to try, not owned */
|
||||
int ai_family; /* matching address family only */
|
||||
cf_ip_connect_create *cf_create; /* for creating cf */
|
||||
@ -362,9 +363,12 @@ struct eyeballer {
|
||||
expire_id timeout_id; /* ID for Curl_expire() */
|
||||
CURLcode result;
|
||||
int error;
|
||||
BIT(rewinded); /* if we rewinded the addr list */
|
||||
BIT(has_started); /* attempts have started */
|
||||
BIT(is_done); /* out of addresses/time */
|
||||
BIT(connected); /* cf has connected */
|
||||
BIT(inconclusive); /* connect was not a hard failure, we
|
||||
* might talk to a restarting server */
|
||||
};
|
||||
|
||||
|
||||
@ -411,7 +415,7 @@ static CURLcode eyeballer_new(struct eyeballer **pballer,
|
||||
#endif
|
||||
"ip"));
|
||||
baller->cf_create = cf_create;
|
||||
baller->addr = addr;
|
||||
baller->first = baller->addr = addr;
|
||||
baller->ai_family = ai_family;
|
||||
baller->primary = primary;
|
||||
baller->delay_ms = delay_ms;
|
||||
@ -441,6 +445,13 @@ static void baller_free(struct eyeballer *baller,
|
||||
}
|
||||
}
|
||||
|
||||
static void baller_rewind(struct eyeballer *baller)
|
||||
{
|
||||
baller->rewinded = TRUE;
|
||||
baller->addr = baller->first;
|
||||
baller->inconclusive = FALSE;
|
||||
}
|
||||
|
||||
static void baller_next_addr(struct eyeballer *baller)
|
||||
{
|
||||
baller->addr = addr_next_match(baller->addr, baller->ai_family);
|
||||
@ -531,6 +542,10 @@ static CURLcode baller_start_next(struct Curl_cfilter *cf,
|
||||
{
|
||||
if(cf->sockindex == FIRSTSOCKET) {
|
||||
baller_next_addr(baller);
|
||||
/* If we get inconclusive answers from the server(s), we make
|
||||
* a second iteration over the address list */
|
||||
if(!baller->addr && baller->inconclusive && !baller->rewinded)
|
||||
baller_rewind(baller);
|
||||
baller_start(cf, data, baller, timeoutms);
|
||||
}
|
||||
else {
|
||||
@ -569,6 +584,8 @@ static CURLcode baller_connect(struct Curl_cfilter *cf,
|
||||
baller->result = CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
}
|
||||
else if(baller->result == CURLE_WEIRD_SERVER_REPLY)
|
||||
baller->inconclusive = TRUE;
|
||||
}
|
||||
return baller->result;
|
||||
}
|
||||
|
@ -2617,27 +2617,9 @@ out:
|
||||
ngtcp2_conn_in_draining_period(ctx->qconn)) {
|
||||
/* When a QUIC server instance is shutting down, it may send us a
|
||||
* CONNECTION_CLOSE right away. Our connection then enters the DRAINING
|
||||
* state.
|
||||
* This may be a stopping of the service or it may be that the server
|
||||
* is reloading and a new instance will start serving soon.
|
||||
* In any case, we tear down our socket and start over with a new one.
|
||||
* We re-open the underlying UDP cf right now, but do not start
|
||||
* connecting until called again.
|
||||
*/
|
||||
int reconn_delay_ms = 200;
|
||||
|
||||
CURL_TRC_CF(data, cf, "connect, remote closed, reconnect after %dms",
|
||||
reconn_delay_ms);
|
||||
Curl_conn_cf_close(cf->next, data);
|
||||
cf_ngtcp2_ctx_clear(ctx);
|
||||
result = Curl_conn_cf_connect(cf->next, data, FALSE, done);
|
||||
if(!result && *done) {
|
||||
*done = FALSE;
|
||||
ctx->reconnect_at = now;
|
||||
ctx->reconnect_at.tv_usec += reconn_delay_ms * 1000;
|
||||
Curl_expire(data, reconn_delay_ms, EXPIRE_QUIC);
|
||||
result = CURLE_OK;
|
||||
}
|
||||
* state. The CONNECT may work in the near future again. Indicate
|
||||
* that as a "weird" reply. */
|
||||
result = CURLE_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_VERBOSE_STRINGS
|
||||
|
@ -1501,27 +1501,9 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
|
||||
else if(quiche_conn_is_draining(ctx->qconn)) {
|
||||
/* When a QUIC server instance is shutting down, it may send us a
|
||||
* CONNECTION_CLOSE right away. Our connection then enters the DRAINING
|
||||
* state.
|
||||
* This may be a stopping of the service or it may be that the server
|
||||
* is reloading and a new instance will start serving soon.
|
||||
* In any case, we tear down our socket and start over with a new one.
|
||||
* We re-open the underlying UDP cf right now, but do not start
|
||||
* connecting until called again.
|
||||
*/
|
||||
int reconn_delay_ms = 200;
|
||||
|
||||
CURL_TRC_CF(data, cf, "connect, remote closed, reconnect after %dms",
|
||||
reconn_delay_ms);
|
||||
Curl_conn_cf_close(cf->next, data);
|
||||
cf_quiche_ctx_clear(ctx);
|
||||
result = Curl_conn_cf_connect(cf->next, data, FALSE, done);
|
||||
if(!result && *done) {
|
||||
*done = FALSE;
|
||||
ctx->reconnect_at = Curl_now();
|
||||
ctx->reconnect_at.tv_usec += reconn_delay_ms * 1000;
|
||||
Curl_expire(data, reconn_delay_ms, EXPIRE_QUIC);
|
||||
result = CURLE_OK;
|
||||
}
|
||||
* state. The CONNECT may work in the near future again. Indicate
|
||||
* that as a "weird" reply. */
|
||||
result = CURLE_WEIRD_SERVER_REPLY;
|
||||
}
|
||||
|
||||
out:
|
||||
|
Loading…
Reference in New Issue
Block a user