summaryrefslogtreecommitdiffhomepage
path: root/src/event/quic/ngx_event_quic_output.c
diff options
context:
space:
mode:
authorVladimir Homutov <vl@nginx.com>2021-10-07 13:48:29 +0300
committerVladimir Homutov <vl@nginx.com>2021-10-07 13:48:29 +0300
commit5f9c4e15a398bc10e23c7d366d181380135e2503 (patch)
tree546ce66ba5e2111124cdeacdfcff10ca1a57af15 /src/event/quic/ngx_event_quic_output.c
parent151985c931b4c96ca95e78b60f28d537e41352cc (diff)
downloadnginx-5f9c4e15a398bc10e23c7d366d181380135e2503.tar.gz
nginx-5f9c4e15a398bc10e23c7d366d181380135e2503.tar.bz2
QUIC: refactored packet creation.
The "min" and "max" arguments refer to UDP datagram size. Generating payload requires to account properly for header size, which is variable and depends on payload size and packet number.
Diffstat (limited to 'src/event/quic/ngx_event_quic_output.c')
-rw-r--r--src/event/quic/ngx_event_quic_output.c121
1 files changed, 58 insertions, 63 deletions
diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c
index 1fc8fadd5..add69b1a2 100644
--- a/src/event/quic/ngx_event_quic_output.c
+++ b/src/event/quic/ngx_event_quic_output.c
@@ -10,10 +10,6 @@
#include <ngx_event_quic_connection.h>
-#define NGX_QUIC_MAX_SHORT_HEADER 25 /* 1 flags + 20 dcid + 4 pn */
-#define NGX_QUIC_MAX_LONG_HEADER 56
- /* 1 flags + 4 version + 2 x (1 + 20) s/dcid + 4 pn + 4 len + token len */
-
#define NGX_QUIC_MAX_UDP_PAYLOAD_OUT 1252
#define NGX_QUIC_MAX_UDP_PAYLOAD_OUT6 1232
@@ -532,12 +528,12 @@ static ssize_t
ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
u_char *data, size_t max, size_t min, ngx_quic_socket_t *qsock)
{
- size_t len, hlen, pad_len;
+ size_t len, pad, min_payload, max_payload;
u_char *p;
ssize_t flen;
- ngx_str_t out, res;
+ ngx_str_t res;
ngx_int_t rc;
- ngx_uint_t nframes, has_pr;
+ ngx_uint_t nframes, expand;
ngx_msec_t now;
ngx_queue_t *q;
ngx_quic_frame_t *f;
@@ -555,18 +551,22 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
ngx_quic_init_packet(c, ctx, qsock, &pkt);
- hlen = (ctx->level == ssl_encryption_application)
- ? NGX_QUIC_MAX_SHORT_HEADER
- : NGX_QUIC_MAX_LONG_HEADER;
+ min_payload = ngx_quic_payload_size(&pkt, min);
+ max_payload = ngx_quic_payload_size(&pkt, max);
+
+ /* RFC 9001, 5.4.2. Header Protection Sample */
+ pad = 4 - pkt.num_len;
+ min_payload = ngx_max(min_payload, pad);
- hlen += EVP_GCM_TLS_TAG_LEN;
- hlen -= NGX_QUIC_MAX_CID_LEN - qsock->cid->len;
+ if (min_payload > max_payload) {
+ return 0;
+ }
now = ngx_current_msec;
nframes = 0;
p = src;
len = 0;
- has_pr = 0;
+ expand = 0;
for (q = ngx_queue_head(&ctx->frames);
q != ngx_queue_sentinel(&ctx->frames);
@@ -574,18 +574,39 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
{
f = ngx_queue_data(q, ngx_quic_frame_t, queue);
- if (f->type == NGX_QUIC_FT_PATH_RESPONSE
- || f->type == NGX_QUIC_FT_PATH_CHALLENGE)
+ if (!expand && (f->type == NGX_QUIC_FT_PATH_RESPONSE
+ || f->type == NGX_QUIC_FT_PATH_CHALLENGE))
{
- has_pr = 1;
+ /*
+ * RFC 9000, 8.2.1. Initiating Path Validation
+ *
+ * An endpoint MUST expand datagrams that contain a
+ * PATH_CHALLENGE frame to at least the smallest allowed
+ * maximum datagram size of 1200 bytes...
+ *
+ * (same applies to PATH_RESPONSE frames)
+ */
+
+ if (max < 1200) {
+ /* expanded packet will not fit */
+ break;
+ }
+
+ if (min < 1200) {
+ min = 1200;
+
+ min_payload = ngx_quic_payload_size(&pkt, min);
+ }
+
+ expand = 1;
}
- if (hlen + len >= max) {
+ if (len >= max_payload) {
break;
}
- if (hlen + len + f->len > max) {
- rc = ngx_quic_split_frame(c, f, max - hlen - len);
+ if (len + f->len > max_payload) {
+ rc = ngx_quic_split_frame(c, f, max_payload - len);
if (rc == NGX_ERROR) {
return NGX_ERROR;
@@ -626,53 +647,21 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
return 0;
}
- out.data = src;
- out.len = len;
-
- pad_len = 4;
-
- if (min || has_pr) {
- hlen = EVP_GCM_TLS_TAG_LEN
- + ngx_quic_create_header(&pkt, NULL, out.len, NULL);
-
- /*
- * RFC 9000, 8.2.1. Initiating Path Validation
- *
- * An endpoint MUST expand datagrams that contain a
- * PATH_CHALLENGE frame to at least the smallest allowed
- * maximum datagram size of 1200 bytes, unless the
- * anti-amplification limit for the path does not permit
- * sending a datagram of this size.
- *
- * (same applies to PATH_RESPONSE frames)
- */
-
- if (has_pr) {
- min = ngx_max(1200, min);
- }
+ if (len < min_payload) {
+ ngx_memset(p, NGX_QUIC_FT_PADDING, min_payload - len);
+ len = min_payload;
+ }
- if (min > hlen + pad_len) {
- pad_len = min - hlen;
- }
- }
-
- if (out.len < pad_len) {
- /* compensate for potentially enlarged header in Length bytes */
- pad_len -= ngx_quic_create_header(&pkt, NULL, pad_len, NULL)
- - ngx_quic_create_header(&pkt, NULL, out.len, NULL);
- ngx_memset(p, NGX_QUIC_FT_PADDING, pad_len - out.len);
- out.len = pad_len;
- }
-
- pkt.payload = out;
+ pkt.payload.data = src;
+ pkt.payload.len = len;
res.data = data;
ngx_log_debug6(NGX_LOG_DEBUG_EVENT, c->log, 0,
"quic packet tx %s bytes:%ui"
" need_ack:%d number:%L encoded nl:%d trunc:0x%xD",
- ngx_quic_level_name(ctx->level), out.len, pkt.need_ack,
- pkt.number, pkt.num_len, pkt.trunc);
+ ngx_quic_level_name(ctx->level), pkt.payload.len,
+ pkt.need_ack, pkt.number, pkt.num_len, pkt.trunc);
if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
return NGX_ERROR;
@@ -1253,6 +1242,7 @@ ssize_t
ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
size_t min, struct sockaddr *sockaddr, socklen_t socklen)
{
+ size_t min_payload, pad;
ssize_t len;
ngx_str_t res;
ngx_quic_header_t pkt;
@@ -1267,6 +1257,11 @@ ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
ngx_quic_init_packet(c, ctx, qc->socket, &pkt);
+ min_payload = min ? ngx_quic_payload_size(&pkt, min) : 0;
+
+ pad = 4 - pkt.num_len;
+ min_payload = ngx_max(min_payload, pad);
+
len = ngx_quic_create_frame(NULL, frame);
if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) {
return -1;
@@ -1279,10 +1274,10 @@ ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
return -1;
}
- if (len < (ssize_t) min) {
- ngx_memset(src + len, NGX_QUIC_FT_PADDING, min - len);
- len = min;
- }
+ if (len < (ssize_t) min_payload) {
+ ngx_memset(src + len, NGX_QUIC_FT_PADDING, min_payload - len);
+ len = min_payload;
+ }
pkt.payload.data = src;
pkt.payload.len = len;