src/event/quic/ngx_event_quic_output.c - nginx

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_UDP_SEGMENT_BUF  65487 /* 65K - IPv6 header */
  9. #define NGX_QUIC_MAX_SEGMENTS            64 /* UDP_MAX_SEGMENTS */

  10. #define NGX_QUIC_RETRY_TOKEN_LIFETIME     3 /* seconds */
  11. #define NGX_QUIC_NEW_TOKEN_LIFETIME     600 /* seconds */
  12. #define NGX_QUIC_RETRY_BUFFER_SIZE      256
  13.     /* 1 flags + 4 version + 3 x (1 + 20) s/o/dcid + itag + token(64) */

  14. /*
  15. * RFC 9000, 10.3.  Stateless Reset
  16. *
  17. * Endpoints MUST discard packets that are too small to be valid QUIC
  18. * packets.  With the set of AEAD functions defined in [QUIC-TLS],
  19. * short header packets that are smaller than 21 bytes are never valid.
  20. */
  21. #define NGX_QUIC_MIN_PKT_LEN             41 /* 21 + 20 (server cid length) */

  22. #define NGX_QUIC_MIN_SR_PACKET           43 /* 5 rand + 16 srt + 22 padding */
  23. #define NGX_QUIC_MAX_SR_PACKET         1200

  24. #define NGX_QUIC_CC_MIN_INTERVAL       1000 /* 1s */

  25. #define NGX_QUIC_SOCKET_RETRY_DELAY      10 /* ms, for NGX_AGAIN on write */


  26. #define ngx_quic_log_packet(log, pkt)                                         \
  27.     ngx_log_debug6(NGX_LOG_DEBUG_EVENT, log, 0,                               \
  28.                    "quic packet tx %s bytes:%ui need_ack:%d"                  \
  29.                    " number:%L encoded nl:%d trunc:0x%xD",                    \
  30.                    ngx_quic_level_name((pkt)->level), (pkt)->payload.len,     \
  31.                    (pkt)->need_ack, (pkt)->number, (pkt)->num_len,            \
  32.                     (pkt)->trunc);


  33. static ngx_int_t ngx_quic_create_datagrams(ngx_connection_t *c);
  34. static void ngx_quic_commit_send(ngx_connection_t *c);
  35. static void ngx_quic_revert_send(ngx_connection_t *c,
  36.     uint64_t preserved_pnum[NGX_QUIC_SEND_CTX_LAST]);
  37. #if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL))
  38. static ngx_uint_t ngx_quic_allow_segmentation(ngx_connection_t *c);
  39. static ngx_int_t ngx_quic_create_segments(ngx_connection_t *c);
  40. static ssize_t ngx_quic_send_segments(ngx_connection_t *c, u_char *buf,
  41.     size_t len, struct sockaddr *sockaddr, socklen_t socklen, size_t segment);
  42. #endif
  43. static ssize_t ngx_quic_output_packet(ngx_connection_t *c,
  44.     ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min,
  45.     ngx_uint_t ack_only);
  46. static void ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
  47.     ngx_quic_header_t *pkt, ngx_quic_path_t *path);
  48. static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
  49. static ssize_t ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
  50.     struct sockaddr *sockaddr, socklen_t socklen);
  51. static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt,
  52.     ngx_quic_send_ctx_t *ctx);
  53. static ngx_int_t ngx_quic_stateless_reset_filter(ngx_connection_t *c);


  54. ngx_int_t
  55. ngx_quic_output(ngx_connection_t *c)
  56. {
  57.     size_t                  in_flight;
  58.     ngx_int_t               rc;
  59.     ngx_quic_congestion_t  *cg;
  60.     ngx_quic_connection_t  *qc;

  61.     c->log->action = "sending frames";

  62.     qc = ngx_quic_get_connection(c);
  63.     cg = &qc->congestion;

  64.     in_flight = cg->in_flight;

  65. #if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL))
  66.     if (ngx_quic_allow_segmentation(c)) {
  67.         rc = ngx_quic_create_segments(c);
  68.     } else
  69. #endif
  70.     {
  71.         rc = ngx_quic_create_datagrams(c);
  72.     }

  73.     if (rc != NGX_OK) {
  74.         return NGX_ERROR;
  75.     }

  76.     if (in_flight == cg->in_flight || qc->closing) {
  77.         /* no ack-eliciting data was sent or we are done */
  78.         return NGX_OK;
  79.     }

  80.     if (!qc->send_timer_set) {
  81.         qc->send_timer_set = 1;
  82.         ngx_add_timer(c->read, qc->tp.max_idle_timeout);
  83.     }

  84.     ngx_quic_set_lost_timer(c);

  85.     return NGX_OK;
  86. }


  87. static ngx_int_t
  88. ngx_quic_create_datagrams(ngx_connection_t *c)
  89. {
  90.     size_t                  len, min;
  91.     ssize_t                 n;
  92.     u_char                 *p;
  93.     uint64_t                preserved_pnum[NGX_QUIC_SEND_CTX_LAST];
  94.     ngx_uint_t              i, pad;
  95.     ngx_quic_path_t        *path;
  96.     ngx_quic_send_ctx_t    *ctx;
  97.     ngx_quic_congestion_t  *cg;
  98.     ngx_quic_connection_t  *qc;
  99.     static u_char           dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];

  100.     qc = ngx_quic_get_connection(c);
  101.     cg = &qc->congestion;
  102.     path = qc->path;

  103. #if (NGX_SUPPRESS_WARN)
  104.     ngx_memzero(preserved_pnum, sizeof(preserved_pnum));
  105. #endif

  106.     do {
  107.         p = dst;

  108.         len = ngx_quic_path_limit(c, path, path->mtu);

  109.         pad = ngx_quic_get_padding_level(c);

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

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

  112.             preserved_pnum[i] = ctx->pnum;

  113.             if (ngx_quic_generate_ack(c, ctx) != NGX_OK) {
  114.                 return NGX_ERROR;
  115.             }

  116.             min = (i == pad && p - dst < NGX_QUIC_MIN_INITIAL_SIZE)
  117.                   ? NGX_QUIC_MIN_INITIAL_SIZE - (p - dst) : 0;

  118.             if (min > len) {
  119.                 /* padding can't be applied - avoid sending the packet */
  120.                 ngx_quic_revert_send(c, preserved_pnum);
  121.                 return NGX_OK;
  122.             }

  123.             n = ngx_quic_output_packet(c, ctx, p, len, min,
  124.                                        cg->in_flight >= cg->window);
  125.             if (n == NGX_ERROR) {
  126.                 return NGX_ERROR;
  127.             }

  128.             p += n;
  129.             len -= n;
  130.         }

  131.         len = p - dst;
  132.         if (len == 0) {
  133.             break;
  134.         }

  135.         n = ngx_quic_send(c, dst, len, path->sockaddr, path->socklen);

  136.         if (n == NGX_ERROR) {
  137.             return NGX_ERROR;
  138.         }

  139.         if (n == NGX_AGAIN) {
  140.             ngx_quic_revert_send(c, preserved_pnum);
  141.             ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY);
  142.             break;
  143.         }

  144.         ngx_quic_commit_send(c);

  145.         path->sent += len;

  146.     } while (cg->in_flight < cg->window);

  147.     return NGX_OK;
  148. }


  149. static void
  150. ngx_quic_commit_send(ngx_connection_t *c)
  151. {
  152.     ngx_uint_t              i, idle;
  153.     ngx_queue_t            *q;
  154.     ngx_quic_frame_t       *f;
  155.     ngx_quic_send_ctx_t    *ctx;
  156.     ngx_quic_congestion_t  *cg;
  157.     ngx_quic_connection_t  *qc;

  158.     qc = ngx_quic_get_connection(c);
  159.     cg = &qc->congestion;

  160.     idle = 1;

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

  163.         if (!ngx_queue_empty(&ctx->frames)) {
  164.             idle = 0;
  165.         }

  166.         while (!ngx_queue_empty(&ctx->sending)) {

  167.             q = ngx_queue_head(&ctx->sending);
  168.             f = ngx_queue_data(q, ngx_quic_frame_t, queue);

  169.             ngx_queue_remove(q);

  170.             if (f->pkt_need_ack && !qc->closing) {
  171.                 ngx_queue_insert_tail(&ctx->sent, q);

  172.                 cg->in_flight += f->plen;

  173.             } else {
  174.                 ngx_quic_free_frame(c, f);
  175.             }
  176.         }
  177.     }

  178.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  179.                    "quic congestion send if:%uz", cg->in_flight);

  180.     ngx_quic_congestion_idle(c, idle);
  181. }


  182. static void
  183. ngx_quic_revert_send(ngx_connection_t *c, uint64_t pnum[NGX_QUIC_SEND_CTX_LAST])
  184. {
  185.     ngx_uint_t              i;
  186.     ngx_queue_t            *q;
  187.     ngx_quic_send_ctx_t    *ctx;
  188.     ngx_quic_connection_t  *qc;

  189.     qc = ngx_quic_get_connection(c);

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

  192.         if (ngx_queue_empty(&ctx->sending)) {
  193.             continue;
  194.         }

  195.         do {
  196.             q = ngx_queue_last(&ctx->sending);
  197.             ngx_queue_remove(q);
  198.             ngx_queue_insert_head(&ctx->frames, q);
  199.         } while (!ngx_queue_empty(&ctx->sending));

  200.         ctx->pnum = pnum[i];
  201.     }

  202.     ngx_quic_congestion_idle(c, 1);
  203. }


  204. #if ((NGX_HAVE_UDP_SEGMENT) && (NGX_HAVE_MSGHDR_MSG_CONTROL))

  205. static ngx_uint_t
  206. ngx_quic_allow_segmentation(ngx_connection_t *c)
  207. {
  208.     size_t                  bytes, len;
  209.     ngx_queue_t            *q;
  210.     ngx_quic_frame_t       *f;
  211.     ngx_quic_send_ctx_t    *ctx;
  212.     ngx_quic_connection_t  *qc;

  213.     qc = ngx_quic_get_connection(c);

  214.     if (!qc->conf->gso_enabled) {
  215.         return 0;
  216.     }

  217.     if (!qc->path->validated) {
  218.         /* don't even try to be faster on non-validated paths */
  219.         return 0;
  220.     }

  221.     ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_INITIAL);
  222.     if (!ngx_queue_empty(&ctx->frames)) {
  223.         return 0;
  224.     }

  225.     ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_HANDSHAKE);
  226.     if (!ngx_queue_empty(&ctx->frames)) {
  227.         return 0;
  228.     }

  229.     ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);

  230.     bytes = 0;
  231.     len = ngx_min(qc->path->mtu, NGX_QUIC_MAX_UDP_SEGMENT_BUF);

  232.     for (q = ngx_queue_head(&ctx->frames);
  233.          q != ngx_queue_sentinel(&ctx->frames);
  234.          q = ngx_queue_next(q))
  235.     {
  236.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);

  237.         bytes += f->len;

  238.         if (qc->congestion.in_flight + bytes >= qc->congestion.window) {
  239.             return 0;
  240.         }

  241.         if (bytes > len * 3) {
  242.             /* require at least ~3 full packets to batch */
  243.             return 1;
  244.         }
  245.     }

  246.     return 0;
  247. }


  248. static ngx_int_t
  249. ngx_quic_create_segments(ngx_connection_t *c)
  250. {
  251.     size_t                  len, segsize;
  252.     ssize_t                 n;
  253.     u_char                 *p, *end;
  254.     ngx_uint_t              nseg, level;
  255.     ngx_quic_path_t        *path;
  256.     ngx_quic_send_ctx_t    *ctx;
  257.     ngx_quic_congestion_t  *cg;
  258.     ngx_quic_connection_t  *qc;
  259.     static u_char           dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF];
  260.     static uint64_t         preserved_pnum[NGX_QUIC_SEND_CTX_LAST];

  261.     qc = ngx_quic_get_connection(c);
  262.     cg = &qc->congestion;
  263.     path = qc->path;

  264.     ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_APPLICATION);

  265.     if (ngx_quic_generate_ack(c, ctx) != NGX_OK) {
  266.         return NGX_ERROR;
  267.     }

  268.     segsize = ngx_min(path->mtu, NGX_QUIC_MAX_UDP_SEGMENT_BUF);
  269.     p = dst;
  270.     end = dst + sizeof(dst);

  271.     nseg = 0;

  272.     level = ctx - qc->send_ctx;
  273.     preserved_pnum[level] = ctx->pnum;

  274.     for ( ;; ) {

  275.         len = ngx_min(segsize, (size_t) (end - p));

  276.         if (len && cg->in_flight + (p - dst) < cg->window) {

  277.             n = ngx_quic_output_packet(c, ctx, p, len, len, 0);
  278.             if (n == NGX_ERROR) {
  279.                 return NGX_ERROR;
  280.             }

  281.             if (n) {
  282.                 p += n;
  283.                 nseg++;
  284.             }

  285.         } else {
  286.             n = 0;
  287.         }

  288.         if (p == dst) {
  289.             break;
  290.         }

  291.         if (n == 0 || nseg == NGX_QUIC_MAX_SEGMENTS) {
  292.             n = ngx_quic_send_segments(c, dst, p - dst, path->sockaddr,
  293.                                        path->socklen, segsize);
  294.             if (n == NGX_ERROR) {
  295.                 return NGX_ERROR;
  296.             }

  297.             if (n == NGX_AGAIN) {
  298.                 ngx_quic_revert_send(c, preserved_pnum);
  299.                 ngx_add_timer(&qc->push, NGX_QUIC_SOCKET_RETRY_DELAY);
  300.                 break;
  301.             }

  302.             ngx_quic_commit_send(c);

  303.             path->sent += n;

  304.             p = dst;
  305.             nseg = 0;
  306.             preserved_pnum[level] = ctx->pnum;
  307.         }
  308.     }

  309.     return NGX_OK;
  310. }


  311. static ssize_t
  312. ngx_quic_send_segments(ngx_connection_t *c, u_char *buf, size_t len,
  313.     struct sockaddr *sockaddr, socklen_t socklen, size_t segment)
  314. {
  315.     size_t           clen;
  316.     ssize_t          n;
  317.     uint16_t        *valp;
  318.     struct iovec     iov;
  319.     struct msghdr    msg;
  320.     struct cmsghdr  *cmsg;

  321. #if (NGX_HAVE_ADDRINFO_CMSG)
  322.     char             msg_control[CMSG_SPACE(sizeof(uint16_t))
  323.                              + CMSG_SPACE(sizeof(ngx_addrinfo_t))];
  324. #else
  325.     char             msg_control[CMSG_SPACE(sizeof(uint16_t))];
  326. #endif

  327.     ngx_memzero(&msg, sizeof(struct msghdr));
  328.     ngx_memzero(msg_control, sizeof(msg_control));

  329.     iov.iov_len = len;
  330.     iov.iov_base = (void *) buf;

  331.     msg.msg_iov = &iov;
  332.     msg.msg_iovlen = 1;

  333.     msg.msg_name = sockaddr;
  334.     msg.msg_namelen = socklen;

  335.     msg.msg_control = msg_control;
  336.     msg.msg_controllen = sizeof(msg_control);

  337.     cmsg = CMSG_FIRSTHDR(&msg);

  338.     cmsg->cmsg_level = SOL_UDP;
  339.     cmsg->cmsg_type = UDP_SEGMENT;
  340.     cmsg->cmsg_len = CMSG_LEN(sizeof(uint16_t));

  341.     clen = CMSG_SPACE(sizeof(uint16_t));

  342.     valp = (void *) CMSG_DATA(cmsg);
  343.     *valp = segment;

  344. #if (NGX_HAVE_ADDRINFO_CMSG)
  345.     if (c->listening && c->listening->wildcard && c->local_sockaddr) {
  346.         cmsg = CMSG_NXTHDR(&msg, cmsg);
  347.         clen += ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr);
  348.     }
  349. #endif

  350.     msg.msg_controllen = clen;

  351.     n = ngx_sendmsg(c, &msg, 0);
  352.     if (n < 0) {
  353.         return n;
  354.     }

  355.     c->sent += n;

  356.     return n;
  357. }

  358. #endif



  359. static ngx_uint_t
  360. ngx_quic_get_padding_level(ngx_connection_t *c)
  361. {
  362.     ngx_uint_t              i;
  363.     ngx_queue_t            *q;
  364.     ngx_quic_frame_t       *f;
  365.     ngx_quic_send_ctx_t    *ctx;
  366.     ngx_quic_connection_t  *qc;

  367.     /*
  368.      * RFC 9000, 14.1.  Initial Datagram Size
  369.      *
  370.      * Similarly, a server MUST expand the payload of all UDP datagrams
  371.      * carrying ack-eliciting Initial packets to at least the smallest
  372.      * allowed maximum datagram size of 1200 bytes.
  373.      */

  374.     qc = ngx_quic_get_connection(c);
  375.     ctx = ngx_quic_get_send_ctx(qc, NGX_QUIC_ENCRYPTION_INITIAL);

  376.     for (q = ngx_queue_head(&ctx->frames);
  377.          q != ngx_queue_sentinel(&ctx->frames);
  378.          q = ngx_queue_next(q))
  379.     {
  380.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);

  381.         if (f->need_ack) {
  382.             for (i = 0; i + 1 < NGX_QUIC_SEND_CTX_LAST; i++) {
  383.                 ctx = &qc->send_ctx[i + 1];

  384.                 if (ngx_queue_empty(&ctx->frames)) {
  385.                     break;
  386.                 }
  387.             }

  388.             return i;
  389.         }
  390.     }

  391.     return NGX_QUIC_SEND_CTX_LAST;
  392. }


  393. static ssize_t
  394. ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
  395.     u_char *data, size_t max, size_t min, ngx_uint_t ack_only)
  396. {
  397.     size_t                  len, pad, min_payload, max_payload;
  398.     u_char                 *p;
  399.     ssize_t                 flen;
  400.     ngx_str_t               res;
  401.     ngx_int_t               rc;
  402.     ngx_uint_t              nframes;
  403.     ngx_msec_t              now;
  404.     ngx_queue_t            *q;
  405.     ngx_quic_frame_t       *f;
  406.     ngx_quic_header_t       pkt;
  407.     ngx_quic_connection_t  *qc;
  408.     static u_char           src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];

  409.     if (ngx_queue_empty(&ctx->frames)) {
  410.         return 0;
  411.     }

  412.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  413.                    "quic output %s packet max:%uz min:%uz",
  414.                    ngx_quic_level_name(ctx->level), max, min);

  415.     qc = ngx_quic_get_connection(c);

  416.     if (!ngx_quic_keys_available(qc->keys, ctx->level, 1)) {
  417.         ngx_log_error(NGX_LOG_ALERT, c->log, 0, "quic %s write keys discarded",
  418.                       ngx_quic_level_name(ctx->level));

  419.         while (!ngx_queue_empty(&ctx->frames)) {
  420.             q = ngx_queue_head(&ctx->frames);
  421.             ngx_queue_remove(q);

  422.             f = ngx_queue_data(q, ngx_quic_frame_t, queue);
  423.             ngx_quic_free_frame(c, f);
  424.         }

  425.         return 0;
  426.     }

  427.     ngx_quic_init_packet(c, ctx, &pkt, qc->path);

  428.     min_payload = ngx_quic_payload_size(&pkt, min);
  429.     max_payload = ngx_quic_payload_size(&pkt, max);

  430.     /* RFC 9001, 5.4.2.  Header Protection Sample */
  431.     pad = 4 - pkt.num_len;
  432.     min_payload = ngx_max(min_payload, pad);

  433.     if (min_payload > max_payload) {
  434.         return 0;
  435.     }

  436.     now = ngx_current_msec;
  437.     nframes = 0;
  438.     p = src;
  439.     len = 0;

  440.     for (q = ngx_queue_head(&ctx->frames);
  441.          q != ngx_queue_sentinel(&ctx->frames);
  442.          q = ngx_queue_next(q))
  443.     {
  444.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);

  445.         if (ack_only && f->type != NGX_QUIC_FT_ACK) {
  446.             break;
  447.         }

  448.         if (len >= max_payload) {
  449.             break;
  450.         }

  451.         if (len + f->len > max_payload) {
  452.             rc = ngx_quic_split_frame(c, f, max_payload - len);

  453.             if (rc == NGX_ERROR) {
  454.                 return NGX_ERROR;
  455.             }

  456.             if (rc == NGX_DECLINED) {
  457.                 break;
  458.             }
  459.         }

  460.         if (f->need_ack) {
  461.             pkt.need_ack = 1;
  462.         }

  463.         f->pnum = ctx->pnum;
  464.         f->send_time = now;
  465.         f->plen = 0;

  466.         ngx_quic_log_frame(c->log, f, 1);

  467.         flen = ngx_quic_create_frame(p, f);
  468.         if (flen == -1) {
  469.             return NGX_ERROR;
  470.         }

  471.         len += flen;
  472.         p += flen;

  473.         nframes++;
  474.     }

  475.     if (nframes == 0) {
  476.         return 0;
  477.     }

  478.     if (len < min_payload) {
  479.         ngx_memset(p, NGX_QUIC_FT_PADDING, min_payload - len);
  480.         len = min_payload;
  481.     }

  482.     pkt.payload.data = src;
  483.     pkt.payload.len = len;

  484.     res.data = data;

  485.     ngx_quic_log_packet(c->log, &pkt);

  486.     if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
  487.         return NGX_ERROR;
  488.     }

  489.     ctx->pnum++;

  490.     if (pkt.need_ack) {
  491.         q = ngx_queue_head(&ctx->frames);
  492.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);

  493.         f->plen = res.len;
  494.     }

  495.     while (nframes--) {
  496.         q = ngx_queue_head(&ctx->frames);
  497.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);

  498.         f->pkt_need_ack = pkt.need_ack;

  499.         ngx_queue_remove(q);
  500.         ngx_queue_insert_tail(&ctx->sending, q);
  501.     }

  502.     return res.len;
  503. }


  504. static void
  505. ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
  506.     ngx_quic_header_t *pkt, ngx_quic_path_t *path)
  507. {
  508.     ngx_quic_connection_t  *qc;

  509.     qc = ngx_quic_get_connection(c);

  510.     ngx_memzero(pkt, sizeof(ngx_quic_header_t));

  511.     pkt->flags = NGX_QUIC_PKT_FIXED_BIT;

  512.     if (ctx->level == NGX_QUIC_ENCRYPTION_INITIAL) {
  513.         pkt->flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL;

  514.     } else if (ctx->level == NGX_QUIC_ENCRYPTION_HANDSHAKE) {
  515.         pkt->flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_HANDSHAKE;

  516.     } else {
  517.         if (qc->key_phase) {
  518.             pkt->flags |= NGX_QUIC_PKT_KPHASE;
  519.         }
  520.     }

  521.     pkt->dcid.data = path->cid->id;
  522.     pkt->dcid.len = path->cid->len;

  523.     pkt->scid = qc->tp.initial_scid;

  524.     pkt->version = qc->version;
  525.     pkt->log = c->log;
  526.     pkt->level = ctx->level;

  527.     pkt->keys = qc->keys;

  528.     ngx_quic_set_packet_number(pkt, ctx);
  529. }


  530. static ssize_t
  531. ngx_quic_send(ngx_connection_t *c, u_char *buf, size_t len,
  532.     struct sockaddr *sockaddr, socklen_t socklen)
  533. {
  534.     ssize_t          n;
  535.     struct iovec     iov;
  536.     struct msghdr    msg;
  537. #if (NGX_HAVE_ADDRINFO_CMSG)
  538.     struct cmsghdr  *cmsg;
  539.     char             msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))];
  540. #endif

  541.     ngx_memzero(&msg, sizeof(struct msghdr));

  542.     iov.iov_len = len;
  543.     iov.iov_base = (void *) buf;

  544.     msg.msg_iov = &iov;
  545.     msg.msg_iovlen = 1;

  546.     msg.msg_name = sockaddr;
  547.     msg.msg_namelen = socklen;

  548. #if (NGX_HAVE_ADDRINFO_CMSG)
  549.     if (c->listening && c->listening->wildcard && c->local_sockaddr) {

  550.         msg.msg_control = msg_control;
  551.         msg.msg_controllen = sizeof(msg_control);
  552.         ngx_memzero(msg_control, sizeof(msg_control));

  553.         cmsg = CMSG_FIRSTHDR(&msg);

  554.         msg.msg_controllen = ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr);
  555.     }
  556. #endif

  557.     n = ngx_sendmsg(c, &msg, 0);
  558.     if (n < 0) {
  559.         return n;
  560.     }

  561.     c->sent += n;

  562.     return n;
  563. }


  564. static void
  565. ngx_quic_set_packet_number(ngx_quic_header_t *pkt, ngx_quic_send_ctx_t *ctx)
  566. {
  567.     uint64_t  delta;

  568.     delta = ctx->pnum - ctx->largest_ack;
  569.     pkt->number = ctx->pnum;

  570.     if (delta <= 0x7F) {
  571.         pkt->num_len = 1;
  572.         pkt->trunc = ctx->pnum & 0xff;

  573.     } else if (delta <= 0x7FFF) {
  574.         pkt->num_len = 2;
  575.         pkt->flags |= 0x1;
  576.         pkt->trunc = ctx->pnum & 0xffff;

  577.     } else if (delta <= 0x7FFFFF) {
  578.         pkt->num_len = 3;
  579.         pkt->flags |= 0x2;
  580.         pkt->trunc = ctx->pnum & 0xffffff;

  581.     } else {
  582.         pkt->num_len = 4;
  583.         pkt->flags |= 0x3;
  584.         pkt->trunc = ctx->pnum & 0xffffffff;
  585.     }
  586. }


  587. ngx_int_t
  588. ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt)
  589. {
  590.     size_t             len;
  591.     ngx_quic_header_t  pkt;
  592.     static u_char      buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];

  593.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
  594.                    "sending version negotiation packet");

  595.     pkt.log = c->log;
  596.     pkt.flags = NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_FIXED_BIT;
  597.     pkt.dcid = inpkt->scid;
  598.     pkt.scid = inpkt->dcid;

  599.     len = ngx_quic_create_version_negotiation(&pkt, buf);

  600. #ifdef NGX_QUIC_DEBUG_PACKETS
  601.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  602.                    "quic vnego packet to send len:%uz %*xs", len, len, buf);
  603. #endif

  604.     (void) ngx_quic_send(c, buf, len, c->sockaddr, c->socklen);

  605.     return NGX_DONE;
  606. }


  607. ngx_int_t
  608. ngx_quic_send_stateless_reset(ngx_connection_t *c, ngx_quic_conf_t *conf,
  609.     ngx_quic_header_t *pkt)
  610. {
  611.     u_char     *token;
  612.     size_t      len, max;
  613.     uint16_t    rndbytes;
  614.     ngx_int_t   rc;
  615.     u_char      buf[NGX_QUIC_MAX_SR_PACKET];

  616.     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
  617.                    "quic handle stateless reset output");

  618.     if (pkt->len <= NGX_QUIC_MIN_PKT_LEN) {
  619.         return NGX_DECLINED;
  620.     }

  621.     rc = ngx_quic_stateless_reset_filter(c);
  622.     if (rc != NGX_OK) {
  623.         return rc;
  624.     }

  625.     if (pkt->len <= NGX_QUIC_MIN_SR_PACKET) {
  626.         len = pkt->len - 1;

  627.     } else {
  628.         max = ngx_min(NGX_QUIC_MAX_SR_PACKET, pkt->len);

  629.         if (RAND_bytes((u_char *) &rndbytes, sizeof(rndbytes)) != 1) {
  630.             return NGX_ERROR;
  631.         }

  632.         len = (rndbytes % (max - NGX_QUIC_MIN_SR_PACKET))
  633.               + NGX_QUIC_MIN_SR_PACKET;
  634.     }

  635.     if (RAND_bytes(buf, len - NGX_QUIC_SR_TOKEN_LEN) != 1) {
  636.         return NGX_ERROR;
  637.     }

  638.     buf[0] &= ~NGX_QUIC_PKT_LONG;
  639.     buf[0] |= NGX_QUIC_PKT_FIXED_BIT;

  640.     token = &buf[len - NGX_QUIC_SR_TOKEN_LEN];

  641.     if (ngx_quic_new_sr_token(c, &pkt->dcid, conf->sr_token_key, token)
  642.         != NGX_OK)
  643.     {
  644.         return NGX_ERROR;
  645.     }

  646.     (void) ngx_quic_send(c, buf, len, c->sockaddr, c->socklen);

  647.     return NGX_DECLINED;
  648. }


  649. static ngx_int_t
  650. ngx_quic_stateless_reset_filter(ngx_connection_t *c)
  651. {
  652.     time_t      now;
  653.     u_char      salt;
  654.     ngx_uint_t  i, n, m, hit;
  655.     u_char      hash[20];

  656.     static time_t   t;
  657.     static u_char   rndbyte;
  658.     static uint8_t  bitmap[65536];

  659.     now = ngx_time();

  660.     if (t != now) {
  661.         t = now;

  662.         if (RAND_bytes(&rndbyte, 1) != 1) {
  663.             return NGX_ERROR;
  664.         }

  665.         ngx_memzero(bitmap, sizeof(bitmap));
  666.     }

  667.     hit = 0;

  668.     for (i = 0; i < 3; i++) {
  669.         salt = rndbyte + i;

  670.         ngx_quic_address_hash(c->sockaddr, c->socklen, 0, &salt, 1, hash);

  671.         n = hash[0] | hash[1] << 8;
  672.         m = 1 << hash[2] % 8;

  673.         if (!(bitmap[n] & m)) {
  674.             bitmap[n] |= m;

  675.         } else {
  676.             hit++;
  677.         }
  678.     }

  679.     if (hit == 3) {
  680.         return NGX_DECLINED;
  681.     }

  682.     return NGX_OK;
  683. }


  684. ngx_int_t
  685. ngx_quic_send_cc(ngx_connection_t *c)
  686. {
  687.     ngx_quic_frame_t       *frame;
  688.     ngx_quic_connection_t  *qc;

  689.     qc = ngx_quic_get_connection(c);

  690.     if (qc->draining) {
  691.         return NGX_OK;
  692.     }

  693.     if (qc->closing
  694.         && ngx_current_msec - qc->last_cc < NGX_QUIC_CC_MIN_INTERVAL)
  695.     {
  696.         /* dot not send CC too often */
  697.         return NGX_OK;
  698.     }

  699.     frame = ngx_quic_alloc_frame(c);
  700.     if (frame == NULL) {
  701.         return NGX_ERROR;
  702.     }

  703.     frame->level = qc->error_level;
  704.     frame->type = qc->error_app ? NGX_QUIC_FT_CONNECTION_CLOSE_APP
  705.                                 : NGX_QUIC_FT_CONNECTION_CLOSE;
  706.     frame->u.close.error_code = qc->error;
  707.     frame->u.close.frame_type = qc->error_ftype;

  708.     if (qc->error_reason) {
  709.         frame->u.close.reason.len = ngx_strlen(qc->error_reason);
  710.         frame->u.close.reason.data = (u_char *) qc->error_reason;
  711.     }

  712.     frame->ignore_congestion = 1;

  713.     qc->last_cc = ngx_current_msec;

  714.     return ngx_quic_frame_sendto(c, frame, 0, qc->path);
  715. }


  716. ngx_int_t
  717. ngx_quic_send_early_cc(ngx_connection_t *c, ngx_quic_header_t *inpkt,
  718.     ngx_uint_t err, const char *reason)
  719. {
  720.     ssize_t            len;
  721.     ngx_str_t          res;
  722.     ngx_quic_keys_t    keys;
  723.     ngx_quic_frame_t   frame;
  724.     ngx_quic_header_t  pkt;

  725.     static u_char       src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
  726.     static u_char       dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];

  727.     ngx_memzero(&frame, sizeof(ngx_quic_frame_t));
  728.     ngx_memzero(&pkt, sizeof(ngx_quic_header_t));

  729.     frame.level = inpkt->level;
  730.     frame.type = NGX_QUIC_FT_CONNECTION_CLOSE;
  731.     frame.u.close.error_code = err;

  732.     frame.u.close.reason.data = (u_char *) reason;
  733.     frame.u.close.reason.len = ngx_strlen(reason);

  734.     ngx_quic_log_frame(c->log, &frame, 1);

  735.     len = ngx_quic_create_frame(NULL, &frame);
  736.     if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) {
  737.         return NGX_ERROR;
  738.     }

  739.     len = ngx_quic_create_frame(src, &frame);
  740.     if (len == -1) {
  741.         return NGX_ERROR;
  742.     }

  743.     ngx_memzero(&keys, sizeof(ngx_quic_keys_t));

  744.     pkt.keys = &keys;

  745.     if (ngx_quic_keys_set_initial_secret(pkt.keys, &inpkt->dcid, c->log)
  746.         != NGX_OK)
  747.     {
  748.         return NGX_ERROR;
  749.     }

  750.     pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG
  751.                 | NGX_QUIC_PKT_INITIAL;

  752.     pkt.num_len = 1;
  753.     /*
  754.      * pkt.num = 0;
  755.      * pkt.trunc = 0;
  756.      */

  757.     pkt.version = inpkt->version;
  758.     pkt.log = c->log;
  759.     pkt.level = inpkt->level;
  760.     pkt.dcid = inpkt->scid;
  761.     pkt.scid = inpkt->dcid;
  762.     pkt.payload.data = src;
  763.     pkt.payload.len = len;

  764.     res.data = dst;

  765.     ngx_quic_log_packet(c->log, &pkt);

  766.     if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
  767.         ngx_quic_keys_cleanup(pkt.keys);
  768.         return NGX_ERROR;
  769.     }

  770.     if (ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen) < 0) {
  771.         ngx_quic_keys_cleanup(pkt.keys);
  772.         return NGX_ERROR;
  773.     }

  774.     ngx_quic_keys_cleanup(pkt.keys);

  775.     return NGX_DONE;
  776. }


  777. ngx_int_t
  778. ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf,
  779.     ngx_quic_header_t *inpkt)
  780. {
  781.     time_t             expires;
  782.     ssize_t            len;
  783.     ngx_str_t          res, token;
  784.     ngx_quic_header_t  pkt;

  785.     u_char             buf[NGX_QUIC_RETRY_BUFFER_SIZE];
  786.     u_char             dcid[NGX_QUIC_SERVER_CID_LEN];
  787.     u_char             tbuf[NGX_QUIC_TOKEN_BUF_SIZE];

  788.     expires = ngx_time() + NGX_QUIC_RETRY_TOKEN_LIFETIME;

  789.     token.data = tbuf;
  790.     token.len = NGX_QUIC_TOKEN_BUF_SIZE;

  791.     if (ngx_quic_new_token(c->log, c->sockaddr, c->socklen, conf->av_token_key,
  792.                            &token, &inpkt->dcid, expires, 1)
  793.         != NGX_OK)
  794.     {
  795.         return NGX_ERROR;
  796.     }

  797.     ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
  798.     pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_RETRY;
  799.     pkt.version = inpkt->version;
  800.     pkt.log = c->log;

  801.     pkt.odcid = inpkt->dcid;
  802.     pkt.dcid = inpkt->scid;

  803.     /* TODO: generate routable dcid */
  804.     if (RAND_bytes(dcid, NGX_QUIC_SERVER_CID_LEN) != 1) {
  805.         return NGX_ERROR;
  806.     }

  807.     pkt.scid.len = NGX_QUIC_SERVER_CID_LEN;
  808.     pkt.scid.data = dcid;

  809.     pkt.token = token;

  810.     res.data = buf;

  811.     if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
  812.         return NGX_ERROR;
  813.     }

  814. #ifdef NGX_QUIC_DEBUG_PACKETS
  815.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  816.                    "quic packet to send len:%uz %xV", res.len, &res);
  817. #endif

  818.     len = ngx_quic_send(c, res.data, res.len, c->sockaddr, c->socklen);
  819.     if (len < 0) {
  820.         return NGX_ERROR;
  821.     }

  822.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  823.                    "quic retry packet sent to %xV", &pkt.dcid);

  824.     /*
  825.      * RFC 9000, 17.2.5.1.  Sending a Retry Packet
  826.      *
  827.      * A server MUST NOT send more than one Retry
  828.      * packet in response to a single UDP datagram.
  829.      * NGX_DONE will stop quic_input() from processing further
  830.      */
  831.     return NGX_DONE;
  832. }


  833. ngx_int_t
  834. ngx_quic_send_new_token(ngx_connection_t *c, ngx_quic_path_t *path)
  835. {
  836.     time_t                  expires;
  837.     ngx_str_t               token;
  838.     ngx_chain_t            *out;
  839.     ngx_quic_frame_t       *frame;
  840.     ngx_quic_connection_t  *qc;

  841.     u_char                  tbuf[NGX_QUIC_TOKEN_BUF_SIZE];

  842.     qc = ngx_quic_get_connection(c);

  843.     expires = ngx_time() + NGX_QUIC_NEW_TOKEN_LIFETIME;

  844.     token.data = tbuf;
  845.     token.len = NGX_QUIC_TOKEN_BUF_SIZE;

  846.     if (ngx_quic_new_token(c->log, path->sockaddr, path->socklen,
  847.                            qc->conf->av_token_key, &token, NULL, expires, 0)
  848.         != NGX_OK)
  849.     {
  850.         return NGX_ERROR;
  851.     }

  852.     out = ngx_quic_copy_buffer(c, token.data, token.len);
  853.     if (out == NGX_CHAIN_ERROR) {
  854.         return NGX_ERROR;
  855.     }

  856.     frame = ngx_quic_alloc_frame(c);
  857.     if (frame == NULL) {
  858.         return NGX_ERROR;
  859.     }

  860.     frame->level = NGX_QUIC_ENCRYPTION_APPLICATION;
  861.     frame->type = NGX_QUIC_FT_NEW_TOKEN;
  862.     frame->data = out;
  863.     frame->u.token.length = token.len;

  864.     ngx_quic_queue_frame(qc, frame);

  865.     return NGX_OK;
  866. }


  867. ngx_int_t
  868. ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)
  869. {
  870.     size_t                  len, left;
  871.     uint64_t                ack_delay;
  872.     ngx_buf_t              *b;
  873.     ngx_uint_t              i;
  874.     ngx_chain_t            *cl, **ll;
  875.     ngx_quic_frame_t       *frame;
  876.     ngx_quic_connection_t  *qc;

  877.     qc = ngx_quic_get_connection(c);

  878.     ack_delay = ngx_current_msec - ctx->largest_received;
  879.     ack_delay *= 1000;
  880.     ack_delay >>= qc->tp.ack_delay_exponent;

  881.     frame = ngx_quic_alloc_frame(c);
  882.     if (frame == NULL) {
  883.         return NGX_ERROR;
  884.     }

  885.     ll = &frame->data;
  886.     b = NULL;

  887.     for (i = 0; i < ctx->nranges; i++) {
  888.         len = ngx_quic_create_ack_range(NULL, ctx->ranges[i].gap,
  889.                                         ctx->ranges[i].range);

  890.         left = b ? b->end - b->last : 0;

  891.         if (left < len) {
  892.             cl = ngx_quic_alloc_chain(c);
  893.             if (cl == NULL) {
  894.                 return NGX_ERROR;
  895.             }

  896.             *ll = cl;
  897.             ll = &cl->next;

  898.             b = cl->buf;
  899.             left = b->end - b->last;

  900.             if (left < len) {
  901.                 return NGX_ERROR;
  902.             }
  903.         }

  904.         b->last += ngx_quic_create_ack_range(b->last, ctx->ranges[i].gap,
  905.                                              ctx->ranges[i].range);

  906.         frame->u.ack.ranges_length += len;
  907.     }

  908.     *ll = NULL;

  909.     frame->level = ctx->level;
  910.     frame->type = NGX_QUIC_FT_ACK;
  911.     frame->u.ack.largest = ctx->largest_range;
  912.     frame->u.ack.delay = ack_delay;
  913.     frame->u.ack.range_count = ctx->nranges;
  914.     frame->u.ack.first_range = ctx->first_range;
  915.     frame->len = ngx_quic_create_frame(NULL, frame);

  916.     ngx_queue_insert_head(&ctx->frames, &frame->queue);

  917.     return NGX_OK;
  918. }


  919. ngx_int_t
  920. ngx_quic_send_ack_range(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
  921.     uint64_t smallest, uint64_t largest)
  922. {
  923.     ngx_quic_frame_t       *frame;
  924.     ngx_quic_connection_t  *qc;

  925.     qc = ngx_quic_get_connection(c);

  926.     frame = ngx_quic_alloc_frame(c);
  927.     if (frame == NULL) {
  928.         return NGX_ERROR;
  929.     }

  930.     frame->level = ctx->level;
  931.     frame->type = NGX_QUIC_FT_ACK;
  932.     frame->u.ack.largest = largest;
  933.     frame->u.ack.delay = 0;
  934.     frame->u.ack.range_count = 0;
  935.     frame->u.ack.first_range = largest - smallest;

  936.     ngx_quic_queue_frame(qc, frame);

  937.     return NGX_OK;
  938. }


  939. ngx_int_t
  940. ngx_quic_frame_sendto(ngx_connection_t *c, ngx_quic_frame_t *frame,
  941.     size_t min, ngx_quic_path_t *path)
  942. {
  943.     size_t                  max, max_payload, min_payload, pad;
  944.     ssize_t                 len, sent;
  945.     ngx_str_t               res;
  946.     ngx_msec_t              now;
  947.     ngx_quic_header_t       pkt;
  948.     ngx_quic_send_ctx_t    *ctx;
  949.     ngx_quic_congestion_t  *cg;
  950.     ngx_quic_connection_t  *qc;

  951.     static u_char           src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
  952.     static u_char           dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];

  953.     qc = ngx_quic_get_connection(c);
  954.     cg = &qc->congestion;
  955.     ctx = ngx_quic_get_send_ctx(qc, frame->level);

  956.     now = ngx_current_msec;

  957.     max = ngx_quic_path_limit(c, path, path->mtu);

  958.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  959.                    "quic sendto %s packet max:%uz min:%uz",
  960.                    ngx_quic_level_name(ctx->level), max, min);

  961.     if (cg->in_flight >= cg->window && !frame->ignore_congestion) {
  962.         ngx_quic_free_frame(c, frame);
  963.         return NGX_AGAIN;
  964.     }

  965.     ngx_quic_init_packet(c, ctx, &pkt, path);

  966.     min_payload = ngx_quic_payload_size(&pkt, min);
  967.     max_payload = ngx_quic_payload_size(&pkt, max);

  968.     /* RFC 9001, 5.4.2.  Header Protection Sample */
  969.     pad = 4 - pkt.num_len;
  970.     min_payload = ngx_max(min_payload, pad);

  971.     if (min_payload > max_payload) {
  972.         ngx_quic_free_frame(c, frame);
  973.         return NGX_AGAIN;
  974.     }

  975. #if (NGX_DEBUG)
  976.     frame->pnum = pkt.number;
  977. #endif

  978.     ngx_quic_log_frame(c->log, frame, 1);

  979.     len = ngx_quic_create_frame(NULL, frame);
  980.     if ((size_t) len > max_payload) {
  981.         ngx_quic_free_frame(c, frame);
  982.         return NGX_AGAIN;
  983.     }

  984.     len = ngx_quic_create_frame(src, frame);
  985.     if (len == -1) {
  986.         ngx_quic_free_frame(c, frame);
  987.         return NGX_ERROR;
  988.     }

  989.     if (len < (ssize_t) min_payload) {
  990.         ngx_memset(src + len, NGX_QUIC_FT_PADDING, min_payload - len);
  991.         len = min_payload;
  992.     }

  993.     pkt.payload.data = src;
  994.     pkt.payload.len = len;

  995.     res.data = dst;

  996.     ngx_quic_log_packet(c->log, &pkt);

  997.     if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
  998.         ngx_quic_free_frame(c, frame);
  999.         return NGX_ERROR;
  1000.     }

  1001.     frame->pnum = ctx->pnum;
  1002.     frame->send_time = now;
  1003.     frame->plen = res.len;

  1004.     ctx->pnum++;

  1005.     sent = ngx_quic_send(c, res.data, res.len, path->sockaddr, path->socklen);
  1006.     if (sent < 0) {
  1007.         ngx_quic_free_frame(c, frame);
  1008.         return sent;
  1009.     }

  1010.     path->sent += sent;

  1011.     if (frame->need_ack && !qc->closing) {
  1012.         ngx_queue_insert_tail(&ctx->sent, &frame->queue);

  1013.         cg->in_flight += frame->plen;

  1014.     } else {
  1015.         ngx_quic_free_frame(c, frame);
  1016.         return NGX_OK;
  1017.     }

  1018.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  1019.                    "quic congestion send if:%uz", cg->in_flight);

  1020.     if (!qc->send_timer_set) {
  1021.         qc->send_timer_set = 1;
  1022.         ngx_add_timer(c->read, qc->tp.max_idle_timeout);
  1023.     }

  1024.     ngx_quic_set_lost_timer(c);

  1025.     return NGX_OK;
  1026. }


  1027. size_t
  1028. ngx_quic_path_limit(ngx_connection_t *c, ngx_quic_path_t *path, size_t size)
  1029. {
  1030.     off_t  max;

  1031.     if (!path->validated) {
  1032.         max = path->received * 3;
  1033.         max = (path->sent >= max) ? 0 : max - path->sent;

  1034.         if ((off_t) size > max) {
  1035.             return max;
  1036.         }
  1037.     }

  1038.     return size;
  1039. }