summaryrefslogtreecommitdiffhomepage
path: root/src/event/quic/ngx_event_quic_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/event/quic/ngx_event_quic_output.c')
-rw-r--r--src/event/quic/ngx_event_quic_output.c203
1 files changed, 170 insertions, 33 deletions
diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c
index c8e483afb..d6085db8b 100644
--- a/src/event/quic/ngx_event_quic_output.c
+++ b/src/event/quic/ngx_event_quic_output.c
@@ -35,10 +35,14 @@
#define NGX_QUIC_CC_MIN_INTERVAL 1000 /* 1s */
+static ngx_int_t ngx_quic_socket_output(ngx_connection_t *c,
+ ngx_quic_socket_t *qsock);
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_send_ctx_t *ctx, u_char *data, size_t max, size_t min,
+ ngx_quic_socket_t *qsock);
static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
-static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len);
+static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
+ struct sockaddr *sockaddr, socklen_t socklen);
static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt,
ngx_quic_send_ctx_t *ctx);
@@ -61,11 +65,29 @@ ngx_quic_max_udp_payload(ngx_connection_t *c)
ngx_int_t
ngx_quic_output(ngx_connection_t *c)
{
+ ngx_quic_connection_t *qc;
+
+ qc = ngx_quic_get_connection(c);
+
+ if (ngx_quic_socket_output(c, qc->socket) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_quic_set_lost_timer(c);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_quic_socket_output(ngx_connection_t *c, ngx_quic_socket_t *qsock)
+{
off_t max;
size_t len, min, in_flight;
ssize_t n;
u_char *p;
ngx_uint_t i, pad;
+ ngx_quic_path_t *path;
ngx_quic_send_ctx_t *ctx;
ngx_quic_congestion_t *cg;
ngx_quic_connection_t *qc;
@@ -78,15 +100,18 @@ ngx_quic_output(ngx_connection_t *c)
in_flight = cg->in_flight;
+ path = qsock->path;
+
for ( ;; ) {
p = dst;
len = ngx_min(qc->ctp.max_udp_payload_size,
NGX_QUIC_MAX_UDP_PAYLOAD_SIZE);
- if (!qc->validated) {
- max = qc->received * 3;
- max = (c->sent >= max) ? 0 : max - c->sent;
+ if (path->state != NGX_QUIC_PATH_VALIDATED) {
+ max = path->received * 3;
+ max = (path->sent >= max) ? 0 : max - path->sent;
+
len = ngx_min(len, (size_t) max);
}
@@ -103,7 +128,7 @@ ngx_quic_output(ngx_connection_t *c)
min = (i == pad && p - dst < NGX_QUIC_MIN_INITIAL_SIZE)
? NGX_QUIC_MIN_INITIAL_SIZE - (p - dst) : 0;
- n = ngx_quic_output_packet(c, ctx, p, len, min);
+ n = ngx_quic_output_packet(c, ctx, p, len, min, qsock);
if (n == NGX_ERROR) {
return NGX_ERROR;
}
@@ -117,10 +142,13 @@ ngx_quic_output(ngx_connection_t *c)
break;
}
- n = ngx_quic_send(c, dst, len);
+ n = ngx_quic_send(c, dst, len, path->sockaddr, path->socklen);
+
if (n == NGX_ERROR) {
return NGX_ERROR;
}
+
+ path->sent += len;
}
if (in_flight != cg->in_flight && !qc->send_timer_set && !qc->closing) {
@@ -128,7 +156,6 @@ ngx_quic_output(ngx_connection_t *c)
ngx_add_timer(c->read, qc->tp.max_idle_timeout);
}
- ngx_quic_set_lost_timer(c);
return NGX_OK;
}
@@ -176,14 +203,14 @@ ngx_quic_get_padding_level(ngx_connection_t *c)
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)
+ u_char *data, size_t max, size_t min, ngx_quic_socket_t *qsock)
{
size_t len, hlen, pad_len;
u_char *p;
ssize_t flen;
ngx_str_t out, res;
ngx_int_t rc;
- ngx_uint_t nframes;
+ ngx_uint_t nframes, has_pr;
ngx_msec_t now;
ngx_queue_t *q;
ngx_quic_frame_t *f;
@@ -196,9 +223,10 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
return 0;
}
- ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "quic output %s packet max:%uz min:%uz",
- ngx_quic_level_name(ctx->level), max, min);
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "quic output sock #%uL %s packet max:%uz min:%uz",
+ qsock->sid.seqnum, ngx_quic_level_name(ctx->level),
+ max, min);
qc = ngx_quic_get_connection(c);
cg = &qc->congestion;
@@ -208,7 +236,7 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
: NGX_QUIC_MAX_LONG_HEADER;
hlen += EVP_GCM_TLS_TAG_LEN;
- hlen -= NGX_QUIC_MAX_CID_LEN - qc->scid.len;
+ hlen -= NGX_QUIC_MAX_CID_LEN - qsock->cid->len;
ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
@@ -216,6 +244,7 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
nframes = 0;
p = src;
len = 0;
+ has_pr = 0;
for (q = ngx_queue_head(&ctx->frames);
q != ngx_queue_sentinel(&ctx->frames);
@@ -227,6 +256,12 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
max = cg->window;
}
+ if (f->type == NGX_QUIC_FT_PATH_RESPONSE
+ || f->type == NGX_QUIC_FT_PATH_CHALLENGE)
+ {
+ has_pr = 1;
+ }
+
if (hlen + len >= max) {
break;
}
@@ -296,15 +331,33 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
pkt.version = qc->version;
pkt.log = c->log;
pkt.level = ctx->level;
- pkt.dcid = qc->scid;
- pkt.scid = qc->dcid;
+
+ pkt.dcid.data = qsock->cid->id;
+ pkt.dcid.len = qsock->cid->len;
+
+ pkt.scid.data = qsock->sid.id;
+ pkt.scid.len = qsock->sid.len;
pad_len = 4;
- if (min) {
+ if (min || has_pr) {
hlen = EVP_GCM_TLS_TAG_LEN
+ ngx_quic_create_header(&pkt, NULL, out.len, NULL);
+ /*
+ * 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;
}
@@ -364,11 +417,14 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
}
-ssize_t
-ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len)
+static ssize_t
+ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
+ struct sockaddr *sockaddr, socklen_t socklen)
{
- ngx_buf_t b;
- ngx_chain_t cl, *res;
+ ngx_buf_t b;
+ socklen_t orig_socklen;
+ ngx_chain_t cl, *res;
+ struct sockaddr *orig_sockaddr;
ngx_memzero(&b, sizeof(ngx_buf_t));
@@ -380,7 +436,17 @@ ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len)
cl.buf = &b;
cl.next= NULL;
+ orig_socklen = c->socklen;
+ orig_sockaddr = c->sockaddr;
+
+ c->sockaddr = sockaddr;
+ c->socklen = socklen;
+
res = c->send_chain(c, &cl, 0);
+
+ c->sockaddr = orig_sockaddr;
+ c->socklen = orig_socklen;
+
if (res == NGX_CHAIN_ERROR) {
return NGX_ERROR;
}
@@ -441,7 +507,7 @@ ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt)
"quic vnego packet to send len:%uz %*xs", len, len, buf);
#endif
- (void) ngx_quic_send(c, buf, len);
+ (void) ngx_quic_send(c, buf, len, c->sockaddr, c->socklen);
return NGX_ERROR;
}
@@ -524,7 +590,7 @@ ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf,
return NGX_ERROR;
}
- (void) ngx_quic_send(c, buf, len);
+ (void) ngx_quic_send(c, buf, len, c->sockaddr, c->socklen);
return NGX_DECLINED;
}
@@ -642,7 +708,9 @@ ngx_quic_send_early_cc(ngx_connection_t *c, ngx_quic_header_t *inpkt,
return NGX_ERROR;
}
- if (ngx_quic_send(c, res.data, res.len) == NGX_ERROR) {
+ if (ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen)
+ == NGX_ERROR)
+ {
return NGX_ERROR;
}
@@ -664,8 +732,8 @@ ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf,
expires = ngx_time() + NGX_QUIC_RETRY_TOKEN_LIFETIME;
- if (ngx_quic_new_token(c, conf->av_token_key, &token, &inpkt->dcid,
- expires, 1)
+ if (ngx_quic_new_token(c, c->sockaddr, c->socklen, conf->av_token_key,
+ &token, &inpkt->dcid, expires, 1)
!= NGX_OK)
{
return NGX_ERROR;
@@ -700,7 +768,7 @@ ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf,
"quic packet to send len:%uz %xV", res.len, &res);
#endif
- len = ngx_quic_send(c, res.data, res.len);
+ len = ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen);
if (len == NGX_ERROR) {
return NGX_ERROR;
}
@@ -718,7 +786,7 @@ ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf,
ngx_int_t
-ngx_quic_send_new_token(ngx_connection_t *c)
+ngx_quic_send_new_token(ngx_connection_t *c, ngx_quic_path_t *path)
{
time_t expires;
ngx_str_t token;
@@ -727,13 +795,10 @@ ngx_quic_send_new_token(ngx_connection_t *c)
qc = ngx_quic_get_connection(c);
- if (!qc->conf->retry) {
- return NGX_OK;
- }
-
expires = ngx_time() + NGX_QUIC_NEW_TOKEN_LIFETIME;
- if (ngx_quic_new_token(c, qc->conf->av_token_key, &token, NULL, expires, 0)
+ if (ngx_quic_new_token(c, path->sockaddr, path->socklen,
+ qc->conf->av_token_key, &token, NULL, expires, 0)
!= NGX_OK)
{
return NGX_ERROR;
@@ -849,3 +914,75 @@ ngx_quic_send_ack_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
return NGX_OK;
}
+
+
+ssize_t
+ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
+ size_t min, struct sockaddr *sockaddr, socklen_t socklen)
+{
+ ssize_t len;
+ ngx_str_t res;
+ ngx_quic_header_t pkt;
+ ngx_quic_send_ctx_t *ctx;
+ ngx_quic_connection_t *qc;
+
+ static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
+ static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
+
+ qc = ngx_quic_get_connection(c);
+
+ ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
+
+ len = ngx_quic_create_frame(NULL, frame);
+ if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) {
+ return -1;
+ }
+
+ ngx_quic_log_frame(c->log, frame, 1);
+
+ len = ngx_quic_create_frame(src, frame);
+ if (len == -1) {
+ return -1;
+ }
+
+ if (len < (ssize_t) min) {
+ ngx_memset(src + len, NGX_QUIC_FT_PADDING, min - len);
+ len = min;
+ }
+
+ pkt.keys = qc->keys;
+ pkt.flags = NGX_QUIC_PKT_FIXED_BIT;
+
+ if (qc->key_phase) {
+ pkt.flags |= NGX_QUIC_PKT_KPHASE;
+ }
+
+ ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
+
+ ngx_quic_set_packet_number(&pkt, ctx);
+
+ pkt.version = qc->version;
+ pkt.log = c->log;
+ pkt.level = ctx->level;
+
+ pkt.dcid.data = qc->socket->cid->id;
+ pkt.dcid.len = qc->socket->cid->len;
+
+ pkt.scid.data = qc->socket->sid.id;
+ pkt.scid.len = qc->socket->sid.len;
+
+ pkt.payload.data = src;
+ pkt.payload.len = len;
+
+ res.data = dst;
+
+ if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
+ return -1;
+ }
+
+ ctx->pnum++;
+
+ len = ngx_quic_send(c, res.data, res.len, sockaddr, socklen);
+
+ return len;
+}