src/http/v3/ngx_http_v3_uni.c - nginx source code

Data types defined

Functions defined

Source code


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


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. typedef struct {
  9.     ngx_http_v3_parse_uni_t         parse;
  10.     ngx_int_t                       index;
  11. } ngx_http_v3_uni_stream_t;


  12. static void ngx_http_v3_close_uni_stream(ngx_connection_t *c);
  13. static void ngx_http_v3_uni_read_handler(ngx_event_t *rev);
  14. static void ngx_http_v3_uni_dummy_read_handler(ngx_event_t *wev);
  15. static void ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev);


  16. void
  17. ngx_http_v3_init_uni_stream(ngx_connection_t *c)
  18. {
  19.     uint64_t                   n;
  20.     ngx_http_v3_session_t     *h3c;
  21.     ngx_http_v3_uni_stream_t  *us;

  22.     h3c = ngx_http_v3_get_session(c);
  23.     if (h3c->hq) {
  24.         ngx_http_v3_finalize_connection(c,
  25.                                         NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR,
  26.                                         "uni stream in hq mode");
  27.         c->data = NULL;
  28.         ngx_http_v3_close_uni_stream(c);
  29.         return;
  30.     }

  31.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init uni stream");

  32.     n = c->quic->id >> 2;

  33.     if (n >= NGX_HTTP_V3_MAX_UNI_STREAMS) {
  34.         ngx_http_v3_finalize_connection(c,
  35.                                       NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR,
  36.                                       "reached maximum number of uni streams");
  37.         c->data = NULL;
  38.         ngx_http_v3_close_uni_stream(c);
  39.         return;
  40.     }

  41.     ngx_quic_cancelable_stream(c);

  42.     us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t));
  43.     if (us == NULL) {
  44.         ngx_http_v3_finalize_connection(c,
  45.                                         NGX_HTTP_V3_ERR_INTERNAL_ERROR,
  46.                                         "memory allocation error");
  47.         c->data = NULL;
  48.         ngx_http_v3_close_uni_stream(c);
  49.         return;
  50.     }

  51.     us->index = -1;

  52.     c->data = us;

  53.     c->read->handler = ngx_http_v3_uni_read_handler;
  54.     c->write->handler = ngx_http_v3_uni_dummy_write_handler;

  55.     ngx_http_v3_uni_read_handler(c->read);
  56. }


  57. static void
  58. ngx_http_v3_close_uni_stream(ngx_connection_t *c)
  59. {
  60.     ngx_pool_t                *pool;
  61.     ngx_http_v3_session_t     *h3c;
  62.     ngx_http_v3_uni_stream_t  *us;

  63.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 close stream");

  64.     us = c->data;

  65.     if (us && us->index >= 0) {
  66.         h3c = ngx_http_v3_get_session(c);
  67.         h3c->known_streams[us->index] = NULL;
  68.     }

  69.     c->destroyed = 1;

  70.     pool = c->pool;

  71.     ngx_close_connection(c);

  72.     ngx_destroy_pool(pool);
  73. }


  74. ngx_int_t
  75. ngx_http_v3_register_uni_stream(ngx_connection_t *c, uint64_t type)
  76. {
  77.     ngx_int_t                  index;
  78.     ngx_http_v3_session_t     *h3c;
  79.     ngx_http_v3_uni_stream_t  *us;

  80.     h3c = ngx_http_v3_get_session(c);

  81.     switch (type) {

  82.     case NGX_HTTP_V3_STREAM_ENCODER:

  83.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  84.                        "http3 encoder stream");
  85.         index = NGX_HTTP_V3_STREAM_CLIENT_ENCODER;
  86.         break;

  87.     case NGX_HTTP_V3_STREAM_DECODER:

  88.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  89.                        "http3 decoder stream");
  90.         index = NGX_HTTP_V3_STREAM_CLIENT_DECODER;
  91.         break;

  92.     case NGX_HTTP_V3_STREAM_CONTROL:

  93.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  94.                        "http3 control stream");
  95.         index = NGX_HTTP_V3_STREAM_CLIENT_CONTROL;

  96.         break;

  97.     default:

  98.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  99.                        "http3 stream 0x%02xL", type);

  100.         if (h3c->known_streams[NGX_HTTP_V3_STREAM_CLIENT_ENCODER] == NULL
  101.             || h3c->known_streams[NGX_HTTP_V3_STREAM_CLIENT_DECODER] == NULL
  102.             || h3c->known_streams[NGX_HTTP_V3_STREAM_CLIENT_CONTROL] == NULL)
  103.         {
  104.             ngx_log_error(NGX_LOG_INFO, c->log, 0, "missing mandatory stream");
  105.             return NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR;
  106.         }

  107.         index = -1;
  108.     }

  109.     if (index >= 0) {
  110.         if (h3c->known_streams[index]) {
  111.             ngx_log_error(NGX_LOG_INFO, c->log, 0, "stream exists");
  112.             return NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR;
  113.         }

  114.         h3c->known_streams[index] = c;

  115.         us = c->data;
  116.         us->index = index;
  117.     }

  118.     return NGX_OK;
  119. }


  120. static void
  121. ngx_http_v3_uni_read_handler(ngx_event_t *rev)
  122. {
  123.     u_char                     buf[128];
  124.     ssize_t                    n;
  125.     ngx_buf_t                  b;
  126.     ngx_int_t                  rc;
  127.     ngx_connection_t          *c;
  128.     ngx_http_v3_session_t     *h3c;
  129.     ngx_http_v3_uni_stream_t  *us;

  130.     c = rev->data;
  131.     us = c->data;

  132.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read handler");

  133.     if (c->close) {
  134.         ngx_http_v3_close_uni_stream(c);
  135.         return;
  136.     }

  137.     ngx_memzero(&b, sizeof(ngx_buf_t));

  138.     while (rev->ready) {

  139.         n = c->recv(c, buf, sizeof(buf));

  140.         if (n == NGX_ERROR) {
  141.             rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
  142.             goto failed;
  143.         }

  144.         if (n == 0) {
  145.             if (us->index >= 0) {
  146.                 rc = NGX_HTTP_V3_ERR_CLOSED_CRITICAL_STREAM;
  147.                 goto failed;
  148.             }

  149.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 read eof");
  150.             ngx_http_v3_close_uni_stream(c);
  151.             return;
  152.         }

  153.         if (n == NGX_AGAIN) {
  154.             break;
  155.         }

  156.         b.pos = buf;
  157.         b.last = buf + n;

  158.         h3c = ngx_http_v3_get_session(c);
  159.         h3c->total_bytes += n;

  160.         if (ngx_http_v3_check_flood(c) != NGX_OK) {
  161.             ngx_http_v3_close_uni_stream(c);
  162.             return;
  163.         }

  164.         rc = ngx_http_v3_parse_uni(c, &us->parse, &b);

  165.         if (rc == NGX_DONE) {
  166.             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  167.                            "http3 read done");
  168.             ngx_http_v3_close_uni_stream(c);
  169.             return;
  170.         }

  171.         if (rc > 0) {
  172.             goto failed;
  173.         }

  174.         if (rc != NGX_AGAIN) {
  175.             rc = NGX_HTTP_V3_ERR_GENERAL_PROTOCOL_ERROR;
  176.             goto failed;
  177.         }
  178.     }

  179.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  180.         rc = NGX_HTTP_V3_ERR_INTERNAL_ERROR;
  181.         goto failed;
  182.     }

  183.     return;

  184. failed:

  185.     ngx_http_v3_finalize_connection(c, rc, "stream error");
  186.     ngx_http_v3_close_uni_stream(c);
  187. }


  188. static void
  189. ngx_http_v3_uni_dummy_read_handler(ngx_event_t *rev)
  190. {
  191.     u_char             ch;
  192.     ngx_connection_t  *c;

  193.     c = rev->data;

  194.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy read handler");

  195.     if (c->close) {
  196.         ngx_http_v3_close_uni_stream(c);
  197.         return;
  198.     }

  199.     if (rev->ready) {
  200.         if (c->recv(c, &ch, 1) != 0) {
  201.             ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_NO_ERROR, NULL);
  202.             ngx_http_v3_close_uni_stream(c);
  203.             return;
  204.         }
  205.     }

  206.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  207.         ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
  208.                                         NULL);
  209.         ngx_http_v3_close_uni_stream(c);
  210.     }
  211. }


  212. static void
  213. ngx_http_v3_uni_dummy_write_handler(ngx_event_t *wev)
  214. {
  215.     ngx_connection_t  *c;

  216.     c = wev->data;

  217.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 dummy write handler");

  218.     if (ngx_handle_write_event(wev, 0) != NGX_OK) {
  219.         ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
  220.                                         NULL);
  221.         ngx_http_v3_close_uni_stream(c);
  222.     }
  223. }


  224. ngx_connection_t *
  225. ngx_http_v3_get_uni_stream(ngx_connection_t *c, ngx_uint_t type)
  226. {
  227.     u_char                     buf[NGX_HTTP_V3_VARLEN_INT_LEN];
  228.     size_t                     n;
  229.     ngx_int_t                  index;
  230.     ngx_connection_t          *sc;
  231.     ngx_http_v3_session_t     *h3c;
  232.     ngx_http_v3_uni_stream_t  *us;

  233.     switch (type) {
  234.     case NGX_HTTP_V3_STREAM_ENCODER:
  235.         index = NGX_HTTP_V3_STREAM_SERVER_ENCODER;
  236.         break;
  237.     case NGX_HTTP_V3_STREAM_DECODER:
  238.         index = NGX_HTTP_V3_STREAM_SERVER_DECODER;
  239.         break;
  240.     case NGX_HTTP_V3_STREAM_CONTROL:
  241.         index = NGX_HTTP_V3_STREAM_SERVER_CONTROL;
  242.         break;
  243.     default:
  244.         index = -1;
  245.     }

  246.     h3c = ngx_http_v3_get_session(c);

  247.     if (index >= 0) {
  248.         if (h3c->known_streams[index]) {
  249.             return h3c->known_streams[index];
  250.         }
  251.     }

  252.     sc = ngx_quic_open_stream(c, 0);
  253.     if (sc == NULL) {
  254.         goto failed;
  255.     }

  256.     ngx_quic_cancelable_stream(sc);

  257.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  258.                    "http3 create uni stream, type:%ui", type);

  259.     us = ngx_pcalloc(sc->pool, sizeof(ngx_http_v3_uni_stream_t));
  260.     if (us == NULL) {
  261.         goto failed;
  262.     }

  263.     us->index = index;

  264.     sc->data = us;

  265.     sc->read->handler = ngx_http_v3_uni_dummy_read_handler;
  266.     sc->write->handler = ngx_http_v3_uni_dummy_write_handler;

  267.     if (index >= 0) {
  268.         h3c->known_streams[index] = sc;
  269.     }

  270.     n = (u_char *) ngx_http_v3_encode_varlen_int(buf, type) - buf;

  271.     h3c = ngx_http_v3_get_session(c);
  272.     h3c->total_bytes += n;

  273.     if (sc->send(sc, buf, n) != (ssize_t) n) {
  274.         goto failed;
  275.     }

  276.     ngx_post_event(sc->read, &ngx_posted_events);

  277.     return sc;

  278. failed:

  279.     ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to create server stream");

  280.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_STREAM_CREATION_ERROR,
  281.                                     "failed to create server stream");
  282.     if (sc) {
  283.         ngx_http_v3_close_uni_stream(sc);
  284.     }

  285.     return NULL;
  286. }


  287. ngx_int_t
  288. ngx_http_v3_send_settings(ngx_connection_t *c)
  289. {
  290.     u_char                  *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 6];
  291.     size_t                   n;
  292.     ngx_connection_t        *cc;
  293.     ngx_http_v3_session_t   *h3c;
  294.     ngx_http_v3_srv_conf_t  *h3scf;

  295.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings");

  296.     cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL);
  297.     if (cc == NULL) {
  298.         return NGX_ERROR;
  299.     }

  300.     h3scf = ngx_http_v3_get_module_srv_conf(c, ngx_http_v3_module);

  301.     n = ngx_http_v3_encode_varlen_int(NULL,
  302.                                       NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY);
  303.     n += ngx_http_v3_encode_varlen_int(NULL, h3scf->max_table_capacity);
  304.     n += ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_PARAM_BLOCKED_STREAMS);
  305.     n += ngx_http_v3_encode_varlen_int(NULL, h3scf->max_blocked_streams);

  306.     p = (u_char *) ngx_http_v3_encode_varlen_int(buf,
  307.                                                  NGX_HTTP_V3_FRAME_SETTINGS);
  308.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, n);
  309.     p = (u_char *) ngx_http_v3_encode_varlen_int(p,
  310.                                          NGX_HTTP_V3_PARAM_MAX_TABLE_CAPACITY);
  311.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_table_capacity);
  312.     p = (u_char *) ngx_http_v3_encode_varlen_int(p,
  313.                                             NGX_HTTP_V3_PARAM_BLOCKED_STREAMS);
  314.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, h3scf->max_blocked_streams);
  315.     n = p - buf;

  316.     h3c = ngx_http_v3_get_session(c);
  317.     h3c->total_bytes += n;

  318.     if (cc->send(cc, buf, n) != (ssize_t) n) {
  319.         goto failed;
  320.     }

  321.     return NGX_OK;

  322. failed:

  323.     ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to send settings");

  324.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  325.                                     "failed to send settings");
  326.     ngx_http_v3_close_uni_stream(cc);

  327.     return NGX_ERROR;
  328. }


  329. ngx_int_t
  330. ngx_http_v3_send_goaway(ngx_connection_t *c, uint64_t id)
  331. {
  332.     u_char                 *p, buf[NGX_HTTP_V3_VARLEN_INT_LEN * 3];
  333.     size_t                  n;
  334.     ngx_connection_t       *cc;
  335.     ngx_http_v3_session_t  *h3c;

  336.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send goaway %uL", id);

  337.     cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL);
  338.     if (cc == NULL) {
  339.         return NGX_ERROR;
  340.     }

  341.     n = ngx_http_v3_encode_varlen_int(NULL, id);
  342.     p = (u_char *) ngx_http_v3_encode_varlen_int(buf, NGX_HTTP_V3_FRAME_GOAWAY);
  343.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, n);
  344.     p = (u_char *) ngx_http_v3_encode_varlen_int(p, id);
  345.     n = p - buf;

  346.     h3c = ngx_http_v3_get_session(c);
  347.     h3c->total_bytes += n;

  348.     if (cc->send(cc, buf, n) != (ssize_t) n) {
  349.         goto failed;
  350.     }

  351.     return NGX_OK;

  352. failed:

  353.     ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to send goaway");

  354.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  355.                                     "failed to send goaway");
  356.     ngx_http_v3_close_uni_stream(cc);

  357.     return NGX_ERROR;
  358. }


  359. ngx_int_t
  360. ngx_http_v3_send_ack_section(ngx_connection_t *c, ngx_uint_t stream_id)
  361. {
  362.     u_char                  buf[NGX_HTTP_V3_PREFIX_INT_LEN];
  363.     size_t                  n;
  364.     ngx_connection_t       *dc;
  365.     ngx_http_v3_session_t  *h3c;

  366.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  367.                    "http3 send section acknowledgement %ui", stream_id);

  368.     dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
  369.     if (dc == NULL) {
  370.         return NGX_ERROR;
  371.     }

  372.     buf[0] = 0x80;
  373.     n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 7) - buf;

  374.     h3c = ngx_http_v3_get_session(c);
  375.     h3c->total_bytes += n;

  376.     if (dc->send(dc, buf, n) != (ssize_t) n) {
  377.         goto failed;
  378.     }

  379.     return NGX_OK;

  380. failed:

  381.     ngx_log_error(NGX_LOG_ERR, c->log, 0,
  382.                   "failed to send section acknowledgement");

  383.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  384.                                     "failed to send section acknowledgement");
  385.     ngx_http_v3_close_uni_stream(dc);

  386.     return NGX_ERROR;
  387. }


  388. ngx_int_t
  389. ngx_http_v3_send_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id)
  390. {
  391.     u_char                  buf[NGX_HTTP_V3_PREFIX_INT_LEN];
  392.     size_t                  n;
  393.     ngx_connection_t       *dc;
  394.     ngx_http_v3_session_t  *h3c;

  395.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  396.                    "http3 send stream cancellation %ui", stream_id);

  397.     dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
  398.     if (dc == NULL) {
  399.         return NGX_ERROR;
  400.     }

  401.     buf[0] = 0x40;
  402.     n = (u_char *) ngx_http_v3_encode_prefix_int(buf, stream_id, 6) - buf;

  403.     h3c = ngx_http_v3_get_session(c);
  404.     h3c->total_bytes += n;

  405.     if (dc->send(dc, buf, n) != (ssize_t) n) {
  406.         goto failed;
  407.     }

  408.     return NGX_OK;

  409. failed:

  410.     ngx_log_error(NGX_LOG_ERR, c->log, 0, "failed to send stream cancellation");

  411.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  412.                                     "failed to send stream cancellation");
  413.     ngx_http_v3_close_uni_stream(dc);

  414.     return NGX_ERROR;
  415. }


  416. ngx_int_t
  417. ngx_http_v3_send_inc_insert_count(ngx_connection_t *c, ngx_uint_t inc)
  418. {
  419.     u_char                  buf[NGX_HTTP_V3_PREFIX_INT_LEN];
  420.     size_t                  n;
  421.     ngx_connection_t       *dc;
  422.     ngx_http_v3_session_t  *h3c;

  423.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  424.                    "http3 send insert count increment %ui", inc);

  425.     dc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_DECODER);
  426.     if (dc == NULL) {
  427.         return NGX_ERROR;
  428.     }

  429.     buf[0] = 0;
  430.     n = (u_char *) ngx_http_v3_encode_prefix_int(buf, inc, 6) - buf;

  431.     h3c = ngx_http_v3_get_session(c);
  432.     h3c->total_bytes += n;

  433.     if (dc->send(dc, buf, n) != (ssize_t) n) {
  434.         goto failed;
  435.     }

  436.     return NGX_OK;

  437. failed:

  438.     ngx_log_error(NGX_LOG_ERR, c->log, 0,
  439.                   "failed to send insert count increment");

  440.     ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_EXCESSIVE_LOAD,
  441.                                     "failed to send insert count increment");
  442.     ngx_http_v3_close_uni_stream(dc);

  443.     return NGX_ERROR;
  444. }


  445. ngx_int_t
  446. ngx_http_v3_cancel_stream(ngx_connection_t *c, ngx_uint_t stream_id)
  447. {
  448.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  449.                    "http3 cancel stream %ui", stream_id);

  450.     /* we do not use dynamic tables */

  451.     return NGX_OK;
  452. }