src/stream/ngx_stream_core_module.c - nginx

Global variables defined

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_stream.h>


  8. static ngx_uint_t ngx_stream_preread_can_peek(ngx_connection_t *c);
  9. static ngx_int_t ngx_stream_preread_peek(ngx_stream_session_t *s,
  10.     ngx_stream_phase_handler_t *ph);
  11. static ngx_int_t ngx_stream_preread(ngx_stream_session_t *s,
  12.     ngx_stream_phase_handler_t *ph);
  13. static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf);
  14. static void *ngx_stream_core_create_main_conf(ngx_conf_t *cf);
  15. static char *ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf);
  16. static void *ngx_stream_core_create_srv_conf(ngx_conf_t *cf);
  17. static char *ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
  18.     void *child);
  19. static char *ngx_stream_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
  20.     void *conf);
  21. static char *ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
  22.     void *conf);
  23. static char *ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
  24.     void *conf);
  25. static char *ngx_stream_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
  26.     void *conf);
  27. static char *ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
  28.     void *conf);


  29. static ngx_command_t  ngx_stream_core_commands[] = {

  30.     { ngx_string("variables_hash_max_size"),
  31.       NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
  32.       ngx_conf_set_num_slot,
  33.       NGX_STREAM_MAIN_CONF_OFFSET,
  34.       offsetof(ngx_stream_core_main_conf_t, variables_hash_max_size),
  35.       NULL },

  36.     { ngx_string("variables_hash_bucket_size"),
  37.       NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
  38.       ngx_conf_set_num_slot,
  39.       NGX_STREAM_MAIN_CONF_OFFSET,
  40.       offsetof(ngx_stream_core_main_conf_t, variables_hash_bucket_size),
  41.       NULL },

  42.     { ngx_string("server_names_hash_max_size"),
  43.       NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
  44.       ngx_conf_set_num_slot,
  45.       NGX_STREAM_MAIN_CONF_OFFSET,
  46.       offsetof(ngx_stream_core_main_conf_t, server_names_hash_max_size),
  47.       NULL },

  48.     { ngx_string("server_names_hash_bucket_size"),
  49.       NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
  50.       ngx_conf_set_num_slot,
  51.       NGX_STREAM_MAIN_CONF_OFFSET,
  52.       offsetof(ngx_stream_core_main_conf_t, server_names_hash_bucket_size),
  53.       NULL },

  54.     { ngx_string("server"),
  55.       NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
  56.       ngx_stream_core_server,
  57.       0,
  58.       0,
  59.       NULL },

  60.     { ngx_string("listen"),
  61.       NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
  62.       ngx_stream_core_listen,
  63.       NGX_STREAM_SRV_CONF_OFFSET,
  64.       0,
  65.       NULL },

  66.     { ngx_string("server_name"),
  67.       NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
  68.       ngx_stream_core_server_name,
  69.       NGX_STREAM_SRV_CONF_OFFSET,
  70.       0,
  71.       NULL },

  72.     { ngx_string("error_log"),
  73.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
  74.       ngx_stream_core_error_log,
  75.       NGX_STREAM_SRV_CONF_OFFSET,
  76.       0,
  77.       NULL },

  78.     { ngx_string("resolver"),
  79.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
  80.       ngx_stream_core_resolver,
  81.       NGX_STREAM_SRV_CONF_OFFSET,
  82.       0,
  83.       NULL },

  84.     { ngx_string("resolver_timeout"),
  85.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
  86.       ngx_conf_set_msec_slot,
  87.       NGX_STREAM_SRV_CONF_OFFSET,
  88.       offsetof(ngx_stream_core_srv_conf_t, resolver_timeout),
  89.       NULL },

  90.     { ngx_string("proxy_protocol_timeout"),
  91.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
  92.       ngx_conf_set_msec_slot,
  93.       NGX_STREAM_SRV_CONF_OFFSET,
  94.       offsetof(ngx_stream_core_srv_conf_t, proxy_protocol_timeout),
  95.       NULL },

  96.     { ngx_string("tcp_nodelay"),
  97.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
  98.       ngx_conf_set_flag_slot,
  99.       NGX_STREAM_SRV_CONF_OFFSET,
  100.       offsetof(ngx_stream_core_srv_conf_t, tcp_nodelay),
  101.       NULL },

  102.     { ngx_string("preread_buffer_size"),
  103.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
  104.       ngx_conf_set_size_slot,
  105.       NGX_STREAM_SRV_CONF_OFFSET,
  106.       offsetof(ngx_stream_core_srv_conf_t, preread_buffer_size),
  107.       NULL },

  108.     { ngx_string("preread_timeout"),
  109.       NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
  110.       ngx_conf_set_msec_slot,
  111.       NGX_STREAM_SRV_CONF_OFFSET,
  112.       offsetof(ngx_stream_core_srv_conf_t, preread_timeout),
  113.       NULL },

  114.       ngx_null_command
  115. };


  116. static ngx_stream_module_t  ngx_stream_core_module_ctx = {
  117.     ngx_stream_core_preconfiguration,      /* preconfiguration */
  118.     NULL,                                  /* postconfiguration */

  119.     ngx_stream_core_create_main_conf,      /* create main configuration */
  120.     ngx_stream_core_init_main_conf,        /* init main configuration */

  121.     ngx_stream_core_create_srv_conf,       /* create server configuration */
  122.     ngx_stream_core_merge_srv_conf         /* merge server configuration */
  123. };


  124. ngx_module_t  ngx_stream_core_module = {
  125.     NGX_MODULE_V1,
  126.     &ngx_stream_core_module_ctx,           /* module context */
  127.     ngx_stream_core_commands,              /* module directives */
  128.     NGX_STREAM_MODULE,                     /* module type */
  129.     NULL,                                  /* init master */
  130.     NULL,                                  /* init module */
  131.     NULL,                                  /* init process */
  132.     NULL,                                  /* init thread */
  133.     NULL,                                  /* exit thread */
  134.     NULL,                                  /* exit process */
  135.     NULL,                                  /* exit master */
  136.     NGX_MODULE_V1_PADDING
  137. };


  138. void
  139. ngx_stream_core_run_phases(ngx_stream_session_t *s)
  140. {
  141.     ngx_int_t                     rc;
  142.     ngx_stream_phase_handler_t   *ph;
  143.     ngx_stream_core_main_conf_t  *cmcf;

  144.     cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

  145.     ph = cmcf->phase_engine.handlers;

  146.     while (ph[s->phase_handler].checker) {

  147.         rc = ph[s->phase_handler].checker(s, &ph[s->phase_handler]);

  148.         if (rc == NGX_OK) {
  149.             return;
  150.         }
  151.     }
  152. }


  153. ngx_int_t
  154. ngx_stream_core_generic_phase(ngx_stream_session_t *s,
  155.     ngx_stream_phase_handler_t *ph)
  156. {
  157.     ngx_int_t  rc;

  158.     /*
  159.      * generic phase checker,
  160.      * used by all phases, except for preread and content
  161.      */

  162.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
  163.                    "generic phase: %ui", s->phase_handler);

  164.     rc = ph->handler(s);

  165.     if (rc == NGX_OK) {
  166.         s->phase_handler = ph->next;
  167.         return NGX_AGAIN;
  168.     }

  169.     if (rc == NGX_DECLINED) {
  170.         s->phase_handler++;
  171.         return NGX_AGAIN;
  172.     }

  173.     if (rc == NGX_AGAIN || rc == NGX_DONE) {
  174.         return NGX_OK;
  175.     }

  176.     if (rc == NGX_ERROR) {
  177.         rc = NGX_STREAM_INTERNAL_SERVER_ERROR;
  178.     }

  179.     ngx_stream_finalize_session(s, rc);

  180.     return NGX_OK;
  181. }


  182. ngx_int_t
  183. ngx_stream_core_preread_phase(ngx_stream_session_t *s,
  184.     ngx_stream_phase_handler_t *ph)
  185. {
  186.     ngx_int_t                    rc;
  187.     ngx_connection_t            *c;
  188.     ngx_stream_core_srv_conf_t  *cscf;

  189.     c = s->connection;

  190.     c->log->action = "prereading client data";

  191.     cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);

  192.     if (c->read->timedout) {
  193.         rc = NGX_STREAM_OK;
  194.         goto done;
  195.     }

  196.     if (!c->read->timer_set) {
  197.         rc = ph->handler(s);

  198.         if (rc != NGX_AGAIN) {
  199.             goto done;
  200.         }
  201.     }

  202.     if (c->buffer == NULL) {
  203.         c->buffer = ngx_create_temp_buf(c->pool, cscf->preread_buffer_size);
  204.         if (c->buffer == NULL) {
  205.             rc = NGX_ERROR;
  206.             goto done;
  207.         }
  208.     }

  209.     if (ngx_stream_preread_can_peek(c)) {
  210.         rc = ngx_stream_preread_peek(s, ph);

  211.     } else {
  212.         rc = ngx_stream_preread(s, ph);
  213.     }

  214. done:

  215.     if (rc == NGX_AGAIN) {
  216.         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  217.             ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
  218.             return NGX_OK;
  219.         }

  220.         if (!c->read->timer_set) {
  221.             ngx_add_timer(c->read, cscf->preread_timeout);
  222.         }

  223.         c->read->handler = ngx_stream_session_handler;

  224.         return NGX_OK;
  225.     }

  226.     if (c->read->timer_set) {
  227.         ngx_del_timer(c->read);
  228.     }

  229.     if (rc == NGX_OK) {
  230.         s->phase_handler = ph->next;
  231.         return NGX_AGAIN;
  232.     }

  233.     if (rc == NGX_DECLINED) {
  234.         s->phase_handler++;
  235.         return NGX_AGAIN;
  236.     }

  237.     if (rc == NGX_DONE) {
  238.         return NGX_OK;
  239.     }

  240.     if (rc == NGX_ERROR) {
  241.         rc = NGX_STREAM_INTERNAL_SERVER_ERROR;
  242.     }

  243.     ngx_stream_finalize_session(s, rc);

  244.     return NGX_OK;
  245. }


  246. static ngx_uint_t
  247. ngx_stream_preread_can_peek(ngx_connection_t *c)
  248. {
  249. #if (NGX_STREAM_SSL)
  250.     if (c->ssl) {
  251.         return 0;
  252.     }
  253. #endif

  254.     if ((ngx_event_flags & NGX_USE_CLEAR_EVENT) == 0) {
  255.         return 0;
  256.     }

  257. #if (NGX_HAVE_KQUEUE)
  258.     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  259.         return 1;
  260.     }
  261. #endif

  262. #if (NGX_HAVE_EPOLLRDHUP)
  263.     if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) {
  264.         return 1;
  265.     }
  266. #endif

  267.     return 0;
  268. }


  269. static ngx_int_t
  270. ngx_stream_preread_peek(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph)
  271. {
  272.     ssize_t            n;
  273.     ngx_int_t          rc;
  274.     ngx_err_t          err;
  275.     ngx_connection_t  *c;

  276.     c = s->connection;

  277.     n = recv(c->fd, (char *) c->buffer->last,
  278.              c->buffer->end - c->buffer->last, MSG_PEEK);

  279.     err = ngx_socket_errno;

  280.     ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream recv(): %z", n);

  281.     if (n == -1) {
  282.         if (err == NGX_EAGAIN) {
  283.             c->read->ready = 0;
  284.             return NGX_AGAIN;
  285.         }

  286.         ngx_connection_error(c, err, "recv() failed");
  287.         return NGX_STREAM_OK;
  288.     }

  289.     if (n == 0) {
  290.         return NGX_STREAM_OK;
  291.     }

  292.     c->buffer->last += n;

  293.     rc = ph->handler(s);

  294.     if (rc != NGX_AGAIN) {
  295.         c->buffer->last = c->buffer->pos;
  296.         return rc;
  297.     }

  298.     if (c->buffer->last == c->buffer->end) {
  299.         ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
  300.         return NGX_STREAM_BAD_REQUEST;
  301.     }

  302.     if (c->read->pending_eof) {
  303.         return NGX_STREAM_OK;
  304.     }

  305.     c->buffer->last = c->buffer->pos;

  306.     return NGX_AGAIN;
  307. }


  308. static ngx_int_t
  309. ngx_stream_preread(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph)
  310. {
  311.     ssize_t            n;
  312.     ngx_int_t          rc;
  313.     ngx_connection_t  *c;

  314.     c = s->connection;

  315.     while (c->read->ready) {

  316.         n = c->recv(c, c->buffer->last, c->buffer->end - c->buffer->last);

  317.         if (n == NGX_AGAIN) {
  318.             return NGX_AGAIN;
  319.         }

  320.         if (n == NGX_ERROR || n == 0) {
  321.             return NGX_STREAM_OK;
  322.         }

  323.         c->buffer->last += n;

  324.         rc = ph->handler(s);

  325.         if (rc != NGX_AGAIN) {
  326.             return rc;
  327.         }

  328.         if (c->buffer->last == c->buffer->end) {
  329.             ngx_log_error(NGX_LOG_ERR, c->log, 0, "preread buffer full");
  330.             return NGX_STREAM_BAD_REQUEST;
  331.         }
  332.     }

  333.     return NGX_AGAIN;
  334. }


  335. ngx_int_t
  336. ngx_stream_core_content_phase(ngx_stream_session_t *s,
  337.     ngx_stream_phase_handler_t *ph)
  338. {
  339.     ngx_connection_t            *c;
  340.     ngx_stream_core_srv_conf_t  *cscf;

  341.     c = s->connection;

  342.     c->log->action = NULL;

  343.     cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);

  344.     if (c->type == SOCK_STREAM
  345.         && cscf->tcp_nodelay
  346.         && ngx_tcp_nodelay(c) != NGX_OK)
  347.     {
  348.         ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
  349.         return NGX_OK;
  350.     }

  351.     if (cscf->handler == NULL) {
  352.         ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
  353.                        "no handler for server");
  354.         ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
  355.         return NGX_OK;
  356.     }

  357.     cscf->handler(s);

  358.     return NGX_OK;
  359. }


  360. ngx_int_t
  361. ngx_stream_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)
  362. {
  363.     u_char     *h, ch;
  364.     size_t      i, dot_pos, host_len;
  365.     ngx_int_t   port;

  366.     enum {
  367.         sw_host_start = 0,
  368.         sw_host,
  369.         sw_host_ip_literal,
  370.         sw_host_end,
  371.         sw_port,
  372.     } state;

  373.     dot_pos = host->len;
  374.     host_len = host->len;
  375.     port = 0;

  376.     h = host->data;

  377.     state = sw_host_start;

  378.     for (i = 0; i < host->len; i++) {
  379.         ch = h[i];

  380.         switch (state) {

  381.         case sw_host_start:

  382.             if (ch == '[') {
  383.                 state = sw_host_ip_literal;
  384.                 break;
  385.             }

  386.             state = sw_host;

  387.             /* fall through */

  388.         case sw_host:

  389.             if (ch >= 'A' && ch <= 'Z') {
  390.                 alloc = 1;
  391.                 break;
  392.             }

  393.             if (ch >= 'a' && ch <= 'z') {
  394.                 break;
  395.             }

  396.             if (ch >= '0' && ch <= '9') {
  397.                 break;
  398.             }

  399.             switch (ch) {
  400.             case ':':
  401.                 host_len = i;
  402.                 state = sw_port;
  403.                 break;
  404.             case '-':
  405.                 break;
  406.             case '.':
  407.                 if (dot_pos == i - 1) {
  408.                     return NGX_DECLINED;
  409.                 }
  410.                 dot_pos = i;
  411.                 break;
  412.             case '_':
  413.             case '~':
  414.                 /* unreserved */
  415.                 break;
  416.             case '!':
  417.             case '$':
  418.             case '&':
  419.             case '\'':
  420.             case '(':
  421.             case ')':
  422.             case '*':
  423.             case '+':
  424.             case ',':
  425.             case ';':
  426.             case '=':
  427.                 /* sub-delims */
  428.                 break;
  429.             case '%':
  430.                 /* pct-encoded */
  431.                 break;
  432.             default:
  433.                 return NGX_DECLINED;
  434.             }
  435.             break;

  436.         case sw_host_ip_literal:

  437.             if (ch >= 'A' && ch <= 'Z') {
  438.                 alloc = 1;
  439.                 break;
  440.             }

  441.             if (ch >= 'a' && ch <= 'z') {
  442.                 break;
  443.             }

  444.             if (ch >= '0' && ch <= '9') {
  445.                 break;
  446.             }

  447.             switch (ch) {
  448.             case ':':
  449.                 break;
  450.             case ']':
  451.                 host_len = i + 1;
  452.                 state = sw_host_end;
  453.                 break;
  454.             case '-':
  455.                 break;
  456.             case '.':
  457.                 if (dot_pos == i - 1) {
  458.                     return NGX_DECLINED;
  459.                 }
  460.                 dot_pos = i;
  461.                 break;
  462.             case '_':
  463.             case '~':
  464.                 /* unreserved */
  465.                 break;
  466.             case '!':
  467.             case '$':
  468.             case '&':
  469.             case '\'':
  470.             case '(':
  471.             case ')':
  472.             case '*':
  473.             case '+':
  474.             case ',':
  475.             case ';':
  476.             case '=':
  477.                 /* sub-delims */
  478.                 break;
  479.             default:
  480.                 return NGX_DECLINED;
  481.             }
  482.             break;

  483.         case sw_host_end:

  484.             if (ch == ':') {
  485.                 state = sw_port;
  486.                 break;
  487.             }
  488.             return NGX_DECLINED;

  489.         case sw_port:

  490.             if (ch >= '0' && ch <= '9') {
  491.                 if (port >= 6553 && (port > 6553 || (ch - '0') > 5)) {
  492.                     return NGX_DECLINED;
  493.                 }

  494.                 port = port * 10 + (ch - '0');
  495.                 break;
  496.             }
  497.             return NGX_DECLINED;
  498.         }
  499.     }

  500.     if (state == sw_host_ip_literal) {
  501.         return NGX_DECLINED;
  502.     }

  503.     if (dot_pos == host_len - 1) {
  504.         host_len--;
  505.     }

  506.     if (host_len == 0) {
  507.         return NGX_DECLINED;
  508.     }

  509.     if (alloc) {
  510.         host->data = ngx_pnalloc(pool, host_len);
  511.         if (host->data == NULL) {
  512.             return NGX_ERROR;
  513.         }

  514.         ngx_strlow(host->data, h, host_len);
  515.     }

  516.     host->len = host_len;

  517.     return NGX_OK;
  518. }


  519. ngx_int_t
  520. ngx_stream_find_virtual_server(ngx_stream_session_t *s,
  521.     ngx_str_t *host, ngx_stream_core_srv_conf_t **cscfp)
  522. {
  523.     ngx_stream_core_srv_conf_t  *cscf;

  524.     if (s->virtual_names == NULL) {
  525.         return NGX_DECLINED;
  526.     }

  527.     cscf = ngx_hash_find_combined(&s->virtual_names->names,
  528.                                   ngx_hash_key(host->data, host->len),
  529.                                   host->data, host->len);

  530.     if (cscf) {
  531.         *cscfp = cscf;
  532.         return NGX_OK;
  533.     }

  534. #if (NGX_PCRE)

  535.     if (host->len && s->virtual_names->nregex) {
  536.         ngx_int_t                  n;
  537.         ngx_uint_t                 i;
  538.         ngx_stream_server_name_t  *sn;

  539.         sn = s->virtual_names->regex;

  540.         for (i = 0; i < s->virtual_names->nregex; i++) {

  541.             n = ngx_stream_regex_exec(s, sn[i].regex, host);

  542.             if (n == NGX_DECLINED) {
  543.                 continue;
  544.             }

  545.             if (n == NGX_OK) {
  546.                 *cscfp = sn[i].server;
  547.                 return NGX_OK;
  548.             }

  549.             return NGX_ERROR;
  550.         }
  551.     }

  552. #endif /* NGX_PCRE */

  553.     return NGX_DECLINED;
  554. }


  555. static ngx_int_t
  556. ngx_stream_core_preconfiguration(ngx_conf_t *cf)
  557. {
  558.     return ngx_stream_variables_add_core_vars(cf);
  559. }


  560. static void *
  561. ngx_stream_core_create_main_conf(ngx_conf_t *cf)
  562. {
  563.     ngx_stream_core_main_conf_t  *cmcf;

  564.     cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_core_main_conf_t));
  565.     if (cmcf == NULL) {
  566.         return NULL;
  567.     }

  568.     if (ngx_array_init(&cmcf->servers, cf->pool, 4,
  569.                        sizeof(ngx_stream_core_srv_conf_t *))
  570.         != NGX_OK)
  571.     {
  572.         return NULL;
  573.     }

  574.     cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT;
  575.     cmcf->server_names_hash_bucket_size = NGX_CONF_UNSET_UINT;

  576.     cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT;
  577.     cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT;

  578.     return cmcf;
  579. }


  580. static char *
  581. ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf)
  582. {
  583.     ngx_stream_core_main_conf_t *cmcf = conf;

  584.     ngx_conf_init_uint_value(cmcf->server_names_hash_max_size, 512);
  585.     ngx_conf_init_uint_value(cmcf->server_names_hash_bucket_size,
  586.                              ngx_cacheline_size);

  587.     cmcf->server_names_hash_bucket_size =
  588.             ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size);


  589.     ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024);
  590.     ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64);

  591.     cmcf->variables_hash_bucket_size =
  592.                ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);

  593.     if (cmcf->ncaptures) {
  594.         cmcf->ncaptures = (cmcf->ncaptures + 1) * 3;
  595.     }

  596.     return NGX_CONF_OK;
  597. }


  598. static void *
  599. ngx_stream_core_create_srv_conf(ngx_conf_t *cf)
  600. {
  601.     ngx_stream_core_srv_conf_t  *cscf;

  602.     cscf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_core_srv_conf_t));
  603.     if (cscf == NULL) {
  604.         return NULL;
  605.     }

  606.     /*
  607.      * set by ngx_pcalloc():
  608.      *
  609.      *     cscf->handler = NULL;
  610.      *     cscf->error_log = NULL;
  611.      */

  612.     if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4,
  613.                        sizeof(ngx_stream_server_name_t))
  614.         != NGX_OK)
  615.     {
  616.         return NULL;
  617.     }

  618.     cscf->file_name = cf->conf_file->file.name.data;
  619.     cscf->line = cf->conf_file->line;
  620.     cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
  621.     cscf->proxy_protocol_timeout = NGX_CONF_UNSET_MSEC;
  622.     cscf->tcp_nodelay = NGX_CONF_UNSET;
  623.     cscf->preread_buffer_size = NGX_CONF_UNSET_SIZE;
  624.     cscf->preread_timeout = NGX_CONF_UNSET_MSEC;

  625.     return cscf;
  626. }


  627. static char *
  628. ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
  629. {
  630.     ngx_stream_core_srv_conf_t *prev = parent;
  631.     ngx_stream_core_srv_conf_t *conf = child;

  632.     ngx_str_t                  name;
  633.     ngx_stream_server_name_t  *sn;

  634.     ngx_conf_merge_msec_value(conf->resolver_timeout,
  635.                               prev->resolver_timeout, 30000);

  636.     if (conf->resolver == NULL) {

  637.         if (prev->resolver == NULL) {

  638.             /*
  639.              * create dummy resolver in stream {} context
  640.              * to inherit it in all servers
  641.              */

  642.             prev->resolver = ngx_resolver_create(cf, NULL, 0);
  643.             if (prev->resolver == NULL) {
  644.                 return NGX_CONF_ERROR;
  645.             }
  646.         }

  647.         conf->resolver = prev->resolver;
  648.     }

  649.     if (conf->error_log == NULL) {
  650.         if (prev->error_log) {
  651.             conf->error_log = prev->error_log;
  652.         } else {
  653.             conf->error_log = &cf->cycle->new_log;
  654.         }
  655.     }

  656.     ngx_conf_merge_msec_value(conf->proxy_protocol_timeout,
  657.                               prev->proxy_protocol_timeout, 30000);

  658.     ngx_conf_merge_value(conf->tcp_nodelay, prev->tcp_nodelay, 1);

  659.     ngx_conf_merge_size_value(conf->preread_buffer_size,
  660.                               prev->preread_buffer_size, 16384);

  661.     ngx_conf_merge_msec_value(conf->preread_timeout,
  662.                               prev->preread_timeout, 30000);

  663.     if (conf->server_names.nelts == 0) {
  664.         /* the array has 4 empty preallocated elements, so push cannot fail */
  665.         sn = ngx_array_push(&conf->server_names);
  666. #if (NGX_PCRE)
  667.         sn->regex = NULL;
  668. #endif
  669.         sn->server = conf;
  670.         ngx_str_set(&sn->name, "");
  671.     }

  672.     sn = conf->server_names.elts;
  673.     name = sn[0].name;

  674. #if (NGX_PCRE)
  675.     if (sn->regex) {
  676.         name.len++;
  677.         name.data--;
  678.     } else
  679. #endif

  680.     if (name.data[0] == '.') {
  681.         name.len--;
  682.         name.data++;
  683.     }

  684.     conf->server_name.len = name.len;
  685.     conf->server_name.data = ngx_pstrdup(cf->pool, &name);
  686.     if (conf->server_name.data == NULL) {
  687.         return NGX_CONF_ERROR;
  688.     }

  689.     return NGX_CONF_OK;
  690. }


  691. static char *
  692. ngx_stream_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  693. {
  694.     ngx_stream_core_srv_conf_t  *cscf = conf;

  695.     return ngx_log_set_log(cf, &cscf->error_log);
  696. }


  697. static char *
  698. ngx_stream_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  699. {
  700.     char                         *rv;
  701.     void                         *mconf;
  702.     ngx_uint_t                    m;
  703.     ngx_conf_t                    pcf;
  704.     ngx_stream_module_t          *module;
  705.     ngx_stream_conf_ctx_t        *ctx, *stream_ctx;
  706.     ngx_stream_core_srv_conf_t   *cscf, **cscfp;
  707.     ngx_stream_core_main_conf_t  *cmcf;

  708.     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_conf_ctx_t));
  709.     if (ctx == NULL) {
  710.         return NGX_CONF_ERROR;
  711.     }

  712.     stream_ctx = cf->ctx;
  713.     ctx->main_conf = stream_ctx->main_conf;

  714.     /* the server{}'s srv_conf */

  715.     ctx->srv_conf = ngx_pcalloc(cf->pool,
  716.                                 sizeof(void *) * ngx_stream_max_module);
  717.     if (ctx->srv_conf == NULL) {
  718.         return NGX_CONF_ERROR;
  719.     }

  720.     for (m = 0; cf->cycle->modules[m]; m++) {
  721.         if (cf->cycle->modules[m]->type != NGX_STREAM_MODULE) {
  722.             continue;
  723.         }

  724.         module = cf->cycle->modules[m]->ctx;

  725.         if (module->create_srv_conf) {
  726.             mconf = module->create_srv_conf(cf);
  727.             if (mconf == NULL) {
  728.                 return NGX_CONF_ERROR;
  729.             }

  730.             ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf;
  731.         }
  732.     }

  733.     /* the server configuration context */

  734.     cscf = ctx->srv_conf[ngx_stream_core_module.ctx_index];
  735.     cscf->ctx = ctx;

  736.     cmcf = ctx->main_conf[ngx_stream_core_module.ctx_index];

  737.     cscfp = ngx_array_push(&cmcf->servers);
  738.     if (cscfp == NULL) {
  739.         return NGX_CONF_ERROR;
  740.     }

  741.     *cscfp = cscf;


  742.     /* parse inside server{} */

  743.     pcf = *cf;
  744.     cf->ctx = ctx;
  745.     cf->cmd_type = NGX_STREAM_SRV_CONF;

  746.     rv = ngx_conf_parse(cf, NULL);

  747.     *cf = pcf;

  748.     if (rv == NGX_CONF_OK && !cscf->listen) {
  749.         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  750.                       "no \"listen\" is defined for server in %s:%ui",
  751.                       cscf->file_name, cscf->line);
  752.         return NGX_CONF_ERROR;
  753.     }

  754.     return rv;
  755. }


  756. static char *
  757. ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  758. {
  759.     ngx_stream_core_srv_conf_t  *cscf = conf;

  760.     ngx_str_t                *value, size;
  761.     ngx_url_t                 u;
  762.     ngx_uint_t                n, i, backlog;
  763.     ngx_stream_listen_opt_t   lsopt;

  764.     cscf->listen = 1;

  765.     value = cf->args->elts;

  766.     ngx_memzero(&u, sizeof(ngx_url_t));

  767.     u.url = value[1];
  768.     u.listen = 1;

  769.     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
  770.         if (u.err) {
  771.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  772.                                "%s in \"%V\" of the \"listen\" directive",
  773.                                u.err, &u.url);
  774.         }

  775.         return NGX_CONF_ERROR;
  776.     }

  777.     ngx_memzero(&lsopt, sizeof(ngx_stream_listen_opt_t));

  778.     lsopt.backlog = NGX_LISTEN_BACKLOG;
  779.     lsopt.type = SOCK_STREAM;
  780.     lsopt.rcvbuf = -1;
  781.     lsopt.sndbuf = -1;
  782. #if (NGX_HAVE_SETFIB)
  783.     lsopt.setfib = -1;
  784. #endif
  785. #if (NGX_HAVE_TCP_FASTOPEN)
  786.     lsopt.fastopen = -1;
  787. #endif
  788. #if (NGX_HAVE_INET6)
  789.     lsopt.ipv6only = 1;
  790. #endif

  791.     backlog = 0;

  792.     for (i = 2; i < cf->args->nelts; i++) {

  793.         if (ngx_strcmp(value[i].data, "default_server") == 0) {
  794.             lsopt.default_server = 1;
  795.             continue;
  796.         }

  797. #if !(NGX_WIN32)
  798.         if (ngx_strcmp(value[i].data, "udp") == 0) {
  799.             lsopt.type = SOCK_DGRAM;
  800.             continue;
  801.         }
  802. #endif

  803.         if (ngx_strcmp(value[i].data, "bind") == 0) {
  804.             lsopt.set = 1;
  805.             lsopt.bind = 1;
  806.             continue;
  807.         }

  808. #if (NGX_HAVE_SETFIB)
  809.         if (ngx_strncmp(value[i].data, "setfib=", 7) == 0) {
  810.             lsopt.setfib = ngx_atoi(value[i].data + 7, value[i].len - 7);
  811.             lsopt.set = 1;
  812.             lsopt.bind = 1;

  813.             if (lsopt.setfib == NGX_ERROR) {
  814.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  815.                                    "invalid setfib \"%V\"", &value[i]);
  816.                 return NGX_CONF_ERROR;
  817.             }

  818.             continue;
  819.         }
  820. #endif

  821. #if (NGX_HAVE_TCP_FASTOPEN)
  822.         if (ngx_strncmp(value[i].data, "fastopen=", 9) == 0) {
  823.             lsopt.fastopen = ngx_atoi(value[i].data + 9, value[i].len - 9);
  824.             lsopt.set = 1;
  825.             lsopt.bind = 1;

  826.             if (lsopt.fastopen == NGX_ERROR) {
  827.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  828.                                    "invalid fastopen \"%V\"", &value[i]);
  829.                 return NGX_CONF_ERROR;
  830.             }

  831.             continue;
  832.         }
  833. #endif

  834.         if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
  835.             lsopt.backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
  836.             lsopt.set = 1;
  837.             lsopt.bind = 1;

  838.             if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) {
  839.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  840.                                    "invalid backlog \"%V\"", &value[i]);
  841.                 return NGX_CONF_ERROR;
  842.             }

  843.             backlog = 1;

  844.             continue;
  845.         }

  846.         if (ngx_strncmp(value[i].data, "rcvbuf=", 7) == 0) {
  847.             size.len = value[i].len - 7;
  848.             size.data = value[i].data + 7;

  849.             lsopt.rcvbuf = ngx_parse_size(&size);
  850.             lsopt.set = 1;
  851.             lsopt.bind = 1;

  852.             if (lsopt.rcvbuf == NGX_ERROR) {
  853.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  854.                                    "invalid rcvbuf \"%V\"", &value[i]);
  855.                 return NGX_CONF_ERROR;
  856.             }

  857.             continue;
  858.         }

  859.         if (ngx_strncmp(value[i].data, "sndbuf=", 7) == 0) {
  860.             size.len = value[i].len - 7;
  861.             size.data = value[i].data + 7;

  862.             lsopt.sndbuf = ngx_parse_size(&size);
  863.             lsopt.set = 1;
  864.             lsopt.bind = 1;

  865.             if (lsopt.sndbuf == NGX_ERROR) {
  866.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  867.                                    "invalid sndbuf \"%V\"", &value[i]);
  868.                 return NGX_CONF_ERROR;
  869.             }

  870.             continue;
  871.         }

  872.         if (ngx_strncmp(value[i].data, "accept_filter=", 14) == 0) {
  873. #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
  874.             lsopt.accept_filter = (char *) &value[i].data[14];
  875.             lsopt.set = 1;
  876.             lsopt.bind = 1;
  877. #else
  878.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  879.                                "accept filters \"%V\" are not supported "
  880.                                "on this platform, ignored",
  881.                                &value[i]);
  882. #endif
  883.             continue;
  884.         }

  885.         if (ngx_strcmp(value[i].data, "deferred") == 0) {
  886. #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
  887.             lsopt.deferred_accept = 1;
  888.             lsopt.set = 1;
  889.             lsopt.bind = 1;
  890. #else
  891.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  892.                                "the deferred accept is not supported "
  893.                                "on this platform, ignored");
  894. #endif
  895.             continue;
  896.         }

  897.         if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
  898. #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
  899.             if (ngx_strcmp(&value[i].data[10], "n") == 0) {
  900.                 lsopt.ipv6only = 1;

  901.             } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
  902.                 lsopt.ipv6only = 0;

  903.             } else {
  904.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  905.                                    "invalid ipv6only flags \"%s\"",
  906.                                    &value[i].data[9]);
  907.                 return NGX_CONF_ERROR;
  908.             }

  909.             lsopt.set = 1;
  910.             lsopt.bind = 1;

  911.             continue;
  912. #else
  913.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  914.                                "ipv6only is not supported "
  915.                                "on this platform");
  916.             return NGX_CONF_ERROR;
  917. #endif
  918.         }

  919.         if (ngx_strcmp(value[i].data, "reuseport") == 0) {
  920. #if (NGX_HAVE_REUSEPORT)
  921.             lsopt.reuseport = 1;
  922.             lsopt.set = 1;
  923.             lsopt.bind = 1;
  924. #else
  925.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  926.                                "reuseport is not supported "
  927.                                "on this platform, ignored");
  928. #endif
  929.             continue;
  930.         }

  931.         if (ngx_strcmp(value[i].data, "multipath") == 0) {
  932. #ifdef IPPROTO_MPTCP
  933.             lsopt.protocol = IPPROTO_MPTCP;
  934.             lsopt.set = 1;
  935.             lsopt.bind = 1;
  936. #else
  937.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  938.                                "multipath is not supported "
  939.                                "on this platform, ignored");
  940. #endif
  941.             continue;
  942.         }

  943.         if (ngx_strcmp(value[i].data, "ssl") == 0) {
  944. #if (NGX_STREAM_SSL)
  945.             lsopt.ssl = 1;
  946.             continue;
  947. #else
  948.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  949.                                "the \"ssl\" parameter requires "
  950.                                "ngx_stream_ssl_module");
  951.             return NGX_CONF_ERROR;
  952. #endif
  953.         }

  954.         if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {

  955.             if (ngx_strcmp(&value[i].data[13], "on") == 0) {
  956.                 lsopt.so_keepalive = 1;

  957.             } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
  958.                 lsopt.so_keepalive = 2;

  959.             } else {

  960. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  961.                 u_char     *p, *end;
  962.                 ngx_str_t   s;

  963.                 end = value[i].data + value[i].len;
  964.                 s.data = value[i].data + 13;

  965.                 p = ngx_strlchr(s.data, end, ':');
  966.                 if (p == NULL) {
  967.                     p = end;
  968.                 }

  969.                 if (p > s.data) {
  970.                     s.len = p - s.data;

  971.                     lsopt.tcp_keepidle = ngx_parse_time(&s, 1);
  972.                     if (lsopt.tcp_keepidle == (time_t) NGX_ERROR) {
  973.                         goto invalid_so_keepalive;
  974.                     }
  975.                 }

  976.                 s.data = (p < end) ? (p + 1) : end;

  977.                 p = ngx_strlchr(s.data, end, ':');
  978.                 if (p == NULL) {
  979.                     p = end;
  980.                 }

  981.                 if (p > s.data) {
  982.                     s.len = p - s.data;

  983.                     lsopt.tcp_keepintvl = ngx_parse_time(&s, 1);
  984.                     if (lsopt.tcp_keepintvl == (time_t) NGX_ERROR) {
  985.                         goto invalid_so_keepalive;
  986.                     }
  987.                 }

  988.                 s.data = (p < end) ? (p + 1) : end;

  989.                 if (s.data < end) {
  990.                     s.len = end - s.data;

  991.                     lsopt.tcp_keepcnt = ngx_atoi(s.data, s.len);
  992.                     if (lsopt.tcp_keepcnt == NGX_ERROR) {
  993.                         goto invalid_so_keepalive;
  994.                     }
  995.                 }

  996.                 if (lsopt.tcp_keepidle == 0 && lsopt.tcp_keepintvl == 0
  997.                     && lsopt.tcp_keepcnt == 0)
  998.                 {
  999.                     goto invalid_so_keepalive;
  1000.                 }

  1001.                 lsopt.so_keepalive = 1;

  1002. #else

  1003.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1004.                                    "the \"so_keepalive\" parameter accepts "
  1005.                                    "only \"on\" or \"off\" on this platform");
  1006.                 return NGX_CONF_ERROR;

  1007. #endif
  1008.             }

  1009.             lsopt.set = 1;
  1010.             lsopt.bind = 1;

  1011.             continue;

  1012. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  1013.         invalid_so_keepalive:

  1014.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1015.                                "invalid so_keepalive value: \"%s\"",
  1016.                                &value[i].data[13]);
  1017.             return NGX_CONF_ERROR;
  1018. #endif
  1019.         }

  1020.         if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) {
  1021.             lsopt.proxy_protocol = 1;
  1022.             continue;
  1023.         }

  1024.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1025.                            "invalid parameter \"%V\"", &value[i]);
  1026.         return NGX_CONF_ERROR;
  1027.     }

  1028.     if (lsopt.type == SOCK_DGRAM) {
  1029. #if (NGX_HAVE_TCP_FASTOPEN)
  1030.         if (lsopt.fastopen != -1) {
  1031.             return "\"fastopen\" parameter is incompatible with \"udp\"";
  1032.         }
  1033. #endif

  1034.         if (backlog) {
  1035.             return "\"backlog\" parameter is incompatible with \"udp\"";
  1036.         }

  1037. #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
  1038.         if (lsopt.accept_filter) {
  1039.             return "\"accept_filter\" parameter is incompatible with \"udp\"";
  1040.         }
  1041. #endif

  1042. #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
  1043.         if (lsopt.deferred_accept) {
  1044.             return "\"deferred\" parameter is incompatible with \"udp\"";
  1045.         }
  1046. #endif

  1047. #ifdef IPPROTO_MPTCP
  1048.         if (lsopt.protocol == IPPROTO_MPTCP) {
  1049.             return "\"multipath\" parameter is incompatible with \"udp\"";
  1050.         }
  1051. #endif

  1052. #if (NGX_STREAM_SSL)
  1053.         if (lsopt.ssl) {
  1054.             return "\"ssl\" parameter is incompatible with \"udp\"";
  1055.         }
  1056. #endif

  1057.         if (lsopt.so_keepalive) {
  1058.             return "\"so_keepalive\" parameter is incompatible with \"udp\"";
  1059.         }

  1060.         if (lsopt.proxy_protocol) {
  1061.             return "\"proxy_protocol\" parameter is incompatible with \"udp\"";
  1062.         }
  1063.     }

  1064.     for (n = 0; n < u.naddrs; n++) {

  1065.         for (i = 0; i < n; i++) {
  1066.             if (ngx_cmp_sockaddr(u.addrs[n].sockaddr, u.addrs[n].socklen,
  1067.                                  u.addrs[i].sockaddr, u.addrs[i].socklen, 1)
  1068.                 == NGX_OK)
  1069.             {
  1070.                 goto next;
  1071.             }
  1072.         }

  1073.         lsopt.sockaddr = u.addrs[n].sockaddr;
  1074.         lsopt.socklen = u.addrs[n].socklen;
  1075.         lsopt.addr_text = u.addrs[n].name;
  1076.         lsopt.wildcard = ngx_inet_wildcard(lsopt.sockaddr);

  1077.         if (ngx_stream_add_listen(cf, cscf, &lsopt) != NGX_OK) {
  1078.             return NGX_CONF_ERROR;
  1079.         }

  1080.     next:
  1081.         continue;
  1082.     }

  1083.     return NGX_CONF_OK;
  1084. }


  1085. static char *
  1086. ngx_stream_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1087. {
  1088.     ngx_stream_core_srv_conf_t *cscf = conf;

  1089.     u_char                     ch;
  1090.     ngx_str_t                 *value;
  1091.     ngx_uint_t                 i;
  1092.     ngx_stream_server_name_t  *sn;

  1093.     value = cf->args->elts;

  1094.     for (i = 1; i < cf->args->nelts; i++) {

  1095.         ch = value[i].data[0];

  1096.         if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
  1097.             || (ch == '.' && value[i].len < 2))
  1098.         {
  1099.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1100.                                "server name \"%V\" is invalid", &value[i]);
  1101.             return NGX_CONF_ERROR;
  1102.         }

  1103.         if (ngx_strchr(value[i].data, '/')) {
  1104.             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  1105.                                "server name \"%V\" has suspicious symbols",
  1106.                                &value[i]);
  1107.         }

  1108.         sn = ngx_array_push(&cscf->server_names);
  1109.         if (sn == NULL) {
  1110.             return NGX_CONF_ERROR;
  1111.         }

  1112. #if (NGX_PCRE)
  1113.         sn->regex = NULL;
  1114. #endif
  1115.         sn->server = cscf;

  1116.         if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {
  1117.             sn->name = cf->cycle->hostname;

  1118.         } else {
  1119.             sn->name = value[i];
  1120.         }

  1121.         if (value[i].data[0] != '~') {
  1122.             ngx_strlow(sn->name.data, sn->name.data, sn->name.len);
  1123.             continue;
  1124.         }

  1125. #if (NGX_PCRE)
  1126.         {
  1127.         u_char               *p;
  1128.         ngx_regex_compile_t   rc;
  1129.         u_char                errstr[NGX_MAX_CONF_ERRSTR];

  1130.         if (value[i].len == 1) {
  1131.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1132.                                "empty regex in server name \"%V\"", &value[i]);
  1133.             return NGX_CONF_ERROR;
  1134.         }

  1135.         value[i].len--;
  1136.         value[i].data++;

  1137.         ngx_memzero(&rc, sizeof(ngx_regex_compile_t));

  1138.         rc.pattern = value[i];
  1139.         rc.err.len = NGX_MAX_CONF_ERRSTR;
  1140.         rc.err.data = errstr;

  1141.         for (p = value[i].data; p < value[i].data + value[i].len; p++) {
  1142.             if (*p >= 'A' && *p <= 'Z') {
  1143.                 rc.options = NGX_REGEX_CASELESS;
  1144.                 break;
  1145.             }
  1146.         }

  1147.         sn->regex = ngx_stream_regex_compile(cf, &rc);
  1148.         if (sn->regex == NULL) {
  1149.             return NGX_CONF_ERROR;
  1150.         }

  1151.         sn->name = value[i];
  1152.         cscf->captures = (rc.captures > 0);
  1153.         }
  1154. #else
  1155.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  1156.                            "using regex \"%V\" "
  1157.                            "requires PCRE library", &value[i]);

  1158.         return NGX_CONF_ERROR;
  1159. #endif
  1160.     }

  1161.     return NGX_CONF_OK;
  1162. }


  1163. static char *
  1164. ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  1165. {
  1166.     ngx_stream_core_srv_conf_t  *cscf = conf;

  1167.     ngx_str_t  *value;

  1168.     if (cscf->resolver) {
  1169.         return "is duplicate";
  1170.     }

  1171.     value = cf->args->elts;

  1172.     cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
  1173.     if (cscf->resolver == NULL) {
  1174.         return NGX_CONF_ERROR;
  1175.     }

  1176.     return NGX_CONF_OK;
  1177. }