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

@ -290,12 +290,15 @@ const struct Curl_handler Curl_handler_ftps = {
};
#endif
static void close_secondarysocket(struct Curl_easy *data,
struct connectdata *conn)
static void close_secondarysocket(struct Curl_easy *data, bool premature)
{
if(!premature) {
CURL_TRC_FTP(data, "[%s] shutting down DATA connection", FTP_DSTATE(data));
Curl_conn_shutdown_blocking(data, SECONDARYSOCKET);
}
CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_DSTATE(data));
Curl_conn_close(data, SECONDARYSOCKET);
Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
Curl_conn_cf_discard_all(data, data->conn, SECONDARYSOCKET);
}
/*
@ -475,7 +478,7 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
Curl_set_in_callback(data, false);
if(error) {
close_secondarysocket(data, conn);
close_secondarysocket(data, TRUE);
return CURLE_ABORTED_BY_CALLBACK;
}
}
@ -2980,7 +2983,13 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_CCC:
if(ftpcode < 500) {
/* First shut down the SSL layer (note: this call will block) */
result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET);
/* This has only been tested on the proftpd server, and the mod_tls
* code sends a close notify alert without waiting for a close notify
* alert in response. Thus we wait for a close notify alert from the
* server, but we do not send one. Let's hope other servers do
* the same... */
result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET,
(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE));
if(result)
failf(data, "Failed to clear the command channel (CCC)");
@ -3457,7 +3466,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
}
}
close_secondarysocket(data, conn);
close_secondarysocket(data, result != CURLE_OK);
}
if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
@ -4425,7 +4434,7 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
CURLcode result = ftp_do_more(data, &completed);
if(result) {
close_secondarysocket(data, conn);
close_secondarysocket(data, TRUE);
return result;
}
}