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

@ -1010,6 +1010,30 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
cf->connected = FALSE;
}
static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done)
{
if(cf->connected) {
struct cf_socket_ctx *ctx = cf->ctx;
CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" CURL_FORMAT_SOCKET_T
")", ctx->sock);
/* On TCP, and when the socket looks well and non-blocking mode
* can be enabled, receive dangling bytes before close to avoid
* entering RST states unnecessarily. */
if(ctx->sock != CURL_SOCKET_BAD &&
ctx->transport == TRNSPRT_TCP &&
(curlx_nonblock(ctx->sock, TRUE) >= 0)) {
unsigned char buf[1024];
(void)sread(ctx->sock, buf, sizeof(buf));
}
cf_socket_close(cf, data);
}
*done = TRUE;
return CURLE_OK;
}
static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
@ -1729,6 +1753,7 @@ struct Curl_cftype Curl_cft_tcp = {
cf_socket_destroy,
cf_tcp_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
@ -1872,6 +1897,7 @@ struct Curl_cftype Curl_cft_udp = {
cf_socket_destroy,
cf_udp_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
@ -1923,6 +1949,7 @@ struct Curl_cftype Curl_cft_unix = {
cf_socket_destroy,
cf_tcp_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
@ -1987,6 +2014,7 @@ struct Curl_cftype Curl_cft_tcp_accept = {
cf_socket_destroy,
cf_tcp_accept_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_get_host, /* TODO: not accurate */
cf_socket_adjust_pollset,
cf_socket_data_pending,