# HG changeset patch # User Roman Arutyunyan # Date 1595865102 -10800 # Node ID 455a8536eaa7ce22f2dae82b1d216a473960e23e # Parent e334ca1b23ba6310979331122564c7b7687a5ee9 QUIC: limited the number of server-initiated streams. Also, ngx_quic_create_uni_stream() is replaced with ngx_quic_open_stream() which is capable of creating a bidi stream. 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 @@ -39,12 +39,15 @@ typedef struct { ngx_rbtree_t tree; ngx_rbtree_node_t sentinel; - ngx_uint_t id_counter; - uint64_t received; uint64_t sent; uint64_t recv_max_data; uint64_t send_max_data; + + uint64_t server_max_streams_uni; + uint64_t server_max_streams_bidi; + uint64_t server_streams_uni; + uint64_t server_streams_bidi; } ngx_quic_streams_t; @@ -243,6 +246,8 @@ static ngx_int_t ngx_quic_handle_reset_s ngx_quic_header_t *pkt, ngx_quic_reset_stream_frame_t *f); static ngx_int_t ngx_quic_handle_stop_sending_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_stop_sending_frame_t *f); +static ngx_int_t ngx_quic_handle_max_streams_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_max_streams_frame_t *f); static void ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame); @@ -494,6 +499,9 @@ ngx_quic_add_handshake_data(ngx_ssl_conn } #endif + qc->streams.server_max_streams_bidi = qc->ctp.initial_max_streams_bidi; + qc->streams.server_max_streams_uni = qc->ctp.initial_max_streams_uni; + qc->client_tp_done = 1; } @@ -2100,6 +2108,17 @@ ngx_quic_payload_handler(ngx_connection_ break; + case NGX_QUIC_FT_MAX_STREAMS: + case NGX_QUIC_FT_MAX_STREAMS2: + + if (ngx_quic_handle_max_streams_frame(c, pkt, &frame.u.max_streams) + != NGX_OK) + { + return NGX_ERROR; + } + + break; + case NGX_QUIC_FT_NEW_CONNECTION_ID: case NGX_QUIC_FT_RETIRE_CONNECTION_ID: case NGX_QUIC_FT_PATH_CHALLENGE: @@ -3273,6 +3292,35 @@ ngx_quic_handle_stop_sending_frame(ngx_c } +static ngx_int_t +ngx_quic_handle_max_streams_frame(ngx_connection_t *c, + ngx_quic_header_t *pkt, ngx_quic_max_streams_frame_t *f) +{ + ngx_quic_connection_t *qc; + + qc = c->quic; + + if (f->bidi) { + if (qc->streams.server_max_streams_bidi < f->limit) { + qc->streams.server_max_streams_bidi = f->limit; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic max_streams_bidi:%uL", f->limit); + } + + } else { + if (qc->streams.server_max_streams_uni < f->limit) { + qc->streams.server_max_streams_uni = f->limit; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic max_streams_uni:%uL", f->limit); + } + } + + return NGX_OK; +} + + static void ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame) { @@ -3750,26 +3798,61 @@ ngx_quic_detect_lost(ngx_connection_t *c ngx_connection_t * -ngx_quic_create_uni_stream(ngx_connection_t *c) +ngx_quic_open_stream(ngx_connection_t *c, ngx_uint_t bidi) { - ngx_uint_t id; + size_t rcvbuf_size; + uint64_t id; ngx_quic_stream_t *qs, *sn; ngx_quic_connection_t *qc; qs = c->qs; qc = qs->parent->quic; - id = (qc->streams.id_counter << 2) - | NGX_QUIC_STREAM_SERVER_INITIATED - | NGX_QUIC_STREAM_UNIDIRECTIONAL; - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic creating server uni stream #%ui id %ui", - qc->streams.id_counter, id); - - qc->streams.id_counter++; - - sn = ngx_quic_create_stream(qs->parent, id, 0); + if (bidi) { + if (qc->streams.server_streams_bidi + >= qc->streams.server_max_streams_bidi) + { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic too many server bidi streams: %uL", + qc->streams.server_streams_bidi); + return NULL; + } + + id = (qc->streams.server_streams_bidi << 2) + | NGX_QUIC_STREAM_SERVER_INITIATED; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic creating server bidi stream %uL/%uL id:%uL", + qc->streams.server_streams_bidi, + qc->streams.server_max_streams_bidi, id); + + qc->streams.server_streams_bidi++; + rcvbuf_size = qc->tp.initial_max_stream_data_bidi_local; + + } else { + if (qc->streams.server_streams_uni + >= qc->streams.server_max_streams_uni) + { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic too many server uni streams: %uL", + qc->streams.server_streams_uni); + return NULL; + } + + id = (qc->streams.server_streams_uni << 2) + | NGX_QUIC_STREAM_SERVER_INITIATED + | NGX_QUIC_STREAM_UNIDIRECTIONAL; + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic creating server uni stream %uL/%uL id:%uL", + qc->streams.server_streams_uni, + qc->streams.server_max_streams_uni, id); + + qc->streams.server_streams_uni++; + rcvbuf_size = 0; + } + + sn = ngx_quic_create_stream(qs->parent, id, rcvbuf_size); if (sn == NULL) { return NULL; } 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 @@ -113,7 +113,7 @@ struct ngx_quic_stream_s { void ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_conf_t *conf); -ngx_connection_t *ngx_quic_create_uni_stream(ngx_connection_t *c); +ngx_connection_t *ngx_quic_open_stream(ngx_connection_t *c, ngx_uint_t bidi); void ngx_quic_finalize_connection(ngx_connection_t *c, ngx_uint_t err, const char *reason); diff --git a/src/http/v3/ngx_http_v3_streams.c b/src/http/v3/ngx_http_v3_streams.c --- a/src/http/v3/ngx_http_v3_streams.c +++ b/src/http/v3/ngx_http_v3_streams.c @@ -55,16 +55,8 @@ ngx_http_v3_init_connection(ngx_connecti return NGX_OK; } - h3c = c->qs->parent->data; - - if (!h3c->settings_sent) { - h3c->settings_sent = 1; - - if (ngx_http_v3_send_settings(c) != NGX_OK) { - ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, - "could not send settings"); - return NGX_ERROR; - } + if (ngx_http_v3_send_settings(c) == NGX_ERROR) { + return NGX_ERROR; } if ((c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) { @@ -361,7 +353,7 @@ ngx_http_v3_get_uni_stream(ngx_connectio } } - sc = ngx_quic_create_uni_stream(c); + sc = ngx_quic_open_stream(c, 0); if (sc == NULL) { return NULL; } @@ -410,14 +402,19 @@ ngx_http_v3_send_settings(ngx_connection ngx_http_v3_srv_conf_t *h3scf; ngx_http_v3_connection_t *h3c; + h3c = c->qs->parent->data; + + if (h3c->settings_sent) { + return NGX_OK; + } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings"); cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL); if (cc == NULL) { - return NGX_ERROR; + return NGX_DECLINED; } - h3c = c->qs->parent->data; h3scf = ngx_http_get_module_srv_conf(h3c->hc.conf_ctx, ngx_http_v3_module); n = ngx_http_v3_encode_varlen_int(NULL, @@ -441,12 +438,17 @@ ngx_http_v3_send_settings(ngx_connection goto failed; } + h3c->settings_sent = 1; + return NGX_OK; failed: ngx_http_v3_close_uni_stream(cc); + ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR, + "could not send settings"); + return NGX_ERROR; }