summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/event/ngx_event_quic.c86
-rw-r--r--src/event/ngx_event_quic_transport.c67
-rw-r--r--src/event/ngx_event_quic_transport.h10
3 files changed, 134 insertions, 29 deletions
diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c
index 76ff3a94b..8c9e8da2e 100644
--- 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_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;
}
diff --git a/src/event/ngx_event_quic_transport.c b/src/event/ngx_event_quic_transport.c
index a91fcfc0f..99c474de9 100644
--- a/src/event/ngx_event_quic_transport.c
+++ b/src/event/ngx_event_quic_transport.c
@@ -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:
@@ -1112,6 +1126,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)
{
/*
diff --git a/src/event/ngx_event_quic_transport.h b/src/event/ngx_event_quic_transport.h
index f6bd96d04..c44db4144 100644
--- a/src/event/ngx_event_quic_transport.h
+++ b/src/event/ngx_event_quic_transport.h
@@ -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,