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.
This commit is contained in:
Roman Arutyunyan 2020-07-27 18:51:42 +03:00
parent da55aaa1f3
commit d6157edc80
3 changed files with 111 additions and 26 deletions

View file

@ -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_stream_frame(ngx_connection_t *c,
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_t *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_t *c, ngx_quic_header_t *pkt)
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_connection_t *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_uint_t ack)
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;
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;
}
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic creating server uni stream #%ui id %ui",
qc->streams.id_counter, id);
id = (qc->streams.server_streams_bidi << 2)
| NGX_QUIC_STREAM_SERVER_INITIATED;
qc->streams.id_counter++;
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);
sn = ngx_quic_create_stream(qs->parent, id, 0);
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;
}

View file

@ -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);

View file

@ -55,16 +55,8 @@ ngx_http_v3_init_connection(ngx_connection_t *c)
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_connection_t *c, ngx_uint_t type)
}
}
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_t *c)
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_t *c)
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;
}