Beispiel #1
0
char *
ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char  *p = conf;

    time_t           *sp;
    ngx_str_t        *value;
    ngx_conf_post_t  *post;


    sp = (time_t *) (p + cmd->offset);
    if (*sp != NGX_CONF_UNSET) {
        return "is duplicate";
    }

    value = cf->args->elts;

    *sp = ngx_parse_time(&value[1], 1);
    if (*sp == (time_t) NGX_ERROR) {
        return "invalid value";
    }

    if (cmd->post) {
        post = cmd->post;
        return post->post_handler(cf, post, sp);
    }

    return NGX_CONF_OK;
}
Beispiel #2
0
static char *
ngx_http_tfs_rcs_heartbeat(ngx_conf_t *cf, ngx_http_tfs_upstream_t *tu)
{
    ngx_str_t  *value, s;
    ngx_msec_t  interval;
    ngx_uint_t  i;

    value = cf->args->elts;

    for (i = 1; i < cf->args->nelts; i++) {
        if (ngx_strncmp(value[i].data, "lock_file=", 10) == 0) {
            s.data = value[i].data + 10;
            s.len = value[i].len - 10;

            if (ngx_conf_full_name(cf->cycle, &s, 0) != NGX_OK) {
                goto rcs_timers_error;
            }

            tu->lock_file = s;
            continue;
        }

        if (ngx_strncmp(value[i].data, "interval=", 9) == 0) {
            s.data = value[i].data + 9;
            s.len = value[i].len - 9;

            interval = ngx_parse_time(&s, 0);

            if (interval == (ngx_msec_t) NGX_ERROR) {
                return "invalid value";
            }

            tu->rcs_interval = interval;
            continue;
        }

        goto rcs_timers_error;
    }

    if (tu->lock_file.len == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "tfs_poll directive must have lock file");
        return NGX_CONF_ERROR;
    }

    if (tu->rcs_interval < NGX_HTTP_TFS_MIN_TIMER_DELAY) {
        tu->rcs_interval = NGX_HTTP_TFS_MIN_TIMER_DELAY;
        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                           "tfs_poll interval is small, "
                           "so reset this value to 1000");
    }

    return NGX_CONF_OK;

rcs_timers_error:
    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "invalid value \"%V\" in \"%V\" directive",
                       &value[i], &value[0]);
    return NGX_CONF_ERROR;
}
Beispiel #3
0
int nchan_parse_message_buffer_config(ngx_http_request_t *r, nchan_loc_conf_t *cf, char **err) {
  ngx_str_t                      val;
  nchan_loc_conf_shared_data_t  *shcf;
  
  if(!cf->complex_message_timeout && !cf->complex_max_messages) {
    return 1;
  }
  
  if(cf->complex_message_timeout) {
    time_t    timeout;
    if(ngx_http_complex_value(r, cf->complex_message_timeout, &val) != NGX_OK) {
      nchan_log_request_error(r, "cannot evaluate nchan_message_timeout value");
      *err = NULL;
      return 0;
    }
    if(val.len == 0) {
      *err = "missing nchan_message_timeout value";
      nchan_log_request_error(r, "%s", *err);
      return 0;
    }
    
    if((timeout = ngx_parse_time(&val, 1)) == (time_t )NGX_ERROR) {
      *err = "invalid nchan_message_timeout value";
      nchan_log_request_error(r, "%s '%V'", *err, &val);
      return 0;
    }
    
    shcf = memstore_get_conf_shared_data(cf);
    shcf->message_timeout = timeout;
  }
  if(cf->complex_max_messages) {
    ngx_int_t                      num;
    if(ngx_http_complex_value(r, cf->complex_max_messages, &val) != NGX_OK) {
      nchan_log_request_error(r, "cannot evaluate nchan_message_buffer_length value");
      *err = NULL;
      return 0;
    }
    
    if(val.len == 0) {
      *err = "missing nchan_message_buffer_length value";
      nchan_log_request_error(r, "%s", *err);
      return 0;
    }
    
    num = ngx_atoi(val.data, val.len);
    if(num == NGX_ERROR || num < 0) {
      *err = "invalid nchan_message_buffer_length value";
      nchan_log_request_error(r, "%s %V", *err, &val);
      return 0;
    }
    
    shcf = memstore_get_conf_shared_data(cf);
    shcf->max_messages = num;
  }
  return 1;
}
char *ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
  ngx_http_headers_conf_t *hcf = conf;

  ngx_uint_t   minus;
  ngx_str_t   *value;

  if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) {
    return "is duplicate";
  }

  value = cf->args->elts;

  if (ngx_strcmp(value[1].data, "epoch") == 0) {
    hcf->expires = NGX_HTTP_EXPIRES_EPOCH;
    return NGX_CONF_OK;
  }

  if (ngx_strcmp(value[1].data, "off") == 0) {
    hcf->expires = NGX_HTTP_EXPIRES_OFF;
    return NGX_CONF_OK;
  }

  if (value[1].data[0] == '+') {
    value[1].data++;
    value[1].len--;
    minus = 0;

  } else if (value[1].data[0] == '-') {
    value[1].data++;
    value[1].len--;
    minus = 1;

  } else {
    minus = 0;
  }

  hcf->expires = ngx_parse_time(&value[1], 1);
  if (hcf->expires == NGX_ERROR) {
    return "invalid value";
  }

  if (hcf->expires == NGX_PARSE_LARGE_TIME) {
    return "value must be less than 68 years";
  }

  if (minus) {
    hcf->expires = - hcf->expires;
  }

  return NGX_CONF_OK;
}
static char * ngx_http_identifier_timeout(ngx_conf_t * cf, ngx_command_t * cmd, void * conf)
{
    ngx_http_hustdb_ha_main_conf_t * mcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_hustdb_ha_module);
    if (!mcf || 2 != cf->args->nelts)
    {
        return "ngx_http_identifier_timeout error";
    }
    ngx_str_t * value = cf->args->elts;
    mcf->identifier_timeout = ngx_parse_time(&value[1], 0);
    if (NGX_ERROR == mcf->identifier_timeout)
    {
        return "ngx_http_identifier_timeout error";
    }
    // TODO: you can modify the value here
    return NGX_CONF_OK;
}
static void
ngx_http_poller_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
{
  ngx_http_poller_t  *poller;
  ngx_str_t           interval;
  ngx_time_t         *tp;
  ngx_msec_t          msec;
  uint64_t            now;

  poller = ngx_http_get_module_ctx(r, ngx_http_poller_module);
  if (poller->handler.finalize != NULL) {
    poller->handler.finalize(r, rc);
  }

  if (ngx_http_complex_value(r, &poller->interval, &interval) != NGX_OK) {
    return;
  }

  msec = ngx_parse_time(&interval, 0);
  if (msec == (ngx_msec_t)NGX_ERROR) {
    return;
  }

  tp = ngx_timeofday();
  now = tp->sec * 1000 + tp->msec;
  if (now > poller->poll_start) {
    if (now - poller->poll_start < msec) {
      msec -= (now - poller->poll_start);
    } else {
      msec = 0;
    }
  }

  ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
		 "[poller] %V: calling again in %uD ms",
		 &poller->name, (uint32_t)msec);

  ngx_add_timer(&poller->poll_event, msec);

  r->connection->log->log_level = NGX_LOG_EMERG;
}
/* TODO This function is probably not neccesary. Nginx provides a means of
 * easily setting scalar time values with ngx_conf_set_msec_slot() in the
 * ngx_command_t structure. I couldn't manage to make it work, not knowing
 * what I should be using for the two offset parameters. 
 */ 
static char *
max_connections_queue_timeout_command (ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
  ngx_http_upstream_srv_conf_t *uscf = 
    ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);

  max_connections_srv_conf_t *maxconn_cf = 
    ngx_http_conf_upstream_srv_conf(uscf, max_connections_module);

  ngx_str_t        *value; 

  value = cf->args->elts;    

  ngx_msec_t ms = ngx_parse_time(&value[1], 0); 
  if (ms == (ngx_msec_t) NGX_ERROR) {
      return "invalid value";
  }

  maxconn_cf->queue_timeout = ms;

  return NGX_CONF_OK;
}
static char *
ngx_http_encrypted_session_expires(ngx_conf_t *cf, ngx_command_t *cmd,
    void *conf)
{
    ngx_str_t                          *value;
    ngx_http_encrypted_session_conf_t  *llcf = conf;

    if (llcf->expires != NGX_CONF_UNSET) {
        return "is duplicate";
    }

    value = cf->args->elts;

    llcf->expires = ngx_parse_time(&value[1], 1);

    if (llcf->expires == NGX_ERROR) {
        return "invalid value";
    }

    dd("expires: %d", (int)llcf->expires);

    return NGX_CONF_OK;
}
Beispiel #9
0
char *
ndk_conf_set_sec_flag_slot (ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char  *p = conf;

    time_t              *tp;
    ngx_str_t           *value;
    ngx_conf_post_t     *post;

    tp = (time_t *) (p + cmd->offset);

    if (*tp != NGX_CONF_UNSET) {
        return  "is duplicate";
    }

    value = cf->args->elts;

    if (ngx_strcasecmp (value[1].data, (u_char *) "on") == 0) {
        *tp = NDK_CONF_SET_TRUE;

    } else if (ngx_strcasecmp (value[1].data, (u_char *) "off") == 0) {
        *tp = NDK_CONF_SET_FALSE;

    } else {
        *tp = ngx_parse_time (&value[1], 1);
        if (*tp == NGX_ERROR) {
            return  "has an invalid time and not 'on'/'off'";
        }
    }

    if (cmd->post) {
        post = cmd->post;
        return  post->post_handler (cf, post, tp);
    }

    return  NGX_CONF_OK;
}
Beispiel #10
0
char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char  *p = conf;

    ngx_msec_t       *msp;
    ngx_str_t        *value;
    ngx_conf_post_t  *post;


    msp = (ngx_msec_t *) (p + cmd->offset);
    if (*msp != NGX_CONF_UNSET_MSEC)
    {
        return "is duplicate";
    }

    value = cf->args->elts;

    *msp = ngx_parse_time(&value[1], 0);
    if (*msp == (ngx_msec_t) NGX_ERROR)
    {
        return "invalid value";
    }

    if (*msp == (ngx_msec_t) NGX_PARSE_LARGE_TIME)
    {
        return "value must be less than 597 hours";
    }

    if (cmd->post)
    {
        post = cmd->post;
        return post->post_handler(cf, post, msp);
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_session_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_session_store_loc_conf_t  *sslcf = conf;

    ngx_str_t   *value, s;
    ngx_uint_t   i, n;

    if (sslcf->store_shm_zone) {
        return "is duplicate";
    }

    value = cf->args->elts;
    n = 0;

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

        if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {

            s.len = value[i].len - 5;
            s.data = value[i].data + 5;

            sslcf->store_shm_zone = ngx_shared_memory_add(cf, &s, 0,
                    &ngx_http_session_store_module);
            if (sslcf->store_shm_zone == NULL) {
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "expire=", 7) == 0) {

            s.len = value[i].len - 7;
            s.data = value[i].data + 7;

            sslcf->expire = ngx_parse_time(&s, 1);
            if (sslcf->expire == (time_t) NGX_ERROR) {
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (value[i].data[0] == '$') {

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

            sslcf->store_index[n] = ngx_http_get_variable_index(cf, &value[i]);
            if (sslcf->store_index[n] == (ngx_uint_t) NGX_ERROR) {
                return NGX_CONF_ERROR;
            }

            n++;

            continue;
        }


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

    if (sslcf->store_shm_zone == NULL) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    if (sslcf->store_shm_zone->data == NULL) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "unknown session_store_zone \"%V\"",
                &sslcf->store_shm_zone->shm.name);
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_stream_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_stream_upstream_srv_conf_t  *uscf = conf;

    time_t                         fail_timeout;
    ngx_str_t                     *value, s;
    ngx_url_t                      u;
    ngx_int_t                      weight, max_fails;
    ngx_uint_t                     i;
    ngx_stream_upstream_server_t  *us;

    us = ngx_array_push(uscf->servers);
    if (us == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(us, sizeof(ngx_stream_upstream_server_t));

    value = cf->args->elts;

    weight = 1;
    max_fails = 1;
    fail_timeout = 10;

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

        if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {

            if (!(uscf->flags & NGX_STREAM_UPSTREAM_WEIGHT)) {
                goto not_supported;
            }

            weight = ngx_atoi(&value[i].data[7], value[i].len - 7);

            if (weight == NGX_ERROR || weight == 0) {
                goto invalid;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {

            if (!(uscf->flags & NGX_STREAM_UPSTREAM_MAX_FAILS)) {
                goto not_supported;
            }

            max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);

            if (max_fails == NGX_ERROR) {
                goto invalid;
            }

            continue;
        }

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

            if (!(uscf->flags & NGX_STREAM_UPSTREAM_FAIL_TIMEOUT)) {
                goto not_supported;
            }

            s.len = value[i].len - 13;
            s.data = &value[i].data[13];

            fail_timeout = ngx_parse_time(&s, 1);

            if (fail_timeout == (time_t) NGX_ERROR) {
                goto invalid;
            }

            continue;
        }

        if (ngx_strcmp(value[i].data, "backup") == 0) {

            if (!(uscf->flags & NGX_STREAM_UPSTREAM_BACKUP)) {
                goto not_supported;
            }

            us->backup = 1;

            continue;
        }

        if (ngx_strcmp(value[i].data, "down") == 0) {

            if (!(uscf->flags & NGX_STREAM_UPSTREAM_DOWN)) {
                goto not_supported;
            }

            us->down = 1;

            continue;
        }

        goto invalid;
    }

    ngx_memzero(&u, sizeof(ngx_url_t));

    u.url = value[1];

    if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
        if (u.err) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "%s in upstream \"%V\"", u.err, &u.url);
        }

        return NGX_CONF_ERROR;
    }

    if (u.no_port) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "no port in upstream \"%V\"", &u.url);
        return NGX_CONF_ERROR;
    }

    us->name = u.url;
    us->addrs = u.addrs;
    us->naddrs = u.naddrs;
    us->weight = weight;
    us->max_fails = max_fails;
    us->fail_timeout = fail_timeout;

    return NGX_CONF_OK;

invalid:

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "invalid parameter \"%V\"", &value[i]);

    return NGX_CONF_ERROR;

not_supported:

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "balancing method does not support parameter \"%V\"",
                       &value[i]);

    return NGX_CONF_ERROR;
}
static char *
ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_mail_core_srv_conf_t  *cscf = conf;

    ngx_str_t                  *value;
    ngx_url_t                   u;
    ngx_uint_t                  i, m;
    ngx_mail_listen_t          *ls;
    ngx_mail_module_t          *module;
    ngx_mail_core_main_conf_t  *cmcf;

    cscf->listen = 1;

    value = cf->args->elts;

    ngx_memzero(&u, sizeof(ngx_url_t));

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

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

        return NGX_CONF_ERROR;
    }

    cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);

    ls = cmcf->listen.elts;

    for (i = 0; i < cmcf->listen.nelts; i++) {

        if (ngx_cmp_sockaddr(&ls[i].sockaddr.sockaddr, ls[i].socklen,
                             (struct sockaddr *) &u.sockaddr, u.socklen, 1)
            != NGX_OK)
        {
            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "duplicate \"%V\" address and port pair", &u.url);
        return NGX_CONF_ERROR;
    }

    ls = ngx_array_push(&cmcf->listen);
    if (ls == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(ls, sizeof(ngx_mail_listen_t));

    ngx_memcpy(&ls->sockaddr.sockaddr, &u.sockaddr, u.socklen);

    ls->socklen = u.socklen;
    ls->backlog = NGX_LISTEN_BACKLOG;
    ls->wildcard = u.wildcard;
    ls->ctx = cf->ctx;

#if (NGX_HAVE_INET6)
    ls->ipv6only = 1;
#endif

    if (cscf->protocol == NULL) {
        for (m = 0; cf->cycle->modules[m]; m++) {
            if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
                continue;
            }

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

            if (module->protocol == NULL) {
                continue;
            }

            for (i = 0; module->protocol->port[i]; i++) {
                if (module->protocol->port[i] == u.port) {
                    cscf->protocol = module->protocol;
                    break;
                }
            }
        }
    }

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

        if (ngx_strcmp(value[i].data, "bind") == 0) {
            ls->bind = 1;
            continue;
        }

        if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
            ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
            ls->bind = 1;

            if (ls->backlog == NGX_ERROR || ls->backlog == 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid backlog \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
            size_t  len;
            u_char  buf[NGX_SOCKADDR_STRLEN];

            if (ls->sockaddr.sockaddr.sa_family == AF_INET6) {

                if (ngx_strcmp(&value[i].data[10], "n") == 0) {
                    ls->ipv6only = 1;

                } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
                    ls->ipv6only = 0;

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

                ls->bind = 1;

            } else {
                len = ngx_sock_ntop(&ls->sockaddr.sockaddr, ls->socklen, buf,
                                    NGX_SOCKADDR_STRLEN, 1);

                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "ipv6only is not supported "
                                   "on addr \"%*s\", ignored", len, buf);
            }

            continue;
#else
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "bind ipv6only is not supported "
                               "on this platform");
            return NGX_CONF_ERROR;
#endif
        }

        if (ngx_strcmp(value[i].data, "ssl") == 0) {
#if (NGX_MAIL_SSL)
            ls->ssl = 1;
            continue;
#else
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "the \"ssl\" parameter requires "
                               "ngx_mail_ssl_module");
            return NGX_CONF_ERROR;
#endif
        }

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

            if (ngx_strcmp(&value[i].data[13], "on") == 0) {
                ls->so_keepalive = 1;

            } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
                ls->so_keepalive = 2;

            } else {

#if (NGX_HAVE_KEEPALIVE_TUNABLE)
                u_char     *p, *end;
                ngx_str_t   s;

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

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

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

                    ls->tcp_keepidle = ngx_parse_time(&s, 1);
                    if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

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

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

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

                    ls->tcp_keepintvl = ngx_parse_time(&s, 1);
                    if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

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

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

                    ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
                    if (ls->tcp_keepcnt == NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

                if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
                    && ls->tcp_keepcnt == 0)
                {
                    goto invalid_so_keepalive;
                }

                ls->so_keepalive = 1;

#else

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

#endif
            }

            ls->bind = 1;

            continue;

#if (NGX_HAVE_KEEPALIVE_TUNABLE)
        invalid_so_keepalive:

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

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "the invalid \"%V\" parameter", &value[i]);
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
// Overwrite the nginx "server" directive based on its
// implementation of "ngx_http_upstream_server" from
// src/http/ngx_http_upstream.c (nginx version 1.7.7), and should be kept in
// sync with nginx's source code. Customizations noted in comments.
// This make possible use the same syntax of nginx comercial version.
static char * ngx_http_upstream_dynamic_server_directive(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) {
    // BEGIN CUSTOMIZATION: differs from default "server" implementation
    ngx_http_upstream_srv_conf_t                  *uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
    ngx_http_upstream_dynamic_server_main_conf_t  *udsmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_dynamic_servers_module);
    ngx_http_upstream_dynamic_server_conf_t       *dynamic_server = NULL;
    // END CUSTOMIZATION

    time_t                       fail_timeout;
    ngx_str_t                   *value, s;
    ngx_url_t                    u;
    ngx_int_t                    weight, max_fails;
    ngx_uint_t                   i;
    ngx_http_upstream_server_t  *us;

#if nginx_version <= 1007002
    if (uscf->servers == NULL) {
        uscf->servers = ngx_array_create(cf->pool, 4,
                                         sizeof(ngx_http_upstream_server_t));
        if (uscf->servers == NULL) {
            return NGX_CONF_ERROR;
        }
    }
#endif

    us = ngx_array_push(uscf->servers);
    if (us == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(us, sizeof(ngx_http_upstream_server_t));

    value = cf->args->elts;

    weight = 1;
    max_fails = 1;
    fail_timeout = 10;

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

        if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {

            if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
                goto not_supported;
            }

            weight = ngx_atoi(&value[i].data[7], value[i].len - 7);

            if (weight == NGX_ERROR || weight == 0) {
                goto invalid;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {

            if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
                goto not_supported;
            }

            max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);

            if (max_fails == NGX_ERROR) {
                goto invalid;
            }

            continue;
        }

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

            if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
                goto not_supported;
            }

            s.len = value[i].len - 13;
            s.data = &value[i].data[13];

            fail_timeout = ngx_parse_time(&s, 1);

            if (fail_timeout == (time_t) NGX_ERROR) {
                goto invalid;
            }

            continue;
        }

        if (ngx_strcmp(value[i].data, "backup") == 0) {

            if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) {
                goto not_supported;
            }

            us->backup = 1;

            continue;
        }

        if (ngx_strcmp(value[i].data, "down") == 0) {

            if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
                goto not_supported;
            }

            us->down = 1;

            continue;
        }

        // BEGIN CUSTOMIZATION: differs from default "server" implementation
        if (ngx_strcmp(value[i].data, "resolve") == 0) {
            // Determine if the server given is an IP address or a hostname by running
            // through ngx_parse_url with no_resolve enabled. Only if a hostname is given
            // will we add this to the list of dynamic servers that we will resolve again.

            ngx_memzero(&u, sizeof(ngx_url_t));
            u.url = value[1];
            u.default_port = 80;
            u.no_resolve = 1;
            ngx_parse_url(cf->pool, &u);
            if (!u.addrs || !u.addrs[0].sockaddr) {
                dynamic_server = ngx_array_push(&udsmcf->dynamic_servers);
                if (dynamic_server == NULL) {
                    return NGX_CONF_ERROR;
                }

                ngx_memzero(dynamic_server, sizeof(ngx_http_upstream_dynamic_server_conf_t));
                dynamic_server->server = us;
                dynamic_server->upstream_conf = uscf;

                dynamic_server->host = u.host;
                dynamic_server->port = (in_port_t) (u.no_port ? u.default_port : u.port);
            }

            continue;
        }
        // END CUSTOMIZATION

        goto invalid;
    }

    ngx_memzero(&u, sizeof(ngx_url_t));

    u.url = value[1];
    u.default_port = 80;

    // BEGIN CUSTOMIZATION: differs from default "server" implementation
    if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
        if (u.err) {
            ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
                               "%s in upstream \"%V\"", u.err, &u.url);
        }

        // If the domain fails to resolve on start up, mark this server as down,
        // and assign a static IP that should never route. This is to account for
        // various things inside nginx that seem to expect a server to always have
        // at least 1 IP.
        us->down = 1;

        u.url = ngx_http_upstream_dynamic_server_null_route;
        u.default_port = u.port;
        u.no_resolve = 1;

        if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
            if (u.err) {
                ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
                                   "%s in upstream \"%V\"", u.err, &u.url);
            }

            return NGX_CONF_ERROR;
        }
    }
    // END CUSTOMIZATION

#if nginx_version >= 1007002
    us->name = u.url;
#endif
    us->addrs = u.addrs;
    us->naddrs = u.naddrs;
    us->weight = weight;
    us->max_fails = max_fails;
    us->fail_timeout = fail_timeout;

    return NGX_CONF_OK;

invalid:

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "invalid parameter \"%V\"", &value[i]);

    return NGX_CONF_ERROR;

not_supported:

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "balancing method does not support parameter \"%V\"",
                       &value[i]);

    return NGX_CONF_ERROR;
}
//获取expires配置的时间
static ngx_int_t
ngx_http_parse_expires(ngx_str_t *value, ngx_http_expires_t *expires,
    time_t *expires_time, char **err)
{
    ngx_uint_t  minus;

    if (*expires != NGX_HTTP_EXPIRES_MODIFIED) {

        if (value->len == 5 && ngx_strncmp(value->data, "epoch", 5) == 0) {
            *expires = NGX_HTTP_EXPIRES_EPOCH; //expire modified epoch
            return NGX_OK;
        }

        if (value->len == 3 && ngx_strncmp(value->data, "max", 3) == 0) {
            *expires = NGX_HTTP_EXPIRES_MAX; //expire modified max
            return NGX_OK;
        }

        if (value->len == 3 && ngx_strncmp(value->data, "off", 3) == 0) {
            *expires = NGX_HTTP_EXPIRES_OFF;  //expire modified off
            return NGX_OK;
        }
    }

    if (value->len && value->data[0] == '@') {
        value->data++;
        value->len--;
        minus = 0;

        if (*expires == NGX_HTTP_EXPIRES_MODIFIED) {
            *err = "daily time cannot be used with \"modified\" parameter";
            return NGX_ERROR;
        }

        *expires = NGX_HTTP_EXPIRES_DAILY;

    } else if (value->len && value->data[0] == '+') {
        value->data++;
        value->len--;
        minus = 0;

    } else if (value->len && value->data[0] == '-') {
        value->data++;
        value->len--;
        minus = 1;

    } else {
        minus = 0;
    }

    *expires_time = ngx_parse_time(value, 1);

    if (*expires_time == (time_t) NGX_ERROR) {
        *err = "invalid value";
        return NGX_ERROR;
    }

    if (*expires == NGX_HTTP_EXPIRES_DAILY
        && *expires_time > 24 * 60 * 60)
    {
        *err = "daily time value must be less than 24 hours";
        return NGX_ERROR;
    }

    if (minus) { //时间为负数,转为整数
        *expires_time = - *expires_time;
    }

    return NGX_OK;
}
/*
 * Function called when the sticky command is parsed on the conf file
 */
static char *
ngx_http_sticky_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    time_t                        expires = NGX_CONF_UNSET;
    ngx_str_t                     tmp;
    ngx_str_t                     name = ngx_string("route");
    ngx_str_t                     domain = ngx_string("");
    ngx_str_t                     path = ngx_string("");
    ngx_str_t                     hmac_key = ngx_string("");
    ngx_str_t                    *value = cf->args->elts;
    ngx_uint_t                    i;
    ngx_uint_t                    no_fallback = 0;
    ngx_http_sticky_srv_conf_t   *sticky_conf;
    ngx_http_upstream_srv_conf_t *upstream_conf;
    ngx_http_sticky_misc_hash_pt  hash = NGX_CONF_UNSET_PTR;
    ngx_http_sticky_misc_hmac_pt  hmac = NULL;

    /* parse all elements */
    for (i = 1; i < cf->args->nelts; i++) {

        if (ngx_strncmp(value[i].data, "name=", 5) == 0) {

            /* save what's after "name=" */
            name.len = value[i].len - 5;
            name.data = value[i].data + 5;
            continue;
        } 

        if (ngx_strncmp(value[i].data, "domain=", 7) == 0) {

            /* save what's after "domain=" */
            domain.len = value[i].len - 7;
            domain.data = value[i].data + 7;
            continue;
        }

        if (ngx_strncmp(value[i].data, "path=", 5) == 0) {

            /* save what's after "path=" */
            path.len = value[i].len - 5;
            path.data = value[i].data + 5;
        }

        if (ngx_strncmp(value[i].data, "expires=", 8) == 0) {

            /* extract value */
            tmp.len =  value[i].len - 8;
            tmp.data = value[i].data + 8;

            /* convert to time, save and validate */
            expires = ngx_parse_time(&tmp, 1);
            if (expires == NGX_ERROR || expires < 1) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        /* is "hash=" is starting the argument ? */
        if (ngx_strncmp(value[i].data, "hash=", 5) == 0) {

            /* only hash or hmac can be used, not both */
            if (hmac) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    "please choose between \"hash=\" and \"hmac=\"");
                return NGX_CONF_ERROR;
            }

            /* extract value to temp */
            tmp.len =  value[i].len - ngx_strlen("hash=");
            tmp.data = (u_char *)(value[i].data + sizeof("hash=") - 1);

            /* is hash=index */
            if (ngx_strncmp(tmp.data, "index", sizeof("index") - 1) == 0 ) {
                hash = NULL;
                continue;
            }

            /* is hash=md5 */
            if (ngx_strncmp(tmp.data, "md5", sizeof("md5") - 1) == 0 ) {
                hash = ngx_http_sticky_misc_md5;
                continue;
            }

            /* is hash=sha1 */
            if (ngx_strncmp(tmp.data, "sha1", sizeof("sha1") - 1) == 0 ) {
                hash = ngx_http_sticky_misc_sha1;
                continue;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "wrong value for \"hash=\": index, md5 or sha1");

            return NGX_CONF_ERROR;
        }

        if (ngx_strncmp(value[i].data, "hmac=", 5) == 0) {

            /* only hash or hmac can be used, not both */
            if (hash != NGX_CONF_UNSET_PTR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                    "please choose between \"hash=\" and \"hmac=\"");
                return NGX_CONF_ERROR;
            }

            /* extract value */
            tmp.len =  value[i].len - 5;
            tmp.data = value[i].data + 5;

            /* is hmac=md5 ? */
            if (ngx_strncmp(tmp.data, "md5", sizeof("md5") - 1) == 0 ) {
                hmac = ngx_http_sticky_misc_hmac_md5;
                continue;
            }

            /* is hmac=sha1 ? */
            if (ngx_strncmp(tmp.data, "sha1", sizeof("sha1") - 1) == 0 ) {
                hmac = ngx_http_sticky_misc_hmac_sha1;
                continue;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "wrong value for \"hmac=\": md5 or sha1");
            return NGX_CONF_ERROR;
        }

        if (ngx_strncmp(value[i].data, "hmac_key=", 9) == 0) {

            /* save what's after "hmac_key=" */
            hmac_key.len = value[i].len - 9;
            hmac_key.data = value[i].data + 9;
            continue;
        }

        /* is "no_fallback" flag present ? */
        if (ngx_strncmp(value[i].data, "no_fallback",
                        sizeof("no_fallback") - 1) == 0 ) {
            no_fallback = 1;
            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid arguement (%V)", &value[i]);
        return NGX_CONF_ERROR;
    }

    /* if has and hmac have not been set, default to md5 */
    if (hash == NGX_CONF_UNSET_PTR && hmac == NULL) {
        hash = ngx_http_sticky_misc_md5;
    }

    /* don't allow meaning less parameters */
    if (hmac_key.len > 0 && hash != NGX_CONF_UNSET_PTR) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"hmac_key=\" is meaningless when "
                           "\"hash\" is used. Please remove it.");
        return NGX_CONF_ERROR;
    }

    /* ensure we have an hmac key if hmac's been set */
    if (hmac_key.len == 0 && hmac != NULL) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "please specify "
                           "\"hmac_key=\" when using \"hmac\"");
        return NGX_CONF_ERROR;
    }

    /* ensure hash is NULL to avoid conflicts later */
    if (hash == NGX_CONF_UNSET_PTR) {
        hash = NULL;
    }

    /* save the sticky parameters */
    sticky_conf = ngx_http_conf_get_module_srv_conf(cf,
                                                    ngx_http_sticky_module);
    sticky_conf->cookie_name = name;
    sticky_conf->cookie_domain = domain;
    sticky_conf->cookie_path = path;
    sticky_conf->cookie_expires = expires;
    sticky_conf->hash = hash;
    sticky_conf->hmac = hmac;
    sticky_conf->hmac_key = hmac_key;
    sticky_conf->no_fallback = no_fallback;
    sticky_conf->peers = NULL; /* ensure it's null before running */

    upstream_conf = ngx_http_conf_get_module_srv_conf(cf,
                                                      ngx_http_upstream_module);

    /* 
     * ensure another upstream module has not been already loaded
     * peer.init_upstream is set to null and the upstream module use RR if not set
     * But this check only works when the other module is declared before sticky
     */
    if (upstream_conf->peer.init_upstream) {

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "You can't use sticky with another upstream module");

        return NGX_CONF_ERROR;
    }

    /* configure the upstream to get back to this module */
    upstream_conf->peer.init_upstream = ngx_http_init_upstream_sticky;

    upstream_conf->flags = NGX_HTTP_UPSTREAM_CREATE
                         | NGX_HTTP_UPSTREAM_MAX_FAILS
                         | NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
                         | NGX_HTTP_UPSTREAM_DOWN;

    return NGX_CONF_OK;
}
char *
ngx_xconf_include_uri(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_str_t          *arg, uri, filename, scheme_name;
    ngx_xconf_ctx_t     ctx;
    ngx_flag_t          is_last_elt;
    ngx_uint_t          i;
    ngx_str_t          *cmd_name;
    u_char              need_next;
    ngx_str_t           ofilename_prefix = ngx_string("$file"),
                        ofilename_suffix = ngx_string("l$line.conf"),
                        ofilename_suffix2 = ngx_string("conf");
    char               *rv;
    u_char             *s; /* 用于临时分配内存用 */;
    lua_State          *L;
    ngx_xconf_scheme_t *scheme;


    arg = cf->args->elts;
    cmd_name = &arg[0];

    scheme = ngx_xconf_schemes;
    if ((scheme == NULL) || (scheme->name.len == 0)) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: no scheme define.",
                cmd_name);

        return NGX_CONF_ERROR;
    }

    /* 参数说明见 README */

    uri.len = 0;        /* 如果没设定报错 */
    filename.len = 0;   /* 如果没设定就默认给一个 */
    ctx.evaluri = 1;    /* 默认 eval uri */
    ctx.keep_error_cachefile = 0;   /* 默认删除解析出错的 cachefile */
    ctx.pre_usecache = -1;   /* 默认不使用 cachefile */
    ctx.fail_usecache = -1;   /* 默认不使用 cachefile */

    ctx.fetch_content = NULL;
    ctx.do_cachefile = 0;

    need_next = 0;
    is_last_elt = 0;

    /* 解析参数 {{{ */
    for (i = 1; i < cf->args->nelts; i++) {
        if (! (arg[i].len)) {
            continue;
        }

        is_last_elt = i == cf->args->nelts - 1;

        if (need_next) {
            switch(need_next) {
                case 'o':
                    filename.data = arg[i].data;
                    filename.len = arg[i].len;
                    break;
                case 'O':
                    filename.len = ofilename_prefix.len + arg[i].len + ofilename_suffix.len + sizeof("..") - 1;
                    filename.data = ngx_palloc(cf->pool, filename.len + 1);
                    ngx_snprintf(filename.data, filename.len,
                            "%V.%V.%V",
                            &ofilename_prefix, &arg[i], &ofilename_suffix);
                    break;
                case 'I':
                    filename.len = ofilename_prefix.len + arg[i].len + ofilename_suffix2.len + sizeof("..") - 1;
                    filename.data = ngx_palloc(cf->pool, filename.len + 1);
                    ngx_snprintf(filename.data, filename.len,
                            "%V.%V.%V",
                            &ofilename_prefix, &arg[i], &ofilename_suffix2);
                    break;
                case 't':
                    ctx.timeout = ngx_parse_time(&arg[i], 1);
                    if (ctx.timeout == NGX_ERROR) {
                        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                "%V: option [-t %V] value error.",
                                cmd_name, &arg[i]);

                        return NGX_CONF_ERROR;
                    }
                    break;
                case 'c':
                    if (arg[i].len == 2 && arg[i].data[0] == '-' && arg[i].data[1] == '1') {
                        ctx.pre_usecache = -1 * (arg[i].data[1] - '0');
                    } else {
                        ctx.pre_usecache = ngx_parse_time(&arg[i], 1);
                        if (ctx.pre_usecache == NGX_ERROR) {
                            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                    "%V: option [-c %V] value error.",
                                    cmd_name, &arg[i]);

                            return NGX_CONF_ERROR;
                        }
                    }
                    break;
                case 'C':
                    if (arg[i].len == 2 && arg[i].data[0] == '-' &&
                            (arg[i].data[1] >= '1' && arg[i].data[1] <= '2')) {
                        ctx.fail_usecache = -1 * (arg[i].data[1] - '0');
                    } else {
                        ctx.fail_usecache = ngx_parse_time(&arg[i], 1);
                        if (ctx.fail_usecache == NGX_ERROR) {
                            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                    "%V: option [-C %V] value error.",
                                    cmd_name, &arg[i]);

                            return NGX_CONF_ERROR;
                        }
                    }
                    break;
                default:
                    /* 通常不会到这里 */
                    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                            "%V: unknown option [%c] .",
                            cmd_name, need_next);

                    return NGX_CONF_ERROR;
            }

            need_next = 0;
            continue;
        } else {
            if (arg[i].data[0] == '-') {
                /* 现在只支持 -x */
                if (arg[i].len != 2) {
                    goto unknow_opt;
                }
                switch(arg[i].data[1]) {
                    case 'K':
                        ctx.keep_error_cachefile = 1;
                        break;
                    case 'n':
                        ctx.evaluri = 0;
                        break;
                    case 'c':
                    case 'C':
                    case 'o':
                    case 'I':
                    case 'O':
                    case 't':
                        need_next = arg[i].data[1];

                        if (is_last_elt) {
                            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                    "%V: option [-%c] need a value.",
                                    cmd_name, need_next);

                            return NGX_CONF_ERROR;
                        }

                        break;
                    default:
                        goto unknow_opt;
                }

                continue;
            } else { /* this will be the uri */
                uri.data = arg[i].data;
                uri.len = arg[i].len;

                continue;
            }
        }

        goto unknow_opt;
    }
    /* }}} */

    /* 因为上面不需要用到 lua 的功能,所有此刻才初始化 lua vm {{{ */
    L = luaL_newstate();

    if (L == NULL) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: create lua vm fail.",
                cmd_name);

        return NGX_CONF_ERROR;
    }

    /* XXX 从这以下如果出错,需要 goto error; 因为要 close lua vm */

    ctx.lua = L;

    luaL_openlibs(L);
    {
        int         rc;
        ngx_str_t   msg;

        rc = luaL_loadbuffer(L, (const char*) xconf_util_lua, sizeof(xconf_util_lua), "ngx_xconf_util.lua(embed)");
        if (rc != 0) {
            msg.data = (u_char *) lua_tolstring(L, -1, &msg.len);

            if (msg.data == NULL) {
                msg.data = (u_char *) "unknown reason";
                msg.len = sizeof("unknown reason") - 1;
            }

            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "xconf load lua code error: %V.",
                    &msg);

            lua_pop(L, 1);

            rv = NULL;
            goto error;
        }
    }
    /* 这个 lua 文件会创建 若干个 全局函数,如: format */

    if (ngx_xconf_util_lua_pcall(cf, L, 0, 0, 0, 0) != NGX_OK) {
        rv = NULL;
        goto error;
    }
    /* }}} */

    /* 创建变量 table 到 lua vm (var_ctx) 里,用于变量插值 {{{ */
    lua_createtable(L, /* i */0, /* key */10); /* var_ctx */
    lua_pushlstring(L, (char *)cf->conf_file->file.name.data, cf->conf_file->file.name.len);
    lua_setfield(L, -2, "file");
    lua_pushnumber(L, cf->conf_file->line);
    lua_setfield(L, -2, "line");
    lua_pushlstring(L, (char *)cf->cycle->prefix.data, cf->cycle->prefix.len);
    lua_setfield(L, -2, "prefix");
    lua_pushlstring(L, (char *)cf->cycle->conf_prefix.data, cf->cycle->conf_prefix.len);
    lua_setfield(L, -2, "conf_prefix");
    lua_pushnumber(L, (int) ngx_pid);
    lua_setfield(L, -2, "pid");
    lua_pushlstring(L, (char *)cf->cycle->hostname.data, cf->cycle->hostname.len);
    lua_setfield(L, -2, "hostname");
    {
        ngx_time_t *tp = ngx_timeofday();

        lua_pushnumber(L, (int) (tp->sec));
        lua_setfield(L, -2, "time"); /* var_ctx */
    }

    lua_setfield(L, LUA_GLOBALSINDEX, "var_ctx");
    /* }}} */

    /* 对 uri 进行变量插值 {{{ */
    if (ctx.evaluri) {
        lua_getfield(L, LUA_GLOBALSINDEX, "format"); /* got the format function */
        lua_pushlstring(L, (char *) uri.data, uri.len);
        if (ngx_xconf_util_lua_pcall(cf, L, 1, 1, 0, 0) != NGX_OK) {
            rv = NULL;
            goto error;
        }
        uri.data = (u_char *) lua_tolstring(L, -1, &uri.len);
        s = ngx_palloc(cf->pool, uri.len);
        ngx_memcpy(s, uri.data, uri.len);
        uri.data = s;
        s = NULL;
        lua_pop(L, 1);
    }

    if (! (uri.len)) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: must give us uri.",
                cmd_name);

        rv = NULL;
        goto error;
    }

    ctx.uri.len = uri.len;
    ctx.uri.data = uri.data;
    /* }}} */

    /* 计算 uri 的 scheme_name {{{ */
    /* 如果以 '//' 开头 认为是 http: */
    if (uri.len > 2 && uri.data[0] == '/' && uri.data[1] == '/') {
        ctx.noscheme_uri.data = uri.data;
        ctx.noscheme_uri.len = uri.len;

        scheme_name.len = sizeof("http") - 1;
        scheme_name.data = ngx_palloc(cf->pool, scheme_name.len + 1);
        ngx_cpystrn(scheme_name.data, (u_char *)"http", scheme_name.len + 1);
    /* 如果以 '/' 或 './' 开头 认为是 file: */
    } else if (uri.data[0] == '/'
            || (uri.len > 2 && uri.data[0] == '.' && uri.data[1] == '/')) {

        size_t is_abs = uri.data[0] == '/';
        u_char *data = uri.data + (is_abs ? 0 : 2);
        size_t len = uri.len - (is_abs ? 0 : 2);

        ctx.noscheme_uri.len = len + 2;
        ctx.noscheme_uri.data = ngx_palloc(cf->pool, len + 2 + 1);
        ctx.noscheme_uri.data[0] = '/';
        ctx.noscheme_uri.data[1] = '/';
        ngx_cpystrn(ctx.noscheme_uri.data + 2, data, len + 1);

        scheme_name.len = sizeof("file") - 1;
        scheme_name.data = ngx_palloc(cf->pool, scheme_name.len + 1);
        ngx_cpystrn(scheme_name.data, (u_char *)"file", scheme_name.len + 1);
    } else {
        u_char      c;
        ngx_str_t   tmp_scheme;
        size_t      i, maxi, found;

        /* find scheme: [a-z_][a-z_0-9+.-]: , max_scheme_len */
        tmp_scheme.data = ngx_palloc(cf->pool, max_scheme_len);
        tmp_scheme.len = 0;
        i = 0;
        maxi = uri.len - 1;
        found = 0;

        while (i < max_scheme_len && i <= maxi) {
            c = uri.data[i];

            if (c == ':') {
                found = 1;
                break;
            }

            tmp_scheme.data[i] = c;
            tmp_scheme.len++;
            if ((c >= 'a' && c <= 'z')
                    || (c >= 'A' && c <= 'Z')
                    || (c >= '0' && c <= '9')
                    || c == '+' || c == '-' || c == '.') {
            } else {
                ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                        "%V: uri (%V...) have no valid scheme name.",
                        cmd_name, &tmp_scheme);

                rv = NULL;
                goto error;
            }

            /* XXX important */
            i++;
        }

        if (! (found && tmp_scheme.len)) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: uri (%V) have no valid scheme name.",
                    cmd_name, &uri);

            rv = NULL;
            goto error;
        }

        scheme_name.len = tmp_scheme.len;
        scheme_name.data = tmp_scheme.data;
        scheme_name.data[tmp_scheme.len] = '\0';

        /* 1 -> the ':' after scheme name */
        ctx.noscheme_uri.len = uri.len - tmp_scheme.len - 1;
        ctx.noscheme_uri.data = uri.data + tmp_scheme.len + 1;
    }
    /* }}} */

    /* 查找当前 scheme {{{ */
    for ( /* void */ ; scheme->name.len; scheme++) {
        if (scheme_name.len == scheme->name.len &&
                ngx_strcmp(scheme_name.data, scheme->name.data) == 0) {
            break;
        }
    }

    if (! scheme->name.len) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: no scheme found for \"%V\".",
                cmd_name, &ctx.scheme);

        rv = NULL;
        goto error;
    }
    /* }}} */

    ctx.scheme = scheme;

    /* 如果 scheme usecache 则计算 filename 并 判断 pre_usecache {{{ */
    if (scheme->usecache) {
        /* filename 计算, 插值, 展开 {{{ */
        if (! (filename.len)) {
            filename.len = ofilename_prefix.len + ofilename_suffix.len + sizeof(".") - 1;
            filename.data = ngx_palloc(cf->pool, filename.len + 1);
            ngx_snprintf(filename.data, filename.len,
                    "%V.%V",
                    &ofilename_prefix, &ofilename_suffix);
        }

        /* FIXME filename.data 是否需要 free ?? */
        lua_getfield(L, LUA_GLOBALSINDEX, "format"); /* got the format function */
        lua_pushlstring(L, (char *) filename.data, filename.len);
        if (ngx_xconf_util_lua_pcall(cf, L, 1, 1, 0, 0) != NGX_OK) {
            rv = NULL;
            goto error;
        }
        filename.data = (u_char *) lua_tolstring(L, -1, &filename.len);
        s = ngx_palloc(cf->pool, filename.len + 1);
        ngx_cpystrn(s, filename.data, filename.len + 1); /* 让 ngx_cpystrn 帮忙添加个 \0 */
        filename.data = s;
        s = NULL;
        lua_pop(L, 1);

        if (ngx_conf_full_name(cf->cycle, &filename, 1) != NGX_OK) {
            rv = NULL;
            goto error;
        }
        /* }}} */

        ctx.cachefile = ngx_palloc(cf->pool, sizeof(ngx_file_t));
        if (ctx.cachefile == NULL) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: alloc cachefile error.",
                    cmd_name);

            rv = NULL;
            goto error;
        }
        ngx_memzero(ctx.cachefile, sizeof(ngx_file_t));

        ctx.cachefile->name = filename;
        ctx.cachefile->log = cf->log;

        dd("pre-usecache: %d, %d", (int)ctx.scheme->pre_usecache, (int)ctx.pre_usecache);
        if (ctx.scheme->pre_usecache && ctx.pre_usecache > -1) {
            ngx_file_t  *file;

            file = ctx.cachefile;

            /* 获取文件信息 FAIL */
            if (ngx_file_info(file->name.data, &file->info) == -1) {
                /* 如果文件不存在则忽略,否则报错 */
                if (errno != ENOENT) {
                    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                            "%V: get file \"%V\" info error: %s.",
                            cmd_name, file->name, strerror(errno));

                    rv = NULL;
                    goto error;
                }
            /* 获取文件信息 OK, 有没可能是个 目录 ?? ,如果谁这么配置 !!! */
            } else {
                int     now;

                /* 只要文件存在就用 */
                if (ctx.pre_usecache == 0) {
                    goto do_cachefile;
                }

                ngx_time_update();
                now = (int)ngx_time();

                dd("pre-usecache now: %d, mtime: %d, diff: %d, pref: %d.",
                        now, (int)file->info.st_mtime, now - (int)file->info.st_mtime, (int)ctx.pre_usecache);

                if (now - file->info.st_mtime <= ctx.pre_usecache) {
                    goto do_cachefile;
                }
            }
        }
    }
    /* }}} */

    ngx_log_error(NGX_LOG_INFO, cf->log, 0,
            "\n- - - - - - - -\ncmd_name: %V\nfileneme: %V\nuri: %V\npre_usecache: %d\nfail_usecache: %d\nevaluri: %d\nscheme: %V\nnoscheme_uri: %V\n- - - - - - - -",
            cmd_name, &filename, &uri, ctx.pre_usecache, ctx.fail_usecache, ctx.evaluri, &ctx.scheme->name, &ctx.noscheme_uri);

    /* 执行具体 scheme {{{ */
    rv = scheme->handler(cf, cmd, conf, &ctx);

    if (rv == NGX_CONF_OK) {
        goto done;
    } else if (rv == NGX_XCONF_FETCH_ERROR) {
        /* do fail_usecache */
        if (scheme->usecache) {
            goto fetch_fail;
        } else {
            /* 不可能 */
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "if you see this error, please report it to author with \"%V\".",
                    &scheme->name);

            rv = NULL;
            goto error;
        }
    } else if (rv == NGX_XCONF_FETCH_OK) {
        if (scheme->usecache) {
            if (ctx.fetch_content != NULL) {
                goto save_cachefile;
            } else if (ctx.do_cachefile) {
                goto do_cachefile;
            }
        }

        goto done;
    } else {
        goto error;
    }
    /* }}} */

    goto done;

fetch_fail:
    dd("fail-usecache: %d, %d", (int)ctx.scheme->fail_usecache, (int)ctx.fail_usecache);

    if (ctx.scheme->fail_usecache && ctx.fail_usecache != -1) {
        /* 删除 */
        if (ctx.fail_usecache != -2) {
            ngx_delete_file(ctx.cachefile->name.data);

            rv = NULL;
            goto error;

        } else if (ctx.fail_usecache >= 0) {
            ngx_file_t  *file;

            file = ctx.cachefile;

            /* 获取文件信息 FAIL */
            if (ngx_file_info(file->name.data, &file->info) == -1) {
                ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                        "%V: get file \"%V\" info in fetch_fail error: %s.",
                        cmd_name, file->name, strerror(errno));

                rv = NULL;
                goto error;
            /* 获取文件信息 OK, 有没可能是个 目录 ?? ,如果谁这么配置 !!! */
            } else {
                int     now;

                /* 只要文件存在就用 */
                if (ctx.fail_usecache == 0) {
                    goto do_cachefile;
                }

                ngx_time_update();
                now = (int)ngx_time();

                dd("fail-usecache now: %d, mtime: %d, diff: %d, pref: %d.",
                        now, (int)file->info.st_mtime, now - (int)file->info.st_mtime, (int)ctx.fail_usecache);

                if (now - file->info.st_mtime <= ctx.fail_usecache) {
                    goto do_cachefile;
                }
            }
        } else {
            /* 不可能 */

            rv = NULL;
            goto error;
        }
    }

    rv = NULL;
    goto error;

save_cachefile:
    {
        int rc;

        ctx.cachefile->fd = ngx_open_file(ctx.cachefile->name.data, O_WRONLY, O_CREAT | O_TRUNC , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);

        if (ctx.cachefile->fd == NGX_INVALID_FILE) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: open (%V) error: \"%s\".",
                    cmd_name, &ctx.cachefile->name, strerror(errno));

            rv = NULL;
            goto error;
        }

        dd("open cachefd: %s, %d", (char *)ctx.cachefile->name.data, ctx.cachefile->fd);

        rc = ngx_write_fd(ctx.cachefile->fd, ctx.fetch_content->data, ctx.fetch_content->len);
        if (rc == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: write data to (%V) error: \"%s\".",
                    cmd_name, ctx.cachefile->name, strerror(errno));

            rv = NULL;
            goto error;
        } else if ((size_t)rc != ctx.fetch_content->len) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%V: write data to (%V) incomplete: %z of %uz.",
                    cmd_name, ctx.cachefile->name, rc, ctx.fetch_content->len);

            rv = NULL;
            goto error;
        }

        if (ngx_close_file(ctx.cachefile->fd) == NGX_FILE_ERROR) {
            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                    "%: close cachefile error.",
                    cmd_name);

            rv = NULL;
            goto error;
        }

        goto do_cachefile;
    }

do_cachefile:
    if (! scheme->usecache) {
        ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                "%V: current scheme \"%V\" can not usecache.",
                cmd_name, &scheme->name);

        rv = NULL;
        goto error;
    }

    dd("do cachefile");
    rv = ngx_conf_parse(cf, &ctx.cachefile->name);

    if (rv != NGX_CONF_OK) {
        ngx_log_error(NGX_LOG_WARN, cf->log, 0,
                "%V: do cachefile \"%V\" error.",
                cmd_name, &ctx.cachefile->name);

        /* 删除解析出错的 cachefile */
        if (! ctx.keep_error_cachefile) {
            if (ngx_delete_file(ctx.cachefile->name.data) == NGX_FILE_ERROR) {
                    ngx_log_error(NGX_LOG_WARN, cf->log, 0,
                            "%V: delete cachefile \"%V\" error.",
                            cmd_name, &ctx.cachefile->name);
            }
        }

        goto error;
    }

    goto done;

done:
    lua_close(L);

    return NGX_CONF_OK;

unknow_opt:
    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
            "%V: unknown option [%V].",
            cmd_name, &arg[i]);

    return NGX_CONF_ERROR;

error:
    lua_close(L);

    return rv == NULL ? NGX_CONF_ERROR : rv;
}
Beispiel #18
0
char *
ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    off_t                   max_size;
    u_char                 *last, *p;
    time_t                  inactive;
    ssize_t                 size;
    ngx_str_t               s, name, *value;
    ngx_uint_t              i, n;
    ngx_http_file_cache_t  *cache;

    cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
    if (cache == NULL) {
        return NGX_CONF_ERROR;
    }

    cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
    if (cache->path == NULL) {
        return NGX_CONF_ERROR;
    }

    inactive = 600;

    name.len = 0;
    size = 0;
    max_size = NGX_MAX_OFF_T_VALUE;

    value = cf->args->elts;

    cache->path->name = value[1];

    if (cache->path->name.data[cache->path->name.len - 1] == '/') {
        cache->path->name.len--;
    }

    if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

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

        if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {

            p = value[i].data + 7;
            last = value[i].data + value[i].len;

            for (n = 0; n < 3 && p < last; n++) {

                if (*p > '0' && *p < '3') {

                    cache->path->level[n] = *p++ - '0';
                    cache->path->len += cache->path->level[n] + 1;

                    if (p == last) {
                        break;
                    }

                    if (*p++ == ':' && n < 2 && p != last) {
                        continue;
                    }

                    goto invalid_levels;
                }

                goto invalid_levels;
            }

            if (cache->path->len < 10 + 3) {
                continue;
            }

        invalid_levels:

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid \"levels\" \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

        if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {

            name.data = value[i].data + 10;

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p) {
                *p = '\0';

                name.len = p - name.data;

                p++;

                s.len = value[i].data + value[i].len - p;
                s.data = p;

                size = ngx_parse_size(&s);
                if (size > 8191) {
                    continue;
                }
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid keys zone size \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

        if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {

            s.len = value[i].len - 9;
            s.data = value[i].data + 9;

            inactive = ngx_parse_time(&s, 1);
            if (inactive < 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid inactive value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) {

            s.len = value[i].len - 9;
            s.data = value[i].data + 9;

            max_size = ngx_parse_offset(&s);
            if (max_size < 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid max_size value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

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

    if (name.len == 0 || size == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"keys_zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    cache->path->manager = ngx_http_file_cache_manager;
    cache->path->loader = ngx_http_file_cache_loader;
    cache->path->data = cache;

    if (ngx_add_path(cf, &cache->path) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
    if (cache->shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

    if (cache->shm_zone->data) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "duplicate zone \"%V\"", &name);
        return NGX_CONF_ERROR;
    }


    cache->shm_zone->init = ngx_http_file_cache_init;
    cache->shm_zone->data = cache;

    cache->inactive = inactive;
    cache->max_size = max_size;

    return NGX_CONF_OK;
}
static char *
ngx_tcp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_tcp_core_srv_conf_t    *cscf = conf;

    size_t                      len, off;
    in_port_t                   port;
    ngx_str_t                  *value,size;
    ngx_url_t                   u;
    ngx_uint_t                  i;
    struct sockaddr            *sa;
    ngx_tcp_listen_t          *lsopt;
    struct sockaddr_in         *sin;
    ngx_tcp_core_main_conf_t  *cmcf;

    cscf->listen = 1;

    value = cf->args->elts;

    ngx_memzero(&u, sizeof(ngx_url_t));

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

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

        return NGX_CONF_ERROR;
    }

    cmcf = ngx_tcp_conf_get_module_main_conf(cf, ngx_tcp_core_module);

    lsopt = cmcf->listen.elts;

    for (i = 0; i < cmcf->listen.nelts; i++) {

        sa = (struct sockaddr *) lsopt[i].sockaddr;

        if (sa->sa_family != u.family) {
            continue;
        }

        switch (sa->sa_family) {

        //no care NGX_HAVE_INET6/NGX_HAVE_UNIX_DOMAIN

        default: /* AF_INET */
            off = offsetof(struct sockaddr_in, sin_addr);
            len = 4;
            sin = (struct sockaddr_in *) sa;
            port = htons(sin->sin_port);
            break;
        }

        if (ngx_memcmp(lsopt[i].sockaddr + off, u.sockaddr + off, len) != 0) {
            //continue;/*暂时严格端口不重复*/
        }

        if (port != u.port) {
            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "duplicate \"%V\" address and port pair", &u.url);
        return NGX_CONF_ERROR;
    }

    lsopt = ngx_array_push(&cmcf->listen);
    if (lsopt == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(lsopt, sizeof(ngx_tcp_listen_t));

    ngx_memcpy(lsopt->sockaddr, u.sockaddr, u.socklen);

    lsopt->socklen = u.socklen;
    lsopt->wildcard = u.wildcard;
    lsopt->ctx = cf->ctx;
    lsopt->backlog = NGX_LISTEN_BACKLOG;
    lsopt->rcvbuf = -1;
    lsopt->sndbuf = -1;

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

        if (ngx_strcmp(value[i].data, "bind") == 0) {
            lsopt->bind = 1;
            continue;
        }
        
        if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
            lsopt->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
            lsopt->bind = 1;

            if (lsopt->backlog == NGX_ERROR || lsopt->backlog == 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid backlog \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

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

            lsopt->rcvbuf = ngx_parse_size(&size);
            lsopt->bind = 1;

            if (lsopt->rcvbuf == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid rcvbuf \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

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

            lsopt->sndbuf = ngx_parse_size(&size);
            lsopt->bind = 1;

            if (lsopt->sndbuf == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid sndbuf \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

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

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

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

            } else {

#if (NGX_HAVE_KEEPALIVE_TUNABLE)
                u_char     *p, *end;
                ngx_str_t   s;

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

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

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

                    lsopt->tcp_keepidle = ngx_parse_time(&s, 1);
                    if (lsopt->tcp_keepidle == (time_t) NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

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

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

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

                    lsopt->tcp_keepintvl = ngx_parse_time(&s, 1);
                    if (lsopt->tcp_keepintvl == (time_t) NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

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

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

                    lsopt->tcp_keepcnt = ngx_atoi(s.data, s.len);
                    if (lsopt->tcp_keepcnt == NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

                if (lsopt->tcp_keepidle == 0 && lsopt->tcp_keepintvl == 0
                    && lsopt->tcp_keepcnt == 0)
                {
                    goto invalid_so_keepalive;
                }

                lsopt->so_keepalive = 1;

#else

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

#endif
            }

            lsopt->bind = 1;

            continue;

#if (NGX_HAVE_KEEPALIVE_TUNABLE)
        invalid_so_keepalive:

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid so_keepalive value: \"%s\"",
                               &value[i].data[13]);
            return NGX_CONF_ERROR;
#endif
        }
        
        if (ngx_strcmp(value[i].data, "deferred") == 0) {
#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
            lsopt->deferred_accept = 1;
            lsopt->bind = 1;
#else
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "the deferred accept is not supported "
                               "on this platform, ignored");
#endif
            continue;
        }

        if (ngx_strcmp(value[i].data, "ssl") == 0) {
#if (NGX_TCP_SSL)
            lsopt->ssl = 1;
            continue;
#else
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "the \"ssl\" parameter requires "
                               "ngx_tcp_ssl_module");
            return NGX_CONF_ERROR;
#endif
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "the invalid \"%V\" parameter", &value[i]);
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
/*
 *	Q:	怎样找到函数中创建的 ngx_http_file_cache_t?
 *	A:	1. 可以通过path中的data字段找到此cache
 *		2. 通过共享内存区 shm_zone.data 字段找到
 */
char *
ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    off_t                   max_size;				//	cache磁盘空间大小
    u_char                 *last, *p;
    time_t                  inactive;				//	cache不活跃的时间
    ssize_t                 size;					//	共享内存区的大小(必须大于8k)
    ngx_str_t               s, name, *value;		//	name: 共享内存区的名称
    ngx_int_t               loader_files;
    ngx_msec_t              loader_sleep, loader_threshold;
    ngx_uint_t              i, n;
    ngx_http_file_cache_t  *cache;

    cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
    if (cache == NULL) {
        return NGX_CONF_ERROR;
    }

    cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
    if (cache->path == NULL) {
        return NGX_CONF_ERROR;
    }

    inactive = 600;							//	不活跃时间默认是10分钟
    loader_files = 100;
    loader_sleep = 50;
    loader_threshold = 200;

    name.len = 0;
    size = 0;
    max_size = NGX_MAX_OFF_T_VALUE;

    value = cf->args->elts;

	//	cache路径, 如果以"/"结尾将被自动去掉
    cache->path->name = value[1];			

    if (cache->path->name.data[cache->path->name.len - 1] == '/') {
        cache->path->name.len--;
    }

	//	获取cache的完整路径
    if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) {
        return NGX_CONF_ERROR;
    }


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

		//	设置子目录数和子目录的文件名长度
        if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {

            p = value[i].data + 7;
            last = value[i].data + value[i].len;

            for (n = 0; n < 3 && p < last; n++) {

                if (*p > '0' && *p < '3') {

                    cache->path->level[n] = *p++ - '0';
                    cache->path->len += cache->path->level[n] + 1;

                    if (p == last) {
                        break;
                    }

                    if (*p++ == ':' && n < 2 && p != last) {
                        continue;
                    }

                    goto invalid_levels;
                }

                goto invalid_levels;
            }

            if (cache->path->len < 10 + 3) {
                continue;
            }

        invalid_levels:

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid \"levels\" \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }


		//	设置cache的共享存储区
        if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {

            name.data = value[i].data + 10;					//	共享内存区的名字

            p = (u_char *) ngx_strchr(name.data, ':');

            if (p) {
                *p = '\0';

                name.len = p - name.data;					//	共享内存区的名字长度

                p++;

                s.len = value[i].data + value[i].len - p;	//	共享内存区的大小
                s.data = p;

                size = ngx_parse_size(&s);					//	申请的共享内存区大小(必须大于8K)
                if (size > 8191) {							
                    continue;
                }
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid keys zone size \"%V\"", &value[i]);
            return NGX_CONF_ERROR;
        }

		//	设置cache不活跃的时间
        if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {

            s.len = value[i].len - 9;
            s.data = value[i].data + 9;

            inactive = ngx_parse_time(&s, 1);
            if (inactive == (time_t) NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid inactive value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }


		//	设置缓存磁盘空间大小 max_size
        if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) {

            s.len = value[i].len - 9;
            s.data = value[i].data + 9;

            max_size = ngx_parse_offset(&s);
            if (max_size < 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid max_size value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }


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

            loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);
            if (loader_files == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid loader_files value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

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

            s.len = value[i].len - 13;
            s.data = value[i].data + 13;

            loader_sleep = ngx_parse_time(&s, 0);
            if (loader_sleep == (ngx_msec_t) NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid loader_sleep value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }


		//	loader_threshold
        if (ngx_strncmp(value[i].data, "loader_threshold=", 17) == 0) {

            s.len = value[i].len - 17;
            s.data = value[i].data + 17;

            loader_threshold = ngx_parse_time(&s, 0);
            if (loader_threshold == (ngx_msec_t) NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid loader_threshold value \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid parameter \"%V\"", &value[i]);
        return NGX_CONF_ERROR;
    }	//	for

    if (name.len == 0 || size == 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%V\" must have \"keys_zone\" parameter",
                           &cmd->name);
        return NGX_CONF_ERROR;
    }

    cache->path->manager = ngx_http_file_cache_manager;
    cache->path->loader = ngx_http_file_cache_loader;
    cache->path->data = cache;								//	设置 ngx_http_file_cache_t 结构
    cache->path->conf_file = cf->conf_file->file.name.data;
    cache->path->line = cf->conf_file->line;
    cache->loader_files = loader_files;
    cache->loader_sleep = loader_sleep;
    cache->loader_threshold = loader_threshold;

	//	添加目录到系统管理目录表中
    if (ngx_add_path(cf, &cache->path) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

	//	添加共享内存到系统管理表中
    cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
    if (cache->shm_zone == NULL) {
        return NGX_CONF_ERROR;
    }

	/*	e.g. "proxy_cache" 与 "proxy_cache_path" 这两个指令的使用是有顺序的, 
			 "proxy_cache" 指令仅初始化共享内存信息,cache->shm_zone->data字段设置为NULL,
			  如果data字段被设置,说明重复定义了共享内存区	*/
    if (cache->shm_zone->data) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "duplicate zone \"%V\"", &name);
        return NGX_CONF_ERROR;
    }


    cache->shm_zone->init = ngx_http_file_cache_init;
    cache->shm_zone->data = cache;

    cache->inactive = inactive;
    cache->max_size = max_size;

    return NGX_CONF_OK;
}
Beispiel #21
0
static char *
ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_mail_core_srv_conf_t  *cscf = conf;

    size_t                      len, off;
    in_port_t                   port;
    ngx_str_t                  *value;
    ngx_url_t                   u;
    ngx_uint_t                  i, m;
    struct sockaddr            *sa;
    ngx_mail_listen_t          *ls;
    ngx_mail_module_t          *module;
    struct sockaddr_in         *sin;
    ngx_mail_core_main_conf_t  *cmcf;
#if (NGX_HAVE_INET6)
    struct sockaddr_in6        *sin6;
#endif

    value = cf->args->elts;

    ngx_memzero(&u, sizeof(ngx_url_t));

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

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

        return NGX_CONF_ERROR;
    }

    cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);

    ls = cmcf->listen.elts;

    for (i = 0; i < cmcf->listen.nelts; i++) {

        sa = (struct sockaddr *) ls[i].sockaddr;

        if (sa->sa_family != u.family) {
            continue;
        }

        switch (sa->sa_family) {

#if (NGX_HAVE_INET6)
        case AF_INET6:
            off = offsetof(struct sockaddr_in6, sin6_addr);
            len = 16;
            sin6 = (struct sockaddr_in6 *) sa;
            port = ntohs(sin6->sin6_port);
            break;
#endif

#if (NGX_HAVE_UNIX_DOMAIN)
        case AF_UNIX:
            off = offsetof(struct sockaddr_un, sun_path);
            len = sizeof(((struct sockaddr_un *) sa)->sun_path);
            port = 0;
            break;
#endif

        default: /* AF_INET */
            off = offsetof(struct sockaddr_in, sin_addr);
            len = 4;
            sin = (struct sockaddr_in *) sa;
            port = ntohs(sin->sin_port);
            break;
        }

        if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) {
            continue;
        }

        if (port != u.port) {
            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "duplicate \"%V\" address and port pair", &u.url);
        return NGX_CONF_ERROR;
    }

    ls = ngx_array_push(&cmcf->listen);
    if (ls == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(ls, sizeof(ngx_mail_listen_t));

    ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen);

    ls->socklen = u.socklen;
    ls->wildcard = u.wildcard;
    ls->ctx = cf->ctx;

#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
    ls->ipv6only = 1;
#endif

    if (cscf->protocol == NULL) {
        for (m = 0; ngx_modules[m]; m++) {
            if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
                continue;
            }

            module = ngx_modules[m]->ctx;

            if (module->protocol == NULL) {
                continue;
            }

            for (i = 0; module->protocol->port[i]; i++) {
                if (module->protocol->port[i] == u.port) {
                    cscf->protocol = module->protocol;
                    break;
                }
            }
        }
    }

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

        if (ngx_strcmp(value[i].data, "bind") == 0) {
            ls->bind = 1;
            continue;
        }

        if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
            struct sockaddr  *sa;
            u_char            buf[NGX_SOCKADDR_STRLEN];

            sa = (struct sockaddr *) ls->sockaddr;

            if (sa->sa_family == AF_INET6) {

                if (ngx_strcmp(&value[i].data[10], "n") == 0) {
                    ls->ipv6only = 1;

                } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
                    ls->ipv6only = 0;

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

                ls->bind = 1;

            } else {
                len = ngx_sock_ntop(sa, ls->socklen, buf,
                                    NGX_SOCKADDR_STRLEN, 1);

                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "ipv6only is not supported "
                                   "on addr \"%*s\", ignored", len, buf);
            }

            continue;
#else
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "bind ipv6only is not supported "
                               "on this platform");
            return NGX_CONF_ERROR;
#endif
        }

        if (ngx_strcmp(value[i].data, "ssl") == 0) {
#if (NGX_MAIL_SSL)
            ls->ssl = 1;
            continue;
#else
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "the \"ssl\" parameter requires "
                               "ngx_mail_ssl_module");
            return NGX_CONF_ERROR;
#endif
        }

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

            if (ngx_strcmp(&value[i].data[13], "on") == 0) {
                ls->so_keepalive = 1;

            } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
                ls->so_keepalive = 2;

            } else {

#if (NGX_HAVE_KEEPALIVE_TUNABLE)
                u_char     *p, *end;
                ngx_str_t   s;

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

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

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

                    ls->tcp_keepidle = ngx_parse_time(&s, 1);
                    if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

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

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

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

                    ls->tcp_keepintvl = ngx_parse_time(&s, 1);
                    if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

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

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

                    ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
                    if (ls->tcp_keepcnt == NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

                if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
                    && ls->tcp_keepcnt == 0)
                {
                    goto invalid_so_keepalive;
                }

                ls->so_keepalive = 1;

#else

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

#endif
            }

            ls->bind = 1;

            continue;

#if (NGX_HAVE_KEEPALIVE_TUNABLE)
        invalid_so_keepalive:

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

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "the invalid \"%V\" parameter", &value[i]);
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
Beispiel #22
0
static ngx_int_t ngx_http_shmtest_add_or_update(ngx_http_request_t *r,int func){
	ngx_int_t rc = NGX_HTTP_OK;
	ngx_str_t key = ngx_null_string;
	int32_t ikey = 0;
	ngx_str_t value = ngx_null_string;
 	char* szFunc = funcs[func];
	
	if(ngx_http_arg(r, (u_char*)"key", 3, &key)!=NGX_OK){
		NLOG_ERROR("get arg 'key' failed!");
		return NGX_HTTP_BAD_REQUEST;
	}

	if(ngx_http_arg(r, (u_char*)"value", 5, &value)!=NGX_OK){
		NLOG_ERROR("get arg 'value' failed!");
		return NGX_HTTP_BAD_REQUEST;
	}

	//如果key开始为0x 表示使用数字的KEY.
	if(key.len > 2 && key.data[0] == '0' &&	key.data[1] == 'x'){
		key.data += 2;
		key.len -= 2;
		ikey = ngx_hextoi(key.data, key.len);
		ngx_str_set_int32(&key, &ikey);
		NLOG_DEBUG("use int key ikey=%d", ikey);
	}
	
	uint64_t exptime = 0;
	ngx_str_t sexptime = ngx_null_string;
	if(ngx_http_arg(r, (u_char*)"exptime", 7, &sexptime)==NGX_OK){
		exptime = ngx_parse_time(&sexptime, 1);
	}

	if(ikey != 0){
		NLOG_DEBUG("%s(key=%d,value=%V,exptime=%d)", szFunc,ikey,&value,exptime);
	}else{
		NLOG_DEBUG("%s(key=%V,value=%V,exptime=%d)", szFunc,&key,&value,exptime);
	}
	shmtest_main_conf_t* smcf;
	smcf = ngx_http_get_module_main_conf(r, ngx_http_shmtest_module);
	if(smcf == NULL){
		NLOG_ERROR("get module ngx_http_shmtest_module's main conf failed!");
		return NGX_HTTP_INTERNAL_SERVER_ERROR;
	}

	ngx_shm_zone_t* zone = smcf->shmap;
	
	int ret = 0;
	switch(func){
	case FUNC_ADD:
		ret = ngx_shmap_add(zone, &key,&value,VT_STRING,exptime,0);
	break;
	case FUNC_SET:
		ret = ngx_shmap_set(zone, &key,&value,VT_STRING,exptime,0);
	break;
	case FUNC_REPLACE:
		ret = ngx_shmap_replace(zone, &key,&value,VT_STRING,exptime,0);
	break;
	default:
		NLOG_ERROR("un process type [%d]", func);
		return NGX_HTTP_BAD_REQUEST;
	}

	char* rsp = ngx_pcalloc(r->connection->pool, 256);
	int rsp_len = 0;
	if(ret == 0){
		rsp_len = sprintf(rsp, "%s success!\n", szFunc);
	}else{
		rsp_len = sprintf(rsp, "%s failed!\n", szFunc);
	}

	ngx_chain_t* chain = ngx_http_shmtest_resp(r, rsp, rsp_len);
	if(chain != NULL){
	    r->headers_out.content_length_n = rsp_len;
	}else{
		r->headers_out.content_length_n = 0;
	}

    rc = ngx_http_send_header(r);

    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        
    }else{
    	rc = ngx_http_output_filter(r, chain);
    }

	return rc;
}
/*
 * access_log off;
 * access_log file;
 * access_log file format_name;
 * access_log file trunc=1m;
 * access_log file format_name trunc=1m;
 */
static char *
ngx_rtmp_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_rtmp_log_app_conf_t    *lacf = conf;

    ngx_rtmp_log_main_conf_t   *lmcf;
    ngx_rtmp_log_fmt_t         *fmt;
    ngx_rtmp_log_t             *log;
    ngx_str_t                  *value, name, timer;
    ngx_uint_t                  n;
    ngx_flag_t                  format_configured;

    name.len = 0;
    format_configured = 0;

    value = cf->args->elts;

    if (ngx_strcmp(value[1].data, "off") == 0) {
        lacf->off = 1;
        return NGX_CONF_OK;
    }

    if (lacf->logs == NULL) {
        lacf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_rtmp_log_t));
        if (lacf->logs == NULL) {
            return NGX_CONF_ERROR;
        }
    }

    log = ngx_array_push(lacf->logs);
    if (log == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(log, sizeof(*log));

    lmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_log_module);

    log->file = ngx_conf_open_file(cf->cycle, &value[1]);
    if (log->file == NULL) {
        return NGX_CONF_ERROR;
    }

    for (n = 2; n < cf->args->nelts; ++n) {
        /* sizeof("trunc=") - 1 = 6 */
        if (ngx_memcmp("trunc=", value[n].data, 6) == 0) {
            timer.data = value[n].data + 6;
            timer.len = value[n].len - 6;

            log->trunc_timer = ngx_parse_time(&timer, 0);
            if (log->trunc_timer == (ngx_msec_t) NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                        "unknown trunc timer format \"%V\"", &timer);
                return NGX_CONF_ERROR;
            }
        } else {
            if (format_configured) {
                ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                        "format name has been configured");
                return NGX_CONF_ERROR;
            }

            format_configured = 1;
            name = value[n];
        }
    }

    if (name.len == 0) {
        ngx_str_set(&name, "combined");
        lmcf->combined_used = 1;

    } else {
        if (ngx_strcmp(name.data, "combined") == 0) {
            lmcf->combined_used = 1;
        }
    }

    fmt = lmcf->formats.elts;
    for (n = 0; n < lmcf->formats.nelts; ++n, ++fmt) {
        if (fmt->name.len == name.len &&
            ngx_strncasecmp(fmt->name.data, name.data, name.len) == 0)
        {
            log->format = fmt;
            break;
        }
    }

    if (log->format == NULL) {
        ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "unknown log format \"%V\"",
                           &name);
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
ngx_resolver_t *
ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
{
    ngx_str_t              s;
    ngx_url_t              u;
    ngx_uint_t             i;
    ngx_resolver_t        *r;
    ngx_pool_cleanup_t    *cln;
    ngx_udp_connection_t  *uc;

    cln = ngx_pool_cleanup_add(cf->pool, 0);
    if (cln == NULL) {
        return NULL;
    }

    cln->handler = ngx_resolver_cleanup;

    r = ngx_calloc(sizeof(ngx_resolver_t), cf->log);
    if (r == NULL) {
        return NULL;
    }

    if (n) {
        if (ngx_array_init(&r->udp_connections, cf->pool, n,
                           sizeof(ngx_udp_connection_t))
            != NGX_OK)
        {
            return NULL;
        }
    }

    cln->data = r;

    r->event = ngx_calloc(sizeof(ngx_event_t), cf->log);
    if (r->event == NULL) {
        return NULL;
    }

    ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel,
                    ngx_resolver_rbtree_insert_value);

    ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
                    ngx_rbtree_insert_value);

    ngx_queue_init(&r->name_resend_queue);
    ngx_queue_init(&r->addr_resend_queue);

    ngx_queue_init(&r->name_expire_queue);
    ngx_queue_init(&r->addr_expire_queue);

    r->event->handler = ngx_resolver_resend_handler;
    r->event->data = r;
    r->event->log = &cf->cycle->new_log;
    r->ident = -1;

    r->resend_timeout = 5;
    r->expire = 30;
    r->valid = 0;

    r->log = &cf->cycle->new_log;
    r->log_level = NGX_LOG_ERR;

    for (i = 0; i < n; i++) {
        if (ngx_strncmp(names[i].data, "valid=", 6) == 0) {
            s.len = names[i].len - 6;
            s.data = names[i].data + 6;

            r->valid = ngx_parse_time(&s, 1);

            if (r->valid == NGX_ERROR) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid parameter: %V", &names[i]);
                return NULL;
            }

            continue;
        }

        ngx_memzero(&u, sizeof(ngx_url_t));

        u.host = names[i];
        u.port = 53;

        if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err);
            return NULL;
        }

        uc = ngx_array_push(&r->udp_connections);
        if (uc == NULL) {
            return NULL;
        }

        ngx_memzero(uc, sizeof(ngx_udp_connection_t));

        uc->sockaddr = u.addrs->sockaddr;
        uc->socklen = u.addrs->socklen;
        uc->server = u.addrs->name;

        uc->log = cf->cycle->new_log;
        uc->log.handler = ngx_resolver_log_error;
        uc->log.data = uc;
        uc->log.action = "resolving";
    }

    return r;
}
static char *ngx_http_upstream_resolveMK(ngx_conf_t *cf, ngx_command_t *cmd,
    void *conf)
{
	ngx_http_upstream_srv_conf_t *uscf;
	ngx_http_upstream_resolveMK_srv_conf_t *urcf;
	ngx_http_upstream_server_t *us;

	time_t interval;
	ngx_str_t *value, domain, s;
	ngx_int_t max_ip;
	ngx_uint_t retry;
	ngx_http_upstream_resolveMK_peer_t *paddr;
	ngx_url_t u;
	ngx_uint_t i;

	interval = 10;
	max_ip = 20;
	retry = 1;
	domain.data = NULL;
	domain.len = 0;
	uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);

	/* Just For Padding, upstream { } need it */
	if (uscf->servers == NULL) {
		uscf->servers = ngx_array_create(cf->pool, 1,
		                                 sizeof(ngx_http_upstream_server_t));

		if (uscf->servers == NULL) {
			return NGX_CONF_ERROR;
		}
	}

	us = ngx_array_push(uscf->servers);

	if (us == NULL) {
		return NGX_CONF_ERROR;
	}

	ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
	urcf = ngx_http_conf_upstream_srv_conf(uscf,
	                                       ngx_http_upstream_resolveMK_module);
	uscf->peer.init_upstream = ngx_http_upstream_resolveMK_init;
	value = cf->args->elts;

	if (value[1].len == 0) {
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
		                   "domain is not given");

		return NGX_CONF_ERROR;
	}

	domain.data = value[1].data;
	domain.len  = value[1].len;

	if (ngx_strncmp(value[2].data, "service=", 8) != 0) {
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
		                   "service is not given");

		return NGX_CONF_ERROR;
	}

	urcf->resolver_service.len = value[2].len - 8;
	urcf->resolver_service.data = &value[2].data[8];

	for (i = 3; i < cf->args->nelts; i++) {

		if (ngx_strncmp(value[i].data, "interval=", 9) == 0) {
			s.len = value[i].len - 9;
			s.data = &value[i].data[9];
			interval = ngx_parse_time(&s, 1);

			if (interval == (time_t) NGX_ERROR) {
				goto invalid;
			}

			continue;
		}

		if (ngx_strncmp(value[i].data, "max_ip=", 7) == 0) {
			max_ip = ngx_atoi(value[i].data + 7, value[i].len - 7);

			if (max_ip == NGX_ERROR || max_ip < 1) {
				goto invalid;
			}

			continue;
		}

		if (ngx_strncmp(value[i].data, "retry_off", 9) == 0) {
			retry = 0;
			continue;
		}

		goto invalid;
	}

	urcf->peers = ngx_pcalloc(cf->pool,
	                          max_ip * sizeof(ngx_http_upstream_resolveMK_peer_t));

	if (urcf->peers == NULL) {
		ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
		                   "ngx_palloc peers fail");
		return NGX_CONF_ERROR;
	}

	urcf->resolver_interval = interval;
	urcf->resolver_domain = domain;
	urcf->resolver_max_ip = max_ip;
	urcf->upstream_retry = retry;
	ngx_memzero(&u, sizeof(ngx_url_t));
	u.url = value[1];

	if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
		if (u.err) {
			ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
			                   "%s in upstream \"%V\"", u.err, &u.url);
		}

		return NGX_CONF_ERROR;
	}

	urcf->resolved_num = 0;

	for (i = 0; i < u.naddrs ; i++) {
		paddr = &urcf->peers[urcf->resolved_num];
		paddr->sockaddr = *(struct sockaddr*)u.addrs[i].sockaddr;
		paddr->socklen = u.addrs[i].socklen;
		paddr->name = u.addrs[i].name;
		urcf->resolved_num++;

		if (urcf->resolved_num >= urcf->resolver_max_ip) {
			break;
		}
	}

	/* urcf->resolved_index = 0 */
	urcf->resolved_access = ngx_time();

	return NGX_CONF_OK;
invalid:
	ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
	                   "invalid parameter \"%V\"", &value[i]);

	return NGX_CONF_ERROR;
}
static char *
ngx_http_upstream_dynamic(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_upstream_srv_conf_t            *uscf;
    ngx_http_upstream_dynamic_srv_conf_t    *dcf;
    ngx_str_t   *value, s;
    ngx_uint_t   i;
    time_t       fail_timeout;
    ngx_int_t    fallback;

    uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);

    dcf = ngx_http_conf_upstream_srv_conf(uscf,
                                          ngx_http_upstream_dynamic_module);

    if (dcf->original_init_upstream) {
        return "is duplicate";
    }

    dcf->original_init_upstream = uscf->peer.init_upstream
                                  ? uscf->peer.init_upstream
                                  : ngx_http_upstream_init_round_robin;

    uscf->peer.init_upstream = ngx_http_upstream_init_dynamic;

    /* read options */

    value = cf->args->elts;

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

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

            s.len = value[i].len - 13;
            s.data = &value[i].data[13];

            fail_timeout = ngx_parse_time(&s, 1);

            if (fail_timeout == (time_t) NGX_ERROR) {
                return "invalid fail_timeout";
            }

            dcf->fail_timeout = fail_timeout;

            continue;
        }

        if (ngx_strncmp(value[i].data, "fallback=", 9) == 0) {

            s.len = value[i].len - 9;
            s.data = &value[i].data[9];

            if (ngx_strncmp(s.data, "next", 4) == 0) {
                fallback = NGX_HTTP_UPSTREAM_DYN_RESOLVE_NEXT;
            } else if (ngx_strncmp(s.data, "stale", 5) == 0) {
                fallback = NGX_HTTP_UPSTREAM_DYN_RESOLVE_STALE;
            } else if (ngx_strncmp(s.data, "shutdown", 8) == 0) {
                fallback = NGX_HTTP_UPSTREAM_DYN_RESOLVE_SHUTDOWN;
            } else {
                return "invalid fallback action";
            }

            dcf->fallback = fallback;

            continue;
        }
    }

    return NGX_CONF_OK;
}
static char *
ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_http_headers_conf_t *hcf = conf;

    ngx_uint_t   minus, n;
    ngx_str_t   *value;

    if (hcf->expires != NGX_CONF_UNSET_UINT) {
        return "is duplicate";
    }

    value = cf->args->elts;

    if (cf->args->nelts == 2) {

        if (ngx_strcmp(value[1].data, "epoch") == 0) {
            hcf->expires = NGX_HTTP_EXPIRES_EPOCH;
            return NGX_CONF_OK;
        }

        if (ngx_strcmp(value[1].data, "max") == 0) {
            hcf->expires = NGX_HTTP_EXPIRES_MAX;
            return NGX_CONF_OK;
        }

        if (ngx_strcmp(value[1].data, "off") == 0) {
            hcf->expires = NGX_HTTP_EXPIRES_OFF;
            return NGX_CONF_OK;
        }

        hcf->expires = NGX_HTTP_EXPIRES_ACCESS;

        n = 1;

    } else { /* cf->args->nelts == 3 */

        if (ngx_strcmp(value[1].data, "modified") != 0) {
            return "invalid value";
        }

        hcf->expires = NGX_HTTP_EXPIRES_MODIFIED;

        n = 2;
    }

    if (value[n].data[0] == '@') {
        value[n].data++;
        value[n].len--;
        minus = 0;

        if (hcf->expires == NGX_HTTP_EXPIRES_MODIFIED) {
            return "daily time can not be used with \"modified\" parameter";
        }

        hcf->expires = NGX_HTTP_EXPIRES_DAILY;

    } else if (value[n].data[0] == '+') {
        value[n].data++;
        value[n].len--;
        minus = 0;

    } else if (value[n].data[0] == '-') {
        value[n].data++;
        value[n].len--;
        minus = 1;

    } else {
        minus = 0;
    }

    hcf->expires_time = ngx_parse_time(&value[n], 1);

    if (hcf->expires_time == NGX_ERROR) {
        return "invalid value";
    }

    if (hcf->expires == NGX_HTTP_EXPIRES_DAILY
        && hcf->expires_time > 24 * 60 * 60)
    {
        return "daily time value must be less than 24 hours";
    }

    if (hcf->expires_time == NGX_PARSE_LARGE_TIME) {
        return "value must be less than 68 years";
    }

    if (minus) {
        hcf->expires_time = - hcf->expires_time;
    }

    return NGX_CONF_OK;
}
Beispiel #28
0
char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
                                  void *conf)
{
    char  *p = conf;

    ngx_uint_t             i, dup, invalid;
    ngx_str_t             *value, line;
    ngx_http_busy_lock_t  *bl, **blp;

    blp = (ngx_http_busy_lock_t **) (p + cmd->offset);
    if (*blp) {
        return "is duplicate";
    }

    /* ngx_calloc_shared() */
    bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t));
    if (bl == NULL) {
        return NGX_CONF_ERROR;
    }
    *blp = bl;

    /* ngx_calloc_shared() */
    bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t));
    if (bl->mutex == NULL) {
        return NGX_CONF_ERROR;
    }

    dup = 0;
    invalid = 0;
    value = cf->args->elts;

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

        if (value[i].data[1] != '=') {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid value \"%s\"", value[i].data);
            return NGX_CONF_ERROR;
        }

        switch (value[i].data[0]) {

        case 'b':
            if (bl->max_busy) {
                dup = 1;
                break;
            }

            bl->max_busy = ngx_atoi(value[i].data + 2, value[i].len - 2);
            if (bl->max_busy == NGX_ERROR) {
                invalid = 1;
                break;
            }

            continue;

        case 'w':
            if (bl->max_waiting) {
                dup = 1;
                break;
            }

            bl->max_waiting = ngx_atoi(value[i].data + 2, value[i].len - 2);
            if (bl->max_waiting == NGX_ERROR) {
                invalid = 1;
                break;
            }

            continue;

        case 't':
            if (bl->timeout) {
                dup = 1;
                break;
            }

            line.len = value[i].len - 2;
            line.data = value[i].data + 2;

            bl->timeout = ngx_parse_time(&line, 1);
            if (bl->timeout == NGX_ERROR) {
                invalid = 1;
                break;
            }

            continue;

        default:
            invalid = 1;
        }

        if (dup) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "duplicate value \"%s\"", value[i].data);
            return NGX_CONF_ERROR;
        }

        if (invalid) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "invalid value \"%s\"", value[i].data);
            return NGX_CONF_ERROR;
        }
    }

    if (bl->timeout == 0 && bl->max_waiting) {
        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
                           "busy lock waiting is useless with zero timeout, ignoring");
    }

    return NGX_CONF_OK;
}
Beispiel #29
0
char *
ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
    void *conf)
{
    char  *p = conf;

    time_t                    valid;
    ngx_str_t                *value;
    ngx_uint_t                i, n, status;
    ngx_array_t             **a;
    ngx_http_cache_valid_t   *v;
    static ngx_uint_t         statuses[] = { 200, 301, 302 };

    a = (ngx_array_t **) (p + cmd->offset);

    if (*a == NGX_CONF_UNSET_PTR) {
        *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_cache_valid_t));
        if (*a == NULL) {
            return NGX_CONF_ERROR;
        }
    }

    value = cf->args->elts;
    n = cf->args->nelts - 1;

    valid = ngx_parse_time(&value[n], 1);
    if (valid < 0) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "invalid time value \"%V\"", &value[n]);
        return NGX_CONF_ERROR;
    }

    if (n == 1) {

        for (i = 0; i < 3; i++) {
            v = ngx_array_push(*a);
            if (v == NULL) {
                return NGX_CONF_ERROR;
            }

            v->status = statuses[i];
            v->valid = valid;
        }

        return NGX_CONF_OK;
    }

    for (i = 1; i < n; i++) {

        if (ngx_strcmp(value[i].data, "any") == 0) {

            status = 0;

        } else {

            status = ngx_atoi(value[i].data, value[i].len);
            if (status < 100) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid status \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }
        }

        v = ngx_array_push(*a);
        if (v == NULL) {
            return NGX_CONF_ERROR;
        }

        v->status = status;
        v->valid = valid;
    }

    return NGX_CONF_OK;
}
// 解析stream/server{}里的listen指令,监听tcp端口
// 遍历已经添加的端口,如果重复则报错
// 检查其他参数,如bind/backlog等,但没有sndbuf/rcvbuf
static char *
ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    size_t                        len, off;
    in_port_t                     port;
    ngx_str_t                    *value;
    ngx_url_t                     u;
    ngx_uint_t                    i, backlog;
    struct sockaddr              *sa;
    struct sockaddr_in           *sin;
    ngx_stream_listen_t          *ls;
    ngx_stream_core_main_conf_t  *cmcf;
#if (NGX_HAVE_INET6)
    struct sockaddr_in6          *sin6;
#endif

    value = cf->args->elts;

    ngx_memzero(&u, sizeof(ngx_url_t));

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

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

        return NGX_CONF_ERROR;
    }

    // 获取stream core模块的main_conf,只有一个
    cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);

    // 准备添加监听端口
    ls = cmcf->listen.elts;

    // 遍历已经添加的端口,如果重复则报错
    for (i = 0; i < cmcf->listen.nelts; i++) {

        sa = &ls[i].u.sockaddr;

        if (sa->sa_family != u.family) {
            continue;
        }

        switch (sa->sa_family) {

#if (NGX_HAVE_INET6)
        case AF_INET6:
            off = offsetof(struct sockaddr_in6, sin6_addr);
            len = 16;
            sin6 = &ls[i].u.sockaddr_in6;
            port = sin6->sin6_port;
            break;
#endif

#if (NGX_HAVE_UNIX_DOMAIN)
        case AF_UNIX:
            off = offsetof(struct sockaddr_un, sun_path);
            len = sizeof(((struct sockaddr_un *) sa)->sun_path);
            port = 0;
            break;
#endif

        default: /* AF_INET */
            off = offsetof(struct sockaddr_in, sin_addr);
            len = 4;
            sin = &ls[i].u.sockaddr_in;
            port = sin->sin_port;
            break;
        }

        if (ngx_memcmp(ls[i].u.sockaddr_data + off, u.sockaddr + off, len)
            != 0)
        {
            continue;
        }

        if (port != u.port) {
            continue;
        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "duplicate \"%V\" address and port pair", &u.url);
        return NGX_CONF_ERROR;
    }

    // 向数组里添加一个ngx_stream_listen_t结构体
    ls = ngx_array_push(&cmcf->listen);
    if (ls == NULL) {
        return NGX_CONF_ERROR;
    }

    ngx_memzero(ls, sizeof(ngx_stream_listen_t));

    ngx_memcpy(&ls->u.sockaddr, u.sockaddr, u.socklen);

    // 从ngx_url_t里拷贝信息
    ls->socklen = u.socklen;
    ls->backlog = NGX_LISTEN_BACKLOG;
    ls->type = SOCK_STREAM;
    ls->wildcard = u.wildcard;

    // 注意这里,存储了cf->ctx,也就是此server的配置数组ngx_stream_conf_ctx_t
    ls->ctx = cf->ctx;

#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
    ls->ipv6only = 1;
#endif

    backlog = 0;

    // 检查其他参数,如bind/backlog等,但没有sndbuf/rcvbuf
    for (i = 2; i < cf->args->nelts; i++) {

        // 是否是udp协议,如果是udp那么type就是DGRAM,否则是STREAM
#if !(NGX_WIN32)
        if (ngx_strcmp(value[i].data, "udp") == 0) {
            ls->type = SOCK_DGRAM;
            continue;
        }
#endif

        if (ngx_strcmp(value[i].data, "bind") == 0) {
            ls->bind = 1;
            continue;
        }

        // tcp协议支持backlog选项
        if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
            ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
            ls->bind = 1;

            if (ls->backlog == NGX_ERROR || ls->backlog == 0) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "invalid backlog \"%V\"", &value[i]);
                return NGX_CONF_ERROR;
            }

            backlog = 1;

            continue;
        }

        if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
            u_char  buf[NGX_SOCKADDR_STRLEN];

            sa = &ls->u.sockaddr;

            if (sa->sa_family == AF_INET6) {

                if (ngx_strcmp(&value[i].data[10], "n") == 0) {
                    ls->ipv6only = 1;

                } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
                    ls->ipv6only = 0;

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

                ls->bind = 1;

            } else {
                len = ngx_sock_ntop(sa, ls->socklen, buf,
                                    NGX_SOCKADDR_STRLEN, 1);

                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "ipv6only is not supported "
                                   "on addr \"%*s\", ignored", len, buf);
            }

            continue;
#else
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "bind ipv6only is not supported "
                               "on this platform");
            return NGX_CONF_ERROR;
#endif
        }

        // reuseport选项,可以不用accept_mutex负载均衡
        if (ngx_strcmp(value[i].data, "reuseport") == 0) {
#if (NGX_HAVE_REUSEPORT)
            ls->reuseport = 1;
            ls->bind = 1;
#else
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "reuseport is not supported "
                               "on this platform, ignored");
#endif
            continue;
        }

        if (ngx_strcmp(value[i].data, "ssl") == 0) {
#if (NGX_STREAM_SSL)
            ls->ssl = 1;
            continue;
#else
            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "the \"ssl\" parameter requires "
                               "ngx_stream_ssl_module");
            return NGX_CONF_ERROR;
#endif
        }

        // tcp的keepalive
        if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {

            if (ngx_strcmp(&value[i].data[13], "on") == 0) {
                ls->so_keepalive = 1;

            } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
                ls->so_keepalive = 2;

            } else {

#if (NGX_HAVE_KEEPALIVE_TUNABLE)
                u_char     *p, *end;
                ngx_str_t   s;

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

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

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

                    ls->tcp_keepidle = ngx_parse_time(&s, 1);
                    if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

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

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

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

                    ls->tcp_keepintvl = ngx_parse_time(&s, 1);
                    if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

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

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

                    ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
                    if (ls->tcp_keepcnt == NGX_ERROR) {
                        goto invalid_so_keepalive;
                    }
                }

                if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
                    && ls->tcp_keepcnt == 0)
                {
                    goto invalid_so_keepalive;
                }

                ls->so_keepalive = 1;

#else

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

#endif
            }

            ls->bind = 1;

            continue;

#if (NGX_HAVE_KEEPALIVE_TUNABLE)
        invalid_so_keepalive:

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

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "the invalid \"%V\" parameter", &value[i]);
        return NGX_CONF_ERROR;
    }

    // udp协议做检查,有的选项不可用: backlog/ssl/so_keepalive
    if (ls->type == SOCK_DGRAM) {
        if (backlog) {
            return "\"backlog\" parameter is incompatible with \"udp\"";
        }

#if (NGX_STREAM_SSL)
        if (ls->ssl) {
            return "\"ssl\" parameter is incompatible with \"udp\"";
        }
#endif

        if (ls->so_keepalive) {
            return "\"so_keepalive\" parameter is incompatible with \"udp\"";
        }
    }

    return NGX_CONF_OK;
}