connection: shutdown TLS (for FTP) better

This adds connection shutdown infrastructure and first use for FTP. FTP
data connections, when not encountering an error, are now shut down in a
blocking way with a 2sec timeout.

    - add cfilter `Curl_cft_shutdown` callback
    - keep a shutdown start timestamp and timeout at connectdata
    - provide shutdown timeout default and member in
      `data->set.shutdowntimeout`.
    - provide methods for starting, interrogating and clearing
      shutdown timers
    - provide `Curl_conn_shutdown_blocking()` to shutdown the
      `sockindex` filter chain in a blocking way. Use that in FTP.
    - add `Curl_conn_cf_poll()` to wait for socket events during
      shutdown of a connection filter chain.
      This gets the monitoring sockets and events via the filters
      "adjust_pollset()" methods. This gives correct behaviour when
      shutting down a TLS connection through a HTTP/2 proxy.
    - Implement shutdown for all socket filters
      - for HTTP/2 and h2 proxying to send GOAWAY
      - for TLS backends to the best of their capabilities
      - for tcp socket filter to make a final, nonblocking
        receive to avoid unwanted RST states
    - add shutdown forwarding to happy eyeballers and
      https connect ballers when applicable.

Closes #13904
This commit is contained in:
Stefan Eissing 2024-06-07 10:12:39 +02:00 committed by Daniel Stenberg
parent 7d934267ab
commit c31041b17e
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
33 changed files with 1161 additions and 465 deletions

View file

@ -55,7 +55,8 @@ struct cf_hc_baller {
CURLcode result;
struct curltime started;
int reply_ms;
bool enabled;
BIT(enabled);
BIT(shutdown);
};
static void cf_hc_baller_reset(struct cf_hc_baller *b,
@ -322,6 +323,49 @@ out:
return result;
}
static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
struct Curl_easy *data, bool *done)
{
struct cf_hc_ctx *ctx = cf->ctx;
struct cf_hc_baller *ballers[2];
size_t i;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
}
/* shutdown all ballers that have not done so already. If one fails,
* continue shutting down others until all are shutdown. */
ballers[0] = &ctx->h3_baller;
ballers[1] = &ctx->h21_baller;
for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
struct cf_hc_baller *b = ballers[i];
bool bdone = FALSE;
if(!cf_hc_baller_is_active(b) || b->shutdown)
continue;
b->result = b->cf->cft->do_shutdown(b->cf, data, &bdone);
if(b->result || bdone)
b->shutdown = TRUE; /* treat a failed shutdown as done */
}
*done = TRUE;
for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
if(ballers[i] && !ballers[i]->shutdown)
*done = FALSE;
}
if(*done) {
for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
if(ballers[i] && ballers[i]->result)
result = ballers[i]->result;
}
}
CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
return result;
}
static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
@ -434,6 +478,7 @@ struct Curl_cftype Curl_cft_http_connect = {
cf_hc_destroy,
cf_hc_connect,
cf_hc_close,
cf_hc_shutdown,
Curl_cf_def_get_host,
cf_hc_adjust_pollset,
cf_hc_data_pending,