Mercurial > hg > nginx
diff src/event/ngx_event_quic.c @ 8326:1cdd53532309 quic
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
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Mon, 06 Apr 2020 16:19:26 +0300 |
parents | 9b9d592c0da3 |
children | 0ae50d90658a |
line wrap: on
line diff
--- a/src/event/ngx_event_quic.c +++ b/src/event/ngx_event_quic.c @@ -134,6 +134,8 @@ static ngx_int_t ngx_quic_payload_handle 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 "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 } 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 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 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 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; }