Example #1
0
ngx_int_t
ngx_stream_core_content_phase(ngx_stream_session_t *s,
    ngx_stream_phase_handler_t *ph)
{
    ngx_connection_t            *c;
    ngx_stream_core_srv_conf_t  *cscf;

    c = s->connection;

    c->log->action = NULL;

    cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);

    if (c->type == SOCK_STREAM
        && cscf->tcp_nodelay
        && ngx_tcp_nodelay(c) != NGX_OK)
    {
        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
        return NGX_OK;
    }

    cscf->handler(s);

    return NGX_OK;
}
// 创建ctx数组,用于存储模块的ctx数据
// 调用handler,处理tcp数据,收发等等
static void
ngx_stream_init_session(ngx_connection_t *c)
{
    ngx_stream_session_t        *s;
    ngx_stream_core_srv_conf_t  *cscf;

    // 获得连接关联的会话对象
    s = c->data;
    c->log->action = "handling client connection";

    // 获取ngx_stream_core_module的配置
    // 只与每个server{}块相关的专门配置
    cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);

    // 创建ctx数组,用于存储模块的ctx数据
    s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_stream_max_module);
    if (s->ctx == NULL) {
        ngx_stream_close_connection(c);
        return;
    }

    // 调用handler,处理tcp数据,收发等等
    // 注意没有log模块,不会自动记录访问日志
    cscf->handler(s);
}
static void
ngx_stream_lua_socket_udp_read_handler(ngx_stream_session_t *s,
    ngx_stream_lua_socket_udp_upstream_t *u)
{
    ngx_connection_t            *c;
    ngx_stream_lua_srv_conf_t   *lscf;

    c = u->udp_connection.connection;

    ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
                   "stream lua udp socket read handler");

    if (c->read->timedout) {
        c->read->timedout = 0;

        lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_lua_module);

        if (lscf->log_socket_errors) {
            ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                          "stream lua udp socket read timed out");
        }

        ngx_stream_lua_socket_udp_handle_error(s, u,
                                             NGX_STREAM_LUA_SOCKET_FT_TIMEOUT);
        return;
    }

#if 1
    if (c->read->timer_set) {
        ngx_del_timer(c->read);
    }
#endif

    (void) ngx_stream_lua_socket_udp_read(s, u);
}
static void
ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c)
{
    ngx_stream_session_t   *s;
    ngx_stream_ssl_conf_t  *sslcf;

    if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) {
        ngx_stream_close_connection(c);
        return;
    }

    if (ngx_ssl_handshake(c) == NGX_AGAIN) {

        s = c->data;

        sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);

        ngx_add_timer(c->read, sslcf->handshake_timeout);

        c->ssl->handler = ngx_stream_ssl_handshake_handler;

        return;
    }

    ngx_stream_ssl_handshake_handler(c);
}
static ngx_int_t
ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c)
{
    ngx_int_t               rc;
    ngx_stream_session_t   *s;
    ngx_stream_ssl_conf_t  *sslcf;

    s = c->data;

    if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) {
        return NGX_ERROR;
    }

    rc = ngx_ssl_handshake(c);

    if (rc == NGX_ERROR) {
        return NGX_ERROR;
    }

    if (rc == NGX_AGAIN) {
        sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);

        ngx_add_timer(c->read, sslcf->handshake_timeout);

        c->ssl->handler = ngx_stream_ssl_handshake_handler;

        return NGX_AGAIN;
    }

    /* rc == NGX_OK */

    return NGX_OK;
}
static void
ngx_stream_return_handler(ngx_stream_session_t *s)
{
    ngx_str_t                      text;
    ngx_buf_t                     *b;
    ngx_connection_t              *c;
    ngx_stream_return_ctx_t       *ctx;
    ngx_stream_return_srv_conf_t  *rscf;

    c = s->connection;

    c->log->action = "returning text";

    rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module);

    if (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) {
        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
        return;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "stream return text: \"%V\"", &text);

    if (text.len == 0) {
        ngx_stream_finalize_session(s, NGX_STREAM_OK);
        return;
    }

    ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_return_ctx_t));
    if (ctx == NULL) {
        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
        return;
    }

    ngx_stream_set_ctx(s, ctx, ngx_stream_return_module);

    b = ngx_calloc_buf(c->pool);
    if (b == NULL) {
        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
        return;
    }

    b->memory = 1;
    b->pos = text.data;
    b->last = text.data + text.len;
    b->last_buf = 1;

    ctx->out = ngx_alloc_chain_link(c->pool);
    if (ctx->out == NULL) {
        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
        return;
    }

    ctx->out->buf = b;
    ctx->out->next = NULL;

    c->write->handler = ngx_stream_return_write_handler;

    ngx_stream_return_write_handler(c->write);
}
static ngx_int_t
ngx_stream_ssl_handler(ngx_stream_session_t *s)
{
    ngx_connection_t       *c;
    ngx_stream_ssl_conf_t  *sslcf;

    c = s->connection;

    sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);

    if (s->ssl && c->ssl == NULL) {
        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");
            return NGX_ERROR;
        }

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

    return NGX_OK;
}
ngx_int_t
ngx_stream_upm_read_and_parse_response(ngx_stream_session_t *s)
{
    ngx_int_t                       n, rc;
    ngx_buf_t                       *b;
    ngx_connection_t                *pc; 
    ngx_stream_upm_ctx_t            *ctx;
    ngx_stream_upstream_t           *u;
    ngx_stream_upm_main_conf_t       *ummcf;
    
    ctx = ngx_stream_get_module_ctx(s, ngx_stream_upm_module);
    ummcf = ngx_stream_get_module_srv_conf(s, ngx_stream_upm_module);

    u = s->upstream;
    pc = u->peer.connection;
    
    //Allocate big enough buffer
    //Must be assure the content_length_n big than 2 * ummcf->buffer_size;
    b = ctx->resp_body;
    if (b->start == NULL)  {
        b->start = ngx_pcalloc(ctx->pool, 2 * ummcf->buffer_size);    
        b->pos = b->start;
        b->last = b->start;
        b->end = b->start + 2 * ummcf->buffer_size; 
    }
    
    for (;;) {

        n = pc->recv(pc, b->last, b->end - b->last);
        if (n == NGX_AGAIN) {
            if (ngx_handle_read_event(pc->read, 0) != NGX_OK) {
                return NGX_ERROR;
            }
            return NGX_AGAIN;
        }

        if (n == 0) {
            ngx_log_error(NGX_LOG_ERR, pc->log, 0,
                          "upm upstream prematurely closed connection while read the body");
        }

        if (n == NGX_ERROR || n == 0) {
            return NGX_ERROR;
        }

        b->last += n;
        if (b->last - b->pos == ctx->content_length_n) {
            rc = ngx_stream_upm_parse_resp_body(s);
        } else if (b->last - b->pos < ctx->content_length_n) {
            continue;
        } else {
            ngx_log_error(NGX_LOG_ERR, pc->log, 0,
                          "upm upstream send a response body more than the content_length");
            return NGX_ERROR;
        }
    }

    return rc;
}
static ngx_int_t
ngx_stream_access_handler(ngx_stream_session_t *s)
{
    struct sockaddr_in            *sin;
    ngx_stream_access_srv_conf_t  *ascf;
#if (NGX_HAVE_INET6)
    u_char                        *p;
    in_addr_t                      addr;
    struct sockaddr_in6           *sin6;
#endif

    ascf = ngx_stream_get_module_srv_conf(s, ngx_stream_access_module);

    switch (s->connection->sockaddr->sa_family) {

    case AF_INET:
        if (ascf->rules) {
            sin = (struct sockaddr_in *) s->connection->sockaddr;
            return ngx_stream_access_inet(s, ascf, sin->sin_addr.s_addr);
        }
        break;

#if (NGX_HAVE_INET6)

    case AF_INET6:
        sin6 = (struct sockaddr_in6 *) s->connection->sockaddr;
        p = sin6->sin6_addr.s6_addr;

        if (ascf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
            addr = p[12] << 24;
            addr += p[13] << 16;
            addr += p[14] << 8;
            addr += p[15];
            return ngx_stream_access_inet(s, ascf, htonl(addr));
        }

        if (ascf->rules6) {
            return ngx_stream_access_inet6(s, ascf, p);
        }

        break;

#endif

#if (NGX_HAVE_UNIX_DOMAIN)

    case AF_UNIX:
        if (ascf->rules_un) {
            return ngx_stream_access_unix(s, ascf);
        }

        break;

#endif
    }

    return NGX_DECLINED;
}
static void
ngx_stream_proxy_connect(ngx_stream_session_t *s)
{
    ngx_int_t                     rc;
    ngx_connection_t             *c, *pc;
    ngx_stream_upstream_t        *u;
    ngx_stream_proxy_srv_conf_t  *pscf;

    c = s->connection;

    c->log->action = "connecting to upstream";

    u = s->upstream;

    rc = ngx_event_connect_peer(&u->peer);

    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "proxy connect: %i", rc);

    pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);

    if (rc == NGX_ERROR) {
        ngx_stream_proxy_finalize(s, NGX_ERROR);
        return;
    }

    if (rc == NGX_BUSY) {
        ngx_log_error(NGX_LOG_ERR, c->log, 0, "no live upstreams");
        ngx_stream_proxy_finalize(s, NGX_DECLINED);
        return;
    }

    if (rc == NGX_DECLINED) {
        ngx_stream_proxy_next_upstream(s);
        return;
    }

    /* rc == NGX_OK || rc == NGX_AGAIN || rc == NGX_DONE */

    pc = u->peer.connection;

    pc->data = s;
    pc->log = c->log;
    pc->pool = c->pool;
    pc->read->log = c->log;
    pc->write->log = c->log;

    if (rc != NGX_AGAIN) 
	{
        ngx_stream_proxy_init_upstream(s);
        return;
    }

    pc->read->handler = ngx_stream_proxy_connect_handler;
    pc->write->handler = ngx_stream_proxy_connect_handler;

    ngx_add_timer(pc->write, pscf->connect_timeout);
}
Example #11
0
static void
ngx_stream_hello_handler(ngx_stream_session_t *s)
{
    ngx_stream_hello_srv_conf_t *hscf;

    hscf = ngx_stream_get_module_srv_conf(s, ngx_stream_hello_module);

    s->connection->send(s->connection, hscf->hello.data, hscf->hello.len);
    ngx_stream_close_connection(s->connection);
}
static int
ngx_stream_lua_on_abort(lua_State *L)
{
    ngx_stream_session_t           *s;
    ngx_stream_lua_ctx_t           *ctx;
    ngx_stream_lua_co_ctx_t        *coctx = NULL;
    ngx_stream_lua_srv_conf_t      *lscf;

    s = ngx_stream_lua_get_session(L);
    if (s == NULL) {
        return luaL_error(L, "no session found");
    }

    ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module);
    if (ctx == NULL) {
        return luaL_error(L, "no session ctx found");
    }

    ngx_stream_lua_check_fake_session2(L, s, ctx);

    if (ctx->on_abort_co_ctx) {
        lua_pushnil(L);
        lua_pushliteral(L, "duplicate call");
        return 2;
    }

    lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_lua_module);
    if (!lscf->check_client_abort) {
        lua_pushnil(L);
        lua_pushliteral(L, "lua_check_client_abort is off");
        return 2;
    }

    ngx_stream_lua_coroutine_create_helper(L, s, ctx, &coctx);

    lua_pushlightuserdata(L, &ngx_stream_lua_coroutines_key);
    lua_rawget(L, LUA_REGISTRYINDEX);
    lua_pushvalue(L, -2);

    dd("on_wait thread 1: %p", lua_tothread(L, -1));

    coctx->co_ref = luaL_ref(L, -2);
    lua_pop(L, 1);

    coctx->is_uthread = 1;
    ctx->on_abort_co_ctx = coctx;

    dd("on_wait thread 2: %p", coctx->co);

    coctx->co_status = NGX_STREAM_LUA_CO_SUSPENDED;
    coctx->parent_co_ctx = ctx->cur_co_ctx;

    lua_pushinteger(L, 1);
    return 1;
}
static void
ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc)
{
    long                          rc;
    ngx_stream_session_t         *s;
    ngx_stream_upstream_t        *u;
    ngx_stream_proxy_srv_conf_t  *pscf;

    s = pc->data;

    pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);

    if (pc->ssl->handshaked) {

        if (pscf->ssl_verify) {
            rc = SSL_get_verify_result(pc->ssl->connection);

            if (rc != X509_V_OK) {
                ngx_log_error(NGX_LOG_ERR, pc->log, 0,
                              "upstream SSL certificate verify error: (%l:%s)",
                              rc, X509_verify_cert_error_string(rc));
                goto failed;
            }

            u = s->upstream;

            if (ngx_ssl_check_host(pc, &u->ssl_name) != NGX_OK) {
                ngx_log_error(NGX_LOG_ERR, pc->log, 0,
                              "upstream SSL certificate does not match \"%V\"",
                              &u->ssl_name);
                goto failed;
            }
        }

        if (pscf->ssl_session_reuse) {
            u = s->upstream;
            u->peer.save_session(&u->peer, u->peer.data);
        }

        if (pc->write->timer_set) {
            ngx_del_timer(pc->write);
        }

        ngx_stream_proxy_init_upstream(s);

        return;
    }

failed:

    ngx_stream_proxy_next_upstream(s);
}
Example #14
0
static void
ngx_stream_proxy_next_upstream(ngx_stream_session_t *s)
{
    ngx_msec_t                    timeout;
    ngx_connection_t             *pc;
    ngx_stream_upstream_t        *u;
    ngx_stream_proxy_srv_conf_t  *pscf;

    ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
                   "stream proxy next upstream");

    u = s->upstream;

    if (u->peer.sockaddr) {
        u->peer.free(&u->peer, u->peer.data, NGX_PEER_FAILED);
        u->peer.sockaddr = NULL;
    }

    pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);

    timeout = pscf->next_upstream_timeout;

    if (u->peer.tries == 0
        || !pscf->next_upstream
        || (timeout && ngx_current_msec - u->peer.start_time >= timeout))
    {
        ngx_stream_proxy_finalize(s, NGX_DECLINED);
        return;
    }

    pc = u->peer.connection;

    if (pc) {
        ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
                       "close proxy upstream connection: %d", pc->fd);

#if (NGX_STREAM_SSL)
        if (pc->ssl) {
            pc->ssl->no_wait_shutdown = 1;
            pc->ssl->no_send_shutdown = 1;

            (void) ngx_ssl_shutdown(pc);
        }
#endif

        ngx_close_connection(pc);
        u->peer.connection = NULL;
    }

    ngx_stream_proxy_connect(s);
}
Example #15
0
static void
ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s)
{
    ngx_int_t                     rc;
    ngx_connection_t             *pc;
    ngx_stream_upstream_t        *u;
    ngx_stream_proxy_srv_conf_t  *pscf;

    u = s->upstream;

    pc = u->peer.connection;

    pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);

    if (ngx_ssl_create_connection(pscf->ssl, pc, NGX_SSL_BUFFER|NGX_SSL_CLIENT)
        != NGX_OK)
    {
        ngx_stream_proxy_finalize(s, NGX_ERROR);
        return;
    }

    if (pscf->ssl_server_name || pscf->ssl_verify) {
        if (ngx_stream_proxy_ssl_name(s) != NGX_OK) {
            ngx_stream_proxy_finalize(s, NGX_ERROR);
            return;
        }
    }

    if (pscf->ssl_session_reuse) {
        if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
            ngx_stream_proxy_finalize(s, NGX_ERROR);
            return;
        }
    }

    s->connection->log->action = "SSL handshaking to upstream";

    rc = ngx_ssl_handshake(pc);

    if (rc == NGX_AGAIN) {

        if (!pc->write->timer_set) {
            ngx_add_timer(pc->write, pscf->connect_timeout);
        }

        pc->ssl->handler = ngx_stream_proxy_ssl_handshake;
        return;
    }

    ngx_stream_proxy_ssl_handshake(pc);
}
//发送响应
static void ngx_stream_app_finalize(ngx_event_t *ev)
{
	ngx_stream_session_t  *s;
	ngx_connection_t      *c;
	ngx_stream_app_srv_conf_t  *cscf;

	ssize_t                n;
	c = ev->data;
	s = c->data;

	ngx_log_error(NGX_LOG_ALERT, c->log, 0, "sending task");

	cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_app_module);
	
    if (c->write->timedout) {
        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "sending response timed out");
        ngx_stream_close_connection(c);
        return;
    }

	n = c->send(c,c->buffer->last,c->buffer->end - c->buffer->last);
	if (n == NGX_AGAIN) {

		if (!c->write->timer_set) {
			ngx_add_timer(c->write, cscf->send_timeout);
		}
//		c->write->handler = ngx_stream_app_finalize;
//		c->read->handler =  ngx_app_empty_handler;
		if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
			ngx_stream_close_connection(c);
			return;
		}
		return;
	}
	if (n == NGX_ERROR) {
        ngx_stream_close_connection(c);
        return;
    }

    c->buffer->last += n;

	c->log->action = "sending  request  line to client";

	if(c->buffer->end != c->buffer->last){
		if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
			ngx_stream_close_connection(c);
			return;
		}
	}
}
static void
ngx_stream_init_session(ngx_connection_t *c)
{
    ngx_stream_session_t        *s;
    ngx_stream_core_srv_conf_t  *cscf;

    s = c->data;
    c->log->action = "handling client connection";

    cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);

    s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_stream_max_module);
    if (s->ctx == NULL) {
        ngx_stream_close_connection(c);
        return;
    }

    cscf->handler(s);
}
static void
ngx_stream_return_handler(ngx_stream_session_t *s)
{
    ngx_str_t                      text;
    ngx_connection_t              *c;
    ngx_stream_return_ctx_t       *ctx;
    ngx_stream_return_srv_conf_t  *rscf;

    c = s->connection;

    c->log->action = "returning text";

    rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module);

    if (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) {
        ngx_stream_close_connection(c);
        return;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "stream return text: \"%V\"", &text);

    if (text.len == 0) {
        ngx_stream_close_connection(c);
        return;
    }

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

    ngx_stream_set_ctx(s, ctx, ngx_stream_return_module);

    ctx->buf.pos = text.data;
    ctx->buf.last = text.data + text.len;

    c->write->handler = ngx_stream_return_write_handler;

    ngx_stream_return_write_handler(c->write);
}
ngx_int_t
ngx_stream_core_content_phase(ngx_stream_session_t *s,
    ngx_stream_phase_handler_t *ph)
{
    int                          tcp_nodelay;
    ngx_connection_t            *c;
    ngx_stream_core_srv_conf_t  *cscf;

    c = s->connection;

    c->log->action = NULL;

    cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);

    if (c->type == SOCK_STREAM
        && 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_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
            return NGX_OK;
        }

        c->tcp_nodelay = NGX_TCP_NODELAY_SET;
    }

    cscf->handler(s);

    return NGX_OK;
}
static ngx_int_t ngx_stream_mruby_handler(ngx_stream_session_t *s)
{
  ngx_stream_mruby_srv_conf_t *mscf = ngx_stream_get_module_srv_conf(s, ngx_stream_mruby_module);
  mrb_state *mrb = ngx_stream_mrb_state(s);
  mrb_int ai = mrb_gc_arena_save(mrb);
  ngx_stream_mruby_internal_ctx_t *ictx = mrb->ud;

  ictx->s = s;
  ictx->stream_status = NGX_DECLINED;
  mrb_run(mrb, mscf->code->proc, mrb_top_self(mrb));

  if (mrb->exc) {
    ngx_stream_mruby_raise_error(mrb, mrb_obj_value(mrb->exc), s);
    ngx_stream_mrb_state_clean(mrb);
    mrb_gc_arena_restore(mrb, ai);
    return NGX_ABORT;
  }

  ngx_stream_mrb_state_clean(mrb);
  mrb_gc_arena_restore(mrb, ai);

  /* default NGX_DECLINED */
  return ictx->stream_status;
}
static void
ngx_stream_app_handler(ngx_stream_session_t *s)
{
    ngx_connection_t                *c;
    ngx_stream_app_srv_conf_t     *pscf;

    c = s->connection;

    pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_app_module);

    ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "NGX_LOG_DEBUG_STREAM:app connection handler");

    s->upstream = NULL;

    s->log_handler = ngx_stream_app_log_error;

    c->write->handler = ngx_stream_app_finalize;
    c->read->handler = ngx_app_wait_request_handler;

    if (c->read->ready) {
 	   c->read->handler(c->read);
	   return;
    }
	
	if (!c->read->timer_set) {
		ngx_add_timer(c->read, pscf->client_timeout);
	}

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

}
Example #22
0
static ngx_int_t
ngx_stream_ssl_handler(ngx_stream_session_t *s)
{
    long                    rc;
    X509                   *cert;
    ngx_int_t               rv;
    ngx_connection_t       *c;
    ngx_stream_ssl_conf_t  *sslcf;

    if (!s->ssl) {
        return NGX_OK;
    }

    c = s->connection;

    sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);

    if (c->ssl == NULL) {
        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");
            return NGX_ERROR;
        }

        rv = ngx_stream_ssl_init_connection(&sslcf->ssl, c);

        if (rv != NGX_OK) {
            return rv;
        }
    }

    if (sslcf->verify) {
        rc = SSL_get_verify_result(c->ssl->connection);

        if (rc != X509_V_OK
            && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc)))
        {
            ngx_log_error(NGX_LOG_INFO, c->log, 0,
                          "client SSL certificate verify error: (%l:%s)",
                          rc, X509_verify_cert_error_string(rc));

            ngx_ssl_remove_cached_session(sslcf->ssl.ctx,
                                       (SSL_get0_session(c->ssl->connection)));
            return NGX_ERROR;
        }

        if (sslcf->verify == 1) {
            cert = SSL_get_peer_certificate(c->ssl->connection);

            if (cert == NULL) {
                ngx_log_error(NGX_LOG_INFO, c->log, 0,
                              "client sent no required SSL certificate");

                ngx_ssl_remove_cached_session(sslcf->ssl.ctx,
                                       (SSL_get0_session(c->ssl->connection)));
                return NGX_ERROR;
            }

            X509_free(cert);
        }
    }

    return NGX_OK;
}
Example #23
0
static void
ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream)
{
    ngx_connection_t             *c, *pc;
    ngx_stream_session_t         *s;
    ngx_stream_upstream_t        *u;
    ngx_stream_proxy_srv_conf_t  *pscf;

    c = ev->data;
    s = c->data;
    u = s->upstream;

    if (ev->timedout) {

        if (ev->delayed) {

            ev->timedout = 0;
            ev->delayed = 0;

            if (!ev->ready) {
                if (ngx_handle_read_event(ev, 0) != NGX_OK) {
                    ngx_stream_proxy_finalize(s, NGX_ERROR);
                    return;
                }

                if (u->connected) {
                    pc = u->peer.connection;

                    if (!c->read->delayed && !pc->read->delayed) {
                        pscf = ngx_stream_get_module_srv_conf(s,
                                                       ngx_stream_proxy_module);
                        ngx_add_timer(c->write, pscf->timeout);
                    }
                }

                return;
            }

        } else {
            ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out");
            ngx_stream_proxy_finalize(s, NGX_DECLINED);
            return;
        }

    } else if (ev->delayed) {

        ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
                       "stream connection delayed");

        if (ngx_handle_read_event(ev, 0) != NGX_OK) {
            ngx_stream_proxy_finalize(s, NGX_ERROR);
        }

        return;
    }

    if (from_upstream && !u->connected) {
        return;
    }

    ngx_stream_proxy_process(s, from_upstream, ev->write);
}
Example #24
0
static ngx_int_t
ngx_stream_proxy_ssl_name(ngx_stream_session_t *s)
{
    u_char                       *p, *last;
    ngx_str_t                     name;
    ngx_stream_upstream_t        *u;
    ngx_stream_proxy_srv_conf_t  *pscf;

    pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);

    u = s->upstream;

    name = pscf->ssl_name;

    if (name.len == 0) {
        name = pscf->upstream->host;
    }

    if (name.len == 0) {
        goto done;
    }

    /*
     * ssl name here may contain port, strip it for compatibility
     * with the http module
     */

    p = name.data;
    last = name.data + name.len;

    if (*p == '[') {
        p = ngx_strlchr(p, last, ']');

        if (p == NULL) {
            p = name.data;
        }
    }

    p = ngx_strlchr(p, last, ':');

    if (p != NULL) {
        name.len = p - name.data;
    }

    if (!pscf->ssl_server_name) {
        goto done;
    }

#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME

    /* as per RFC 6066, literal IPv4 and IPv6 addresses are not permitted */

    if (name.len == 0 || *name.data == '[') {
        goto done;
    }

    if (ngx_inet_addr(name.data, name.len) != INADDR_NONE) {
        goto done;
    }

    /*
     * SSL_set_tlsext_host_name() needs a null-terminated string,
     * hence we explicitly null-terminate name here
     */

    p = ngx_pnalloc(s->connection->pool, name.len + 1);
    if (p == NULL) {
        return NGX_ERROR;
    }

    (void) ngx_cpystrn(p, name.data, name.len + 1);

    name.data = p;

    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
                   "upstream SSL server name: \"%s\"", name.data);

    if (SSL_set_tlsext_host_name(u->peer.connection->ssl->connection, name.data)
        == 0)
    {
        ngx_ssl_error(NGX_LOG_ERR, s->connection->log, 0,
                      "SSL_set_tlsext_host_name(\"%s\") failed", name.data);
        return NGX_ERROR;
    }

#endif

done:

    u->ssl_name = name;

    return NGX_OK;
}
Example #25
0
static ngx_int_t
ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s)
{
    u_char                       *p;
    ssize_t                       n, size;
    ngx_connection_t             *c, *pc;
    ngx_stream_upstream_t        *u;
    ngx_stream_proxy_srv_conf_t  *pscf;
    u_char                        buf[NGX_PROXY_PROTOCOL_MAX_HEADER];

    c = s->connection;

    ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "stream proxy send PROXY protocol header");

    p = ngx_proxy_protocol_write(c, buf, buf + NGX_PROXY_PROTOCOL_MAX_HEADER);
    if (p == NULL) {
        ngx_stream_proxy_finalize(s, NGX_ERROR);
        return NGX_ERROR;
    }

    u = s->upstream;

    pc = u->peer.connection;

    size = p - buf;

    n = pc->send(pc, buf, size);

    if (n == NGX_AGAIN) {
        if (ngx_handle_write_event(pc->write, 0) != NGX_OK) {
            ngx_stream_proxy_finalize(s, NGX_ERROR);
            return NGX_ERROR;
        }

        pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);

        ngx_add_timer(pc->write, pscf->timeout);

        pc->write->handler = ngx_stream_proxy_connect_handler;

        return NGX_AGAIN;
    }

    if (n == NGX_ERROR) {
        ngx_stream_proxy_finalize(s, NGX_DECLINED);
        return NGX_ERROR;
    }

    if (n != size) {

        /*
         * PROXY protocol specification:
         * The sender must always ensure that the header
         * is sent at once, so that the transport layer
         * maintains atomicity along the path to the receiver.
         */

        ngx_log_error(NGX_LOG_ERR, c->log, 0,
                      "could not send PROXY protocol header at once");

        ngx_stream_proxy_finalize(s, NGX_DECLINED);

        return NGX_ERROR;
    }

    return NGX_OK;
}
Example #26
0
static void
ngx_stream_proxy_init_upstream(ngx_stream_session_t *s)
{
    u_char                       *p;
    ngx_connection_t             *c, *pc;
    ngx_log_handler_pt            handler;
    ngx_stream_upstream_t        *u;
    ngx_stream_proxy_srv_conf_t  *pscf;

    u = s->upstream;

    if (u->proxy_protocol) {
        if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) {
            return;
        }

        u->proxy_protocol = 0;
    }

    pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);

    pc = u->peer.connection;

#if (NGX_STREAM_SSL)
    if (pscf->ssl && pc->ssl == NULL) {
        ngx_stream_proxy_ssl_init_connection(s);
        return;
    }
#endif

    c = s->connection;

    if (c->log->log_level >= NGX_LOG_INFO) {
        ngx_str_t  s;
        u_char     addr[NGX_SOCKADDR_STRLEN];

        s.len = NGX_SOCKADDR_STRLEN;
        s.data = addr;

        if (ngx_connection_local_sockaddr(pc, &s, 1) == NGX_OK) {
            handler = c->log->handler;
            c->log->handler = NULL;

            ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy %V connected to %V",
                          &s, u->peer.name);

            c->log->handler = handler;
        }
    }

    c->log->action = "proxying connection";

    p = ngx_pnalloc(c->pool, pscf->buffer_size);
    if (p == NULL) {
        ngx_stream_proxy_finalize(s, NGX_ERROR);
        return;
    }

    u->upstream_buf.start = p;
    u->upstream_buf.end = p + pscf->buffer_size;
    u->upstream_buf.pos = p;
    u->upstream_buf.last = p;

    u->connected = 1;

    pc->read->handler = ngx_stream_proxy_upstream_handler;
    pc->write->handler = ngx_stream_proxy_upstream_handler;

    if (ngx_stream_proxy_process(s, 1, 0) != NGX_OK) {
        return;
    }

    ngx_stream_proxy_process(s, 0, 1);
}
Example #27
0
static void
ngx_stream_proxy_handler(ngx_stream_session_t *s)
{
    u_char                          *p;
    ngx_connection_t                *c;
    ngx_stream_upstream_t           *u;
    ngx_stream_proxy_srv_conf_t     *pscf;
    ngx_stream_upstream_srv_conf_t  *uscf;

    c = s->connection;

    pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);

    ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
                   "proxy connection handler");

    u = ngx_pcalloc(c->pool, sizeof(ngx_stream_upstream_t));
    if (u == NULL) {
        ngx_stream_proxy_finalize(s, NGX_ERROR);
        return;
    }

    s->upstream = u;

    s->log_handler = ngx_stream_proxy_log_error;

    u->peer.log = c->log;
    u->peer.log_error = NGX_ERROR_ERR;

    u->peer.local = pscf->local;

    uscf = pscf->upstream;

    if (uscf->peer.init(s, uscf) != NGX_OK) {
        ngx_stream_proxy_finalize(s, NGX_ERROR);
        return;
    }

    u->peer.start_time = ngx_current_msec;

    if (pscf->next_upstream_tries
        && u->peer.tries > pscf->next_upstream_tries)
    {
        u->peer.tries = pscf->next_upstream_tries;
    }

    u->proxy_protocol = pscf->proxy_protocol;
    u->start_sec = ngx_time();

    p = ngx_pnalloc(c->pool, pscf->buffer_size);
    if (p == NULL) {
        ngx_stream_proxy_finalize(s, NGX_ERROR);
        return;
    }

    u->downstream_buf.start = p;
    u->downstream_buf.end = p + pscf->buffer_size;
    u->downstream_buf.pos = p;
    u->downstream_buf.last = p;

    c->write->handler = ngx_stream_proxy_downstream_handler;
    c->read->handler = ngx_stream_proxy_downstream_handler;

    if (u->proxy_protocol
#if (NGX_STREAM_SSL)
        && pscf->ssl == NULL
#endif
        && pscf->buffer_size >= NGX_PROXY_PROTOCOL_MAX_HEADER)
    {
        /* optimization for a typical case */

        ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
                       "stream proxy send PROXY protocol header");

        p = ngx_proxy_protocol_write(c, u->downstream_buf.last,
                                     u->downstream_buf.end);
        if (p == NULL) {
            ngx_stream_proxy_finalize(s, NGX_ERROR);
            return;
        }

        u->downstream_buf.last = p;
        u->proxy_protocol = 0;
    }

    if (ngx_stream_proxy_process(s, 0, 0) != NGX_OK) {
        return;
    }

    ngx_stream_proxy_connect(s);
}
Example #28
0
static ngx_int_t
ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream,
    ngx_uint_t do_write)
{
    off_t                        *received, limit;
    size_t                        size, limit_rate;
    ssize_t                       n;
    ngx_buf_t                    *b;
    ngx_uint_t                    flags;
    ngx_msec_t                    delay;
    ngx_connection_t             *c, *pc, *src, *dst;
    ngx_log_handler_pt            handler;
    ngx_stream_upstream_t        *u;
    ngx_stream_proxy_srv_conf_t  *pscf;

    u = s->upstream;

    c = s->connection;
    pc = u->connected ? u->peer.connection : NULL;

    pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);

    if (from_upstream) {
        src = pc;
        dst = c;
        b = &u->upstream_buf;
        limit_rate = pscf->download_rate;
        received = &u->received;

    } else {
        src = c;
        dst = pc;
        b = &u->downstream_buf;
        limit_rate = pscf->upload_rate;
        received = &s->received;
    }

    for ( ;; ) {

        if (do_write) {

            size = b->last - b->pos;

            if (size && dst && dst->write->ready) {

                n = dst->send(dst, b->pos, size);

                if (n == NGX_ERROR) {
                    ngx_stream_proxy_finalize(s, NGX_DECLINED);
                    return NGX_ERROR;
                }

                if (n > 0) {
                    b->pos += n;

                    if (b->pos == b->last) {
                        b->pos = b->start;
                        b->last = b->start;
                    }
                }
            }
        }

        size = b->end - b->last;

        if (size && src->read->ready && !src->read->delayed) {

            if (limit_rate) {
                limit = (off_t) limit_rate * (ngx_time() - u->start_sec + 1)
                        - *received;

                if (limit <= 0) {
                    src->read->delayed = 1;
                    delay = (ngx_msec_t) (- limit * 1000 / limit_rate + 1);
                    ngx_add_timer(src->read, delay);
                    break;
                }

                if ((off_t) size > limit) {
                    size = (size_t) limit;
                }
            }

            n = src->recv(src, b->last, size);

            if (n == NGX_AGAIN || n == 0) {
                break;
            }

            if (n > 0) {
                if (limit_rate) {
                    delay = (ngx_msec_t) (n * 1000 / limit_rate);

                    if (delay > 0) {
                        src->read->delayed = 1;
                        ngx_add_timer(src->read, delay);
                    }
                }

                *received += n;
                b->last += n;
                do_write = 1;

                continue;
            }

            if (n == NGX_ERROR) {
                src->read->eof = 1;
            }
        }

        break;
    }

    if (src->read->eof && (b->pos == b->last || (dst && dst->read->eof))) {
        handler = c->log->handler;
        c->log->handler = NULL;

        ngx_log_error(NGX_LOG_INFO, c->log, 0,
                      "%s disconnected"
                      ", bytes from/to client:%O/%O"
                      ", bytes from/to upstream:%O/%O",
                      from_upstream ? "upstream" : "client",
                      s->received, c->sent, u->received, pc ? pc->sent : 0);

        c->log->handler = handler;

        ngx_stream_proxy_finalize(s, NGX_OK);
        return NGX_DONE;
    }

    flags = src->read->eof ? NGX_CLOSE_EVENT : 0;

    if (ngx_handle_read_event(src->read, flags) != NGX_OK) {
        ngx_stream_proxy_finalize(s, NGX_ERROR);
        return NGX_ERROR;
    }

    if (dst) {
        if (ngx_handle_write_event(dst->write, 0) != NGX_OK) {
            ngx_stream_proxy_finalize(s, NGX_ERROR);
            return NGX_ERROR;
        }

        if (!c->read->delayed && !pc->read->delayed) {
            ngx_add_timer(c->write, pscf->timeout);

        } else if (c->write->timer_set) {
            ngx_del_timer(c->write);
        }
    }

    return NGX_OK;
}
// 在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_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;
}