예제 #1
0
static ngx_int_t
ngx_stream_geoip_org_variable(ngx_stream_session_t *s,
                              ngx_stream_variable_value_t *v, uintptr_t data)
{
    size_t                    len;
    char                     *val;
    ngx_stream_geoip_conf_t  *gcf;

    gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module);

    if (gcf->org == NULL) {
        goto not_found;
    }

#if (NGX_HAVE_GEOIP_V6)
    val = gcf->org_v6
          ? GeoIP_name_by_ipnum_v6(gcf->org,
                                   ngx_stream_geoip_addr_v6(s, gcf))
          : GeoIP_name_by_ipnum(gcf->org,
                                ngx_stream_geoip_addr(s, gcf));
#else
    val = GeoIP_name_by_ipnum(gcf->org, ngx_stream_geoip_addr(s, gcf));
#endif

    if (val == NULL) {
        goto not_found;
    }

    len = ngx_strlen(val);
    v->data = ngx_pnalloc(s->connection->pool, len);
    if (v->data == NULL) {
        ngx_free(val);
        return NGX_ERROR;
    }

    ngx_memcpy(v->data, val, len);

    v->len = len;
    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;

    ngx_free(val);

    return NGX_OK;

not_found:

    v->not_found = 1;

    return NGX_OK;
}
static mrb_value ngx_stream_mrb_connection_init(mrb_state *mrb, mrb_value self)
{
  ngx_uint_t i;
  mrb_value upstream;
  ngx_stream_mruby_upstream_context *ctx;
  ngx_stream_upstream_main_conf_t *umcf;
  ngx_stream_upstream_srv_conf_t **usp;
  ngx_stream_mruby_internal_ctx_t *ictx = mrb->ud;
  ngx_stream_session_t *s = ictx->s;

  mrb_get_args(mrb, "o", &upstream);

  ctx = (ngx_stream_mruby_upstream_context *)DATA_PTR(self);
  if (ctx) {
    mrb_free(mrb, ctx);
  }
  DATA_TYPE(self) = &ngx_stream_mrb_upstream_context_type;
  DATA_PTR(self) = NULL;
  ctx = (ngx_stream_mruby_upstream_context *)mrb_malloc(mrb, sizeof(ngx_stream_mruby_upstream_context));

  ctx->upstream = upstream;
  ctx->target = NULL;
  ctx->peers = NULL;
  ctx->us = NULL;

  umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module);
  usp = umcf->upstreams.elts;

  for (i = 0; i < umcf->upstreams.nelts; i++) {
    if (ngx_strncasecmp(usp[i]->host.data, (u_char *)RSTRING_PTR(upstream), RSTRING_LEN(upstream)) == 0) {
      ctx->us = usp[i];
      ctx->peers = usp[i]->peer.data;
      if (ctx->peers->number > 1) {
        mrb_raise(mrb, E_RUNTIME_ERROR, "don't support multiple server config");
      }
      ctx->target = ctx->peers->peer;
      break;
    }
  }

  DATA_PTR(self) = ctx;

  if (ctx->us == NULL || ctx->peers == NULL) {
    mrb_raisef(mrb, E_RUNTIME_ERROR, "%S not found upstream config", upstream);
  }

  if (ctx->target == NULL) {
    mrb_raise(mrb, E_RUNTIME_ERROR, "not found server config in upstream");
  }

  return self;
}
예제 #3
0
ngx_stream_variable_value_t *
ngx_stream_get_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index)
{
    ngx_stream_variable_t        *v;
    ngx_stream_core_main_conf_t  *cmcf;

    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

    if (cmcf->variables.nelts <= index) {
        ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
                      "unknown variable index: %ui", index);
        return NULL;
    }

    if (s->variables[index].not_found || s->variables[index].valid) {
        return &s->variables[index];
    }

    v = cmcf->variables.elts;

    if (ngx_stream_variable_depth == 0) {
        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                      "cycle while evaluating variable \"%V\"",
                      &v[index].name);
        return NULL;
    }

    ngx_stream_variable_depth--;

    if (v[index].get_handler(s, &s->variables[index], v[index].data)
        == NGX_OK)
    {
        ngx_stream_variable_depth++;

        if (v[index].flags & NGX_STREAM_VAR_NOCACHEABLE) {
            s->variables[index].no_cacheable = 1;
        }

        return &s->variables[index];
    }

    ngx_stream_variable_depth++;

    s->variables[index].valid = 0;
    s->variables[index].not_found = 1;

    return NULL;
}
예제 #4
0
static ngx_int_t
ngx_stream_geoip_country_variable(ngx_stream_session_t *s,
                                  ngx_stream_variable_value_t *v, uintptr_t data)
{
    ngx_stream_geoip_variable_handler_pt     handler =
        ngx_stream_geoip_country_functions[data];
#if (NGX_HAVE_GEOIP_V6)
    ngx_stream_geoip_variable_handler_v6_pt  handler_v6 =
        ngx_stream_geoip_country_v6_functions[data];
#endif

    const char               *val;
    ngx_stream_geoip_conf_t  *gcf;

    gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module);

    if (gcf->country == NULL) {
        goto not_found;
    }

#if (NGX_HAVE_GEOIP_V6)
    val = gcf->country_v6
          ? handler_v6(gcf->country, ngx_stream_geoip_addr_v6(s, gcf))
          : handler(gcf->country, ngx_stream_geoip_addr(s, gcf));
#else
    val = handler(gcf->country, ngx_stream_geoip_addr(s, gcf));
#endif

    if (val == NULL) {
        goto not_found;
    }

    v->len = ngx_strlen(val);
    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;
    v->data = (u_char *) val;

    return NGX_OK;

not_found:

    v->not_found = 1;

    return NGX_OK;
}
예제 #5
0
ngx_stream_variable_value_t *
ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name,
    ngx_uint_t key)
{
    ngx_stream_variable_t        *v;
    ngx_stream_variable_value_t  *vv;
    ngx_stream_core_main_conf_t  *cmcf;

    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

    v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);

    if (v) {
        if (v->flags & NGX_STREAM_VAR_INDEXED) {
            return ngx_stream_get_flushed_variable(s, v->index);
        }

        if (ngx_stream_variable_depth == 0) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                          "cycle while evaluating variable \"%V\"", name);
            return NULL;
        }

        ngx_stream_variable_depth--;

        vv = ngx_palloc(s->connection->pool,
                        sizeof(ngx_stream_variable_value_t));

        if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
            ngx_stream_variable_depth++;
            return vv;
        }

        ngx_stream_variable_depth++;
        return NULL;
    }

    vv = ngx_palloc(s->connection->pool, sizeof(ngx_stream_variable_value_t));
    if (vv == NULL) {
        return NULL;
    }

    vv->not_found = 1;

    return vv;
}
예제 #6
0
void
ngx_stream_core_run_phases(ngx_stream_session_t *s)
{
    ngx_int_t                     rc;
    ngx_stream_phase_handler_t   *ph;
    ngx_stream_core_main_conf_t  *cmcf;

    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

    ph = cmcf->phase_engine.handlers;

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

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

        if (rc == NGX_OK) {
            return;
        }
    }
}
예제 #7
0
static GeoIPRecord *
ngx_stream_geoip_get_city_record(ngx_stream_session_t *s)
{
    ngx_stream_geoip_conf_t  *gcf;

    gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module);

    if (gcf->city) {
#if (NGX_HAVE_GEOIP_V6)
        return gcf->city_v6
               ? GeoIP_record_by_ipnum_v6(gcf->city,
                                          ngx_stream_geoip_addr_v6(s, gcf))
               : GeoIP_record_by_ipnum(gcf->city,
                                       ngx_stream_geoip_addr(s, gcf));
#else
        return GeoIP_record_by_ipnum(gcf->city, ngx_stream_geoip_addr(s, gcf));
#endif
    }

    return NULL;
}
// 在ngx_stream_optimize_servers里设置有连接发生时的回调函数
// 调用发生在ngx_event_accept.c:ngx_event_accept()
//
// 创建一个处理tcp的会话对象
// 要先检查限速和访问限制这两个功能模块
// 最后调用ngx_stream_init_session
// 创建ctx数组,用于存储模块的ctx数据
// 调用handler,处理tcp数据,收发等等
void
ngx_stream_init_connection(ngx_connection_t *c)
{
    int                           tcp_nodelay;
    u_char                        text[NGX_SOCKADDR_STRLEN];
    size_t                        len;
    ngx_int_t                     rc;
    ngx_uint_t                    i;
    struct sockaddr              *sa;
    ngx_stream_port_t            *port;
    struct sockaddr_in           *sin;
    ngx_stream_in_addr_t         *addr;
    ngx_stream_session_t         *s;
    ngx_stream_addr_conf_t       *addr_conf;
#if (NGX_HAVE_INET6)
    struct sockaddr_in6          *sin6;
    ngx_stream_in6_addr_t        *addr6;
#endif
    ngx_stream_core_srv_conf_t   *cscf;
    ngx_stream_core_main_conf_t  *cmcf;

    /* find the server configuration for the address:port */

    // 取监听同一端口的server信息
    port = c->listening->servers;

    if (port->naddrs > 1) {

        /*
         * There are several addresses on this port and one of them
         * is the "*:port" wildcard so getsockname() is needed to determine
         * the server address.
         *
         * AcceptEx() already gave this address.
         */

        if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
            ngx_stream_close_connection(c);
            return;
        }

        sa = c->local_sockaddr;

        switch (sa->sa_family) {

#if (NGX_HAVE_INET6)
        case AF_INET6:
            sin6 = (struct sockaddr_in6 *) sa;

            addr6 = port->addrs;

            /* the last address is "*" */

            for (i = 0; i < port->naddrs - 1; i++) {
                if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) {
                    break;
                }
            }

            addr_conf = &addr6[i].conf;

            break;
#endif

        default: /* AF_INET */
            sin = (struct sockaddr_in *) sa;

            addr = port->addrs;

            /* the last address is "*" */

            for (i = 0; i < port->naddrs - 1; i++) {
                if (addr[i].addr == sin->sin_addr.s_addr) {
                    break;
                }
            }

            addr_conf = &addr[i].conf;

            break;
        }

    } else {
        // 唯一监听端口的server
        // addr_conf就是端口所在的server的配置数组
        switch (c->local_sockaddr->sa_family) {

#if (NGX_HAVE_INET6)
        case AF_INET6:
            addr6 = port->addrs;
            addr_conf = &addr6[0].conf;
            break;
#endif

        default: /* AF_INET */
            addr = port->addrs;
            addr_conf = &addr[0].conf;
            break;
        }
    }

    // 创建一个处理tcp的会话对象
    s = ngx_pcalloc(c->pool, sizeof(ngx_stream_session_t));
    if (s == NULL) {
        ngx_stream_close_connection(c);
        return;
    }

    // 设置会话对象的标志
    s->signature = NGX_STREAM_MODULE;

    //设置会话正确的配置结构体
    // addr_conf就是端口所在的server的配置数组
    // 之后就可以用宏正确地获取模块的配置信息
    s->main_conf = addr_conf->ctx->main_conf;
    s->srv_conf = addr_conf->ctx->srv_conf;

    // 设置会话关联的连接对象
    s->connection = c;

    // 连接的data指针指向会话对象
    c->data = s;

    // 获取相关的core配置
    cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);

    ngx_set_connection_log(c, cscf->error_log);

    len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1);

    ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V",
                  c->number, len, text, &addr_conf->addr_text);

    // log的一些参数
    c->log->connection = c->number;
    c->log->handler = ngx_stream_log_error;
    c->log->data = s;
    c->log->action = "initializing connection";
    c->log_error = NGX_ERROR_INFO;

    // 一个stream{}块只能有一个main conf
    // 所以连接限速、访问限制的处理函数是相同的
    // 但配置参数每个server可以不同
    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

    // 是否有连接限速设置,在ngx_stream_limit_conn_module.c里设置
    if (cmcf->limit_conn_handler) {
        rc = cmcf->limit_conn_handler(s);

        if (rc != NGX_DECLINED) {
            ngx_stream_close_connection(c);
            return;
        }
    }

    // 是否有访问限制
    if (cmcf->access_handler) {
        rc = cmcf->access_handler(s);

        if (rc != NGX_OK && rc != NGX_DECLINED) {
            ngx_stream_close_connection(c);
            return;
        }
    }

    // 设置TCP_NODELAY,默认启用
    if (cscf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
        ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay");

        tcp_nodelay = 1;

        if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
                       (const void *) &tcp_nodelay, sizeof(int)) == -1)
        {
            ngx_connection_error(c, ngx_socket_errno,
                                 "setsockopt(TCP_NODELAY) failed");
            ngx_stream_close_connection(c);
            return;
        }

        c->tcp_nodelay = NGX_TCP_NODELAY_SET;
    }


#if (NGX_STREAM_SSL)
    {
        ngx_stream_ssl_conf_t  *sslcf;

        sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);

        if (addr_conf->ssl) {
            c->log->action = "SSL handshaking";

            if (sslcf->ssl.ctx == NULL) {
                ngx_log_error(NGX_LOG_ERR, c->log, 0,
                              "no \"ssl_certificate\" is defined "
                              "in server listening on SSL port");
                ngx_stream_close_connection(c);
                return;
            }

            ngx_stream_ssl_init_connection(&sslcf->ssl, c);
            return;
        }
    }
#endif

    // 创建ctx数组,用于存储模块的ctx数据
    // 调用handler,处理tcp数据,收发等等
    ngx_stream_init_session(c);
}
ngx_int_t
ngx_stream_upm_create_request(ngx_stream_session_t *s)
{
    ngx_int_t                        len, uri_len;
    ngx_str_t                        method, uri;
    ngx_buf_t                       *request_buf, *b;
    //ngx_stream_upm_ctx_t            *ctx;
    //ngx_stream_upstream_t           *u;
    ngx_stream_upm_main_conf_t      *ummcf;

    ummcf = ngx_stream_get_module_main_conf(s, ngx_stream_upm_module);
    //u = s->upstream;
    
    if (ummcf->request_prepared) {
        return NGX_OK;
    }

    if (ummcf->method.len) {
        method = ummcf->method;
    } else {
        method.data = (u_char *)"GET";
        method.len = 3;
    }
    //ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module);

    //GET xx_uri VERSION\r\n
    len = method.len + 1 + sizeof(ngx_stream_upm_http_version_11) - 1
          + sizeof(CRLF) - 1;
    
    uri_len = ummcf->um_url->uri.len;
    len += uri_len;
    uri = ummcf->um_url->uri;

    //Only one header:   "Connection: keep-alive\r\n";
    len += 24;
    
    //The end \r\n;
    len += 2;
    
    request_buf = &s->upstream->downstream_buf;
    b = request_buf;

    /* the request line */
    b->last = ngx_copy(b->last, method.data, method.len);
    *b->last++ = ' ';
    b->last = ngx_copy(b->last, uri.data, uri.len);

    /*default use the HTTP/1.1 */
    b->last = ngx_cpymem(b->last, ngx_stream_upm_http_version_11,
                             sizeof(ngx_stream_upm_http_version_11) - 1);
    
    b->last = ngx_copy(b->last, "Connection: keep-alive\r\n", 24);

    /* add "\r\n" at the header end */
    *b->last++ = CR; *b->last++ = LF;

    ngx_log_debug2(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
                   "stream upm header:%N\"%*s\"",
                   (size_t) (b->last - b->pos), b->pos);

    /*Currently without any body;*/
    b->flush = 1;
    return NGX_OK;
}
ngx_int_t
ngx_stream_upm_parse_resp_body(ngx_stream_session_t *s)
{
    int                              port, fail_timeout, max_fail, weight, ta[1024];
    char                            *upname, *host, *t;
    cJSON                           *jsroot, *service, *jinsts, *jinst, *tags;
    ngx_buf_t                       *b;
    ngx_uint_t                       i, j, p, st, sfound, ifound;
    ngx_conf_t                       cf;
    //ngx_pool_t                      *pool;
    ngx_array_t                     *servs, *upstreams;
    ngx_connection_t                *pc; 
    ngx_stream_upstream_t           *u;
    ngx_stream_upm_ctx_t            *ctx;
    ngx_stream_upm_service_t        *ums;
    ngx_stream_upm_main_conf_t       *ummcf;

    ngx_stream_upm_service_inst_t   *umsi;

    ngx_stream_upstream_init_pt      init;
    ngx_stream_upstream_server_t     *us;
    ngx_stream_upstream_srv_conf_t   *uscf;
    ngx_stream_upstream_main_conf_t  *umcf;
 
    ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module);
    ummcf = ngx_stream_get_module_srv_conf(s, ngx_stream_upm_module);

    umcf = ngx_stream_get_module_main_conf(s, ngx_stream_upstream_module);
    upstreams = &umcf->upstreams;
        
    b = ctx->resp_body;
    u = s->upstream; 
    pc = u->peer.connection;
    
    /*
     start to parse the JSON body;
    */
    jsroot = cJSON_Parse((char *)b->start);
    if (jsroot == NULL) {
        ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm json parse failed");
        return ERR_JSON;
    }
    
    /*
     start to parse the JSON;
     */
    service = jsroot->child;  
    if (service == NULL) {
        ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm json with empty service list");
        return ERR_JSON;
    }

    /*service array */
    servs = ngx_array_create(ctx->pool, 16, sizeof(ngx_stream_upm_service_t));
    if (servs == NULL) {
        return NGX_ERROR;
    }

    while( service != NULL ) {
        //Got the service name;
        upname = service->string;
        
        //Got the service related instance;
        jinsts = service->child; 
        if (jinsts == NULL || jinsts->child == NULL) {
            ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upm service: %s without any instance", upname);
        }

        ums = ngx_array_push(servs);
        if (ums == NULL) {
            return NGX_ERROR; 
        }

        ums->service_name.len = ngx_strlen(upname);
        ums->service_name.data = ngx_pcalloc(ctx->pool, ums->service_name.len);
        ngx_memcpy(ums->service_name.data, upname, ums->service_name.len);
        
        ums->insts = ngx_array_create(ctx->pool, 16, sizeof(ngx_stream_upm_service_inst_t));
        if (ums->insts == NULL) {
            return NGX_ERROR;
        }

        //travers all the instance
        jinst = jinsts;
        while (jinst != NULL) {

            //FIXME need check the Item isn't exists;
            host = cJSON_GetObjectItem(jinst, "Host")->valuestring;
            port = cJSON_GetObjectItem(jinst, "Port")->valueint;

            tags = cJSON_GetObjectItem(jinst, "Tags");
            
            fail_timeout = cJSON_GetObjectItem(tags, "fail_timeout")->valueint; 
            max_fail = cJSON_GetObjectItem(tags, "max_fails")->valueint; 
            weight = cJSON_GetObjectItem(tags, "weight")->valueint; 

        
            umsi = ngx_array_push(ums->insts);
            if (umsi == NULL) {
                return NGX_ERROR;
            }
            i = ngx_strlen(host); 

            //Here, ip:port, Max port is 65535
            umsi->name.data = ngx_pcalloc(ctx->pool, (i + 5) * sizeof(char));
            t = (char *)ngx_snprintf(umsi->name.data, i + 5, "%s:%d", (char *)host, port);
            umsi->name.len = t - (char *)umsi->name.data;

            umsi->host.data = (u_char *)host;
            umsi->host.len = i;
            umsi->port = port; 

            umsi->fail_timeout = fail_timeout; 
            umsi->max_fail = max_fail; 
            umsi->weight = weight; 
            jinst = jinst->next;
        }
        service = service->next;
    }

    //Process the upstream msg, check wether we need to update the server;

    cf.name = "ngx_stream_upm_module";

    //Here, we create a memory pool, Only use to the upstream init peer;
    cf.pool = ngx_create_pool(8192, pc->log);
    cf.module_type = NGX_STREAM_MODULE;
    cf.cmd_type = NGX_STREAM_SRV_CONF;
    cf.log = pc->log;

    if (ummcf->pool == NULL) {
        ummcf->pool = cf.pool;   
    } else {
        //pool = cf.pool;
        ummcf->pool = cf.pool;
    }

    for (i = 0; i < servs->nelts; i++) {
        ums = &((ngx_stream_upm_service_t *)(servs->elts))[i];
        sfound = 0;
        /*First: find the upstream name */
        uscf = NULL;
        for (j = 0; j < upstreams->nelts; j++) {
            uscf = &((ngx_stream_upstream_srv_conf_t *)upstreams->elts)[j];
            if (uscf->host.len == ums->service_name.len &&
                ngx_strncmp(uscf->host.data, ums->service_name.data, uscf->host.len) == 0)
            {
                sfound = 1;
            }
        }

        if (sfound == 1) {
            //reset the temporary array to zero;
            //the elt == 1, Means update;
            //the elt == 2, Means create;
            //the elt == 0, Means need set this server to down;
            memset(ta, 0, sizeof(ta));

            us = NULL;
            for (p = 0; p < ums->insts->nelts; p++) {
                umsi = &((ngx_stream_upm_service_inst_t *)ums->insts->elts)[p];
                ifound = 0;
                for (st = 0; st < uscf->servers->nelts; st++) {
                    us = &((ngx_stream_upstream_server_t *)uscf->servers->elts)[st];     
                    if(us->name.len == umsi->name.len && 
                       ngx_strncmp(us->name.data, umsi->name.data, us->name.len ) == 0) 
                    {
                        ifound = 1;
                    }
                }

                //Means server already exists;
                if (ifound == 1) {
                    us->weight = umsi->weight;
                    us->max_fails = umsi->max_fail;
                    us->fail_timeout = umsi->fail_timeout;
                    us->backup = umsi->backup; 
                    us->down = umsi->down; 
                    ta[st] = 1;
                //insert the server;
                } else {
                    us = ngx_array_push(uscf->servers);
                    us->weight = umsi->weight;
                    us->max_fails = umsi->max_fail;
                    us->fail_timeout = umsi->fail_timeout;
                    us->backup = umsi->backup; 
                    us->down = umsi->down; 
                    ta[st] = 2;
                }
            }

            for (st = 0; st < uscf->servers->nelts; st++) {
                us =  &((ngx_stream_upstream_server_t *)uscf->servers->elts)[st];
                if (ta[st] == 0) {
                    //FIXME: Only set this server to down, 
                    //       If the backend change very quikly, there are too many down server list;
                    us->down = 1; 
                }
            }

            /*Reinit the upstream servers*/
            init = uscf->peer.init_upstream ? uscf->peer.init_upstream:
                     ngx_stream_upstream_init_round_robin;
            if (init(&cf, uscf) != NGX_OK) {
                return NGX_ERROR;
            }
        } else {
            //TODO: doesn't support auto discovery the service name?
            //Need alloc the memory from the global;
            ngx_log_error(NGX_LOG_ERR, pc->log, 0, 
                          "config server return uninitilized usptreams: %V", &ums->service_name);
        }
    }
    /*Update the upstream weight*/
    return NGX_OK;
}
void
ngx_stream_init_connection(ngx_connection_t *c)
{
    u_char                        text[NGX_SOCKADDR_STRLEN];
    size_t                        len;
    ngx_int_t                     rc;
    ngx_uint_t                    i;
    struct sockaddr              *sa;
    ngx_stream_port_t            *port;
    struct sockaddr_in           *sin;
    ngx_stream_in_addr_t         *addr;
    ngx_stream_session_t         *s;
    ngx_stream_addr_conf_t       *addr_conf;
#if (NGX_HAVE_INET6)
    struct sockaddr_in6          *sin6;
    ngx_stream_in6_addr_t        *addr6;
#endif
    ngx_stream_core_srv_conf_t   *cscf;
    ngx_stream_core_main_conf_t  *cmcf;

    /* find the server configuration for the address:port */

    port = c->listening->servers;

    if (port->naddrs > 1) {

        /*
         * There are several addresses on this port and one of them
         * is the "*:port" wildcard so getsockname() is needed to determine
         * the server address.
         *
         * AcceptEx() already gave this address.
         */

        if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
            ngx_stream_close_connection(c);
            return;
        }

        sa = c->local_sockaddr;

        switch (sa->sa_family) {

#if (NGX_HAVE_INET6)
        case AF_INET6:
            sin6 = (struct sockaddr_in6 *) sa;

            addr6 = port->addrs;

            /* the last address is "*" */

            for (i = 0; i < port->naddrs - 1; i++) {
                if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) {
                    break;
                }
            }

            addr_conf = &addr6[i].conf;

            break;
#endif

        default: /* AF_INET */
            sin = (struct sockaddr_in *) sa;

            addr = port->addrs;

            /* the last address is "*" */

            for (i = 0; i < port->naddrs - 1; i++) {
                if (addr[i].addr == sin->sin_addr.s_addr) {
                    break;
                }
            }

            addr_conf = &addr[i].conf;

            break;
        }

    } else {
        switch (c->local_sockaddr->sa_family) {

#if (NGX_HAVE_INET6)
        case AF_INET6:
            addr6 = port->addrs;
            addr_conf = &addr6[0].conf;
            break;
#endif

        default: /* AF_INET */
            addr = port->addrs;
            addr_conf = &addr[0].conf;
            break;
        }
    }

    s = ngx_pcalloc(c->pool, sizeof(ngx_stream_session_t));
    if (s == NULL) {
        ngx_stream_close_connection(c);
        return;
    }

    s->signature = NGX_STREAM_MODULE;
    s->main_conf = addr_conf->ctx->main_conf;
    s->srv_conf = addr_conf->ctx->srv_conf;

    s->connection = c;
    c->data = s;

    cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);

    ngx_set_connection_log(c, cscf->error_log);

    len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1);

    ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V",
                  c->number, len, text, &addr_conf->addr_text);

    c->log->connection = c->number;
    c->log->handler = ngx_stream_log_error;
    c->log->data = s;
    c->log->action = "initializing connection";
    c->log_error = NGX_ERROR_INFO;

    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

    if (cmcf->access_handler) {
        rc = cmcf->access_handler(s);

        if (rc != NGX_OK && rc != NGX_DECLINED) {
            ngx_stream_close_connection(c);
            return;
        }
    }

#if (NGX_STREAM_SSL)
    {
    ngx_stream_ssl_conf_t  *sslcf;

    sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);

    if (addr_conf->ssl) {
        c->log->action = "SSL handshaking";

        if (sslcf->ssl.ctx == NULL) {
            ngx_log_error(NGX_LOG_ERR, c->log, 0,
                          "no \"ssl_certificate\" is defined "
                          "in server listening on SSL port");
            ngx_stream_close_connection(c);
            return;
        }

        ngx_stream_ssl_init_connection(&sslcf->ssl, c);
        return;
    }
    }
#endif

    ngx_stream_init_session(c);
}
/*
static void ngx_app_empty_handler(ngx_event_t *wev)
{

}
*/
static void ngx_app_wait_request_handler(ngx_event_t *ev)
{
    ngx_connection_t      *c;
    ngx_stream_session_t  *s;
	ngx_stream_app_main_conf_t  *cscf;
	ngx_stream_app_srv_conf_t  *ascf;
	ngx_stream_app_ctx_t  *s_ctx;
	ngx_app_task_t		  *t;
	ngx_buf_t             *b;
	ngx_str_t			  log_buf;
	ssize_t                n;
	size_t                 size;
	u_char				   *tmp;
    c = ev->data;
    s = c->data;

    if (ev->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
        ngx_stream_close_connection(c);
        return;
    }

    if (c->close) {
        ngx_stream_close_connection(c);
        return;
    }

	cscf = ngx_stream_get_module_main_conf(s, ngx_stream_app_module);

	ascf = ngx_stream_get_module_srv_conf(s, ngx_stream_app_module);
		
	s_ctx = ngx_stream_get_module_ctx(s,ngx_stream_app_module);
	if(s_ctx == NULL){
		s_ctx = ngx_palloc(c->pool, sizeof(ngx_stream_app_ctx_t));
		if(s_ctx == NULL)
			return;
		s_ctx->header = 0;
		ngx_stream_set_ctx(s,s_ctx,ngx_stream_app_module);
	}

	b = c->buffer;

	if (b == NULL) {
		size = ascf->header_len;
		b = ngx_create_temp_buf(c->pool, size);
		if (b == NULL) {
			ngx_stream_close_connection(c);
			return;
		}

		c->buffer = b;

	} else if (b->start == NULL) {

		size = s_ctx->header == 0?ascf->header_len:s_ctx->body_len;

		b->start = ngx_palloc(c->pool, size);
		if (b->start == NULL) {
			ngx_stream_close_connection(c);
			return;
		}

		b->pos = b->start;
		b->last = b->start;
		b->end = b->last + size;
	}
	else {

		size = ascf->header_len + s_ctx->body_len - s->received;
//		size = b->end - b->last;
	}

	n = c->recv(c, b->last, size);
	
    if (n == NGX_AGAIN) {

        if (!c->read->timer_set) {
            ngx_add_timer(c->read, ascf->client_timeout);
        }

        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
            ngx_stream_close_connection(c);
            return;
        }

        return;
    }

	if (n == NGX_ERROR) {
        ngx_stream_close_connection(c);
        return;
    }
	
    if (n == 0) {
        ngx_log_error(NGX_LOG_INFO, c->log, 0,
                      "client closed connection");
        ngx_stream_close_connection(c);
        return;
    }

    b->last += n;
	s->received +=n;

	c->log->action = "reading client request line";
	
	log_buf.len = s->received;
	log_buf.data = b->start;
	ngx_log_error(NGX_LOG_ALERT, c->log, 0, "%d recved [%V],[%d:%d]",n,&log_buf,b->end,b->last);

	if(b->end != b->last){
        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
            ngx_stream_close_connection(c);
            return;
        }
	}
	else {
		if(s_ctx->header == 0){
			s_ctx->body_len = ngx_atoi(b->start,ascf->header_len);
			s_ctx->header = 1;
			if(s_ctx->body_len > 0 ){
				
				tmp = ngx_pcalloc(c->pool, ascf->header_len + s_ctx->body_len);
				if (tmp == NULL) {
					ngx_stream_close_connection(c);
					return;
				}

				ngx_memcpy(tmp,b->start,ascf->header_len);
				ngx_pfree(c->pool, b->start);
				b->start = tmp;
				
				b->pos = b->start + ascf->header_len;
				b->last = b->pos;
				b->end = b->last + s_ctx->body_len;
				
				ngx_app_wait_request_handler(ev);
			}
			else{
				ngx_log_error(NGX_LOG_INFO, c->log, 0, "empty request body");
				ngx_stream_close_connection(c);
				return;
			}

			ngx_log_error(NGX_LOG_ALERT, c->log, 0, "recv header,len[%d]",s_ctx->body_len);

		}
		else{
//			c->read->handler = ngx_app_empty_handler;

			t = (ngx_app_task_t *)ngx_thread_task_alloc(c->pool,
				sizeof(ngx_app_task_t) - sizeof(ngx_thread_task_t));
			if(t == NULL){
				ngx_log_error(NGX_LOG_ERR, c->log, 0, "create thread task failed");
				ngx_stream_close_connection(c);
			}
			t->data = s;
			t->task.handler = ngx_stream_app_process;
			t->task.event.handler = ngx_stream_app_finalize;
			t->task.event.data= c;
			ngx_log_error(NGX_LOG_ALERT, c->log, 0, "t->data[%d]=[%d][%d]",t->data,t->task.ctx,t);
			if(ngx_thread_task_post(cscf->tp,(ngx_thread_task_t *)t) != NGX_OK){
				ngx_log_error(NGX_LOG_ERR, c->log, 0, "post task to thread pool failed");
				ngx_stream_close_connection(c);
				return;
			}
			ngx_log_error(NGX_LOG_ALERT, c->log, 0, "after post task");
		}
	}

	return;
}
예제 #13
0
ngx_int_t
ngx_stream_regex_exec(ngx_stream_session_t *s, ngx_stream_regex_t *re,
    ngx_str_t *str)
{
    ngx_int_t                     rc, index;
    ngx_uint_t                    i, n, len;
    ngx_stream_variable_value_t  *vv;
    ngx_stream_core_main_conf_t  *cmcf;

    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

    if (re->ncaptures) {
        len = cmcf->ncaptures;

        if (s->captures == NULL) {
            s->captures = ngx_palloc(s->connection->pool, len * sizeof(int));
            if (s->captures == NULL) {
                return NGX_ERROR;
            }
        }

    } else {
        len = 0;
    }

    rc = ngx_regex_exec(re->regex, str, s->captures, len);

    if (rc == NGX_REGEX_NO_MATCHED) {
        return NGX_DECLINED;
    }

    if (rc < 0) {
        ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
                      ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
                      rc, str, &re->name);
        return NGX_ERROR;
    }

    for (i = 0; i < re->nvariables; i++) {

        n = re->variables[i].capture;
        index = re->variables[i].index;
        vv = &s->variables[index];

        vv->len = s->captures[n + 1] - s->captures[n];
        vv->valid = 1;
        vv->no_cacheable = 0;
        vv->not_found = 0;
        vv->data = &str->data[s->captures[n]];

#if (NGX_DEBUG)
        {
        ngx_stream_variable_t  *v;

        v = cmcf->variables.elts;

        ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
                       "stream regex set $%V to \"%v\"", &v[index].name, vv);
        }
#endif
    }

    s->ncaptures = rc * 2;
    s->captures_data = str->data;

    return NGX_OK;
}
static mrb_state *ngx_stream_mrb_state(ngx_stream_session_t *s)
{
  return ((ngx_stream_mruby_main_conf_t *)ngx_stream_get_module_main_conf(s, ngx_stream_mruby_module))->ctx->mrb;
}
예제 #15
0
ngx_stream_variable_value_t *
ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name,
    ngx_uint_t key)
{
    size_t                        len;
    ngx_uint_t                    i, n;
    ngx_stream_variable_t        *v;
    ngx_stream_variable_value_t  *vv;
    ngx_stream_core_main_conf_t  *cmcf;

    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);

    v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);

    if (v) {
        if (v->flags & NGX_STREAM_VAR_INDEXED) {
            return ngx_stream_get_flushed_variable(s, v->index);
        }

        if (ngx_stream_variable_depth == 0) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                          "cycle while evaluating variable \"%V\"", name);
            return NULL;
        }

        ngx_stream_variable_depth--;

        vv = ngx_palloc(s->connection->pool,
                        sizeof(ngx_stream_variable_value_t));

        if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
            ngx_stream_variable_depth++;
            return vv;
        }

        ngx_stream_variable_depth++;
        return NULL;
    }

    vv = ngx_palloc(s->connection->pool, sizeof(ngx_stream_variable_value_t));
    if (vv == NULL) {
        return NULL;
    }

    len = 0;

    v = cmcf->prefix_variables.elts;
    n = cmcf->prefix_variables.nelts;

    for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
        if (name->len >= v[i].name.len && name->len > len
            && ngx_strncmp(name->data, v[i].name.data, v[i].name.len) == 0)
        {
            len = v[i].name.len;
            n = i;
        }
    }

    if (n != cmcf->prefix_variables.nelts) {
        if (v[n].get_handler(s, vv, (uintptr_t) name) == NGX_OK) {
            return vv;
        }

        return NULL;
    }

    vv->not_found = 1;

    return vv;
}