[PATCH 1 of 3] QUIC: "handshake_timeout" configuration parameter

Sergey Kandaurov pluknet at nginx.com
Tue Sep 12 13:04:59 UTC 2023


> On 11 Sep 2023, at 15:30, Roman Arutyunyan <arut at nginx.com> wrote:
> 
> # HG changeset patch
> # User Roman Arutyunyan <arut at nginx.com>
> # Date 1694415935 -14400
> #      Mon Sep 11 11:05:35 2023 +0400
> # Node ID 65574b876c4047495ac8622c6161fc87c1b75913
> # Parent  daf8f5ba23d8e9955b22782d945f9c065f4b6baa
> QUIC: "handshake_timeout" configuration parameter.
> 
> Previously QUIC did not have such parameter and handshake duration was
> controlled by HTTP/3.  However that required creating and storing HTTP/3
> session while processing the first client datagram.  Apparently there's

s/while/before ?

> no convenient way to store the session object before QUIC handshake.  In
> the following patch session creation will be postponed until first stream
> creation.
> 
> diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c
> --- a/src/event/quic/ngx_event_quic.c
> +++ b/src/event/quic/ngx_event_quic.c
> @@ -213,6 +213,8 @@ ngx_quic_run(ngx_connection_t *c, ngx_qu
>     ngx_add_timer(c->read, qc->tp.max_idle_timeout);
>     ngx_quic_connstate_dbg(c);
> 
> +    ngx_add_timer(&qc->close, qc->conf->handshake_timeout);
> +

It makes sense to cap handshake_timeout to idle timeout.
I.e. ngx_min(qc->conf->handshake_timeout, qc->tp.max_idle_timeout);

Or additionally handle this in ngx_quic_close_connection(),
by removing the timer if set for the NGX_DONE case.

Otherwise the connection would prolong unnecessarily on idle timeout
for no purpose, because close timer set prevents closing a connection.
As a (somewhat degenerate) ready example, see h3_keepalive.t TODO
with too long connection close after the patch applied.
The test uses "keepalive_timeout 0;" in the configuration.

Also I would move setting close timer before calling
ngx_quic_connstate_dbg() to reflect it's set in the debug log.

>     c->read->handler = ngx_quic_input_handler;
> 
>     return;
> @@ -521,6 +523,10 @@ ngx_quic_close_connection(ngx_connection
>                            qc->error_app ? "app " : "", qc->error,
>                            qc->error_reason ? qc->error_reason : "");
> 
> +            if (qc->close.timer_set) {
> +                ngx_del_timer(&qc->close);
> +            }
> +

Removing timer there makes the check below for the timer set unnecessary:

:                if (rc == NGX_OK && !qc->close.timer_set) {

>             for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
>                 ctx = &qc->send_ctx[i];
> 
> diff --git a/src/event/quic/ngx_event_quic.h b/src/event/quic/ngx_event_quic.h
> --- a/src/event/quic/ngx_event_quic.h
> +++ b/src/event/quic/ngx_event_quic.h
> @@ -67,7 +67,8 @@ typedef struct {
>     ngx_flag_t                     retry;
>     ngx_flag_t                     gso_enabled;
>     ngx_flag_t                     disable_active_migration;
> -    ngx_msec_t                     timeout;
> +    ngx_msec_t                     handshake_timeout;
> +    ngx_msec_t                     idle_timeout;
>     ngx_str_t                      host_key;
>     size_t                         stream_buffer_size;
>     ngx_uint_t                     max_concurrent_streams_bidi;
> diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c
> --- a/src/event/quic/ngx_event_quic_streams.c
> +++ b/src/event/quic/ngx_event_quic_streams.c
> @@ -630,6 +630,10 @@ ngx_quic_do_init_streams(ngx_connection_
> 
>     qc->streams.initialized = 1;
> 
> +    if (!qc->closing && qc->close.timer_set) {
> +        ngx_del_timer(&qc->close);
> +    }
> +
>     return NGX_OK;
> }
> 
> diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c
> --- a/src/event/quic/ngx_event_quic_transport.c
> +++ b/src/event/quic/ngx_event_quic_transport.c
> @@ -1985,7 +1985,7 @@ ngx_quic_init_transport_params(ngx_quic_
>      *     tp->preferred_address = NULL
>      */
> 
> -    tp->max_idle_timeout = qcf->timeout;
> +    tp->max_idle_timeout = qcf->idle_timeout;
> 
>     tp->max_udp_payload_size = NGX_QUIC_MAX_UDP_PAYLOAD_SIZE;
> 
> diff --git a/src/http/v3/ngx_http_v3_module.c b/src/http/v3/ngx_http_v3_module.c
> --- a/src/http/v3/ngx_http_v3_module.c
> +++ b/src/http/v3/ngx_http_v3_module.c
> @@ -192,7 +192,7 @@ ngx_http_v3_create_srv_conf(ngx_conf_t *
>      *     h3scf->quic.host_key = { 0, NULL }
>      *     h3scf->quic.stream_reject_code_uni = 0;
>      *     h3scf->quic.disable_active_migration = 0;
> -     *     h3scf->quic.timeout = 0;
> +     *     h3scf->quic.idle_timeout = 0;
>      *     h3scf->max_blocked_streams = 0;
>      */
> 
> @@ -223,7 +223,8 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *c
>     ngx_http_v3_srv_conf_t *prev = parent;
>     ngx_http_v3_srv_conf_t *conf = child;
> 
> -    ngx_http_ssl_srv_conf_t  *sscf;
> +    ngx_http_ssl_srv_conf_t   *sscf;
> +    ngx_http_core_srv_conf_t  *cscf;
> 
>     ngx_conf_merge_value(conf->enable, prev->enable, 1);
> 
> @@ -281,6 +282,9 @@ ngx_http_v3_merge_srv_conf(ngx_conf_t *c
>         return NGX_CONF_ERROR;
>     }
> 
> +    cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
> +    conf->quic.handshake_timeout = cscf->client_header_timeout;
> +
>     sscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_ssl_module);
>     conf->quic.ssl = &sscf->ssl;
> 
> diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c
> --- a/src/http/v3/ngx_http_v3_request.c
> +++ b/src/http/v3/ngx_http_v3_request.c
> @@ -58,18 +58,15 @@ static const struct {
> void
> ngx_http_v3_init_stream(ngx_connection_t *c)
> {
> -    ngx_http_v3_session_t     *h3c;
>     ngx_http_connection_t     *hc, *phc;
>     ngx_http_v3_srv_conf_t    *h3scf;
>     ngx_http_core_loc_conf_t  *clcf;
> -    ngx_http_core_srv_conf_t  *cscf;
> 
>     hc = c->data;
> 
>     hc->ssl = 1;
> 
>     clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module);
> -    cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module);
>     h3scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module);

Not directly related, h3scf initialization can be moved
under the below condition where it is only used.

> 
>     if (c->quic == NULL) {
> @@ -78,10 +75,7 @@ ngx_http_v3_init_stream(ngx_connection_t
>             return;
>         }
> 
> -        h3c = hc->v3_session;
> -        ngx_add_timer(&h3c->keepalive, cscf->client_header_timeout);
> -
> -        h3scf->quic.timeout = clcf->keepalive_timeout;
> +        h3scf->quic.idle_timeout = clcf->keepalive_timeout;
>         ngx_quic_run(c, &h3scf->quic);
>         return;
>     }

-- 
Sergey Kandaurov


More information about the nginx-devel mailing list