Mercurial > hg > nginx
diff src/event/quic/ngx_event_quic_output.c @ 8894:de7b9af30fc6 quic
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.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Thu, 07 Oct 2021 13:48:29 +0300 |
parents | d8ac4d3c24ac |
children | 25b87b392ce0 |
line wrap: on
line diff
--- a/src/event/quic/ngx_event_quic_output.c Thu Oct 07 12:24:47 2021 +0300 +++ b/src/event/quic/ngx_event_quic_output.c Thu Oct 07 13:48:29 2021 +0300 @@ -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 @@ 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_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); - hlen += EVP_GCM_TLS_TAG_LEN; - hlen -= NGX_QUIC_MAX_CID_LEN - qsock->cid->len; + /* RFC 9001, 5.4.2. Header Protection Sample */ + pad = 4 - pkt.num_len; + min_payload = ngx_max(min_payload, pad); + + 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 @@ { 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 @@ 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); + if (len < min_payload) { + ngx_memset(p, NGX_QUIC_FT_PADDING, min_payload - len); + len = min_payload; + } - /* - * 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 (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 @@ 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_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 @@ 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;