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

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_BUFFER_SIZE  4096

  9. #define ngx_quic_buf_refs(b)         (b)->shadow->num
  10. #define ngx_quic_buf_inc_refs(b)     ngx_quic_buf_refs(b)++
  11. #define ngx_quic_buf_dec_refs(b)     ngx_quic_buf_refs(b)--
  12. #define ngx_quic_buf_set_refs(b, v)  ngx_quic_buf_refs(b) = v


  13. static ngx_buf_t *ngx_quic_alloc_buf(ngx_connection_t *c);
  14. static void ngx_quic_free_buf(ngx_connection_t *c, ngx_buf_t *b);
  15. static ngx_buf_t *ngx_quic_clone_buf(ngx_connection_t *c, ngx_buf_t *b);
  16. static ngx_int_t ngx_quic_split_chain(ngx_connection_t *c, ngx_chain_t *cl,
  17.     off_t offset);


  18. static ngx_buf_t *
  19. ngx_quic_alloc_buf(ngx_connection_t *c)
  20. {
  21.     u_char                 *p;
  22.     ngx_buf_t              *b;
  23.     ngx_quic_connection_t  *qc;

  24.     qc = ngx_quic_get_connection(c);

  25.     b = qc->free_bufs;

  26.     if (b) {
  27.         qc->free_bufs = b->shadow;
  28.         p = b->start;

  29.     } else {
  30.         b = qc->free_shadow_bufs;

  31.         if (b) {
  32.             qc->free_shadow_bufs = b->shadow;

  33. #ifdef NGX_QUIC_DEBUG_ALLOC
  34.             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  35.                            "quic use shadow buffer n:%ui %ui",
  36.                            ++qc->nbufs, --qc->nshadowbufs);
  37. #endif

  38.         } else {
  39.             b = ngx_palloc(c->pool, sizeof(ngx_buf_t));
  40.             if (b == NULL) {
  41.                 return NULL;
  42.             }

  43. #ifdef NGX_QUIC_DEBUG_ALLOC
  44.             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  45.                            "quic new buffer n:%ui", ++qc->nbufs);
  46. #endif
  47.         }

  48.         p = ngx_pnalloc(c->pool, NGX_QUIC_BUFFER_SIZE);
  49.         if (p == NULL) {
  50.             return NULL;
  51.         }
  52.     }

  53. #ifdef NGX_QUIC_DEBUG_ALLOC
  54.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic alloc buffer %p", b);
  55. #endif

  56.     ngx_memzero(b, sizeof(ngx_buf_t));

  57.     b->tag = (ngx_buf_tag_t) &ngx_quic_alloc_buf;
  58.     b->temporary = 1;
  59.     b->shadow = b;

  60.     b->start = p;
  61.     b->pos = p;
  62.     b->last = p;
  63.     b->end = p + NGX_QUIC_BUFFER_SIZE;

  64.     ngx_quic_buf_set_refs(b, 1);

  65.     return b;
  66. }


  67. static void
  68. ngx_quic_free_buf(ngx_connection_t *c, ngx_buf_t *b)
  69. {
  70.     ngx_buf_t              *shadow;
  71.     ngx_quic_connection_t  *qc;

  72.     qc = ngx_quic_get_connection(c);

  73.     ngx_quic_buf_dec_refs(b);

  74. #ifdef NGX_QUIC_DEBUG_ALLOC
  75.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  76.                    "quic free buffer %p r:%ui",
  77.                    b, (ngx_uint_t) ngx_quic_buf_refs(b));
  78. #endif

  79.     shadow = b->shadow;

  80.     if (ngx_quic_buf_refs(b) == 0) {
  81.         shadow->shadow = qc->free_bufs;
  82.         qc->free_bufs = shadow;
  83.     }

  84.     if (b != shadow) {
  85.         b->shadow = qc->free_shadow_bufs;
  86.         qc->free_shadow_bufs = b;
  87.     }

  88. }


  89. static ngx_buf_t *
  90. ngx_quic_clone_buf(ngx_connection_t *c, ngx_buf_t *b)
  91. {
  92.     ngx_buf_t              *nb;
  93.     ngx_quic_connection_t  *qc;

  94.     qc = ngx_quic_get_connection(c);

  95.     nb = qc->free_shadow_bufs;

  96.     if (nb) {
  97.         qc->free_shadow_bufs = nb->shadow;

  98.     } else {
  99.         nb = ngx_palloc(c->pool, sizeof(ngx_buf_t));
  100.         if (nb == NULL) {
  101.             return NULL;
  102.         }

  103. #ifdef NGX_QUIC_DEBUG_ALLOC
  104.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  105.                        "quic new shadow buffer n:%ui", ++qc->nshadowbufs);
  106. #endif
  107.     }

  108.     *nb = *b;

  109.     ngx_quic_buf_inc_refs(b);

  110. #ifdef NGX_QUIC_DEBUG_ALLOC
  111.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  112.                    "quic clone buffer %p %p r:%ui",
  113.                    b, nb, (ngx_uint_t) ngx_quic_buf_refs(b));
  114. #endif

  115.     return nb;
  116. }


  117. static ngx_int_t
  118. ngx_quic_split_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t offset)
  119. {
  120.     ngx_buf_t    *b, *tb;
  121.     ngx_chain_t  *tail;

  122.     b = cl->buf;

  123.     tail = ngx_alloc_chain_link(c->pool);
  124.     if (tail == NULL) {
  125.         return NGX_ERROR;
  126.     }

  127.     tb = ngx_quic_clone_buf(c, b);
  128.     if (tb == NULL) {
  129.         return NGX_ERROR;
  130.     }

  131.     tail->buf = tb;

  132.     tb->pos += offset;

  133.     b->last = tb->pos;
  134.     b->last_buf = 0;

  135.     tail->next = cl->next;
  136.     cl->next = tail;

  137.     return NGX_OK;
  138. }


  139. ngx_quic_frame_t *
  140. ngx_quic_alloc_frame(ngx_connection_t *c)
  141. {
  142.     ngx_queue_t            *q;
  143.     ngx_quic_frame_t       *frame;
  144.     ngx_quic_connection_t  *qc;

  145.     qc = ngx_quic_get_connection(c);

  146.     if (!ngx_queue_empty(&qc->free_frames)) {

  147.         q = ngx_queue_head(&qc->free_frames);
  148.         frame = ngx_queue_data(q, ngx_quic_frame_t, queue);

  149.         ngx_queue_remove(&frame->queue);

  150. #ifdef NGX_QUIC_DEBUG_ALLOC
  151.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  152.                        "quic reuse frame n:%ui", qc->nframes);
  153. #endif

  154.     } else if (qc->nframes < 10000) {
  155.         frame = ngx_palloc(c->pool, sizeof(ngx_quic_frame_t));
  156.         if (frame == NULL) {
  157.             return NULL;
  158.         }

  159.         ++qc->nframes;

  160. #ifdef NGX_QUIC_DEBUG_ALLOC
  161.         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  162.                        "quic alloc frame n:%ui", qc->nframes);
  163. #endif

  164.     } else {
  165.         ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic flood detected");
  166.         return NULL;
  167.     }

  168.     ngx_memzero(frame, sizeof(ngx_quic_frame_t));

  169.     return frame;
  170. }


  171. void
  172. ngx_quic_free_frame(ngx_connection_t *c, ngx_quic_frame_t *frame)
  173. {
  174.     ngx_quic_connection_t  *qc;

  175.     qc = ngx_quic_get_connection(c);

  176.     if (frame->data) {
  177.         ngx_quic_free_chain(c, frame->data);
  178.     }

  179.     ngx_queue_insert_head(&qc->free_frames, &frame->queue);

  180. #ifdef NGX_QUIC_DEBUG_ALLOC
  181.     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  182.                    "quic free frame n:%ui", qc->nframes);
  183. #endif
  184. }


  185. void
  186. ngx_quic_free_chain(ngx_connection_t *c, ngx_chain_t *in)
  187. {
  188.     ngx_chain_t  *cl;

  189.     while (in) {
  190.         cl = in;
  191.         in = in->next;

  192.         ngx_quic_free_buf(c, cl->buf);
  193.         ngx_free_chain(c->pool, cl);
  194.     }
  195. }


  196. void
  197. ngx_quic_free_frames(ngx_connection_t *c, ngx_queue_t *frames)
  198. {
  199.     ngx_queue_t       *q;
  200.     ngx_quic_frame_t  *f;

  201.     do {
  202.         q = ngx_queue_head(frames);

  203.         if (q == ngx_queue_sentinel(frames)) {
  204.             break;
  205.         }

  206.         ngx_queue_remove(q);

  207.         f = ngx_queue_data(q, ngx_quic_frame_t, queue);

  208.         ngx_quic_free_frame(c, f);
  209.     } while (1);
  210. }


  211. void
  212. ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame)
  213. {
  214.     ngx_quic_send_ctx_t  *ctx;

  215.     ctx = ngx_quic_get_send_ctx(qc, frame->level);

  216.     ngx_queue_insert_tail(&ctx->frames, &frame->queue);

  217.     frame->len = ngx_quic_create_frame(NULL, frame);
  218.     /* always succeeds */

  219.     if (qc->closing) {
  220.         return;
  221.     }

  222.     ngx_post_event(&qc->push, &ngx_posted_events);
  223. }


  224. ngx_int_t
  225. ngx_quic_split_frame(ngx_connection_t *c, ngx_quic_frame_t *f, size_t len)
  226. {
  227.     size_t                     shrink;
  228.     ngx_chain_t               *out;
  229.     ngx_quic_frame_t          *nf;
  230.     ngx_quic_buffer_t          qb;
  231.     ngx_quic_ordered_frame_t  *of, *onf;

  232.     switch (f->type) {
  233.     case NGX_QUIC_FT_CRYPTO:
  234.     case NGX_QUIC_FT_STREAM:
  235.         break;

  236.     default:
  237.         return NGX_DECLINED;
  238.     }

  239.     if ((size_t) f->len <= len) {
  240.         return NGX_OK;
  241.     }

  242.     shrink = f->len - len;

  243.     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  244.                    "quic split frame now:%uz need:%uz shrink:%uz",
  245.                    f->len, len, shrink);

  246.     of = &f->u.ord;

  247.     if (of->length <= shrink) {
  248.         return NGX_DECLINED;
  249.     }

  250.     of->length -= shrink;
  251.     f->len = ngx_quic_create_frame(NULL, f);

  252.     if ((size_t) f->len > len) {
  253.         ngx_log_error(NGX_LOG_ERR, c->log, 0, "could not split QUIC frame");
  254.         return NGX_ERROR;
  255.     }

  256.     ngx_memzero(&qb, sizeof(ngx_quic_buffer_t));
  257.     qb.chain = f->data;

  258.     out = ngx_quic_read_buffer(c, &qb, of->length);
  259.     if (out == NGX_CHAIN_ERROR) {
  260.         return NGX_ERROR;
  261.     }

  262.     f->data = out;

  263.     nf = ngx_quic_alloc_frame(c);
  264.     if (nf == NULL) {
  265.         return NGX_ERROR;
  266.     }

  267.     *nf = *f;
  268.     onf = &nf->u.ord;
  269.     onf->offset += of->length;
  270.     onf->length = shrink;
  271.     nf->len = ngx_quic_create_frame(NULL, nf);
  272.     nf->data = qb.chain;

  273.     if (f->type == NGX_QUIC_FT_STREAM) {
  274.         f->u.stream.fin = 0;
  275.     }

  276.     ngx_queue_insert_after(&f->queue, &nf->queue);

  277.     return NGX_OK;
  278. }


  279. ngx_chain_t *
  280. ngx_quic_copy_buffer(ngx_connection_t *c, u_char *data, size_t len)
  281. {
  282.     ngx_buf_t          buf;
  283.     ngx_chain_t        cl, *out;
  284.     ngx_quic_buffer_t  qb;

  285.     ngx_memzero(&buf, sizeof(ngx_buf_t));

  286.     buf.pos = data;
  287.     buf.last = buf.pos + len;
  288.     buf.temporary = 1;

  289.     cl.buf = &buf;
  290.     cl.next = NULL;

  291.     ngx_memzero(&qb, sizeof(ngx_quic_buffer_t));

  292.     if (ngx_quic_write_buffer(c, &qb, &cl, len, 0) == NGX_CHAIN_ERROR) {
  293.         return NGX_CHAIN_ERROR;
  294.     }

  295.     out = ngx_quic_read_buffer(c, &qb, len);
  296.     if (out == NGX_CHAIN_ERROR) {
  297.         return NGX_CHAIN_ERROR;
  298.     }

  299.     ngx_quic_free_buffer(c, &qb);

  300.     return out;
  301. }


  302. ngx_chain_t *
  303. ngx_quic_read_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb, uint64_t limit)
  304. {
  305.     uint64_t      n;
  306.     ngx_buf_t    *b;
  307.     ngx_chain_t  *out, **ll;

  308.     out = qb->chain;

  309.     for (ll = &out; *ll; ll = &(*ll)->next) {
  310.         b = (*ll)->buf;

  311.         if (b->sync) {
  312.             /* hole */
  313.             break;
  314.         }

  315.         if (limit == 0) {
  316.             break;
  317.         }

  318.         n = b->last - b->pos;

  319.         if (n > limit) {
  320.             if (ngx_quic_split_chain(c, *ll, limit) != NGX_OK) {
  321.                 return NGX_CHAIN_ERROR;
  322.             }

  323.             n = limit;
  324.         }

  325.         limit -= n;
  326.         qb->offset += n;
  327.     }

  328.     if (qb->offset >= qb->last_offset) {
  329.         qb->last_chain = NULL;
  330.     }

  331.     qb->chain = *ll;
  332.     *ll = NULL;

  333.     return out;
  334. }


  335. void
  336. ngx_quic_skip_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb,
  337.     uint64_t offset)
  338. {
  339.     size_t        n;
  340.     ngx_buf_t    *b;
  341.     ngx_chain_t  *cl;

  342.     while (qb->chain) {
  343.         if (qb->offset >= offset) {
  344.             break;
  345.         }

  346.         cl = qb->chain;
  347.         b = cl->buf;
  348.         n = b->last - b->pos;

  349.         if (qb->offset + n > offset) {
  350.             n = offset - qb->offset;
  351.             b->pos += n;
  352.             qb->offset += n;
  353.             break;
  354.         }

  355.         qb->offset += n;
  356.         qb->chain = cl->next;

  357.         cl->next = NULL;
  358.         ngx_quic_free_chain(c, cl);
  359.     }

  360.     if (qb->chain == NULL) {
  361.         qb->offset = offset;
  362.     }

  363.     if (qb->offset >= qb->last_offset) {
  364.         qb->last_chain = NULL;
  365.     }
  366. }


  367. ngx_chain_t *
  368. ngx_quic_alloc_chain(ngx_connection_t *c)
  369. {
  370.     ngx_chain_t  *cl;

  371.     cl = ngx_alloc_chain_link(c->pool);
  372.     if (cl == NULL) {
  373.         return NULL;
  374.     }

  375.     cl->buf = ngx_quic_alloc_buf(c);
  376.     if (cl->buf == NULL) {
  377.         return NULL;
  378.     }

  379.     return cl;
  380. }


  381. ngx_chain_t *
  382. ngx_quic_write_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb,
  383.     ngx_chain_t *in, uint64_t limit, uint64_t offset)
  384. {
  385.     u_char       *p;
  386.     uint64_t      n, base;
  387.     ngx_buf_t    *b;
  388.     ngx_chain_t  *cl, **chain;

  389.     if (qb->last_chain && offset >= qb->last_offset) {
  390.         base = qb->last_offset;
  391.         chain = &qb->last_chain;

  392.     } else {
  393.         base = qb->offset;
  394.         chain = &qb->chain;
  395.     }

  396.     while (in && limit) {

  397.         if (offset < base) {
  398.             n = ngx_min((uint64_t) (in->buf->last - in->buf->pos),
  399.                         ngx_min(base - offset, limit));

  400.             in->buf->pos += n;
  401.             offset += n;
  402.             limit -= n;

  403.             if (in->buf->pos == in->buf->last) {
  404.                 in = in->next;
  405.             }

  406.             continue;
  407.         }

  408.         cl = *chain;

  409.         if (cl == NULL) {
  410.             cl = ngx_quic_alloc_chain(c);
  411.             if (cl == NULL) {
  412.                 return NGX_CHAIN_ERROR;
  413.             }

  414.             cl->buf->last = cl->buf->end;
  415.             cl->buf->sync = 1; /* hole */
  416.             cl->next = NULL;
  417.             *chain = cl;
  418.         }

  419.         b = cl->buf;
  420.         n = b->last - b->pos;

  421.         if (base + n <= offset) {
  422.             base += n;
  423.             chain = &cl->next;
  424.             continue;
  425.         }

  426.         if (b->sync && offset > base) {
  427.             if (ngx_quic_split_chain(c, cl, offset - base) != NGX_OK) {
  428.                 return NGX_CHAIN_ERROR;
  429.             }

  430.             continue;
  431.         }

  432.         p = b->pos + (offset - base);

  433.         while (in) {

  434.             if (!ngx_buf_in_memory(in->buf) || in->buf->pos == in->buf->last) {
  435.                 in = in->next;
  436.                 continue;
  437.             }

  438.             if (p == b->last || limit == 0) {
  439.                 break;
  440.             }

  441.             n = ngx_min(b->last - p, in->buf->last - in->buf->pos);
  442.             n = ngx_min(n, limit);

  443.             if (b->sync) {
  444.                 ngx_memcpy(p, in->buf->pos, n);
  445.                 qb->size += n;
  446.             }

  447.             p += n;
  448.             in->buf->pos += n;
  449.             offset += n;
  450.             limit -= n;
  451.         }

  452.         if (b->sync && p == b->last) {
  453.             b->sync = 0;
  454.             continue;
  455.         }

  456.         if (b->sync && p != b->pos) {
  457.             if (ngx_quic_split_chain(c, cl, p - b->pos) != NGX_OK) {
  458.                 return NGX_CHAIN_ERROR;
  459.             }

  460.             b->sync = 0;
  461.         }
  462.     }

  463.     qb->last_offset = base;
  464.     qb->last_chain = *chain;

  465.     return in;
  466. }


  467. void
  468. ngx_quic_free_buffer(ngx_connection_t *c, ngx_quic_buffer_t *qb)
  469. {
  470.     ngx_quic_free_chain(c, qb->chain);

  471.     qb->chain = NULL;
  472.     qb->last_chain = NULL;
  473. }


  474. #if (NGX_DEBUG)

  475. void
  476. ngx_quic_log_frame(ngx_log_t *log, ngx_quic_frame_t *f, ngx_uint_t tx)
  477. {
  478.     u_char      *p, *last, *pos, *end;
  479.     ssize_t      n;
  480.     uint64_t     gap, range, largest, smallest;
  481.     ngx_uint_t   i;
  482.     u_char       buf[NGX_MAX_ERROR_STR];

  483.     p = buf;
  484.     last = buf + sizeof(buf);

  485.     switch (f->type) {

  486.     case NGX_QUIC_FT_CRYPTO:
  487.         p = ngx_slprintf(p, last, "CRYPTO len:%uL off:%uL",
  488.                          f->u.crypto.length, f->u.crypto.offset);

  489. #ifdef NGX_QUIC_DEBUG_FRAMES
  490.         {
  491.             ngx_chain_t  *cl;

  492.             p = ngx_slprintf(p, last, " data:");

  493.             for (cl = f->data; cl; cl = cl->next) {
  494.                 p = ngx_slprintf(p, last, "%*xs",
  495.                                  cl->buf->last - cl->buf->pos, cl->buf->pos);
  496.             }
  497.         }
  498. #endif

  499.         break;

  500.     case NGX_QUIC_FT_PADDING:
  501.         p = ngx_slprintf(p, last, "PADDING");
  502.         break;

  503.     case NGX_QUIC_FT_ACK:
  504.     case NGX_QUIC_FT_ACK_ECN:

  505.         p = ngx_slprintf(p, last, "ACK n:%ui delay:%uL ",
  506.                          f->u.ack.range_count, f->u.ack.delay);

  507.         if (f->data) {
  508.             pos = f->data->buf->pos;
  509.             end = f->data->buf->last;

  510.         } else {
  511.             pos = NULL;
  512.             end = NULL;
  513.         }

  514.         largest = f->u.ack.largest;
  515.         smallest = f->u.ack.largest - f->u.ack.first_range;

  516.         if (largest == smallest) {
  517.             p = ngx_slprintf(p, last, "%uL", largest);

  518.         } else {
  519.             p = ngx_slprintf(p, last, "%uL-%uL", largest, smallest);
  520.         }

  521.         for (i = 0; i < f->u.ack.range_count; i++) {
  522.             n = ngx_quic_parse_ack_range(log, pos, end, &gap, &range);
  523.             if (n == NGX_ERROR) {
  524.                 break;
  525.             }

  526.             pos += n;

  527.             largest = smallest - gap - 2;
  528.             smallest = largest - range;

  529.             if (largest == smallest) {
  530.                 p = ngx_slprintf(p, last, " %uL", largest);

  531.             } else {
  532.                 p = ngx_slprintf(p, last, " %uL-%uL", largest, smallest);
  533.             }
  534.         }

  535.         if (f->type == NGX_QUIC_FT_ACK_ECN) {
  536.             p = ngx_slprintf(p, last, " ECN counters ect0:%uL ect1:%uL ce:%uL",
  537.                              f->u.ack.ect0, f->u.ack.ect1, f->u.ack.ce);
  538.         }
  539.         break;

  540.     case NGX_QUIC_FT_PING:
  541.         p = ngx_slprintf(p, last, "PING");
  542.         break;

  543.     case NGX_QUIC_FT_NEW_CONNECTION_ID:
  544.         p = ngx_slprintf(p, last,
  545.                          "NEW_CONNECTION_ID seq:%uL retire:%uL len:%ud",
  546.                          f->u.ncid.seqnum, f->u.ncid.retire, f->u.ncid.len);
  547.         break;

  548.     case NGX_QUIC_FT_RETIRE_CONNECTION_ID:
  549.         p = ngx_slprintf(p, last, "RETIRE_CONNECTION_ID seqnum:%uL",
  550.                          f->u.retire_cid.sequence_number);
  551.         break;

  552.     case NGX_QUIC_FT_CONNECTION_CLOSE:
  553.     case NGX_QUIC_FT_CONNECTION_CLOSE_APP:
  554.         p = ngx_slprintf(p, last, "CONNECTION_CLOSE%s err:%ui",
  555.                          f->type == NGX_QUIC_FT_CONNECTION_CLOSE ? "" : "_APP",
  556.                          f->u.close.error_code);

  557.         if (f->u.close.reason.len) {
  558.             p = ngx_slprintf(p, last, " %V", &f->u.close.reason);
  559.         }

  560.         if (f->type == NGX_QUIC_FT_CONNECTION_CLOSE) {
  561.             p = ngx_slprintf(p, last, " ft:%ui", f->u.close.frame_type);
  562.         }

  563.         break;

  564.     case NGX_QUIC_FT_STREAM:
  565.         p = ngx_slprintf(p, last, "STREAM id:0x%xL", f->u.stream.stream_id);

  566.         if (f->u.stream.off) {
  567.             p = ngx_slprintf(p, last, " off:%uL", f->u.stream.offset);
  568.         }

  569.         if (f->u.stream.len) {
  570.             p = ngx_slprintf(p, last, " len:%uL", f->u.stream.length);
  571.         }

  572.         if (f->u.stream.fin) {
  573.             p = ngx_slprintf(p, last, " fin:1");
  574.         }

  575. #ifdef NGX_QUIC_DEBUG_FRAMES
  576.         {
  577.             ngx_chain_t  *cl;

  578.             p = ngx_slprintf(p, last, " data:");

  579.             for (cl = f->data; cl; cl = cl->next) {
  580.                 p = ngx_slprintf(p, last, "%*xs",
  581.                                  cl->buf->last - cl->buf->pos, cl->buf->pos);
  582.             }
  583.         }
  584. #endif

  585.         break;

  586.     case NGX_QUIC_FT_MAX_DATA:
  587.         p = ngx_slprintf(p, last, "MAX_DATA max_data:%uL on recv",
  588.                          f->u.max_data.max_data);
  589.         break;

  590.     case NGX_QUIC_FT_RESET_STREAM:
  591.         p = ngx_slprintf(p, last, "RESET_STREAM"
  592.                         " id:0x%xL error_code:0x%xL final_size:0x%xL",
  593.                         f->u.reset_stream.id, f->u.reset_stream.error_code,
  594.                         f->u.reset_stream.final_size);
  595.         break;

  596.     case NGX_QUIC_FT_STOP_SENDING:
  597.         p = ngx_slprintf(p, last, "STOP_SENDING id:0x%xL err:0x%xL",
  598.                          f->u.stop_sending.id, f->u.stop_sending.error_code);
  599.         break;

  600.     case NGX_QUIC_FT_STREAMS_BLOCKED:
  601.     case NGX_QUIC_FT_STREAMS_BLOCKED2:
  602.         p = ngx_slprintf(p, last, "STREAMS_BLOCKED limit:%uL bidi:%ui",
  603.                          f->u.streams_blocked.limit, f->u.streams_blocked.bidi);
  604.         break;

  605.     case NGX_QUIC_FT_MAX_STREAMS:
  606.     case NGX_QUIC_FT_MAX_STREAMS2:
  607.         p = ngx_slprintf(p, last, "MAX_STREAMS limit:%uL bidi:%ui",
  608.                          f->u.max_streams.limit, f->u.max_streams.bidi);
  609.         break;

  610.     case NGX_QUIC_FT_MAX_STREAM_DATA:
  611.         p = ngx_slprintf(p, last, "MAX_STREAM_DATA id:0x%xL limit:%uL",
  612.                          f->u.max_stream_data.id, f->u.max_stream_data.limit);
  613.         break;


  614.     case NGX_QUIC_FT_DATA_BLOCKED:
  615.         p = ngx_slprintf(p, last, "DATA_BLOCKED limit:%uL",
  616.                          f->u.data_blocked.limit);
  617.         break;

  618.     case NGX_QUIC_FT_STREAM_DATA_BLOCKED:
  619.         p = ngx_slprintf(p, last, "STREAM_DATA_BLOCKED id:0x%xL limit:%uL",
  620.                          f->u.stream_data_blocked.id,
  621.                          f->u.stream_data_blocked.limit);
  622.         break;

  623.     case NGX_QUIC_FT_PATH_CHALLENGE:
  624.         p = ngx_slprintf(p, last, "PATH_CHALLENGE data:0x%*xs",
  625.                          sizeof(f->u.path_challenge.data),
  626.                          f->u.path_challenge.data);
  627.         break;

  628.     case NGX_QUIC_FT_PATH_RESPONSE:
  629.         p = ngx_slprintf(p, last, "PATH_RESPONSE data:0x%*xs",
  630.                          sizeof(f->u.path_challenge.data),
  631.                          f->u.path_challenge.data);
  632.         break;

  633.     case NGX_QUIC_FT_NEW_TOKEN:
  634.         p = ngx_slprintf(p, last, "NEW_TOKEN");

  635. #ifdef NGX_QUIC_DEBUG_FRAMES
  636.         {
  637.             ngx_chain_t  *cl;

  638.             p = ngx_slprintf(p, last, " token:");

  639.             for (cl = f->data; cl; cl = cl->next) {
  640.                 p = ngx_slprintf(p, last, "%*xs",
  641.                                  cl->buf->last - cl->buf->pos, cl->buf->pos);
  642.             }
  643.         }
  644. #endif

  645.         break;

  646.     case NGX_QUIC_FT_HANDSHAKE_DONE:
  647.         p = ngx_slprintf(p, last, "HANDSHAKE DONE");
  648.         break;

  649.     default:
  650.         p = ngx_slprintf(p, last, "unknown type 0x%xi", f->type);
  651.         break;
  652.     }

  653.     ngx_log_debug5(NGX_LOG_DEBUG_EVENT, log, 0, "quic frame %s %s:%uL %*s",
  654.                    tx ? "tx" : "rx", ngx_quic_level_name(f->level), f->pnum,
  655.                    p - buf, buf);
  656. }

  657. #endif