ACK ranges processing.
+ since number of ranges in unknown, provide a function to parse them once again in handler to avoid memory allocation + ack handler now processes all ranges, not only the first + ECN counters are parsed and saved into frame if present
This commit is contained in:
parent
c0c3a400ef
commit
88b9aed247
3 changed files with 134 additions and 29 deletions
|
@ -134,6 +134,8 @@ static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c,
|
|||
|
||||
static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c,
|
||||
ngx_quic_header_t *pkt, ngx_quic_ack_frame_t *f);
|
||||
static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c,
|
||||
ngx_quic_namespace_t *ns, uint64_t min, uint64_t max);
|
||||
static ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c,
|
||||
ngx_quic_header_t *pkt, ngx_quic_crypto_frame_t *frame);
|
||||
static ngx_int_t ngx_quic_handle_stream_frame(ngx_connection_t *c,
|
||||
|
@ -1242,9 +1244,10 @@ static ngx_int_t
|
|||
ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
|
||||
ngx_quic_ack_frame_t *ack)
|
||||
{
|
||||
ngx_uint_t found, min;
|
||||
ngx_queue_t *q, range;
|
||||
ngx_quic_frame_t *f;
|
||||
ssize_t n;
|
||||
u_char *pos, *end;
|
||||
uint64_t gap, range;
|
||||
ngx_uint_t i, min, max;
|
||||
ngx_quic_namespace_t *ns;
|
||||
|
||||
ns = &c->quic->ns[ngx_quic_ns(pkt->level)];
|
||||
|
@ -1253,6 +1256,12 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
|
|||
"ngx_quic_handle_ack_frame in namespace %d",
|
||||
ngx_quic_ns(pkt->level));
|
||||
|
||||
/*
|
||||
* TODO: If any computed packet number is negative, an endpoint MUST
|
||||
* generate a connection error of type FRAME_ENCODING_ERROR.
|
||||
* (19.3.1)
|
||||
*/
|
||||
|
||||
if (ack->first_range > ack->largest) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"invalid first range in ack frame");
|
||||
|
@ -1260,6 +1269,62 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
|
|||
}
|
||||
|
||||
min = ack->largest - ack->first_range;
|
||||
max = ack->largest;
|
||||
|
||||
if (ngx_quic_handle_ack_frame_range(c, ns, min, max) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* 13.2.3. Receiver Tracking of ACK Frames */
|
||||
if (ns->largest < max) {
|
||||
ns->largest = max;
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"updated largest received: %ui", max);
|
||||
}
|
||||
|
||||
pos = ack->ranges_start;
|
||||
end = ack->ranges_end;
|
||||
|
||||
for (i = 0; i < ack->range_count; i++) {
|
||||
|
||||
n = ngx_quic_parse_ack_range(pkt, pos, end, &gap, &range);
|
||||
if (n == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
pos += n;
|
||||
|
||||
if (gap >= min) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"invalid range %ui in ack frame", i);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
max = min - 1 - gap;
|
||||
|
||||
if (range > max + 1) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
"invalid range %ui in ack frame", i);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
min = max - range + 1;
|
||||
|
||||
if (ngx_quic_handle_ack_frame_range(c, ns, min, max) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_namespace_t *ns,
|
||||
uint64_t min, uint64_t max)
|
||||
{
|
||||
ngx_uint_t found;
|
||||
ngx_queue_t *q, range;
|
||||
ngx_quic_frame_t *f;
|
||||
|
||||
found = 0;
|
||||
|
||||
|
@ -1271,7 +1336,7 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
|
|||
|
||||
f = ngx_queue_data(q, ngx_quic_frame_t, queue);
|
||||
|
||||
if (f->pnum >= min && f->pnum <= ack->largest) {
|
||||
if (f->pnum >= min && f->pnum <= max) {
|
||||
q = ngx_queue_next(q);
|
||||
ngx_queue_remove(&f->queue);
|
||||
ngx_quic_free_frame(c, f);
|
||||
|
@ -1284,9 +1349,9 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
|
|||
|
||||
if (!found) {
|
||||
|
||||
if (ack->largest <= ns->pnum) {
|
||||
if (max <= ns->pnum) {
|
||||
/* duplicate ACK or ACK for non-ack-eliciting frame */
|
||||
goto done;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||
|
@ -1295,15 +1360,6 @@ ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
|
|||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
/* 13.2.3. Receiver Tracking of ACK Frames */
|
||||
if (ns->largest < ack->largest) {
|
||||
ns->largest = ack->largest;
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"updated largest received: %ui", ns->largest);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -561,9 +561,10 @@ ssize_t
|
|||
ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
|
||||
ngx_quic_frame_t *f)
|
||||
{
|
||||
u_char *p;
|
||||
uint8_t flags;
|
||||
uint64_t varint;
|
||||
u_char *p;
|
||||
uint8_t flags;
|
||||
uint64_t varint;
|
||||
ngx_uint_t i;
|
||||
|
||||
flags = pkt->flags;
|
||||
p = start;
|
||||
|
@ -641,21 +642,19 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
|
|||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (f->u.ack.range_count) {
|
||||
p = ngx_quic_parse_int(p, end, &f->u.ack.ranges[0]);
|
||||
f->u.ack.ranges_start = p;
|
||||
|
||||
/* process all ranges to get bounds, values are ignored */
|
||||
for (i = 0; i < f->u.ack.range_count; i++) {
|
||||
p = ngx_quic_parse_int_multi(p, end, &varint, &varint, NULL);
|
||||
if (p == NULL) {
|
||||
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
|
||||
"failed to parse ack frame first range");
|
||||
"failed to parse ack frame range %ui", i);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (f->type == NGX_QUIC_FT_ACK_ECN) {
|
||||
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
|
||||
"TODO: parse ECN ack frames");
|
||||
/* TODO: add parsing of such frames */
|
||||
return NGX_ERROR;
|
||||
}
|
||||
f->u.ack.ranges_end = p;
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
|
||||
"ACK: { largest=%ui delay=%ui count=%ui first=%ui}",
|
||||
|
@ -664,6 +663,21 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
|
|||
f->u.ack.range_count,
|
||||
f->u.ack.first_range);
|
||||
|
||||
if (f->type == NGX_QUIC_FT_ACK_ECN) {
|
||||
|
||||
p = ngx_quic_parse_int_multi(p, end, &f->u.ack.ect0,
|
||||
&f->u.ack.ect1, &f->u.ack.ce, NULL);
|
||||
if (p == NULL) {
|
||||
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
|
||||
"failed to parse ack frame ECT counts", i);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
|
||||
"ACK ECN counters: %ui %ui %ui",
|
||||
f->u.ack.ect0, f->u.ack.ect1, f->u.ack.ce);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NGX_QUIC_FT_PING:
|
||||
|
@ -1111,6 +1125,35 @@ not_allowed:
|
|||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
ngx_quic_parse_ack_range(ngx_quic_header_t *pkt, u_char *start, u_char *end,
|
||||
uint64_t *gap, uint64_t *range)
|
||||
{
|
||||
u_char *p;
|
||||
|
||||
p = start;
|
||||
|
||||
p = ngx_quic_parse_int(p, end, gap);
|
||||
if (p == NULL) {
|
||||
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
|
||||
"failed to parse ack frame gap");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
p = ngx_quic_parse_int(p, end, range);
|
||||
if (p == NULL) {
|
||||
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
|
||||
"failed to parse ack frame range");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0,
|
||||
"ACK range: gap %ui range %ui", *gap, *range);
|
||||
|
||||
return p - start;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f)
|
||||
{
|
||||
|
|
|
@ -102,8 +102,11 @@ typedef struct {
|
|||
uint64_t delay;
|
||||
uint64_t range_count;
|
||||
uint64_t first_range;
|
||||
uint64_t ranges[20];
|
||||
/* TODO: ecn counts */
|
||||
uint64_t ect0;
|
||||
uint64_t ect1;
|
||||
uint64_t ce;
|
||||
u_char *ranges_start;
|
||||
u_char *ranges_end;
|
||||
} ngx_quic_ack_frame_t;
|
||||
|
||||
|
||||
|
@ -284,6 +287,9 @@ ssize_t ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
|
|||
ngx_quic_frame_t *frame);
|
||||
ssize_t ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f);
|
||||
|
||||
ssize_t ngx_quic_parse_ack_range(ngx_quic_header_t *pkt, u_char *start,
|
||||
u_char *end, uint64_t *gap, uint64_t *range);
|
||||
|
||||
ngx_int_t ngx_quic_parse_transport_params(u_char *p, u_char *end,
|
||||
ngx_quic_tp_t *tp, ngx_log_t *log);
|
||||
ssize_t ngx_quic_create_transport_params(u_char *p, u_char *end,
|
||||
|
|
Loading…
Reference in a new issue