static char *
ngx_tcp_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 
{
    ngx_tcp_proxy_conf_t *pcf = conf;

    u_short                     port = 80;
    ngx_str_t                  *value, *url = &pcf->url;
    ngx_url_t                   u;
    ngx_tcp_core_srv_conf_t    *cscf;

    cscf = ngx_tcp_conf_get_module_srv_conf(cf, ngx_tcp_core_module);

    if (cscf->protocol && ngx_strncmp(cscf->protocol->name.data,
                                      (u_char *)"tcp_generic",
                                      sizeof("tcp_generic") - 1) != 0) {

        return "the protocol should be tcp_generic";
    }

    if (cscf->protocol == NULL) {
        cscf->protocol = &ngx_tcp_generic_protocol;
    }

    if (pcf->upstream.upstream) {
        return "is duplicate";
    }

    value = cf->args->elts;

    url = &value[1];

    ngx_memzero(&u, sizeof(u));

    u.url.len = url->len;
    u.url.data = url->data;
    u.default_port = port;
    u.uri_part = 1;
    u.no_resolve = 1;

    pcf->upstream.upstream = ngx_tcp_upstream_add(cf, &u, 0);
    if (pcf->upstream.upstream == NULL) {
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}
static char *
ngx_tcp_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) 
{
    char                          *rv;
    void                          *mconf;
    ngx_str_t                     *value;
    ngx_url_t                      u;
    ngx_uint_t                     m;
    ngx_conf_t                     pcf;
    ngx_tcp_module_t              *module;
    ngx_tcp_conf_ctx_t            *ctx, *tcp_ctx;
    ngx_tcp_upstream_srv_conf_t   *uscf;

    ngx_memzero(&u, sizeof(ngx_url_t));

    value = cf->args->elts;
    u.host = value[1];
    u.no_resolve = 1;

    uscf = ngx_tcp_upstream_add(cf, &u, 
            NGX_TCP_UPSTREAM_CREATE
            |NGX_TCP_UPSTREAM_WEIGHT
            |NGX_TCP_UPSTREAM_MAX_FAILS
            |NGX_TCP_UPSTREAM_FAIL_TIMEOUT
            |NGX_TCP_UPSTREAM_MAX_BUSY
            |NGX_TCP_UPSTREAM_DOWN
            |NGX_TCP_UPSTREAM_BACKUP);
    if (uscf == NULL) {
        return NGX_CONF_ERROR;
    }

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

    tcp_ctx = cf->ctx;
    ctx->main_conf = tcp_ctx->main_conf;

    /* the upstream{}'s srv_conf */

    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_tcp_max_module);
    if (ctx->srv_conf == NULL) {
        return NGX_CONF_ERROR;
    }

    ctx->srv_conf[ngx_tcp_upstream_module.ctx_index] = uscf;

    uscf->srv_conf = ctx->srv_conf;


    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_TCP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;

        if (module->create_srv_conf) {
            mconf = module->create_srv_conf(cf);
            if (mconf == NULL) {
                return NGX_CONF_ERROR;
            }

            ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
        }

    }

    /* parse inside upstream{} */

    pcf = *cf;
    cf->ctx = ctx;
    cf->cmd_type = NGX_TCP_UPS_CONF;

    rv = ngx_conf_parse(cf, NULL);

    *cf = pcf;

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

    if (uscf->servers == NULL) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "no servers are inside upstream");
        return NGX_CONF_ERROR;
    }

    return rv;
}
static char *
ngx_tcp_websocket_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 
{
    ngx_tcp_websocket_conf_t   *wcf = conf;

    size_t                      add = 0;
    u_short                     port = 80;
    ngx_str_t                  *value, *url = &wcf->url;
    ngx_url_t                   u;
    ngx_tcp_core_srv_conf_t    *cscf;
    ngx_tcp_path_upstream_t    *pu;

    cscf = ngx_tcp_conf_get_module_srv_conf(cf, ngx_tcp_core_module);

    if (cscf->protocol && ngx_strncmp(cscf->protocol->name.data, 
                                      (u_char *)"tcp_websocket",
                                      sizeof("tcp_websocket") - 1) != 0) {

        return "the protocol should be tcp_websocket";
    }

    if (cscf->protocol == NULL) {
        cscf->protocol = &ngx_tcp_websocket_protocol;
    }

    value = cf->args->elts;

    if (cf->args->nelts == 3) {
        url = &value[2];
    }
    else {
        url = &value[1];
    }

    if (ngx_strncasecmp(url->data, (u_char *)"ws://", 5) == 0) {
        add = 5;
        port = 80;
    }
    else if (ngx_strncasecmp(url->data, (u_char *)"wss://", 6) == 0) {
        add = 6;
        port = 443;
    }

    if (add) {
        wcf->scheme.data = url->data;
        wcf->scheme.len = add;
    }
    else {
        wcf->scheme.data = (u_char *)"ws://";
        wcf->scheme.len = 5;
    }

    url->data += add;
    url->len  -= add;

    ngx_memzero(&u, sizeof(u));

    u.url.len = url->len;
    u.url.data = url->data;
    u.default_port = port;
    u.uri_part = 1;
    u.no_resolve = 1;

    if (cf->args->nelts == 3) {
        pu = ngx_array_push(&wcf->path_upstreams);
        if (pu == NULL) {
            return NGX_CONF_ERROR;
        }

        pu->path = value[1];
        pu->upstream = ngx_tcp_upstream_add(cf, &u, 0);
    }
    else {
        if (wcf->upstream.upstream) {
            return "is duplicate default upstream";
        }

        wcf->upstream.upstream = ngx_tcp_upstream_add(cf, &u, 0);
        if (wcf->upstream.upstream == NULL) {
            return NGX_CONF_ERROR;
        }
    }

    return NGX_CONF_OK;
}