# HG changeset patch # User Vladimir Homutov # Date 1584701264 -10800 # Node ID e9891e8ee975914da20d1513bc0dda7111d18252 # Parent 0d9bc77ae30db35b9c91c3bdcc90560f94595afd Configurable transport parameters. - integer parameters can be configured using the following directives: quic_max_idle_timeout quic_max_ack_delay quic_max_packet_size quic_initial_max_data quic_initial_max_stream_data_bidi_local quic_initial_max_stream_data_bidi_remote quic_initial_max_stream_data_uni quic_initial_max_streams_bidi quic_initial_max_streams_uni quic_ack_delay_exponent quic_active_migration quic_active_connection_id_limit - only following parameters are actually sent: active_connection_id_limit initial_max_streams_uni initial_max_streams_bidi initial_max_stream_data_bidi_local initial_max_stream_data_bidi_remote initial_max_stream_data_uni (other parameters are to be added into ngx_quic_create_transport_params() function as needed, should be easy now) - draft 24 and draft 27 are now supported (at compile-time using quic_version macro) diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c --- a/src/event/ngx_event_quic.c +++ b/src/event/ngx_event_quic.c @@ -32,6 +32,8 @@ struct ngx_quic_connection_s { ngx_str_t dcid; ngx_str_t token; + ngx_quic_tp_t tp; + /* current packet numbers for each namespace */ ngx_uint_t initial_pn; ngx_uint_t handshake_pn; @@ -67,7 +69,7 @@ static int ngx_quic_send_alert(ngx_ssl_c static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, - ngx_quic_header_t *pkt); + ngx_quic_tp_t *tp, ngx_quic_header_t *pkt); static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); static void ngx_quic_handshake_handler(ngx_event_t *rev); static void ngx_quic_close_connection(ngx_connection_t *c); @@ -283,8 +285,8 @@ ngx_quic_send_alert(ngx_ssl_conn_t *ssl_ void -ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_msec_t timeout, - ngx_connection_handler_pt handler) +ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp, + ngx_msec_t timeout, ngx_connection_handler_pt handler) { ngx_buf_t *b; ngx_quic_header_t pkt; @@ -302,7 +304,7 @@ ngx_quic_run(ngx_connection_t *c, ngx_ss pkt.data = b->start; pkt.len = b->last - b->start; - if (ngx_quic_new_connection(c, ssl, &pkt) != NGX_OK) { + if (ngx_quic_new_connection(c, ssl, tp, &pkt) != NGX_OK) { ngx_quic_close_connection(c); return; } @@ -320,7 +322,7 @@ ngx_quic_run(ngx_connection_t *c, ngx_ss static ngx_int_t -ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, +ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp, ngx_quic_header_t *pkt) { ngx_quic_connection_t *qc; @@ -354,6 +356,7 @@ ngx_quic_new_connection(ngx_connection_t c->quic = qc; qc->ssl = ssl; + qc->tp = *tp; qc->dcid.len = pkt->dcid.len; qc->dcid.data = ngx_pnalloc(c->pool, pkt->dcid.len); @@ -402,19 +405,11 @@ static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c) { int n, sslerr; + u_char *p; + ssize_t len; ngx_ssl_conn_t *ssl_conn; ngx_quic_connection_t *qc; - static const uint8_t params[] = - "\x00\x29" /* parameters length: 41 bytes */ - "\x00\x0e\x00\x01\x05" /* active connection id limit: 5 */ - "\x00\x04\x00\x04\x80\x98\x96\x80" /* initial max data = 10000000 */ - "\x00\x09\x00\x01\x03" /* initial max streams uni: 3 */ - "\x00\x08\x00\x01\x10" /* initial max streams bidi: 16 */ - "\x00\x05\x00\x02\x40\xff" /* initial max stream bidi local: 255 */ - "\x00\x06\x00\x02\x40\xff" /* initial max stream bidi remote: 255 */ - "\x00\x07\x00\x02\x40\xff"; /* initial max stream data uni: 255 */ - qc = c->quic; if (ngx_ssl_create_connection(qc->ssl, c, NGX_SSL_BUFFER) != NGX_OK) { @@ -429,7 +424,20 @@ ngx_quic_init_connection(ngx_connection_ return NGX_ERROR; } - if (SSL_set_quic_transport_params(ssl_conn, params, sizeof(params) - 1) == 0) { + len = ngx_quic_create_transport_params(NULL, NULL, &qc->tp); + /* always succeeds */ + + p = ngx_pnalloc(c->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + len = ngx_quic_create_transport_params(p, p + len, &qc->tp); + if (len < 0) { + return NGX_ERROR; + } + + if (SSL_set_quic_transport_params(ssl_conn, p, len) == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "SSL_set_quic_transport_params() failed"); return NGX_ERROR; diff --git a/src/event/ngx_event_quic.h b/src/event/ngx_event_quic.h --- a/src/event/ngx_event_quic.h +++ b/src/event/ngx_event_quic.h @@ -15,6 +15,29 @@ //#define quic_version 0xff00001b /* draft-27 (FFN 76) */ +typedef struct { + /* configurable */ + ngx_msec_t max_idle_timeout; + ngx_msec_t max_ack_delay; + + ngx_uint_t max_packet_size; + ngx_uint_t initial_max_data; + ngx_uint_t initial_max_stream_data_bidi_local; + ngx_uint_t initial_max_stream_data_bidi_remote; + ngx_uint_t initial_max_stream_data_uni; + ngx_uint_t initial_max_streams_bidi; + ngx_uint_t initial_max_streams_uni; + ngx_uint_t ack_delay_exponent; + ngx_uint_t disable_active_migration; + ngx_uint_t active_connection_id_limit; + + /* TODO */ + ngx_uint_t original_connection_id; + u_char stateless_reset_token[16]; + void *preferred_address; +} ngx_quic_tp_t; + + struct ngx_quic_stream_s { uint64_t id; ngx_uint_t unidirectional:1; @@ -25,8 +48,8 @@ struct ngx_quic_stream_s { void ngx_quic_init_ssl_methods(SSL_CTX* ctx); -void ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_msec_t timeout, - ngx_connection_handler_pt handler); +void ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp, + ngx_msec_t timeout, ngx_connection_handler_pt handler); ngx_connection_t *ngx_quic_create_uni_stream(ngx_connection_t *c); diff --git a/src/event/ngx_event_quic_transport.c b/src/event/ngx_event_quic_transport.c --- a/src/event/ngx_event_quic_transport.c +++ b/src/event/ngx_event_quic_transport.c @@ -87,6 +87,7 @@ static char *ngx_quic_errors[] = { "INVALID_TOKEN", "", "CRYPTO_BUFFER_EXCEEDED", + "", "CRYPTO_ERROR", }; @@ -639,11 +640,11 @@ ngx_quic_parse_frame(ngx_quic_header_t * return NGX_ERROR; } - if (f->u.close.error_code > NGX_QUIC_ERR_LAST) { + if (f->u.close.error_code >= NGX_QUIC_ERR_LAST) { ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "unkown error code: %ui, truncated", f->u.close.error_code); - f->u.close.error_code = NGX_QUIC_ERR_LAST; + f->u.close.error_code = NGX_QUIC_ERR_LAST - 1; } ngx_log_debug4(NGX_LOG_DEBUG_EVENT, pkt->log, 0, @@ -963,6 +964,105 @@ ngx_quic_create_max_streams(u_char *p, n } +ssize_t +ngx_quic_create_transport_params(u_char *pos, u_char *end, ngx_quic_tp_t *tp) +{ + u_char *p; + size_t len; + +#if (quic_version < 0xff00001b) + +/* older drafts with static transport parameters encoding */ + +#define ngx_quic_tp_len(id, value) \ + 4 + ngx_quic_varint_len(value) + +#define ngx_quic_tp_vint(id, value) \ + do { \ + p = ngx_quic_write_uint16(p, id); \ + p = ngx_quic_write_uint16(p, ngx_quic_varint_len(value)); \ + ngx_quic_build_int(&p, value); \ + } while (0) + +#else + +/* recent drafts with variable integer transport parameters encoding */ + +#define ngx_quic_tp_len(id, value) \ + ngx_quic_varint_len(id) \ + + ngx_quic_varint_len(value) \ + + ngx_quic_varint_len(ngx_quic_varint_len(value)) + +#define ngx_quic_tp_vint(id, value) \ + do { \ + ngx_quic_build_int(&p, id); \ + ngx_quic_build_int(&p, ngx_quic_varint_len(value)); \ + ngx_quic_build_int(&p, value); \ + } while (0) + +#endif + + p = pos; + + len = ngx_quic_tp_len(NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT, + tp->active_connection_id_limit); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_DATA,tp->initial_max_data); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI, + tp->initial_max_streams_uni); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI, + tp->initial_max_streams_bidi); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, + tp->initial_max_stream_data_bidi_local); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, + tp->initial_max_stream_data_bidi_remote); + + len += ngx_quic_tp_len(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI, + tp->initial_max_stream_data_uni); + + if (pos == NULL) { +#if (quic_version < 0xff00001b) + len += ngx_quic_varint_len(len); +#endif + return len; + } + +#if (quic_version < 0xff00001b) + /* TLS extension length */ + p = ngx_quic_write_uint16(p, len); +#endif + + ngx_quic_tp_vint(NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT, + tp->active_connection_id_limit); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_DATA, + tp->initial_max_data); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI, + tp->initial_max_streams_uni); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI, + tp->initial_max_streams_bidi); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL, + tp->initial_max_stream_data_bidi_local); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE, + tp->initial_max_stream_data_bidi_remote); + + ngx_quic_tp_vint(NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI, + tp->initial_max_stream_data_uni); + + ngx_quic_hexdump0(ngx_cycle->log, "transport parameters", pos, p - pos); + + return p - pos; +} + + static size_t ngx_quic_create_close(u_char *p, ngx_quic_close_frame_t *cl) { diff --git a/src/event/ngx_event_quic_transport.h b/src/event/ngx_event_quic_transport.h --- a/src/event/ngx_event_quic_transport.h +++ b/src/event/ngx_event_quic_transport.h @@ -65,10 +65,28 @@ #define NGX_QUIC_ERR_INVALID_TOKEN 0x0B /* 0xC is not defined */ #define NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED 0x0D +/* 0xE is not defined */ #define NGX_QUIC_ERR_CRYPTO_ERROR 0x10 #define NGX_QUIC_ERR_LAST NGX_QUIC_ERR_CRYPTO_ERROR +/* Transport parameters */ +#define NGX_QUIC_TP_ORIGINAL_CONNECTION_ID 0x00 +#define NGX_QUIC_TP_MAX_IDLE_TIMEOUT 0x01 +#define NGX_QUIC_TP_STATELESS_RESET_TOKEN 0x02 +#define NGX_QUIC_TP_MAX_PACKET_SIZE 0x03 +#define NGX_QUIC_TP_INITIAL_MAX_DATA 0x04 +#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL 0x05 +#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE 0x06 +#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI 0x07 +#define NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI 0x08 +#define NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI 0x09 +#define NGX_QUIC_TP_ACK_DELAY_EXPONENT 0x0a +#define NGX_QUIC_TP_MAX_ACK_DELAY 0x0b +#define NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION 0x0c +#define NGX_QUIC_TP_PREFERRED_ADDRESS 0x0d +#define NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT 0x0e + typedef struct { ngx_uint_t pn; @@ -208,4 +226,7 @@ ssize_t ngx_quic_parse_frame(ngx_quic_he ngx_quic_frame_t *frame); ssize_t ngx_quic_create_frame(u_char *p, u_char *end, ngx_quic_frame_t *f); +ssize_t ngx_quic_create_transport_params(u_char *p, u_char *end, + ngx_quic_tp_t *tp); + #endif /* _NGX_EVENT_QUIC_WIRE_H_INCLUDED_ */ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -341,11 +341,14 @@ ngx_http_init_connection(ngx_connection_ #if (NGX_HTTP_V3) if (hc->quic) { + ngx_http_v3_srv_conf_t *v3cf; ngx_http_ssl_srv_conf_t *sscf; + v3cf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v3_module); sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - ngx_quic_run(c, &sscf->ssl, c->listening->post_accept_timeout, + ngx_quic_run(c, &sscf->ssl, &v3cf->quic, + c->listening->post_accept_timeout, ngx_http_quic_stream_handler); return; } diff --git a/src/http/v3/ngx_http_v3.h b/src/http/v3/ngx_http_v3.h --- a/src/http/v3/ngx_http_v3.h +++ b/src/http/v3/ngx_http_v3.h @@ -40,6 +40,11 @@ typedef struct { + ngx_quic_tp_t quic; +} ngx_http_v3_srv_conf_t; + + +typedef struct { ngx_http_connection_t hc; ngx_array_t *dynamic; 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 @@ -11,10 +11,100 @@ static ngx_command_t ngx_http_v3_commands[] = { + + { ngx_string("quic_max_idle_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.max_idle_timeout), + NULL }, + + { ngx_string("quic_max_ack_delay"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.max_ack_delay), + NULL }, + + { ngx_string("quic_max_packet_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.max_packet_size), + NULL }, + + { ngx_string("quic_initial_max_data"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_data), + NULL }, + + { ngx_string("quic_initial_max_stream_data_bidi_local"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_stream_data_bidi_local), + NULL }, + + { ngx_string("quic_initial_max_stream_data_bidi_remote"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_stream_data_bidi_remote), + NULL }, + + { ngx_string("quic_initial_max_stream_data_uni"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_stream_data_uni), + NULL }, + + { ngx_string("quic_initial_max_streams_bidi"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_streams_bidi), + NULL }, + + { ngx_string("quic_initial_max_streams_uni"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.initial_max_streams_uni), + NULL }, + + { ngx_string("quic_ack_delay_exponent"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.ack_delay_exponent), + NULL }, + + { ngx_string("quic_active_migration"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.disable_active_migration), + NULL }, + + { ngx_string("quic_active_connection_id_limit"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_v3_srv_conf_t, quic.active_connection_id_limit), + NULL }, + ngx_null_command }; +static void *ngx_http_v3_create_srv_conf(ngx_conf_t *cf); +static char *ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, + void *parent, void *child); + + static ngx_http_module_t ngx_http_v3_module_ctx = { NULL, /* preconfiguration */ NULL, /* postconfiguration */ @@ -22,8 +112,8 @@ static ngx_http_module_t ngx_http_v3_mo NULL, /* create main configuration */ NULL, /* init main configuration */ - NULL, /* create server configuration */ - NULL, /* merge server configuration */ + ngx_http_v3_create_srv_conf, /* create server configuration */ + ngx_http_v3_merge_srv_conf, /* merge server configuration */ NULL, /* create location configuration */ NULL /* merge location configuration */ @@ -44,3 +134,91 @@ ngx_module_t ngx_http_v3_module = { NULL, /* exit master */ NGX_MODULE_V1_PADDING }; + + +static void * +ngx_http_v3_create_srv_conf(ngx_conf_t *cf) +{ + ngx_http_v3_srv_conf_t *v3cf; + + v3cf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v3_srv_conf_t)); + if (v3cf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * v3cf->quic.original_connection_id = 0; + * v3cf->quic.stateless_reset_token = { 0 } + * conf->quic.preferred_address = NULL + */ + + v3cf->quic.max_idle_timeout = NGX_CONF_UNSET_MSEC; + v3cf->quic.max_ack_delay = NGX_CONF_UNSET_MSEC; + + v3cf->quic.max_packet_size = NGX_CONF_UNSET_UINT; + v3cf->quic.initial_max_data = NGX_CONF_UNSET_UINT; + v3cf->quic.initial_max_stream_data_bidi_local = NGX_CONF_UNSET_UINT; + v3cf->quic.initial_max_stream_data_bidi_remote = NGX_CONF_UNSET_UINT; + v3cf->quic.initial_max_stream_data_uni = NGX_CONF_UNSET_UINT; + v3cf->quic.initial_max_streams_bidi = NGX_CONF_UNSET_UINT; + v3cf->quic.initial_max_streams_uni = NGX_CONF_UNSET_UINT; + v3cf->quic.ack_delay_exponent = NGX_CONF_UNSET_UINT; + v3cf->quic.disable_active_migration = NGX_CONF_UNSET_UINT; + v3cf->quic.active_connection_id_limit = NGX_CONF_UNSET_UINT; + + return v3cf; +} + + +static char * +ngx_http_v3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_v3_srv_conf_t *prev = parent; + ngx_http_v3_srv_conf_t *conf = child; + + ngx_conf_merge_msec_value(conf->quic.max_idle_timeout, + prev->quic.max_idle_timeout, 10000); + + // > 2 ^ 14 is invalid + ngx_conf_merge_msec_value(conf->quic.max_ack_delay, + prev->quic.max_ack_delay, 25); + + // < 1200 is invalid + ngx_conf_merge_uint_value(conf->quic.max_packet_size, + prev->quic.max_packet_size, 65527); + + ngx_conf_merge_uint_value(conf->quic.initial_max_data, + prev->quic.initial_max_data, 10000000); + + ngx_conf_merge_uint_value(conf->quic.initial_max_stream_data_bidi_local, + prev->quic.initial_max_stream_data_bidi_local, + 255); + + ngx_conf_merge_uint_value(conf->quic.initial_max_stream_data_bidi_remote, + prev->quic.initial_max_stream_data_bidi_remote, + 255); + + ngx_conf_merge_uint_value(conf->quic.initial_max_stream_data_uni, + prev->quic.initial_max_stream_data_uni, 255); + + ngx_conf_merge_uint_value(conf->quic.initial_max_streams_bidi, + prev->quic.initial_max_streams_bidi, 16); + + ngx_conf_merge_uint_value(conf->quic.initial_max_streams_uni, + prev->quic.initial_max_streams_uni, 16); + + // > 20 is invalid + ngx_conf_merge_uint_value(conf->quic.ack_delay_exponent, + prev->quic.ack_delay_exponent, 3); + + ngx_conf_merge_uint_value(conf->quic.disable_active_migration, + prev->quic.disable_active_migration, 1); + + // < 2 is invalid + ngx_conf_merge_uint_value(conf->quic.active_connection_id_limit, + prev->quic.active_connection_id_limit, 2); + + return NGX_CONF_OK; +} +