Mercurial > hg > nginx-quic
diff src/event/quic/ngx_event_quic.c @ 8411:bc910a5ec737 quic
QUIC: separate files for output and ack related processing.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Tue, 13 Apr 2021 14:41:20 +0300 |
parents | 41807e581de9 |
children | e19723c40d28 |
line wrap: on
line diff
--- a/src/event/quic/ngx_event_quic.c +++ b/src/event/quic/ngx_event_quic.c @@ -11,28 +11,12 @@ #include <ngx_event_quic_connection.h> -#define ngx_quic_lost_threshold(qc) \ - ngx_max(NGX_QUIC_TIME_THR * ngx_max((qc)->latest_rtt, (qc)->avg_rtt), \ - NGX_QUIC_TIME_GRANULARITY) - /* * 7.4. Cryptographic Message Buffering * Implementations MUST support buffering at least 4096 bytes of data */ #define NGX_QUIC_MAX_BUFFERED 65535 -/* - * Endpoints MUST discard packets that are too small to be valid QUIC - * packets. With the set of AEAD functions defined in [QUIC-TLS], - * packets that are smaller than 21 bytes are never valid. - */ -#define NGX_QUIC_MIN_PKT_LEN 21 - -#define NGX_QUIC_MIN_SR_PACKET 43 /* 5 random + 16 srt + 22 padding */ -#define NGX_QUIC_MAX_SR_PACKET 1200 - -#define NGX_QUIC_MAX_ACK_GAP 2 - #if BORINGSSL_API_VERSION >= 10 static int ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, @@ -50,30 +34,19 @@ static int ngx_quic_set_encryption_secre static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, const uint8_t *data, size_t len); static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); -static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, - enum ssl_encryption_level_t level, uint8_t alert); static ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp); static ngx_quic_connection_t *ngx_quic_new_connection(ngx_connection_t *c, ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); -static ngx_int_t ngx_quic_send_stateless_reset(ngx_connection_t *c, - ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); static ngx_int_t ngx_quic_process_stateless_reset(ngx_connection_t *c, ngx_quic_header_t *pkt); -static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c, - ngx_quic_header_t *inpkt); -static ngx_int_t ngx_quic_send_retry(ngx_connection_t *c, - ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); -static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, u_char *key, - ngx_str_t *token, ngx_str_t *odcid, time_t expires, ngx_uint_t is_retry); static void ngx_quic_address_hash(ngx_connection_t *c, ngx_uint_t no_port, u_char buf[20]); static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c, u_char *key, ngx_quic_header_t *pkt); static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); -static ngx_inline size_t ngx_quic_max_udp_payload(ngx_connection_t *c); static void ngx_quic_input_handler(ngx_event_t *rev); static ngx_int_t ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc); @@ -85,60 +58,21 @@ static ngx_int_t ngx_quic_process_packet ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); static ngx_int_t ngx_quic_process_payload(ngx_connection_t *c, ngx_quic_header_t *pkt); -static ngx_int_t ngx_quic_send_early_cc(ngx_connection_t *c, - ngx_quic_header_t *inpkt, ngx_uint_t err, const char *reason); static void ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level); static ngx_int_t ngx_quic_check_csid(ngx_quic_connection_t *qc, ngx_quic_header_t *pkt); static ngx_int_t ngx_quic_handle_frames(ngx_connection_t *c, ngx_quic_header_t *pkt); -static ngx_int_t ngx_quic_ack_packet(ngx_connection_t *c, - ngx_quic_header_t *pkt); -static ngx_int_t ngx_quic_send_ack_range(ngx_connection_t *c, - ngx_quic_send_ctx_t *ctx, uint64_t smallest, uint64_t largest); -static void ngx_quic_drop_ack_ranges(ngx_connection_t *c, - ngx_quic_send_ctx_t *ctx, uint64_t pn); -static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, - ngx_quic_send_ctx_t *ctx); -static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c); -static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c); - -static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c, - ngx_quic_header_t *pkt, ngx_quic_frame_t *f); -static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c, - ngx_quic_send_ctx_t *ctx, uint64_t min, uint64_t max, - ngx_msec_t *send_time); -static void ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack, - enum ssl_encryption_level_t level, ngx_msec_t send_time); + static ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_frame_t *frame); ngx_int_t ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data); -static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c); -static ngx_int_t ngx_quic_generate_ack(ngx_connection_t *c, - ngx_quic_send_ctx_t *ctx); -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); -static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len); - -static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, - ngx_quic_send_ctx_t *ctx); -static void ngx_quic_pto_handler(ngx_event_t *ev); -static void ngx_quic_lost_handler(ngx_event_t *ev); -static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c); -static void ngx_quic_set_lost_timer(ngx_connection_t *c); -static void ngx_quic_resend_frames(ngx_connection_t *c, - ngx_quic_send_ctx_t *ctx); static void ngx_quic_push_handler(ngx_event_t *ev); -static void ngx_quic_congestion_ack(ngx_connection_t *c, - ngx_quic_frame_t *frame); -static void ngx_quic_congestion_lost(ngx_connection_t *c, - ngx_quic_frame_t *frame); - static ngx_core_module_t ngx_quic_module_ctx = { ngx_string("quic"), @@ -178,7 +112,7 @@ static SSL_QUIC_METHOD quic_method = { #if (NGX_DEBUG) -static void +void ngx_quic_connstate_dbg(ngx_connection_t *c) { u_char *p, *last; @@ -241,10 +175,6 @@ ngx_quic_connstate_dbg(ngx_connection_t "quic %*s", p - buf, buf); } -#else - -#define ngx_quic_connstate_dbg(c) - #endif @@ -468,38 +398,6 @@ ngx_quic_flush_flight(ngx_ssl_conn_t *ss } -static int -ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level, - uint8_t alert) -{ - ngx_connection_t *c; - ngx_quic_connection_t *qc; - - c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic ngx_quic_send_alert() lvl:%d alert:%d", - (int) level, (int) alert); - - qc = ngx_quic_get_connection(c); - if (qc == NULL) { - return 1; - } - - qc->error_level = level; - qc->error = NGX_QUIC_ERR_CRYPTO(alert); - qc->error_reason = "TLS alert"; - qc->error_app = 0; - qc->error_ftype = 0; - - if (ngx_quic_send_cc(c) != NGX_OK) { - return 0; - } - - return 1; -} - - static ngx_int_t ngx_quic_apply_transport_params(ngx_connection_t *c, ngx_quic_tp_t *ctp) { @@ -722,57 +620,6 @@ ngx_quic_new_connection(ngx_connection_t } -static ngx_int_t -ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf, - ngx_quic_header_t *pkt) -{ - u_char *token; - size_t len, max; - uint16_t rndbytes; - u_char buf[NGX_QUIC_MAX_SR_PACKET]; - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic handle stateless reset output"); - - if (pkt->len <= NGX_QUIC_MIN_PKT_LEN) { - return NGX_DECLINED; - } - - if (pkt->len <= NGX_QUIC_MIN_SR_PACKET) { - len = pkt->len - 1; - - } else { - max = ngx_min(NGX_QUIC_MAX_SR_PACKET, pkt->len * 3); - - if (RAND_bytes((u_char *) &rndbytes, sizeof(rndbytes)) != 1) { - return NGX_ERROR; - } - - len = (rndbytes % (max - NGX_QUIC_MIN_SR_PACKET + 1)) - + NGX_QUIC_MIN_SR_PACKET; - } - - if (RAND_bytes(buf, len - NGX_QUIC_SR_TOKEN_LEN) != 1) { - return NGX_ERROR; - } - - buf[0] &= ~NGX_QUIC_PKT_LONG; - buf[0] |= NGX_QUIC_PKT_FIXED_BIT; - - token = &buf[len - NGX_QUIC_SR_TOKEN_LEN]; - - if (ngx_quic_new_sr_token(c, &pkt->dcid, conf->sr_token_key, token) - != NGX_OK) - { - return NGX_ERROR; - } - - (void) ngx_quic_send(c, buf, len); - - return NGX_DECLINED; -} - - ngx_int_t ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid, u_char *secret, u_char *token) @@ -843,102 +690,7 @@ ngx_quic_process_stateless_reset(ngx_con } -static ngx_int_t -ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt) -{ - size_t len; - ngx_quic_header_t pkt; - static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, - "sending version negotiation packet"); - - pkt.log = c->log; - pkt.flags = NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_FIXED_BIT; - pkt.dcid = inpkt->scid; - pkt.scid = inpkt->dcid; - - len = ngx_quic_create_version_negotiation(&pkt, buf); - -#ifdef NGX_QUIC_DEBUG_PACKETS - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic vnego packet to send len:%uz %*xs", len, len, buf); -#endif - - (void) ngx_quic_send(c, buf, len); - - return NGX_ERROR; -} - - -static ngx_int_t -ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf, - ngx_quic_header_t *inpkt) -{ - time_t expires; - ssize_t len; - ngx_str_t res, token; - ngx_quic_header_t pkt; - - u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE]; - u_char dcid[NGX_QUIC_SERVER_CID_LEN]; - - expires = ngx_time() + NGX_QUIC_RETRY_TOKEN_LIFETIME; - - if (ngx_quic_new_token(c, conf->av_token_key, &token, &inpkt->dcid, - expires, 1) - != NGX_OK) - { - return NGX_ERROR; - } - - ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); - pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_RETRY; - pkt.version = inpkt->version; - pkt.log = c->log; - - pkt.odcid = inpkt->dcid; - pkt.dcid = inpkt->scid; - - /* TODO: generate routable dcid */ - if (RAND_bytes(dcid, NGX_QUIC_SERVER_CID_LEN) != 1) { - return NGX_ERROR; - } - - pkt.scid.len = NGX_QUIC_SERVER_CID_LEN; - pkt.scid.data = dcid; - - pkt.token = token; - - res.data = buf; - - if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { - return NGX_ERROR; - } - -#ifdef NGX_QUIC_DEBUG_PACKETS - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic packet to send len:%uz %xV", res.len, &res); -#endif - - len = ngx_quic_send(c, res.data, res.len); - if (len == NGX_ERROR) { - return NGX_ERROR; - } - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic retry packet sent to %xV", &pkt.dcid); - - /* - * quic-transport 17.2.5.1: A server MUST NOT send more than one Retry - * packet in response to a single UDP datagram. - * NGX_DONE will stop quic_input() from processing further - */ - return NGX_DONE; -} - - -static ngx_int_t +ngx_int_t ngx_quic_new_token(ngx_connection_t *c, u_char *key, ngx_str_t *token, ngx_str_t *odcid, time_t exp, ngx_uint_t is_retry) { @@ -1267,21 +1019,6 @@ ngx_quic_init_connection(ngx_connection_ } -static ngx_inline size_t -ngx_quic_max_udp_payload(ngx_connection_t *c) -{ - /* TODO: path MTU discovery */ - -#if (NGX_HAVE_INET6) - if (c->sockaddr->sa_family == AF_INET6) { - return NGX_QUIC_MAX_UDP_PAYLOAD_OUT6; - } -#endif - - return NGX_QUIC_MAX_UDP_PAYLOAD_OUT; -} - - static void ngx_quic_input_handler(ngx_event_t *rev) { @@ -1902,83 +1639,6 @@ ngx_quic_process_payload(ngx_connection_ } -static ngx_int_t -ngx_quic_send_early_cc(ngx_connection_t *c, ngx_quic_header_t *inpkt, - ngx_uint_t err, const char *reason) -{ - ssize_t len; - ngx_str_t res; - ngx_quic_frame_t frame; - ngx_quic_header_t pkt; - - static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; - static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; - - ngx_memzero(&frame, sizeof(ngx_quic_frame_t)); - ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); - - frame.level = inpkt->level; - frame.type = NGX_QUIC_FT_CONNECTION_CLOSE; - frame.u.close.error_code = err; - - frame.u.close.reason.data = (u_char *) reason; - frame.u.close.reason.len = ngx_strlen(reason); - - len = ngx_quic_create_frame(NULL, &frame); - if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) { - return NGX_ERROR; - } - - ngx_quic_log_frame(c->log, &frame, 1); - - len = ngx_quic_create_frame(src, &frame); - if (len == -1) { - return NGX_ERROR; - } - - pkt.keys = ngx_quic_keys_new(c->pool); - if (pkt.keys == NULL) { - return NGX_ERROR; - } - - if (ngx_quic_keys_set_initial_secret(c->pool, pkt.keys, &inpkt->dcid, - inpkt->version) - != NGX_OK) - { - return NGX_ERROR; - } - - pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG - | NGX_QUIC_PKT_INITIAL; - - pkt.num_len = 1; - /* - * pkt.num = 0; - * pkt.trunc = 0; - */ - - pkt.version = inpkt->version; - pkt.log = c->log; - pkt.level = inpkt->level; - pkt.dcid = inpkt->scid; - pkt.scid = inpkt->dcid; - pkt.payload.data = src; - pkt.payload.len = len; - - res.data = dst; - - if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { - return NGX_ERROR; - } - - if (ngx_quic_send(c, res.data, res.len) == NGX_ERROR) { - return NGX_ERROR; - } - - return NGX_OK; -} - - static void ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level) { @@ -2291,736 +1951,6 @@ ngx_quic_handle_frames(ngx_connection_t static ngx_int_t -ngx_quic_ack_packet(ngx_connection_t *c, ngx_quic_header_t *pkt) -{ - uint64_t base, largest, smallest, gs, ge, gap, range, pn; - uint64_t prev_pending; - ngx_uint_t i, nr; - ngx_quic_send_ctx_t *ctx; - ngx_quic_ack_range_t *r; - ngx_quic_connection_t *qc; - - c->log->action = "preparing ack"; - - qc = ngx_quic_get_connection(c); - - ctx = ngx_quic_get_send_ctx(qc, pkt->level); - - ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic ngx_quic_ack_packet pn:%uL largest %L fr:%uL" - " nranges:%ui", pkt->pn, (int64_t) ctx->largest_range, - ctx->first_range, ctx->nranges); - - prev_pending = ctx->pending_ack; - - if (pkt->need_ack) { - - ngx_post_event(&qc->push, &ngx_posted_events); - - if (ctx->send_ack == 0) { - ctx->ack_delay_start = ngx_current_msec; - } - - ctx->send_ack++; - - if (ctx->pending_ack == NGX_QUIC_UNSET_PN - || ctx->pending_ack < pkt->pn) - { - ctx->pending_ack = pkt->pn; - } - } - - base = ctx->largest_range; - pn = pkt->pn; - - if (base == NGX_QUIC_UNSET_PN) { - ctx->largest_range = pn; - ctx->largest_received = pkt->received; - return NGX_OK; - } - - if (base == pn) { - return NGX_OK; - } - - largest = base; - smallest = largest - ctx->first_range; - - if (pn > base) { - - if (pn - base == 1) { - ctx->first_range++; - ctx->largest_range = pn; - ctx->largest_received = pkt->received; - - return NGX_OK; - - } else { - /* new gap in front of current largest */ - - /* no place for new range, send current range as is */ - if (ctx->nranges == NGX_QUIC_MAX_RANGES) { - - if (prev_pending != NGX_QUIC_UNSET_PN) { - if (ngx_quic_send_ack(c, ctx) != NGX_OK) { - return NGX_ERROR; - } - } - - if (prev_pending == ctx->pending_ack || !pkt->need_ack) { - ctx->pending_ack = NGX_QUIC_UNSET_PN; - } - } - - gap = pn - base - 2; - range = ctx->first_range; - - ctx->first_range = 0; - ctx->largest_range = pn; - ctx->largest_received = pkt->received; - - /* packet is out of order, force send */ - if (pkt->need_ack) { - ctx->send_ack = NGX_QUIC_MAX_ACK_GAP; - } - - i = 0; - - goto insert; - } - } - - /* pn < base, perform lookup in existing ranges */ - - /* packet is out of order */ - if (pkt->need_ack) { - ctx->send_ack = NGX_QUIC_MAX_ACK_GAP; - } - - if (pn >= smallest && pn <= largest) { - return NGX_OK; - } - -#if (NGX_SUPPRESS_WARN) - r = NULL; -#endif - - for (i = 0; i < ctx->nranges; i++) { - r = &ctx->ranges[i]; - - ge = smallest - 1; - gs = ge - r->gap; - - if (pn >= gs && pn <= ge) { - - if (gs == ge) { - /* gap size is exactly one packet, now filled */ - - /* data moves to previous range, current is removed */ - - if (i == 0) { - ctx->first_range += r->range + 2; - - } else { - ctx->ranges[i - 1].range += r->range + 2; - } - - nr = ctx->nranges - i - 1; - if (nr) { - ngx_memmove(&ctx->ranges[i], &ctx->ranges[i + 1], - sizeof(ngx_quic_ack_range_t) * nr); - } - - ctx->nranges--; - - } else if (pn == gs) { - /* current gap shrinks from tail (current range grows) */ - r->gap--; - r->range++; - - } else if (pn == ge) { - /* current gap shrinks from head (previous range grows) */ - r->gap--; - - if (i == 0) { - ctx->first_range++; - - } else { - ctx->ranges[i - 1].range++; - } - - } else { - /* current gap is split into two parts */ - - gap = ge - pn - 1; - range = 0; - - if (ctx->nranges == NGX_QUIC_MAX_RANGES) { - if (prev_pending != NGX_QUIC_UNSET_PN) { - if (ngx_quic_send_ack(c, ctx) != NGX_OK) { - return NGX_ERROR; - } - } - - if (prev_pending == ctx->pending_ack || !pkt->need_ack) { - ctx->pending_ack = NGX_QUIC_UNSET_PN; - } - } - - r->gap = pn - gs - 1; - goto insert; - } - - return NGX_OK; - } - - largest = smallest - r->gap - 2; - smallest = largest - r->range; - - if (pn >= smallest && pn <= largest) { - /* this packet number is already known */ - return NGX_OK; - } - - } - - if (pn == smallest - 1) { - /* extend first or last range */ - - if (i == 0) { - ctx->first_range++; - - } else { - r->range++; - } - - return NGX_OK; - } - - /* nothing found, add new range at the tail */ - - if (ctx->nranges == NGX_QUIC_MAX_RANGES) { - /* packet is too old to keep it */ - - if (pkt->need_ack) { - return ngx_quic_send_ack_range(c, ctx, pn, pn); - } - - return NGX_OK; - } - - gap = smallest - 2 - pn; - range = 0; - -insert: - - if (ctx->nranges < NGX_QUIC_MAX_RANGES) { - ctx->nranges++; - } - - ngx_memmove(&ctx->ranges[i + 1], &ctx->ranges[i], - sizeof(ngx_quic_ack_range_t) * (ctx->nranges - i - 1)); - - ctx->ranges[i].gap = gap; - ctx->ranges[i].range = range; - - return NGX_OK; -} - - -static ngx_int_t -ngx_quic_send_ack_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, - uint64_t smallest, uint64_t largest) -{ - ngx_quic_frame_t *frame; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - - frame = ngx_quic_alloc_frame(c); - if (frame == NULL) { - return NGX_ERROR; - } - - frame->level = ctx->level; - frame->type = NGX_QUIC_FT_ACK; - frame->u.ack.largest = largest; - frame->u.ack.delay = 0; - frame->u.ack.range_count = 0; - frame->u.ack.first_range = largest - smallest; - - ngx_quic_queue_frame(qc, frame); - - return NGX_OK; -} - - -static void -ngx_quic_drop_ack_ranges(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, - uint64_t pn) -{ - uint64_t base; - ngx_uint_t i, smallest, largest; - ngx_quic_ack_range_t *r; - - ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic ngx_quic_drop_ack_ranges pn:%uL largest:%uL" - " fr:%uL nranges:%ui", pn, ctx->largest_range, - ctx->first_range, ctx->nranges); - - base = ctx->largest_range; - - if (base == NGX_QUIC_UNSET_PN) { - return; - } - - if (ctx->pending_ack != NGX_QUIC_UNSET_PN && pn >= ctx->pending_ack) { - ctx->pending_ack = NGX_QUIC_UNSET_PN; - } - - largest = base; - smallest = largest - ctx->first_range; - - if (pn >= largest) { - ctx->largest_range = NGX_QUIC_UNSET_PN; - ctx->first_range = 0; - ctx->nranges = 0; - return; - } - - if (pn >= smallest) { - ctx->first_range = largest - pn - 1; - ctx->nranges = 0; - return; - } - - for (i = 0; i < ctx->nranges; i++) { - r = &ctx->ranges[i]; - - largest = smallest - r->gap - 2; - smallest = largest - r->range; - - if (pn >= largest) { - ctx->nranges = i; - return; - } - if (pn >= smallest) { - r->range = largest - pn - 1; - ctx->nranges = i + 1; - return; - } - } -} - - -static ngx_int_t -ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) -{ - size_t len, left; - uint64_t ack_delay; - ngx_buf_t *b; - ngx_uint_t i; - ngx_chain_t *cl, **ll; - ngx_quic_frame_t *frame; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - - ack_delay = ngx_current_msec - ctx->largest_received; - ack_delay *= 1000; - ack_delay >>= qc->tp.ack_delay_exponent; - - frame = ngx_quic_alloc_frame(c); - if (frame == NULL) { - return NGX_ERROR; - } - - ll = &frame->data; - b = NULL; - - for (i = 0; i < ctx->nranges; i++) { - len = ngx_quic_create_ack_range(NULL, ctx->ranges[i].gap, - ctx->ranges[i].range); - - left = b ? b->end - b->last : 0; - - if (left < len) { - cl = ngx_quic_alloc_buf(c); - if (cl == NULL) { - return NGX_ERROR; - } - - *ll = cl; - ll = &cl->next; - - b = cl->buf; - left = b->end - b->last; - - if (left < len) { - return NGX_ERROR; - } - } - - b->last += ngx_quic_create_ack_range(b->last, ctx->ranges[i].gap, - ctx->ranges[i].range); - - frame->u.ack.ranges_length += len; - } - - *ll = NULL; - - frame->level = ctx->level; - frame->type = NGX_QUIC_FT_ACK; - frame->u.ack.largest = ctx->largest_range; - frame->u.ack.delay = ack_delay; - frame->u.ack.range_count = ctx->nranges; - frame->u.ack.first_range = ctx->first_range; - - ngx_quic_queue_frame(qc, frame); - - return NGX_OK; -} - - -static ngx_int_t -ngx_quic_send_cc(ngx_connection_t *c) -{ - ngx_quic_frame_t *frame; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - - if (qc->draining) { - return NGX_OK; - } - - if (qc->closing - && ngx_current_msec - qc->last_cc < NGX_QUIC_CC_MIN_INTERVAL) - { - /* dot not send CC too often */ - return NGX_OK; - } - - frame = ngx_quic_alloc_frame(c); - if (frame == NULL) { - return NGX_ERROR; - } - - frame->level = qc->error_level; - frame->type = qc->error_app ? NGX_QUIC_FT_CONNECTION_CLOSE_APP - : NGX_QUIC_FT_CONNECTION_CLOSE; - frame->u.close.error_code = qc->error; - frame->u.close.frame_type = qc->error_ftype; - - if (qc->error_reason) { - frame->u.close.reason.len = ngx_strlen(qc->error_reason); - frame->u.close.reason.data = (u_char *) qc->error_reason; - } - - ngx_quic_queue_frame(qc, frame); - - qc->last_cc = ngx_current_msec; - - return ngx_quic_output(c); -} - - -static ngx_int_t -ngx_quic_send_new_token(ngx_connection_t *c) -{ - time_t expires; - ngx_str_t token; - ngx_quic_frame_t *frame; - ngx_quic_connection_t *qc; - - 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) - != NGX_OK) - { - return NGX_ERROR; - } - - frame = ngx_quic_alloc_frame(c); - if (frame == NULL) { - return NGX_ERROR; - } - - frame->level = ssl_encryption_application; - frame->type = NGX_QUIC_FT_NEW_TOKEN; - frame->u.token.length = token.len; - frame->u.token.data = token.data; - - ngx_quic_queue_frame(qc, frame); - - return NGX_OK; -} - - -static ngx_int_t -ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, - ngx_quic_frame_t *f) -{ - ssize_t n; - u_char *pos, *end; - uint64_t min, max, gap, range; - ngx_msec_t send_time; - ngx_uint_t i; - ngx_quic_send_ctx_t *ctx; - ngx_quic_ack_frame_t *ack; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - - ctx = ngx_quic_get_send_ctx(qc, pkt->level); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic ngx_quic_handle_ack_frame level:%d", pkt->level); - - ack = &f->u.ack; - - /* - * 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) { - qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "quic invalid first range in ack frame"); - return NGX_ERROR; - } - - min = ack->largest - ack->first_range; - max = ack->largest; - - if (ngx_quic_handle_ack_frame_range(c, ctx, min, max, &send_time) - != NGX_OK) - { - return NGX_ERROR; - } - - /* 13.2.3. Receiver Tracking of ACK Frames */ - if (ctx->largest_ack < max || ctx->largest_ack == NGX_QUIC_UNSET_PN) { - ctx->largest_ack = max; - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic updated largest received ack:%uL", max); - - /* - * An endpoint generates an RTT sample on receiving an - * ACK frame that meets the following two conditions: - * - * - the largest acknowledged packet number is newly acknowledged - * - at least one of the newly acknowledged packets was ack-eliciting. - */ - - if (send_time != NGX_TIMER_INFINITE) { - ngx_quic_rtt_sample(c, ack, pkt->level, send_time); - } - } - - if (f->data) { - pos = f->data->buf->pos; - end = f->data->buf->last; - - } else { - pos = NULL; - end = NULL; - } - - for (i = 0; i < ack->range_count; i++) { - - n = ngx_quic_parse_ack_range(pkt->log, pos, end, &gap, &range); - if (n == NGX_ERROR) { - return NGX_ERROR; - } - pos += n; - - if (gap + 2 > min) { - qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "quic invalid range:%ui in ack frame", i); - return NGX_ERROR; - } - - max = min - gap - 2; - - if (range > max) { - qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR; - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "quic invalid range:%ui in ack frame", i); - return NGX_ERROR; - } - - min = max - range; - - if (ngx_quic_handle_ack_frame_range(c, ctx, min, max, &send_time) - != NGX_OK) - { - return NGX_ERROR; - } - } - - return ngx_quic_detect_lost(c); -} - - -static ngx_int_t -ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx, - uint64_t min, uint64_t max, ngx_msec_t *send_time) -{ - ngx_uint_t found; - ngx_queue_t *q; - ngx_quic_frame_t *f; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - - *send_time = NGX_TIMER_INFINITE; - found = 0; - - q = ngx_queue_last(&ctx->sent); - - while (q != ngx_queue_sentinel(&ctx->sent)) { - - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - q = ngx_queue_prev(q); - - if (f->pnum >= min && f->pnum <= max) { - ngx_quic_congestion_ack(c, f); - - switch (f->type) { - case NGX_QUIC_FT_ACK: - case NGX_QUIC_FT_ACK_ECN: - ngx_quic_drop_ack_ranges(c, ctx, f->u.ack.largest); - break; - - case NGX_QUIC_FT_STREAM0: - case NGX_QUIC_FT_STREAM1: - case NGX_QUIC_FT_STREAM2: - case NGX_QUIC_FT_STREAM3: - case NGX_QUIC_FT_STREAM4: - case NGX_QUIC_FT_STREAM5: - case NGX_QUIC_FT_STREAM6: - case NGX_QUIC_FT_STREAM7: - ngx_quic_handle_stream_ack(c, f); - break; - } - - if (f->pnum == max) { - *send_time = f->last; - } - - ngx_queue_remove(&f->queue); - ngx_quic_free_frame(c, f); - found = 1; - } - } - - if (!found) { - - if (max < ctx->pnum) { - /* duplicate ACK or ACK for non-ack-eliciting frame */ - return NGX_OK; - } - - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "quic ACK for the packet not sent"); - - qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION; - qc->error_ftype = NGX_QUIC_FT_ACK; - qc->error_reason = "unknown packet number"; - - return NGX_ERROR; - } - - if (!qc->push.timer_set) { - ngx_post_event(&qc->push, &ngx_posted_events); - } - - qc->pto_count = 0; - - return NGX_OK; -} - - -static void -ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack, - enum ssl_encryption_level_t level, ngx_msec_t send_time) -{ - ngx_msec_t latest_rtt, ack_delay, adjusted_rtt, rttvar_sample; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - - latest_rtt = ngx_current_msec - send_time; - qc->latest_rtt = latest_rtt; - - if (qc->min_rtt == NGX_TIMER_INFINITE) { - qc->min_rtt = latest_rtt; - qc->avg_rtt = latest_rtt; - qc->rttvar = latest_rtt / 2; - - } else { - qc->min_rtt = ngx_min(qc->min_rtt, latest_rtt); - - ack_delay = ack->delay * (1 << qc->ctp.ack_delay_exponent) / 1000; - - if (c->ssl->handshaked) { - ack_delay = ngx_min(ack_delay, qc->ctp.max_ack_delay); - } - - adjusted_rtt = latest_rtt; - - if (qc->min_rtt + ack_delay < latest_rtt) { - adjusted_rtt -= ack_delay; - } - - qc->avg_rtt = 0.875 * qc->avg_rtt + 0.125 * adjusted_rtt; - rttvar_sample = ngx_abs((ngx_msec_int_t) (qc->avg_rtt - adjusted_rtt)); - qc->rttvar = 0.75 * qc->rttvar + 0.25 * rttvar_sample; - } - - ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic rtt sample latest:%M min:%M avg:%M var:%M", - latest_rtt, qc->min_rtt, qc->avg_rtt, qc->rttvar); -} - - -ngx_msec_t -ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) -{ - ngx_msec_t duration; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - - /* PTO calculation: quic-recovery, Appendix 8 */ - duration = qc->avg_rtt; - - duration += ngx_max(4 * qc->rttvar, NGX_QUIC_TIME_GRANULARITY); - duration <<= qc->pto_count; - - if (qc->congestion.in_flight == 0) { /* no in-flight packets */ - return duration; - } - - if (ctx->level == ssl_encryption_application && c->ssl->handshaked) { - duration += qc->ctp.max_ack_delay << qc->pto_count; - } - - return duration; -} - - -static ngx_int_t ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_frame_t *frame) { @@ -3170,507 +2100,6 @@ ngx_quic_crypto_input(ngx_connection_t * } -ngx_int_t -ngx_quic_output(ngx_connection_t *c) -{ - off_t max; - size_t len, min, in_flight; - ssize_t n; - u_char *p; - ngx_uint_t i, pad; - ngx_quic_send_ctx_t *ctx; - ngx_quic_congestion_t *cg; - ngx_quic_connection_t *qc; - static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; - - c->log->action = "sending frames"; - - qc = ngx_quic_get_connection(c); - cg = &qc->congestion; - - in_flight = cg->in_flight; - - 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; - len = ngx_min(len, (size_t) max); - } - - pad = ngx_quic_get_padding_level(c); - - for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { - - ctx = &qc->send_ctx[i]; - - if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { - return NGX_ERROR; - } - - 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); - if (n == NGX_ERROR) { - return NGX_ERROR; - } - - p += n; - len -= n; - } - - len = p - dst; - if (len == 0) { - break; - } - - n = ngx_quic_send(c, dst, len); - if (n == NGX_ERROR) { - return NGX_ERROR; - } - } - - if (in_flight != cg->in_flight && !qc->send_timer_set && !qc->closing) { - qc->send_timer_set = 1; - ngx_add_timer(c->read, qc->tp.max_idle_timeout); - } - - ngx_quic_set_lost_timer(c); - - return NGX_OK; -} - - -static ngx_uint_t -ngx_quic_get_padding_level(ngx_connection_t *c) -{ - ngx_queue_t *q; - ngx_quic_frame_t *f; - ngx_quic_send_ctx_t *ctx; - ngx_quic_connection_t *qc; - - /* - * 14.1. Initial Datagram Size - * - * Similarly, a server MUST expand the payload of all UDP datagrams - * carrying ack-eliciting Initial packets to at least the smallest - * allowed maximum datagram size of 1200 bytes - */ - - qc = ngx_quic_get_connection(c); - ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial); - - for (q = ngx_queue_head(&ctx->frames); - q != ngx_queue_sentinel(&ctx->frames); - q = ngx_queue_next(q)) - { - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - - if (f->need_ack) { - ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); - - if (ngx_queue_empty(&ctx->frames)) { - return 0; - } - - return 1; - } - } - - return NGX_QUIC_SEND_CTX_LAST; -} - - -static ngx_int_t -ngx_quic_generate_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) -{ - ngx_msec_t delay; - ngx_quic_connection_t *qc; - - if (!ctx->send_ack) { - return NGX_OK; - } - - if (ctx->level == ssl_encryption_application) { - - delay = ngx_current_msec - ctx->ack_delay_start; - qc = ngx_quic_get_connection(c); - - if (ctx->send_ack < NGX_QUIC_MAX_ACK_GAP - && delay < qc->tp.max_ack_delay) - { - if (!qc->push.timer_set && !qc->closing) { - ngx_add_timer(&qc->push, - qc->tp.max_ack_delay - delay); - } - - return NGX_OK; - } - } - - if (ngx_quic_send_ack(c, ctx) != NGX_OK) { - return NGX_ERROR; - } - - ctx->send_ack = 0; - - return NGX_OK; -} - - -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) -{ - 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_msec_t now; - ngx_queue_t *q; - ngx_quic_frame_t *f; - ngx_quic_header_t pkt; - ngx_quic_congestion_t *cg; - ngx_quic_connection_t *qc; - static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; - - if (ngx_queue_empty(&ctx->frames)) { - 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); - - qc = ngx_quic_get_connection(c); - cg = &qc->congestion; - - hlen = (ctx->level == ssl_encryption_application) - ? NGX_QUIC_MAX_SHORT_HEADER - : NGX_QUIC_MAX_LONG_HEADER; - - hlen += EVP_GCM_TLS_TAG_LEN; - hlen -= NGX_QUIC_MAX_CID_LEN - qc->scid.len; - - ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); - - now = ngx_current_msec; - nframes = 0; - p = src; - len = 0; - - for (q = ngx_queue_head(&ctx->frames); - q != ngx_queue_sentinel(&ctx->frames); - q = ngx_queue_next(q)) - { - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - - if (!pkt.need_ack && f->need_ack && max > cg->window) { - max = cg->window; - } - - if (hlen + len >= max) { - break; - } - - if (hlen + len + f->len > max) { - rc = ngx_quic_split_frame(c, f, max - hlen - len); - - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - if (rc == NGX_DECLINED) { - break; - } - } - - if (f->need_ack) { - pkt.need_ack = 1; - } - - ngx_quic_log_frame(c->log, f, 1); - - flen = ngx_quic_create_frame(p, f); - if (flen == -1) { - return NGX_ERROR; - } - - len += flen; - p += flen; - - f->pnum = ctx->pnum; - f->first = now; - f->last = now; - f->plen = 0; - - nframes++; - - if (f->flush) { - break; - } - } - - if (nframes == 0) { - return 0; - } - - out.data = src; - out.len = len; - - pkt.keys = qc->keys; - pkt.flags = NGX_QUIC_PKT_FIXED_BIT; - - if (ctx->level == ssl_encryption_initial) { - pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL; - - } else if (ctx->level == ssl_encryption_handshake) { - pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_HANDSHAKE; - - } else { - if (qc->key_phase) { - pkt.flags |= NGX_QUIC_PKT_KPHASE; - } - } - - ngx_quic_set_packet_number(&pkt, ctx); - - pkt.version = qc->version; - pkt.log = c->log; - pkt.level = ctx->level; - pkt.dcid = qc->scid; - pkt.scid = qc->dcid; - - pad_len = 4; - - if (min) { - hlen = EVP_GCM_TLS_TAG_LEN - + ngx_quic_create_header(&pkt, NULL, out.len, NULL); - - if (min > hlen + pad_len) { - pad_len = min - hlen; - } - } - - if (out.len < pad_len) { - ngx_memset(p, NGX_QUIC_FT_PADDING, pad_len - out.len); - out.len = pad_len; - } - - pkt.payload = out; - - 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); - - if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { - return NGX_ERROR; - } - - ctx->pnum++; - - if (pkt.need_ack) { - /* move frames into the sent queue to wait for ack */ - - if (!qc->closing) { - q = ngx_queue_head(&ctx->frames); - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - f->plen = res.len; - - do { - q = ngx_queue_head(&ctx->frames); - ngx_queue_remove(q); - ngx_queue_insert_tail(&ctx->sent, q); - } while (--nframes); - } - - cg->in_flight += res.len; - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic congestion send if:%uz", cg->in_flight); - } - - while (nframes--) { - q = ngx_queue_head(&ctx->frames); - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - - ngx_queue_remove(q); - ngx_quic_free_frame(c, f); - } - - return res.len; -} - - -static ssize_t -ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len) -{ - ngx_buf_t b; - ngx_chain_t cl, *res; - - ngx_memzero(&b, sizeof(ngx_buf_t)); - - b.pos = b.start = buf; - b.last = b.end = buf + len; - b.last_buf = 1; - b.temporary = 1; - - cl.buf = &b; - cl.next= NULL; - - res = c->send_chain(c, &cl, 0); - if (res == NGX_CHAIN_ERROR) { - return NGX_ERROR; - } - - return len; -} - - -static void -ngx_quic_set_packet_number(ngx_quic_header_t *pkt, ngx_quic_send_ctx_t *ctx) -{ - uint64_t delta; - - delta = ctx->pnum - ctx->largest_ack; - pkt->number = ctx->pnum; - - if (delta <= 0x7F) { - pkt->num_len = 1; - pkt->trunc = ctx->pnum & 0xff; - - } else if (delta <= 0x7FFF) { - pkt->num_len = 2; - pkt->flags |= 0x1; - pkt->trunc = ctx->pnum & 0xffff; - - } else if (delta <= 0x7FFFFF) { - pkt->num_len = 3; - pkt->flags |= 0x2; - pkt->trunc = ctx->pnum & 0xffffff; - - } else { - pkt->num_len = 4; - pkt->flags |= 0x3; - pkt->trunc = ctx->pnum & 0xffffffff; - } -} - - -static void -ngx_quic_pto_handler(ngx_event_t *ev) -{ - ngx_uint_t i; - ngx_msec_t now; - ngx_queue_t *q, *next; - ngx_connection_t *c; - ngx_quic_frame_t *f; - ngx_quic_send_ctx_t *ctx; - ngx_quic_connection_t *qc; - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer"); - - c = ev->data; - qc = ngx_quic_get_connection(c); - now = ngx_current_msec; - - for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { - - ctx = &qc->send_ctx[i]; - - if (ngx_queue_empty(&ctx->sent)) { - continue; - } - - q = ngx_queue_head(&ctx->sent); - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - - if (f->pnum <= ctx->largest_ack - && ctx->largest_ack != NGX_QUIC_UNSET_PN) - { - continue; - } - - if ((ngx_msec_int_t) (f->last + ngx_quic_pto(c, ctx) - now) > 0) { - continue; - } - - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic pto %s pto_count:%ui", - ngx_quic_level_name(ctx->level), qc->pto_count); - - for (q = ngx_queue_head(&ctx->frames); - q != ngx_queue_sentinel(&ctx->frames); - /* void */) - { - next = ngx_queue_next(q); - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - - if (f->type == NGX_QUIC_FT_PING) { - ngx_queue_remove(q); - ngx_quic_free_frame(c, f); - } - - q = next; - } - - for (q = ngx_queue_head(&ctx->sent); - q != ngx_queue_sentinel(&ctx->sent); - /* void */) - { - next = ngx_queue_next(q); - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - - if (f->type == NGX_QUIC_FT_PING) { - ngx_quic_congestion_lost(c, f); - ngx_queue_remove(q); - ngx_quic_free_frame(c, f); - } - - q = next; - } - - /* enforce 2 udp datagrams */ - - f = ngx_quic_alloc_frame(c); - if (f == NULL) { - break; - } - - f->level = ctx->level; - f->type = NGX_QUIC_FT_PING; - f->flush = 1; - - ngx_quic_queue_frame(qc, f); - - f = ngx_quic_alloc_frame(c); - if (f == NULL) { - break; - } - - f->level = ctx->level; - f->type = NGX_QUIC_FT_PING; - - ngx_quic_queue_frame(qc, f); - } - - qc->pto_count++; - - ngx_quic_connstate_dbg(c); -} - - static void ngx_quic_push_handler(ngx_event_t *ev) { @@ -3689,265 +2118,6 @@ ngx_quic_push_handler(ngx_event_t *ev) } -static -void ngx_quic_lost_handler(ngx_event_t *ev) -{ - ngx_connection_t *c; - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic lost timer"); - - c = ev->data; - - if (ngx_quic_detect_lost(c) != NGX_OK) { - ngx_quic_close_connection(c, NGX_ERROR); - } - - ngx_quic_connstate_dbg(c); -} - - -static ngx_int_t -ngx_quic_detect_lost(ngx_connection_t *c) -{ - ngx_uint_t i; - ngx_msec_t now, wait, thr; - ngx_queue_t *q; - ngx_quic_frame_t *start; - ngx_quic_send_ctx_t *ctx; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - now = ngx_current_msec; - thr = ngx_quic_lost_threshold(qc); - - for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { - - ctx = &qc->send_ctx[i]; - - if (ctx->largest_ack == NGX_QUIC_UNSET_PN) { - continue; - } - - while (!ngx_queue_empty(&ctx->sent)) { - - q = ngx_queue_head(&ctx->sent); - start = ngx_queue_data(q, ngx_quic_frame_t, queue); - - if (start->pnum > ctx->largest_ack) { - break; - } - - wait = start->last + thr - now; - - ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic detect_lost pnum:%uL thr:%M wait:%i level:%d", - start->pnum, thr, (ngx_int_t) wait, start->level); - - if ((ngx_msec_int_t) wait > 0 - && ctx->largest_ack - start->pnum < NGX_QUIC_PKT_THR) - { - break; - } - - ngx_quic_resend_frames(c, ctx); - } - } - - ngx_quic_set_lost_timer(c); - - return NGX_OK; -} - - -static void -ngx_quic_set_lost_timer(ngx_connection_t *c) -{ - ngx_uint_t i; - ngx_msec_t now; - ngx_queue_t *q; - ngx_msec_int_t lost, pto, w; - ngx_quic_frame_t *f; - ngx_quic_send_ctx_t *ctx; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - now = ngx_current_msec; - - lost = -1; - pto = -1; - - for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { - ctx = &qc->send_ctx[i]; - - if (ngx_queue_empty(&ctx->sent)) { - continue; - } - - if (ctx->largest_ack != NGX_QUIC_UNSET_PN) { - q = ngx_queue_head(&ctx->sent); - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - w = (ngx_msec_int_t) (f->last + ngx_quic_lost_threshold(qc) - now); - - if (f->pnum <= ctx->largest_ack) { - if (w < 0 || ctx->largest_ack - f->pnum >= NGX_QUIC_PKT_THR) { - w = 0; - } - - if (lost == -1 || w < lost) { - lost = w; - } - } - } - - q = ngx_queue_last(&ctx->sent); - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - w = (ngx_msec_int_t) (f->last + ngx_quic_pto(c, ctx) - now); - - if (w < 0) { - w = 0; - } - - if (pto == -1 || w < pto) { - pto = w; - } - } - - if (qc->pto.timer_set) { - ngx_del_timer(&qc->pto); - } - - if (lost != -1) { - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic lost timer lost:%M", lost); - - qc->pto.handler = ngx_quic_lost_handler; - ngx_add_timer(&qc->pto, lost); - return; - } - - if (pto != -1) { - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic lost timer pto:%M", pto); - - qc->pto.handler = ngx_quic_pto_handler; - ngx_add_timer(&qc->pto, pto); - return; - } - - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic lost timer unset"); -} - - -static void -ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) -{ - size_t n; - ngx_buf_t *b; - ngx_queue_t *q; - ngx_quic_frame_t *f, *start; - ngx_quic_stream_t *sn; - ngx_quic_connection_t *qc; - - qc = ngx_quic_get_connection(c); - q = ngx_queue_head(&ctx->sent); - start = ngx_queue_data(q, ngx_quic_frame_t, queue); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic resend packet pnum:%uL", start->pnum); - - ngx_quic_congestion_lost(c, start); - - do { - f = ngx_queue_data(q, ngx_quic_frame_t, queue); - - if (f->pnum != start->pnum) { - break; - } - - q = ngx_queue_next(q); - - ngx_queue_remove(&f->queue); - - switch (f->type) { - case NGX_QUIC_FT_ACK: - case NGX_QUIC_FT_ACK_ECN: - if (ctx->level == ssl_encryption_application) { - /* force generation of most recent acknowledgment */ - ctx->send_ack = NGX_QUIC_MAX_ACK_GAP; - } - - ngx_quic_free_frame(c, f); - break; - - case NGX_QUIC_FT_PING: - case NGX_QUIC_FT_PATH_RESPONSE: - case NGX_QUIC_FT_CONNECTION_CLOSE: - ngx_quic_free_frame(c, f); - break; - - case NGX_QUIC_FT_MAX_DATA: - f->u.max_data.max_data = qc->streams.recv_max_data; - ngx_quic_queue_frame(qc, f); - break; - - case NGX_QUIC_FT_MAX_STREAMS: - case NGX_QUIC_FT_MAX_STREAMS2: - f->u.max_streams.limit = f->u.max_streams.bidi - ? qc->streams.client_max_streams_bidi - : qc->streams.client_max_streams_uni; - ngx_quic_queue_frame(qc, f); - break; - - case NGX_QUIC_FT_MAX_STREAM_DATA: - sn = ngx_quic_find_stream(&qc->streams.tree, - f->u.max_stream_data.id); - if (sn == NULL) { - ngx_quic_free_frame(c, f); - break; - } - - b = sn->b; - n = sn->fs.received + (b->pos - b->start) + (b->end - b->last); - - if (f->u.max_stream_data.limit < n) { - f->u.max_stream_data.limit = n; - } - - ngx_quic_queue_frame(qc, f); - break; - - case NGX_QUIC_FT_STREAM0: - case NGX_QUIC_FT_STREAM1: - case NGX_QUIC_FT_STREAM2: - case NGX_QUIC_FT_STREAM3: - case NGX_QUIC_FT_STREAM4: - case NGX_QUIC_FT_STREAM5: - case NGX_QUIC_FT_STREAM6: - case NGX_QUIC_FT_STREAM7: - sn = ngx_quic_find_stream(&qc->streams.tree, f->u.stream.stream_id); - - if (sn && sn->c->write->error) { - /* RESET_STREAM was sent */ - ngx_quic_free_frame(c, f); - break; - } - - /* fall through */ - - default: - ngx_queue_insert_tail(&ctx->frames, &f->queue); - } - - } while (q != ngx_queue_sentinel(&ctx->sent)); - - if (qc->closing) { - return; - } - - ngx_post_event(&qc->push, &ngx_posted_events); -} - - void ngx_quic_shutdown_quic(ngx_connection_t *c) { @@ -3981,100 +2151,6 @@ ngx_quic_shutdown_quic(ngx_connection_t } - -static void -ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f) -{ - ngx_msec_t timer; - ngx_quic_congestion_t *cg; - ngx_quic_connection_t *qc; - - if (f->plen == 0) { - return; - } - - qc = ngx_quic_get_connection(c); - cg = &qc->congestion; - - cg->in_flight -= f->plen; - - timer = f->last - cg->recovery_start; - - if ((ngx_msec_int_t) timer <= 0) { - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic congestion ack recovery win:%uz ss:%z if:%uz", - cg->window, cg->ssthresh, cg->in_flight); - - return; - } - - if (cg->window < cg->ssthresh) { - cg->window += f->plen; - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic congestion slow start win:%uz ss:%z if:%uz", - cg->window, cg->ssthresh, cg->in_flight); - - } else { - cg->window += qc->tp.max_udp_payload_size * f->plen / cg->window; - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic congestion avoidance win:%uz ss:%z if:%uz", - cg->window, cg->ssthresh, cg->in_flight); - } - - /* prevent recovery_start from wrapping */ - - timer = cg->recovery_start - ngx_current_msec + qc->tp.max_idle_timeout * 2; - - if ((ngx_msec_int_t) timer < 0) { - cg->recovery_start = ngx_current_msec - qc->tp.max_idle_timeout * 2; - } -} - - -static void -ngx_quic_congestion_lost(ngx_connection_t *c, ngx_quic_frame_t *f) -{ - ngx_msec_t timer; - ngx_quic_congestion_t *cg; - ngx_quic_connection_t *qc; - - if (f->plen == 0) { - return; - } - - qc = ngx_quic_get_connection(c); - cg = &qc->congestion; - - cg->in_flight -= f->plen; - f->plen = 0; - - timer = f->last - cg->recovery_start; - - if ((ngx_msec_int_t) timer <= 0) { - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic congestion lost recovery win:%uz ss:%z if:%uz", - cg->window, cg->ssthresh, cg->in_flight); - - return; - } - - cg->recovery_start = ngx_current_msec; - cg->window /= 2; - - if (cg->window < qc->tp.max_udp_payload_size * 2) { - cg->window = qc->tp.max_udp_payload_size * 2; - } - - cg->ssthresh = cg->window; - - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, - "quic congestion lost win:%uz ss:%z if:%uz", - cg->window, cg->ssthresh, cg->in_flight); -} - - uint32_t ngx_quic_version(ngx_connection_t *c) {