QUIC: send DATA_BLOCKED frame

This commit is contained in:
Jan Prachař 2024-09-10 16:04:21 +02:00
parent 00637cce36
commit 9b1b2c4220
4 changed files with 60 additions and 2 deletions

View File

@ -628,6 +628,12 @@ ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
ngx_quic_queue_frame(qc, f);
break;
case NGX_QUIC_FT_DATA_BLOCKED:
if (qc->streams.send_max_data == f->u.data_blocked.limit) {
ngx_queue_insert_tail(&ctx->frames, &f->queue);
}
break;
case NGX_QUIC_FT_STREAM:
qs = ngx_quic_find_stream(&qc->streams.tree, f->u.stream.stream_id);

View File

@ -159,8 +159,8 @@ typedef struct {
uint64_t client_streams_uni;
uint64_t client_streams_bidi;
ngx_uint_t initialized;
/* unsigned initialized:1; */
unsigned initialized:1;
unsigned flow_control_blocked:1;
} ngx_quic_streams_t;

View File

@ -1046,6 +1046,30 @@ ngx_quic_stream_flush(ngx_quic_stream_t *qs)
}
if (len == 0 && !last) {
/*
* RFC 9000, 4.1. Data Flow Control
*
* A sender SHOULD send a STREAM_DATA_BLOCKED or DATA_BLOCKED frame to
* indicate to the receiver that it has data to write but is blocked by
* flow control limits.
*/
if (qc->streams.send_max_data == qc->streams.send_offset
&& !qc->streams.flow_control_blocked)
{
qc->streams.flow_control_blocked = 1;
frame = ngx_quic_alloc_frame(pc);
if (frame == NULL) {
return NGX_ERROR;
}
frame->level = ssl_encryption_application;
frame->type = NGX_QUIC_FT_DATA_BLOCKED;
frame->u.data_blocked.limit = qc->streams.send_max_data;
ngx_quic_queue_frame(qc, frame);
}
return NGX_OK;
}
@ -1336,6 +1360,8 @@ ngx_quic_handle_max_data_frame(ngx_connection_t *c,
}
qc->streams.send_max_data = f->max_data;
qc->streams.flow_control_blocked = 0;
node = ngx_rbtree_min(tree->root, tree->sentinel);
while (node && qc->streams.send_offset < qc->streams.send_max_data) {

View File

@ -118,6 +118,8 @@ static size_t ngx_quic_create_max_stream_data(u_char *p,
ngx_quic_max_stream_data_frame_t *ms);
static size_t ngx_quic_create_max_data(u_char *p,
ngx_quic_max_data_frame_t *md);
static size_t ngx_quic_create_data_blocked(u_char *p,
ngx_quic_data_blocked_frame_t *db);
static size_t ngx_quic_create_path_challenge(u_char *p,
ngx_quic_path_challenge_frame_t *pc);
static size_t ngx_quic_create_path_response(u_char *p,
@ -1323,6 +1325,9 @@ ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f)
case NGX_QUIC_FT_MAX_DATA:
return ngx_quic_create_max_data(p, &f->u.max_data);
case NGX_QUIC_FT_DATA_BLOCKED:
return ngx_quic_create_data_blocked(p, &f->u.data_blocked);
case NGX_QUIC_FT_PATH_CHALLENGE:
return ngx_quic_create_path_challenge(p, &f->u.path_challenge);
@ -1884,6 +1889,27 @@ ngx_quic_create_max_data(u_char *p, ngx_quic_max_data_frame_t *md)
}
static size_t
ngx_quic_create_data_blocked(u_char *p, ngx_quic_data_blocked_frame_t *db)
{
size_t len;
u_char *start;
if (p == NULL) {
len = ngx_quic_varint_len(NGX_QUIC_FT_DATA_BLOCKED);
len += ngx_quic_varint_len(db->limit);
return len;
}
start = p;
ngx_quic_build_int(&p, NGX_QUIC_FT_DATA_BLOCKED);
ngx_quic_build_int(&p, db->limit);
return p - start;
}
static size_t
ngx_quic_create_path_challenge(u_char *p, ngx_quic_path_challenge_frame_t *pc)
{