src/event/quic/ngx_event_quic_ack.c - nginx source code

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Nginx, Inc.
  3. */


  4. #include <ngx_config.h>
  5. #include <ngx_core.h>
  6. #include <ngx_event.h>
  7. #include <ngx_event_quic_connection.h>


  8. #define NGX_QUIC_MAX_ACK_GAP                 2

  9. /* RFC 9002, 6.1.1. Packet Threshold: kPacketThreshold */
  10. #define NGX_QUIC_PKT_THR                     3 /* packets */
  11. /* RFC 9002, 6.1.2. Time Threshold: kGranularity */
  12. #define NGX_QUIC_TIME_GRANULARITY            1 /* ms */

  13. /* RFC 9002, 7.6.1. Duration: kPersistentCongestionThreshold */
  14. #define NGX_QUIC_PERSISTENT_CONGESTION_THR   3


  15. /* send time of ACK'ed packets */
  16. typedef struct {
  17.     ngx_msec_t                               max_pn;
  18.     ngx_msec_t                               oldest;
  19.     ngx_msec_t                               newest;
  20. } ngx_quic_ack_stat_t;


  21. static ngx_inline ngx_msec_t ngx_quic_lost_threshold(ngx_quic_connection_t *qc);
  22. static void ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack,
  23.     enum ssl_encryption_level_t level, ngx_msec_t send_time);
  24. static ngx_int_t ngx_quic_handle_ack_frame_range(ngx_connection_t *c,
  25.     ngx_quic_send_ctx_t *ctx, uint64_t min, uint64_t max,
  26.     ngx_quic_ack_stat_t *st);
  27. static void ngx_quic_drop_ack_ranges(ngx_connection_t *c,
  28.     ngx_quic_send_ctx_t *ctx, uint64_t pn);
  29. static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c,
  30.     ngx_quic_ack_stat_t *st);
  31. static ngx_msec_t ngx_quic_pcg_duration(ngx_connection_t *c);
  32. static void ngx_quic_persistent_congestion(ngx_connection_t *c);
  33. static void ngx_quic_congestion_lost(ngx_connection_t *c,
  34.     ngx_quic_frame_t *frame);
  35. static void ngx_quic_lost_handler(ngx_event_t *ev);


  36. /* RFC 9002, 6.1.2. Time Threshold: kTimeThreshold, kGranularity */
  37. static ngx_inline ngx_msec_t
  38. ngx_quic_lost_threshold(ngx_quic_connection_t *qc)
  39. {
  40.     ngx_msec_t  thr;

  41.     thr = ngx_max(qc->latest_rtt, qc->avg_rtt);
  42.     thr += thr >> 3;

  43.     return ngx_max(thr, NGX_QUIC_TIME_GRANULARITY);
  44. }


  45. ngx_int_t
  46. ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
  47.     ngx_quic_frame_t *f)
  48. {
  49.     ssize_t                 n;
  50.     u_char                 *pos, *end;
  51.     uint64_t                min, max, gap, range;
  52.     ngx_uint_t              i;
  53.     ngx_quic_ack_stat_t     send_time;
  54.     ngx_quic_send_ctx_t    *ctx;
  55.     ngx_quic_ack_frame_t   *ack;
  56.     ngx_quic_connection_t  *qc;

  57.     qc = ngx_quic_get_connection(c);

  58.     ctx = ngx_quic_get_send_ctx(qc, pkt->level);

  59.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  60.                    "quic ngx_quic_handle_ack_frame level:%d", pkt->level);

  61.     ack = &f->u.ack;

  62.     /*
  63.      * RFC 9000, 19.3.1.  ACK Ranges
  64.      *
  65.      *  If any computed packet number is negative, an endpoint MUST
  66.      *  generate a connection error of type FRAME_ENCODING_ERROR.
  67.      */

  68.     if (ack->first_range > ack->largest) {
  69.         qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
  70.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  71.                       "quic invalid first range in ack frame");
  72.         return NGX_ERROR;
  73.     }

  74.     min = ack->largest - ack->first_range;
  75.     max = ack->largest;

  76.     send_time.oldest = NGX_TIMER_INFINITE;
  77.     send_time.newest = NGX_TIMER_INFINITE;

  78.     if (ngx_quic_handle_ack_frame_range(c, ctx, min, max, &send_time)
  79.         != NGX_OK)
  80.     {
  81.         return NGX_ERROR;
  82.     }

  83.     /* RFC 9000, 13.2.4.  Limiting Ranges by Tracking ACK Frames */
  84.     if (ctx->largest_ack < max || ctx->largest_ack == NGX_QUIC_UNSET_PN) {
  85.         ctx->largest_ack = max;
  86.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  87.                        "quic updated largest received ack:%uL", max);

  88.         /*
  89.          * RFC 9002, 5.1.  Generating RTT Samples
  90.          *
  91.          *  An endpoint generates an RTT sample on receiving an
  92.          *  ACK frame that meets the following two conditions:
  93.          *
  94.          *  - the largest acknowledged packet number is newly acknowledged
  95.          *  - at least one of the newly acknowledged packets was ack-eliciting.
  96.          */

  97.         if (send_time.max_pn != NGX_TIMER_INFINITE) {
  98.             ngx_quic_rtt_sample(c, ack, pkt->level, send_time.max_pn);
  99.         }
  100.     }

  101.     if (f->data) {
  102.         pos = f->data->buf->pos;
  103.         end = f->data->buf->last;

  104.     } else {
  105.         pos = NULL;
  106.         end = NULL;
  107.     }

  108.     for (i = 0; i < ack->range_count; i++) {

  109.         n = ngx_quic_parse_ack_range(pkt->log, pos, end, &gap, &range);
  110.         if (n == NGX_ERROR) {
  111.             return NGX_ERROR;
  112.         }
  113.         pos += n;

  114.         if (gap + 2 > min) {
  115.             qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
  116.             ngx_log_error(NGX_LOG_INFO, c->log, 0,
  117.                           "quic invalid range:%ui in ack frame", i);
  118.             return NGX_ERROR;
  119.         }

  120.         max = min - gap - 2;

  121.         if (range > max) {
  122.             qc->error = NGX_QUIC_ERR_FRAME_ENCODING_ERROR;
  123.             ngx_log_error(NGX_LOG_INFO, c->log, 0,
  124.                           "quic invalid range:%ui in ack frame", i);
  125.             return NGX_ERROR;
  126.         }

  127.         min = max - range;

  128.         if (ngx_quic_handle_ack_frame_range(c, ctx, min, max, &send_time)
  129.             != NGX_OK)
  130.         {
  131.             return NGX_ERROR;
  132.         }
  133.     }

  134.     return ngx_quic_detect_lost(c, &send_time);
  135. }


  136. static void
  137. ngx_quic_rtt_sample(ngx_connection_t *c, ngx_quic_ack_frame_t *ack,
  138.     enum ssl_encryption_level_t level, ngx_msec_t send_time)
  139. {
  140.     ngx_msec_t              latest_rtt, ack_delay, adjusted_rtt, rttvar_sample;
  141.     ngx_quic_connection_t  *qc;

  142.     qc = ngx_quic_get_connection(c);

  143.     latest_rtt = ngx_current_msec - send_time;
  144.     qc->latest_rtt = latest_rtt;

  145.     if (qc->min_rtt == NGX_TIMER_INFINITE) {
  146.         qc->min_rtt = latest_rtt;
  147.         qc->avg_rtt = latest_rtt;
  148.         qc->rttvar = latest_rtt / 2;
  149.         qc->first_rtt = ngx_current_msec;

  150.     } else {
  151.         qc->min_rtt = ngx_min(qc->min_rtt, latest_rtt);

  152.         ack_delay = (ack->delay << qc->ctp.ack_delay_exponent) / 1000;

  153.         if (c->ssl->handshaked) {
  154.             ack_delay = ngx_min(ack_delay, qc->ctp.max_ack_delay);
  155.         }

  156.         adjusted_rtt = latest_rtt;

  157.         if (qc->min_rtt + ack_delay < latest_rtt) {
  158.             adjusted_rtt -= ack_delay;
  159.         }

  160.         rttvar_sample = ngx_abs((ngx_msec_int_t) (qc->avg_rtt - adjusted_rtt));
  161.         qc->rttvar += (rttvar_sample >> 2) - (qc->rttvar >> 2);
  162.         qc->avg_rtt += (adjusted_rtt >> 3) - (qc->avg_rtt >> 3);
  163.     }

  164.     ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
  165.                    "quic rtt sample latest:%M min:%M avg:%M var:%M",
  166.                    latest_rtt, qc->min_rtt, qc->avg_rtt, qc->rttvar);
  167. }


  168. static ngx_int_t
  169. ngx_quic_handle_ack_frame_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
  170.     uint64_t min, uint64_t max, ngx_quic_ack_stat_t *st)
  171. {
  172.     ngx_uint_t              found;
  173.     ngx_queue_t            *q;
  174.     ngx_quic_frame_t       *f;
  175.     ngx_quic_connection_t  *qc;

  176.     qc = ngx_quic_get_connection(c);

  177.     if (ctx->level == ssl_encryption_application) {
  178.         if (ngx_quic_handle_path_mtu(c, qc->path, min, max) != NGX_OK) {
  179.             return NGX_ERROR;
  180.         }
  181.     }

  182.     st->max_pn = NGX_TIMER_INFINITE;
  183.     found = 0;

  184.     q = ngx_queue_head(&ctx->sent);

  185.     while (q != ngx_queue_sentinel(&ctx->sent)) {

  186.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);
  187.         q = ngx_queue_next(q);

  188.         if (f->pnum > max) {
  189.             break;
  190.         }

  191.         if (f->pnum >= min) {
  192.             ngx_quic_congestion_ack(c, f);

  193.             switch (f->type) {
  194.             case NGX_QUIC_FT_ACK:
  195.             case NGX_QUIC_FT_ACK_ECN:
  196.                 ngx_quic_drop_ack_ranges(c, ctx, f->u.ack.largest);
  197.                 break;

  198.             case NGX_QUIC_FT_STREAM:
  199.             case NGX_QUIC_FT_RESET_STREAM:
  200.                 ngx_quic_handle_stream_ack(c, f);
  201.                 break;
  202.             }

  203.             if (f->pnum == max) {
  204.                 st->max_pn = f->send_time;
  205.             }

  206.             /* save earliest and latest send times of frames ack'ed */
  207.             if (st->oldest == NGX_TIMER_INFINITE || f->send_time < st->oldest) {
  208.                 st->oldest = f->send_time;
  209.             }

  210.             if (st->newest == NGX_TIMER_INFINITE || f->send_time > st->newest) {
  211.                 st->newest = f->send_time;
  212.             }

  213.             ngx_queue_remove(&f->queue);
  214.             ngx_quic_free_frame(c, f);
  215.             found = 1;
  216.         }
  217.     }

  218.     if (!found) {

  219.         if (max < ctx->pnum) {
  220.             /* duplicate ACK or ACK for non-ack-eliciting frame */
  221.             return NGX_OK;
  222.         }

  223.         ngx_log_error(NGX_LOG_INFO, c->log, 0,
  224.                       "quic ACK for the packet not sent");

  225.         qc->error = NGX_QUIC_ERR_PROTOCOL_VIOLATION;
  226.         qc->error_ftype = NGX_QUIC_FT_ACK;
  227.         qc->error_reason = "unknown packet number";

  228.         return NGX_ERROR;
  229.     }

  230.     if (!qc->push.timer_set) {
  231.         ngx_post_event(&qc->push, &ngx_posted_events);
  232.     }

  233.     qc->pto_count = 0;

  234.     return NGX_OK;
  235. }


  236. void
  237. ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f)
  238. {
  239.     ngx_uint_t              blocked;
  240.     ngx_msec_t              timer;
  241.     ngx_quic_congestion_t  *cg;
  242.     ngx_quic_connection_t  *qc;

  243.     if (f->plen == 0) {
  244.         return;
  245.     }

  246.     qc = ngx_quic_get_connection(c);
  247.     cg = &qc->congestion;

  248.     if (f->pnum < qc->rst_pnum) {
  249.         return;
  250.     }

  251.     blocked = (cg->in_flight >= cg->window) ? 1 : 0;

  252.     cg->in_flight -= f->plen;

  253.     timer = f->send_time - cg->recovery_start;

  254.     if ((ngx_msec_int_t) timer <= 0) {
  255.         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  256.                        "quic congestion ack recovery win:%uz ss:%z if:%uz",
  257.                        cg->window, cg->ssthresh, cg->in_flight);

  258.         goto done;
  259.     }

  260.     if (cg->window < cg->ssthresh) {
  261.         cg->window += f->plen;

  262.         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  263.                        "quic congestion slow start win:%uz ss:%z if:%uz",
  264.                        cg->window, cg->ssthresh, cg->in_flight);

  265.     } else {
  266.         cg->window += qc->tp.max_udp_payload_size * f->plen / cg->window;

  267.         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  268.                        "quic congestion avoidance win:%uz ss:%z if:%uz",
  269.                        cg->window, cg->ssthresh, cg->in_flight);
  270.     }

  271.     /* prevent recovery_start from wrapping */

  272.     timer = cg->recovery_start - ngx_current_msec + qc->tp.max_idle_timeout * 2;

  273.     if ((ngx_msec_int_t) timer < 0) {
  274.         cg->recovery_start = ngx_current_msec - qc->tp.max_idle_timeout * 2;
  275.     }

  276. done:

  277.     if (blocked && cg->in_flight < cg->window) {
  278.         ngx_post_event(&qc->push, &ngx_posted_events);
  279.     }
  280. }


  281. static void
  282. ngx_quic_drop_ack_ranges(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
  283.     uint64_t pn)
  284. {
  285.     uint64_t               base;
  286.     ngx_uint_t             i, smallest, largest;
  287.     ngx_quic_ack_range_t  *r;

  288.     ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
  289.                    "quic ngx_quic_drop_ack_ranges pn:%uL largest:%uL"
  290.                    " fr:%uL nranges:%ui", pn, ctx->largest_range,
  291.                    ctx->first_range, ctx->nranges);

  292.     base = ctx->largest_range;

  293.     if (base == NGX_QUIC_UNSET_PN) {
  294.         return;
  295.     }

  296.     if (ctx->pending_ack != NGX_QUIC_UNSET_PN && pn >= ctx->pending_ack) {
  297.         ctx->pending_ack = NGX_QUIC_UNSET_PN;
  298.     }

  299.     largest = base;
  300.     smallest = largest - ctx->first_range;

  301.     if (pn >= largest) {
  302.         ctx->largest_range = NGX_QUIC_UNSET_PN;
  303.         ctx->first_range = 0;
  304.         ctx->nranges = 0;
  305.         return;
  306.     }

  307.     if (pn >= smallest) {
  308.         ctx->first_range = largest - pn - 1;
  309.         ctx->nranges = 0;
  310.         return;
  311.     }

  312.     for (i = 0; i < ctx->nranges; i++) {
  313.         r = &ctx->ranges[i];

  314.         largest = smallest - r->gap - 2;
  315.         smallest = largest - r->range;

  316.         if (pn >= largest) {
  317.             ctx->nranges = i;
  318.             return;
  319.         }
  320.         if (pn >= smallest) {
  321.             r->range = largest - pn - 1;
  322.             ctx->nranges = i + 1;
  323.             return;
  324.         }
  325.     }
  326. }


  327. static ngx_int_t
  328. ngx_quic_detect_lost(ngx_connection_t *c, ngx_quic_ack_stat_t *st)
  329. {
  330.     ngx_uint_t              i, nlost;
  331.     ngx_msec_t              now, wait, thr, oldest, newest;
  332.     ngx_queue_t            *q;
  333.     ngx_quic_frame_t       *start;
  334.     ngx_quic_send_ctx_t    *ctx;
  335.     ngx_quic_connection_t  *qc;

  336.     qc = ngx_quic_get_connection(c);
  337.     now = ngx_current_msec;
  338.     thr = ngx_quic_lost_threshold(qc);

  339.     /* send time of lost packets across all send contexts */
  340.     oldest = NGX_TIMER_INFINITE;
  341.     newest = NGX_TIMER_INFINITE;

  342.     nlost = 0;

  343.     for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {

  344.         ctx = &qc->send_ctx[i];

  345.         if (ctx->largest_ack == NGX_QUIC_UNSET_PN) {
  346.             continue;
  347.         }

  348.         while (!ngx_queue_empty(&ctx->sent)) {

  349.             q = ngx_queue_head(&ctx->sent);
  350.             start = ngx_queue_data(q, ngx_quic_frame_t, queue);

  351.             if (start->pnum > ctx->largest_ack) {
  352.                 break;
  353.             }

  354.             wait = start->send_time + thr - now;

  355.             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
  356.                            "quic detect_lost pnum:%uL thr:%M wait:%i level:%d",
  357.                            start->pnum, thr, (ngx_int_t) wait, start->level);

  358.             if ((ngx_msec_int_t) wait > 0
  359.                 && ctx->largest_ack - start->pnum < NGX_QUIC_PKT_THR)
  360.             {
  361.                 break;
  362.             }

  363.             if (start->send_time > qc->first_rtt) {

  364.                 if (oldest == NGX_TIMER_INFINITE || start->send_time < oldest) {
  365.                     oldest = start->send_time;
  366.                 }

  367.                 if (newest == NGX_TIMER_INFINITE || start->send_time > newest) {
  368.                     newest = start->send_time;
  369.                 }

  370.                 nlost++;
  371.             }

  372.             ngx_quic_resend_frames(c, ctx);
  373.         }
  374.     }


  375.     /* RFC 9002, 7.6.2.  Establishing Persistent Congestion */

  376.     /*
  377.      * Once acknowledged, packets are no longer tracked. Thus no send time
  378.      * information is available for such packets. This limits persistent
  379.      * congestion algorithm to packets mentioned within ACK ranges of the
  380.      * latest ACK frame.
  381.      */

  382.     if (st && nlost >= 2 && (st->newest < oldest || st->oldest > newest)) {

  383.         if (newest - oldest > ngx_quic_pcg_duration(c)) {
  384.             ngx_quic_persistent_congestion(c);
  385.         }
  386.     }

  387.     ngx_quic_set_lost_timer(c);

  388.     return NGX_OK;
  389. }


  390. static ngx_msec_t
  391. ngx_quic_pcg_duration(ngx_connection_t *c)
  392. {
  393.     ngx_msec_t              duration;
  394.     ngx_quic_connection_t  *qc;

  395.     qc = ngx_quic_get_connection(c);

  396.     duration = qc->avg_rtt;
  397.     duration += ngx_max(4 * qc->rttvar, NGX_QUIC_TIME_GRANULARITY);
  398.     duration += qc->ctp.max_ack_delay;
  399.     duration *= NGX_QUIC_PERSISTENT_CONGESTION_THR;

  400.     return duration;
  401. }


  402. static void
  403. ngx_quic_persistent_congestion(ngx_connection_t *c)
  404. {
  405.     ngx_quic_congestion_t  *cg;
  406.     ngx_quic_connection_t  *qc;

  407.     qc = ngx_quic_get_connection(c);
  408.     cg = &qc->congestion;

  409.     cg->recovery_start = ngx_current_msec;
  410.     cg->window = qc->tp.max_udp_payload_size * 2;

  411.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  412.                    "quic persistent congestion win:%uz", cg->window);
  413. }


  414. void
  415. ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
  416. {
  417.     uint64_t                pnum;
  418.     ngx_queue_t            *q;
  419.     ngx_quic_frame_t       *f, *start;
  420.     ngx_quic_stream_t      *qs;
  421.     ngx_quic_connection_t  *qc;

  422.     qc = ngx_quic_get_connection(c);
  423.     q = ngx_queue_head(&ctx->sent);
  424.     start = ngx_queue_data(q, ngx_quic_frame_t, queue);
  425.     pnum = start->pnum;

  426.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  427.                    "quic resend packet pnum:%uL", start->pnum);

  428.     ngx_quic_congestion_lost(c, start);

  429.     do {
  430.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);

  431.         if (f->pnum != pnum) {
  432.             break;
  433.         }

  434.         q = ngx_queue_next(q);

  435.         ngx_queue_remove(&f->queue);

  436.         switch (f->type) {
  437.         case NGX_QUIC_FT_ACK:
  438.         case NGX_QUIC_FT_ACK_ECN:
  439.             if (ctx->level == ssl_encryption_application) {
  440.                 /* force generation of most recent acknowledgment */
  441.                 ctx->send_ack = NGX_QUIC_MAX_ACK_GAP;
  442.             }

  443.             ngx_quic_free_frame(c, f);
  444.             break;

  445.         case NGX_QUIC_FT_PING:
  446.         case NGX_QUIC_FT_PATH_CHALLENGE:
  447.         case NGX_QUIC_FT_PATH_RESPONSE:
  448.         case NGX_QUIC_FT_CONNECTION_CLOSE:
  449.             ngx_quic_free_frame(c, f);
  450.             break;

  451.         case NGX_QUIC_FT_MAX_DATA:
  452.             f->u.max_data.max_data = qc->streams.recv_max_data;
  453.             ngx_quic_queue_frame(qc, f);
  454.             break;

  455.         case NGX_QUIC_FT_MAX_STREAMS:
  456.         case NGX_QUIC_FT_MAX_STREAMS2:
  457.             f->u.max_streams.limit = f->u.max_streams.bidi
  458.                                      ? qc->streams.client_max_streams_bidi
  459.                                      : qc->streams.client_max_streams_uni;
  460.             ngx_quic_queue_frame(qc, f);
  461.             break;

  462.         case NGX_QUIC_FT_MAX_STREAM_DATA:
  463.             qs = ngx_quic_find_stream(&qc->streams.tree,
  464.                                       f->u.max_stream_data.id);
  465.             if (qs == NULL) {
  466.                 ngx_quic_free_frame(c, f);
  467.                 break;
  468.             }

  469.             f->u.max_stream_data.limit = qs->recv_max_data;
  470.             ngx_quic_queue_frame(qc, f);
  471.             break;

  472.         case NGX_QUIC_FT_STREAM:
  473.             qs = ngx_quic_find_stream(&qc->streams.tree, f->u.stream.stream_id);

  474.             if (qs == NULL
  475.                 || qs->send_state == NGX_QUIC_STREAM_SEND_RESET_SENT
  476.                 || qs->send_state == NGX_QUIC_STREAM_SEND_RESET_RECVD)
  477.             {
  478.                 ngx_quic_free_frame(c, f);
  479.                 break;
  480.             }

  481.             /* fall through */

  482.         default:
  483.             ngx_queue_insert_tail(&ctx->frames, &f->queue);
  484.         }

  485.     } while (q != ngx_queue_sentinel(&ctx->sent));

  486.     if (qc->closing) {
  487.         return;
  488.     }

  489.     ngx_post_event(&qc->push, &ngx_posted_events);
  490. }


  491. static void
  492. ngx_quic_congestion_lost(ngx_connection_t *c, ngx_quic_frame_t *f)
  493. {
  494.     ngx_uint_t              blocked;
  495.     ngx_msec_t              timer;
  496.     ngx_quic_congestion_t  *cg;
  497.     ngx_quic_connection_t  *qc;

  498.     if (f->plen == 0) {
  499.         return;
  500.     }

  501.     qc = ngx_quic_get_connection(c);
  502.     cg = &qc->congestion;

  503.     if (f->pnum < qc->rst_pnum) {
  504.         return;
  505.     }

  506.     blocked = (cg->in_flight >= cg->window) ? 1 : 0;

  507.     cg->in_flight -= f->plen;
  508.     f->plen = 0;

  509.     timer = f->send_time - cg->recovery_start;

  510.     if ((ngx_msec_int_t) timer <= 0) {
  511.         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  512.                        "quic congestion lost recovery win:%uz ss:%z if:%uz",
  513.                        cg->window, cg->ssthresh, cg->in_flight);

  514.         goto done;
  515.     }

  516.     cg->recovery_start = ngx_current_msec;
  517.     cg->window /= 2;

  518.     if (cg->window < qc->tp.max_udp_payload_size * 2) {
  519.         cg->window = qc->tp.max_udp_payload_size * 2;
  520.     }

  521.     cg->ssthresh = cg->window;

  522.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  523.                    "quic congestion lost win:%uz ss:%z if:%uz",
  524.                    cg->window, cg->ssthresh, cg->in_flight);

  525. done:

  526.     if (blocked && cg->in_flight < cg->window) {
  527.         ngx_post_event(&qc->push, &ngx_posted_events);
  528.     }
  529. }


  530. void
  531. ngx_quic_set_lost_timer(ngx_connection_t *c)
  532. {
  533.     ngx_uint_t              i;
  534.     ngx_msec_t              now;
  535.     ngx_queue_t            *q;
  536.     ngx_msec_int_t          lost, pto, w;
  537.     ngx_quic_frame_t       *f;
  538.     ngx_quic_send_ctx_t    *ctx;
  539.     ngx_quic_connection_t  *qc;

  540.     qc = ngx_quic_get_connection(c);
  541.     now = ngx_current_msec;

  542.     lost = -1;
  543.     pto = -1;

  544.     for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
  545.         ctx = &qc->send_ctx[i];

  546.         if (ngx_queue_empty(&ctx->sent)) {
  547.             continue;
  548.         }

  549.         if (ctx->largest_ack != NGX_QUIC_UNSET_PN) {
  550.             q = ngx_queue_head(&ctx->sent);
  551.             f = ngx_queue_data(q, ngx_quic_frame_t, queue);
  552.             w = (ngx_msec_int_t)
  553.                             (f->send_time + ngx_quic_lost_threshold(qc) - now);

  554.             if (f->pnum <= ctx->largest_ack) {
  555.                 if (w < 0 || ctx->largest_ack - f->pnum >= NGX_QUIC_PKT_THR) {
  556.                     w = 0;
  557.                 }

  558.                 if (lost == -1 || w < lost) {
  559.                     lost = w;
  560.                 }
  561.             }
  562.         }

  563.         q = ngx_queue_last(&ctx->sent);
  564.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);
  565.         w = (ngx_msec_int_t)
  566.                 (f->send_time + (ngx_quic_pto(c, ctx) << qc->pto_count) - now);

  567.         if (w < 0) {
  568.             w = 0;
  569.         }

  570.         if (pto == -1 || w < pto) {
  571.             pto = w;
  572.         }
  573.     }

  574.     if (qc->pto.timer_set) {
  575.         ngx_del_timer(&qc->pto);
  576.     }

  577.     if (lost != -1) {
  578.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  579.                        "quic lost timer lost:%M", lost);

  580.         qc->pto.handler = ngx_quic_lost_handler;
  581.         ngx_add_timer(&qc->pto, lost);
  582.         return;
  583.     }

  584.     if (pto != -1) {
  585.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  586.                        "quic lost timer pto:%M", pto);

  587.         qc->pto.handler = ngx_quic_pto_handler;
  588.         ngx_add_timer(&qc->pto, pto);
  589.         return;
  590.     }

  591.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic lost timer unset");
  592. }


  593. ngx_msec_t
  594. ngx_quic_pto(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
  595. {
  596.     ngx_msec_t              duration;
  597.     ngx_quic_connection_t  *qc;

  598.     qc = ngx_quic_get_connection(c);

  599.     /* RFC 9002, Appendix A.8.  Setting the Loss Detection Timer */

  600.     duration = qc->avg_rtt;
  601.     duration += ngx_max(4 * qc->rttvar, NGX_QUIC_TIME_GRANULARITY);

  602.     if (ctx->level == ssl_encryption_application && c->ssl->handshaked) {
  603.         duration += qc->ctp.max_ack_delay;
  604.     }

  605.     return duration;
  606. }


  607. static
  608. void ngx_quic_lost_handler(ngx_event_t *ev)
  609. {
  610.     ngx_connection_t  *c;

  611.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic lost timer");

  612.     c = ev->data;

  613.     if (ngx_quic_detect_lost(c, NULL) != NGX_OK) {
  614.         ngx_quic_close_connection(c, NGX_ERROR);
  615.         return;
  616.     }

  617.     ngx_quic_connstate_dbg(c);
  618. }


  619. void
  620. ngx_quic_pto_handler(ngx_event_t *ev)
  621. {
  622.     ngx_uint_t              i, n;
  623.     ngx_msec_t              now;
  624.     ngx_queue_t            *q;
  625.     ngx_msec_int_t          w;
  626.     ngx_connection_t       *c;
  627.     ngx_quic_frame_t       *f;
  628.     ngx_quic_send_ctx_t    *ctx;
  629.     ngx_quic_connection_t  *qc;

  630.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "quic pto timer");

  631.     c = ev->data;
  632.     qc = ngx_quic_get_connection(c);
  633.     now = ngx_current_msec;

  634.     for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {

  635.         ctx = &qc->send_ctx[i];

  636.         if (ngx_queue_empty(&ctx->sent)) {
  637.             continue;
  638.         }

  639.         q = ngx_queue_last(&ctx->sent);
  640.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);
  641.         w = (ngx_msec_int_t)
  642.                 (f->send_time + (ngx_quic_pto(c, ctx) << qc->pto_count) - now);

  643.         if (f->pnum <= ctx->largest_ack
  644.             && ctx->largest_ack != NGX_QUIC_UNSET_PN)
  645.         {
  646.             continue;
  647.         }

  648.         if (w > 0) {
  649.             continue;
  650.         }

  651.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  652.                        "quic pto %s pto_count:%ui",
  653.                        ngx_quic_level_name(ctx->level), qc->pto_count);

  654.         for (n = 0; n < 2; n++) {

  655.             f = ngx_quic_alloc_frame(c);
  656.             if (f == NULL) {
  657.                 goto failed;
  658.             }

  659.             f->level = ctx->level;
  660.             f->type = NGX_QUIC_FT_PING;
  661.             f->ignore_congestion = 1;

  662.             if (ngx_quic_frame_sendto(c, f, 0, qc->path) == NGX_ERROR) {
  663.                 goto failed;
  664.             }
  665.         }
  666.     }

  667.     qc->pto_count++;

  668.     ngx_quic_set_lost_timer(c);

  669.     ngx_quic_connstate_dbg(c);

  670.     return;

  671. failed:

  672.     ngx_quic_close_connection(c, NGX_ERROR);
  673.     return;
  674. }


  675. ngx_int_t
  676. ngx_quic_ack_packet(ngx_connection_t *c, ngx_quic_header_t *pkt)
  677. {
  678.     uint64_t                base, largest, smallest, gs, ge, gap, range, pn;
  679.     uint64_t                prev_pending;
  680.     ngx_uint_t              i, nr;
  681.     ngx_quic_send_ctx_t    *ctx;
  682.     ngx_quic_ack_range_t   *r;
  683.     ngx_quic_connection_t  *qc;

  684.     c->log->action = "preparing ack";

  685.     qc = ngx_quic_get_connection(c);

  686.     ctx = ngx_quic_get_send_ctx(qc, pkt->level);

  687.     ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
  688.                    "quic ngx_quic_ack_packet pn:%uL largest %L fr:%uL"
  689.                    " nranges:%ui", pkt->pn, (int64_t) ctx->largest_range,
  690.                    ctx->first_range, ctx->nranges);

  691.     if (!ngx_quic_keys_available(qc->keys, ctx->level, 1)) {
  692.         return NGX_OK;
  693.     }

  694.     prev_pending = ctx->pending_ack;

  695.     if (pkt->need_ack) {

  696.         ngx_post_event(&qc->push, &ngx_posted_events);

  697.         if (ctx->send_ack == 0) {
  698.             ctx->ack_delay_start = ngx_current_msec;
  699.         }

  700.         ctx->send_ack++;

  701.         if (ctx->pending_ack == NGX_QUIC_UNSET_PN
  702.             || ctx->pending_ack < pkt->pn)
  703.         {
  704.             ctx->pending_ack = pkt->pn;
  705.         }
  706.     }

  707.     base = ctx->largest_range;
  708.     pn = pkt->pn;

  709.     if (base == NGX_QUIC_UNSET_PN) {
  710.         ctx->largest_range = pn;
  711.         ctx->largest_received = pkt->received;
  712.         return NGX_OK;
  713.     }

  714.     if (base == pn) {
  715.         return NGX_OK;
  716.     }

  717.     largest = base;
  718.     smallest = largest - ctx->first_range;

  719.     if (pn > base) {

  720.         if (pn - base == 1) {
  721.             ctx->first_range++;
  722.             ctx->largest_range = pn;
  723.             ctx->largest_received = pkt->received;

  724.             return NGX_OK;

  725.         } else {
  726.             /* new gap in front of current largest */

  727.             /* no place for new range, send current range as is */
  728.             if (ctx->nranges == NGX_QUIC_MAX_RANGES) {

  729.                 if (prev_pending != NGX_QUIC_UNSET_PN) {
  730.                     if (ngx_quic_send_ack(c, ctx) != NGX_OK) {
  731.                         return NGX_ERROR;
  732.                     }
  733.                 }

  734.                 if (prev_pending == ctx->pending_ack || !pkt->need_ack) {
  735.                     ctx->pending_ack = NGX_QUIC_UNSET_PN;
  736.                 }
  737.             }

  738.             gap = pn - base - 2;
  739.             range = ctx->first_range;

  740.             ctx->first_range = 0;
  741.             ctx->largest_range = pn;
  742.             ctx->largest_received = pkt->received;

  743.             /* packet is out of order, force send */
  744.             if (pkt->need_ack) {
  745.                 ctx->send_ack = NGX_QUIC_MAX_ACK_GAP;
  746.             }

  747.             i = 0;

  748.             goto insert;
  749.         }
  750.     }

  751.     /*  pn < base, perform lookup in existing ranges */

  752.     /* packet is out of order */
  753.     if (pkt->need_ack) {
  754.         ctx->send_ack = NGX_QUIC_MAX_ACK_GAP;
  755.     }

  756.     if (pn >= smallest && pn <= largest) {
  757.         return NGX_OK;
  758.     }

  759. #if (NGX_SUPPRESS_WARN)
  760.     r = NULL;
  761. #endif

  762.     for (i = 0; i < ctx->nranges; i++) {
  763.         r = &ctx->ranges[i];

  764.         ge = smallest - 1;
  765.         gs = ge - r->gap;

  766.         if (pn >= gs && pn <= ge) {

  767.             if (gs == ge) {
  768.                 /* gap size is exactly one packet, now filled */

  769.                 /* data moves to previous range, current is removed */

  770.                 if (i == 0) {
  771.                     ctx->first_range += r->range + 2;

  772.                 } else {
  773.                     ctx->ranges[i - 1].range += r->range + 2;
  774.                 }

  775.                 nr = ctx->nranges - i - 1;
  776.                 if (nr) {
  777.                     ngx_memmove(&ctx->ranges[i], &ctx->ranges[i + 1],
  778.                                 sizeof(ngx_quic_ack_range_t) * nr);
  779.                 }

  780.                 ctx->nranges--;

  781.             } else if (pn == gs) {
  782.                 /* current gap shrinks from tail (current range grows) */
  783.                 r->gap--;
  784.                 r->range++;

  785.             } else if (pn == ge) {
  786.                 /* current gap shrinks from head (previous range grows) */
  787.                 r->gap--;

  788.                 if (i == 0) {
  789.                     ctx->first_range++;

  790.                 } else {
  791.                     ctx->ranges[i - 1].range++;
  792.                 }

  793.             } else {
  794.                 /* current gap is split into two parts */

  795.                 gap = ge - pn - 1;
  796.                 range = 0;

  797.                 if (ctx->nranges == NGX_QUIC_MAX_RANGES) {
  798.                     if (prev_pending != NGX_QUIC_UNSET_PN) {
  799.                         if (ngx_quic_send_ack(c, ctx) != NGX_OK) {
  800.                             return NGX_ERROR;
  801.                         }
  802.                     }

  803.                     if (prev_pending == ctx->pending_ack || !pkt->need_ack) {
  804.                         ctx->pending_ack = NGX_QUIC_UNSET_PN;
  805.                     }
  806.                 }

  807.                 r->gap = pn - gs - 1;
  808.                 goto insert;
  809.             }

  810.             return NGX_OK;
  811.         }

  812.         largest = smallest - r->gap - 2;
  813.         smallest = largest - r->range;

  814.         if (pn >= smallest && pn <= largest) {
  815.             /* this packet number is already known */
  816.             return NGX_OK;
  817.         }

  818.     }

  819.     if (pn == smallest - 1) {
  820.         /* extend first or last range */

  821.         if (i == 0) {
  822.             ctx->first_range++;

  823.         } else {
  824.             r->range++;
  825.         }

  826.         return NGX_OK;
  827.     }

  828.     /* nothing found, add new range at the tail  */

  829.     if (ctx->nranges == NGX_QUIC_MAX_RANGES) {
  830.         /* packet is too old to keep it */

  831.         if (pkt->need_ack) {
  832.             return ngx_quic_send_ack_range(c, ctx, pn, pn);
  833.         }

  834.         return NGX_OK;
  835.     }

  836.     gap = smallest - 2 - pn;
  837.     range = 0;

  838. insert:

  839.     if (ctx->nranges < NGX_QUIC_MAX_RANGES) {
  840.         ctx->nranges++;
  841.     }

  842.     ngx_memmove(&ctx->ranges[i + 1], &ctx->ranges[i],
  843.                 sizeof(ngx_quic_ack_range_t) * (ctx->nranges - i - 1));

  844.     ctx->ranges[i].gap = gap;
  845.     ctx->ranges[i].range = range;

  846.     return NGX_OK;
  847. }


  848. ngx_int_t
  849. ngx_quic_generate_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
  850. {
  851.     ngx_msec_t              delay;
  852.     ngx_quic_connection_t  *qc;

  853.     if (!ctx->send_ack) {
  854.         return NGX_OK;
  855.     }

  856.     if (ctx->level == ssl_encryption_application) {

  857.         delay = ngx_current_msec - ctx->ack_delay_start;
  858.         qc = ngx_quic_get_connection(c);

  859.         if (ngx_queue_empty(&ctx->frames)
  860.             && ctx->send_ack < NGX_QUIC_MAX_ACK_GAP
  861.             && delay < qc->tp.max_ack_delay)
  862.         {
  863.             if (!qc->push.timer_set && !qc->closing) {
  864.                 ngx_add_timer(&qc->push,
  865.                               qc->tp.max_ack_delay - delay);
  866.             }

  867.             return NGX_OK;
  868.         }
  869.     }

  870.     if (ngx_quic_send_ack(c, ctx) != NGX_OK) {
  871.         return NGX_ERROR;
  872.     }

  873.     ctx->send_ack = 0;

  874.     return NGX_OK;
  875. }