Exemplo n.º 1
0
void 
ngx_http_php_zend_uthread_create(ngx_http_request_t *r, char *func_prefix)
{
    zval *func_main;
    zval *func_valid;
    zval retval;
    ngx_http_php_ctx_t *ctx;
    ngx_http_php_loc_conf_t *plcf;
    ngx_str_t func_name;

    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    if (ctx == NULL) {
        return ;
    }
    
    ctx->generator_closure = (zval *)emalloc(sizeof(zval));

    plcf = ngx_http_get_module_loc_conf(r, ngx_http_php_module);

    //func_name.data = ngx_pnalloc(r->pool, strlen(func_prefix)+sizeof("_18446744073709551616")-1+NGX_TIME_T_LEN);
    //func_name.len = ngx_sprintf(func_name.data, "%s_%V", func_prefix, &(plcf->content_inline_code->code_id)) - func_name.data;

    func_name.data = ngx_pnalloc(r->pool, strlen(func_prefix) + 32);

    func_name.len = ngx_sprintf(func_name.data, "%s_%V", func_prefix, &(plcf->content_inline_code->code_id)) - func_name.data;


    ngx_php_debug("%*s", (int)func_name.len, func_name.data);

    ZVAL_STRINGL(func_main, (char *)func_name.data, func_name.len, 1);
    call_user_function(EG(function_table), NULL, func_main, ctx->generator_closure, 0, NULL TSRMLS_CC);
    zval_ptr_dtor(&func_main);

    if (Z_TYPE_P(ctx->generator_closure) == IS_OBJECT){
    	MAKE_STD_ZVAL(func_valid);
        ZVAL_STRING(&func_valid, "valid", 1);
        if (call_user_function(NULL, &(ctx->generator_closure), func_valid, &retval, 0, NULL TSRMLS_CC) == FAILURE)
        {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed calling valid");
            return ;
        }
        zval_ptr_dtor(&func_valid);

        ngx_php_debug("r:%p, closure:%p, retval:%d", r, ctx->generator_closure, Z_TYPE(retval));

        if (Z_TYPE(retval) == IS_BOOL && Z_BVAL(retval)){
            ctx->phase_status = NGX_AGAIN;
        }else {
            ctx->phase_status = NGX_OK;
        }

    }else {
        ngx_php_debug("r:%p, closure:%p, retval:%d", r, ctx->generator_closure, Z_TYPE(retval));
        efree(ctx->generator_closure);
    }
}
ngx_int_t 
ngx_http_php_socket_recv(ngx_http_request_t *r)
{
    ngx_int_t                           rc;
    ngx_http_php_ctx_t                  *ctx;
    ngx_http_php_socket_upstream_t      *u;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
                   "php tcp receive");
    ngx_php_debug("php socket receive");

    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    u = ctx->upstream;

    if (u == NULL || u->peer.connection == NULL) {

        return NGX_ERROR;
    }

    if (u->request != r) {

        return NGX_ERROR;
    }

    rc = ngx_http_php_socket_upstream_recv(r, u);

    ngx_php_debug("%d", u->enabled_receive);

    if (u->enabled_receive == 0) {
        u->enabled_receive = 1;
    }else {
        ctx->delay_time = 0;
        ngx_http_php_sleep(r);
    }

    if (rc == NGX_AGAIN) {
        
        //return NGX_AGAIN;
    }

    if (rc == NGX_ERROR) {

    }

    if (rc == NGX_OK) {

    }

    /* rc == NGX_AGAIN */

    u->read_event_handler = (ngx_http_php_socket_upstream_handler_pt) ngx_http_php_socket_upstream_recv_handler;

    return NGX_OK;
}
static void 
ngx_http_php_socket_send_handler(ngx_http_request_t *r, 
    ngx_http_php_socket_upstream_t *u)
{
    ngx_connection_t                    *c;
    ngx_http_php_loc_conf_t             *plcf;

    c = u->peer.connection;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
                   "php socket send handler.");
    ngx_php_debug("php socket send handler.");

    if (c->write->timedout) {
        plcf = ngx_http_get_module_loc_conf(r, ngx_http_php_module);

        if (plcf->log_socket_errors) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 
                          "php socket write timed out.");
        }

        return ;
    }

    if (u->request_bufs) {
        (void) ngx_http_php_socket_upstream_send(r, u);
    }

}
void 
ngx_http_php_socket_clear(ngx_http_request_t *r)
{
    ngx_http_php_socket_upstream_t      *u;
    ngx_http_php_ctx_t                  *ctx;

    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    u = ctx->upstream;

    if (u == NULL || 
        u->peer.connection == NULL )
    {
        return ;
    }

    u->enabled_receive = 0;

    if (u->request != r) {

    }

    ngx_php_debug("u->peer.connected: %p, r->connection: %p", u->peer.connection, r->connection);

    ngx_http_php_socket_finalize(r, u);

    return ;
}
void 
ngx_http_php_socket_close(ngx_http_request_t *r)
{
    ngx_http_php_socket_upstream_t      *u;
    ngx_http_php_ctx_t                  *ctx;

    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    u = ctx->upstream;

    if (u == NULL || 
        u->peer.connection == NULL )
    {
        return ;
    }

    u->enabled_receive = 0;

    if (u->request != r) {

    }

    //r->connection->write->handler = ngx_http_php_socket_handler;

    ngx_php_debug("u->peer.connected: %p, r->connection: %p", u->peer.connection, r->connection);

    ngx_http_php_socket_finalize(r, u);

    ctx->delay_time = 0;

    ngx_http_php_sleep(r);

    return ;
}
static void 
ngx_http_php_socket_dummy_handler(ngx_http_request_t *r, 
    ngx_http_php_socket_upstream_t *u)
{
    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
                    "ngx_php tcp socket dummy handler");
    ngx_php_debug("php socket dummy handler");
}
Exemplo n.º 7
0
void 
ngx_http_php_zend_uthread_resume(ngx_http_request_t *r)
{
    ngx_php_request = r;

    ngx_http_php_ctx_t *ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    ngx_php_debug("ctx: %p", ctx);

    if (ctx == NULL) {
        
    }

    zend_try {
        zval *closure;
        zval *func_next;
        zval *func_valid;
        zval retval;

        closure = ctx->generator_closure;

        MAKE_STD_ZVAL(func_valid);
        ZVAL_STRING(func_next, "next", 1);
        call_user_function(NULL, &(closure), func_next, &retval, 0, NULL TSRMLS_CC);
        zval_ptr_dtor(&func_next);

        MAKE_STD_ZVAL(func_valid);
        ZVAL_STRING(func_valid, "valid", 1);
        call_user_function(NULL, &(closure), func_valid, &retval, 0, NULL TSRMLS_CC);
        zval_ptr_dtor(&func_valid);

        ngx_php_debug("r:%p, closure:%p, retval:%d", r, closure, Z_TYPE(retval));

        if (Z_TYPE(retval) == IS_BOOL && Z_BVAL(retval)) {
            ctx->phase_status = NGX_AGAIN;
        }else {
            ctx->phase_status = NGX_OK;
            ngx_http_core_run_phases(r);
            efree(ctx->generator_closure);
            ctx->generator_closure = NULL;
        }

    }zend_catch {

    }zend_end_try();
}
static void 
ngx_http_php_socket_finalize(ngx_http_request_t *r, 
    ngx_http_php_socket_upstream_t *u)
{
    ngx_connection_t        *c;

    ngx_php_debug("request: %p, u: %p, u->cleanup: %p", r, u, u->cleanup);

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "php finalize socket");

    if (u->cleanup) {
        *u->cleanup = NULL;
        u->cleanup = NULL;
    }

    if (u->resolved && u->resolved->ctx) {
        ngx_resolve_name_done(u->resolved->ctx);
        u->resolved->ctx = NULL;
    }

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

    c = u->peer.connection;
    if (c) {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "close http upstream connection: %d",
                       c->fd);

        if (c->pool) {
            ngx_destroy_pool(c->pool);
            c->pool = NULL;
        }

        ngx_close_connection(c);
    }

    ngx_php_debug("socket end");

}
ngx_int_t 
ngx_http_php_socket_send(ngx_http_request_t *r)
{
    ngx_int_t                           rc;
    ngx_connection_t                    *c;
    ngx_http_php_ctx_t                  *ctx;
    ngx_http_php_socket_upstream_t      *u;

    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    u = ctx->upstream;

    if (u == NULL || u->peer.connection == NULL) {

        return NGX_ERROR;
    }

    u->enabled_receive = 0;

    c = u->peer.connection;

    if (c->tcp_nodelay) {

    }

    if (u->request != r) {

        return NGX_ERROR;
    }

    rc = ngx_http_php_socket_upstream_send(r, u);

    ngx_php_debug("socket send returned %d", (int)rc);

    if (rc == NGX_ERROR) {

        return NGX_ERROR;
    }

    if (rc == NGX_OK) {

        return NGX_OK;
    }

    /* rc == NGX_AGAIN */

    return NGX_AGAIN;
}
Exemplo n.º 10
0
void 
ngx_http_php_zend_uthread_access_inline_routine(ngx_http_request_t *r)
{
    ngx_http_php_ctx_t *ctx;
    ngx_http_php_loc_conf_t *plcf;
    ngx_str_t inline_code;

    plcf = ngx_http_get_module_loc_conf(r, ngx_http_php_module);
    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    ctx->phase_status = NGX_OK;

    ngx_php_request = r;

    ngx_php_set_request_status(NGX_DECLINED);

    inline_code.data = ngx_pnalloc(r->pool, sizeof("function ngx_access_(){  }")-1 + ngx_strlen(plcf->access_inline_code->code.string) + 32);

    inline_code.len = ngx_sprintf(inline_code.data, "function ngx_access_%V(){ %*s }", 
                                        &(plcf->access_inline_code->code_id), 
                                        ngx_strlen(plcf->access_inline_code->code.string),
                                        plcf->access_inline_code->code.string
                                    ) - inline_code.data;

    ngx_php_debug("%*s, %d", (int)inline_code.len, inline_code.data, (int)inline_code.len);

    zend_first_try {

        if (!plcf->enabled_access_inline_compile){
            zend_eval_stringl_ex(
                (char *)inline_code.data, 
                inline_code.len, 
                NULL, 
                "ngx_php eval code", 
                1 
                TSRMLS_CC
            );
            plcf->enabled_access_inline_compile = 1;
        }

        ngx_http_php_zend_uthread_create(r, "ngx_access");

    }zend_end_try();
}
static void 
ngx_http_php_socket_upstream_recv_handler(ngx_http_request_t *r, 
    ngx_http_php_socket_upstream_t *u)
{
    //ngx_connection_t                    *c;
    //ngx_http_php_loc_conf_t             *plcf;

    //c = u->peer.connection;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
                   "php socket receive handler.");
    ngx_php_debug("php socket receive handler.");

    u->enabled_receive = 1;

    if (u->buffer.start != NULL) {
        (void) ngx_http_php_socket_upstream_recv(r, u);
    }

}
static void
ngx_http_php_socket_handler(ngx_event_t *ev)
{
    ngx_connection_t                    *c;
    ngx_http_request_t                  *r;
    ngx_http_php_socket_upstream_t      *u;

    c = ev->data;
    u = c->data;
    r = u->request;

    ngx_php_debug("php socket handler, ev->data: %p, ev->write: %d, ev->read: %d", ev->data, ev->write, !ev->write);

    if (ev->write) {
        u->write_event_handler(r, u);
    }else {
        u->read_event_handler(r, u);
    }

    ngx_http_php_zend_uthread_resume(r);

}
Exemplo n.º 13
0
void 
ngx_php_error_cb(int type, 
    const char *error_filename, const uint error_lineno, const char *format, va_list args)
{
    TSRMLS_FETCH();
    char *buffer;
    int buffer_len, display;

    buffer_len = vspprintf(&buffer, PG(log_errors_max_len), format, args);
    
    /* check for repeated errors to be ignored */
    if (PG(ignore_repeated_errors) && PG(last_error_message)) {
        /* no check for PG(last_error_file) is needed since it cannot
         * be NULL if PG(last_error_message) is not NULL */
        if (strcmp(PG(last_error_message), buffer)
            || (!PG(ignore_repeated_source)
                && ((PG(last_error_lineno) != (int)error_lineno)
                    || strcmp(PG(last_error_file), error_filename)))) {
            display = 1;
        } else {
            display = 0;
        }
    } else {
        display = 1;
    }

    /* store the error if it has changed */
    if (display) {
        if (PG(last_error_message)) {
            free(PG(last_error_message));
            PG(last_error_message) = NULL;
        }
        if (PG(last_error_file)) {
            free(PG(last_error_file));
            PG(last_error_file) = NULL;
        }
        if (!error_filename) {
            error_filename = "Unknown";
        }
        PG(last_error_type) = type;
        PG(last_error_message) = strdup(buffer);
        PG(last_error_file) = strdup(error_filename);
        PG(last_error_lineno) = error_lineno;
    }

    /* according to error handling mode, suppress error, throw exception or show it */
    if (EG(error_handling) != EH_NORMAL) {
        switch (type) {
            case E_ERROR:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
            case E_PARSE:
                /* fatal errors are real errors and cannot be made exceptions */
                break;
            case E_STRICT:
            case E_DEPRECATED:
            case E_USER_DEPRECATED:
                /* for the sake of BC to old damaged code */
                break;
            case E_NOTICE:
            case E_USER_NOTICE:
                /* notices are no errors and are not treated as such like E_WARNINGS */
                break;
            default:
                /* throw an exception if we are in EH_THROW mode
                 * but DO NOT overwrite a pending exception
                 */
                if (EG(error_handling) == EH_THROW && !EG(exception)) {
                    zend_throw_error_exception(EG(exception_class), buffer, 0, type TSRMLS_CC);
                }
                efree(buffer);
                return;
        }
    }

    /* display/log the error if necessary */
    if (display && (EG(error_reporting) & type || (type & E_CORE))
        && (PG(log_errors) || PG(display_errors) ) ) {

        char *error_type_str;

        switch (type) {
            case E_ERROR:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
                error_type_str = "Fatal error";
                break;
            case E_RECOVERABLE_ERROR:
                error_type_str = "Catchable fatal error";
                break;
            case E_WARNING:
            case E_CORE_WARNING:
            case E_COMPILE_WARNING:
            case E_USER_WARNING:
                error_type_str = "Warning";
                break;
            case E_PARSE:
                error_type_str = "Parse error";
                break;
            case E_NOTICE:
            case E_USER_NOTICE:
                error_type_str = "Notice";
                break;
            case E_STRICT:
                error_type_str = "Strict Standards";
                break;
            case E_DEPRECATED:
            case E_USER_DEPRECATED:
                error_type_str = "Deprecated";
                break;
            default:
                error_type_str = "Unknown error";
                break;
        }
        buffer_len = spprintf(&buffer, 0, "%s: %s in %s on line %d", error_type_str, buffer, error_filename, error_lineno);

        ngx_buf_t *b;
        ngx_http_php_rputs_chain_list_t *chain;
        ngx_http_php_ctx_t *ctx;
        ngx_http_request_t *r;
        u_char *u_str;
        ngx_str_t ns;

        r = ngx_php_request;
        ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

        if ( ctx == NULL ) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s", buffer);

            ngx_php_debug("ngx_php error handler, ctx is nil.");

            efree(buffer);
            zend_bailout();

            ngx_http_php_zend_uthread_exit(r);
            return ;
        }

        ns.data = (u_char *)buffer;
        ns.len = buffer_len;

        if (ctx->rputs_chain == NULL){
            chain = ngx_pcalloc(r->pool, sizeof(ngx_http_php_rputs_chain_list_t));
            chain->out = ngx_alloc_chain_link(r->pool);
            chain->last = &chain->out;
        }else {
            chain = ctx->rputs_chain;
            (*chain->last)->next = ngx_alloc_chain_link(r->pool);
            chain->last = &(*chain->last)->next;
        }

        b = ngx_calloc_buf(r->pool);
        (*chain->last)->buf = b;
        (*chain->last)->next = NULL;

        u_str = ngx_pstrdup(r->pool, &ns);
        //u_str[ns.len] = '\0';
        (*chain->last)->buf->pos = u_str;
        (*chain->last)->buf->last = u_str + ns.len;
        (*chain->last)->buf->memory = 1;
        ctx->rputs_chain = chain;
        ngx_http_set_ctx(r, ctx, ngx_http_php_module);

        if (r->headers_out.content_length_n == -1){
            r->headers_out.content_length_n += ns.len + 1;
        }else {
            r->headers_out.content_length_n += ns.len;
        }

        if (!r->headers_out.status) {
            r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "%s", buffer);

        ngx_php_debug("ngx_php error handler.");

        efree(buffer);
        zend_bailout();

        ngx_http_php_zend_uthread_exit(r);
        return ;
    }

    /* Log if necessary */
    if (!display) {
        efree(buffer);
        return;
    }

    efree(buffer);
}
ngx_int_t 
ngx_http_php_socket_connect(ngx_http_request_t *r)
{
    ngx_http_php_ctx_t                  *ctx;
    //ngx_http_php_loc_conf_t             *plcf;
    //ngx_str_t                           host;
    //int                                 port;
    ngx_resolver_ctx_t                  *rctx, temp;
    ngx_http_core_loc_conf_t            *clcf;

    ngx_url_t                           url;

    ngx_int_t                           rc;
    ngx_peer_connection_t               *peer;

    ngx_http_php_socket_upstream_t      *u;

    ngx_connection_t                    *c;

    c = r->connection;

    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    if (ctx->upstream == NULL){
        ctx->upstream = ngx_pcalloc(r->pool, sizeof(ngx_http_php_socket_upstream_t));
    }

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

    //r->keepalive = 0;

    u = ctx->upstream;

    u->connect_timeout = 60000;
    u->read_timeout = 60000;
    u->write_timeout = 60000;

    u->enabled_receive = 0;

    u->request = r;

    peer = &u->peer;

    peer->log = r->connection->log;
    peer->log_error = NGX_ERROR_ERR;

    ngx_php_debug("php peer connection log: %p %p", peer->log, peer);

    ngx_memzero(&url, sizeof(ngx_url_t));

    url.url.len = ctx->host.len;
    url.url.data = ctx->host.data;
    url.default_port = (in_port_t) ctx->port;
    url.no_resolve = 1;

    if (ngx_parse_url(r->pool, &url) != NGX_OK) {
        if (url.err) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "%s in upstream \"%V\"", url.err, &url.url);
        }else {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 
                          "failed to parse host name \"%s\"", ctx->host.data);
        }
        return NGX_ERROR;
    }

    u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
    if (u->resolved == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_pcalloc resolved error. %s.", strerror(errno));
        return NGX_ERROR;
    }

    if (url.addrs && url.addrs[0].sockaddr) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
                       "php socket network address given directly");

        u->resolved->sockaddr = url.addrs[0].sockaddr;
        u->resolved->socklen = url.addrs[0].socklen;
        u->resolved->naddrs = 1;
        u->resolved->host = url.addrs[0].name;
    } else {
        u->resolved->host = ctx->host;
        u->resolved->port = (in_port_t) ctx->port;
    }

    // Already real ip address, is not url and not resolve.
    if (u->resolved->sockaddr) {
        rc = ngx_http_php_socket_resolve_retval_handler(r, u);
        if (rc == NGX_AGAIN) {
            return NGX_AGAIN;
        }

        return rc;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    temp.name = ctx->host;
    rctx = ngx_resolve_start(clcf->resolver, &temp);
    if (rctx == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 
                      "failed to start the resolver");
        return NGX_ERROR;
    }

    if (rctx == NGX_NO_RESOLVER) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 
                      "no resolver defined to resolve \"%s\"", ctx->host.data);
        return NGX_ERROR;
    }

    rctx->name = ctx->host;
    rctx->handler = ngx_http_php_socket_resolve_handler;
    rctx->data = u;
    rctx->timeout = clcf->resolver_timeout;

    u->resolved->ctx = rctx;

    if (ngx_resolve_name(rctx) != NGX_OK) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "php tcp socket fail to run resolver immediately");
        return NGX_ERROR;
    }

    return NGX_OK;   
}
static ngx_int_t 
ngx_http_php_socket_upstream_recv(ngx_http_request_t *r, 
    ngx_http_php_socket_upstream_t *u)
{
    //ngx_int_t                         rc;
    ngx_connection_t                    *c;
    ngx_event_t                         *rev;
    ngx_buf_t                           *b;
    size_t                              size;
    ssize_t                             n;

    ngx_http_php_ctx_t                  *ctx;

    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    c = u->peer.connection;
    rev = c->read;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, 
                   "php socket receive data");
    ngx_php_debug("php socket receive data");

    b = &u->buffer;

    if (b->start == NULL) {
        b->start = ngx_palloc(r->pool, u->buffer_size);

        b->pos = b->start;
        b->last = b->start;
        b->end = b->start + u->buffer_size;
        b->temporary = 1;
    }

    for (;;) {
        size = b->end - b->last;

        if (size == 0) {
            b->start = NULL;
            break;
        }

        if (!rev->ready) {
            ngx_php_debug("recv ready: %d", rev->ready);
            if (ngx_handle_read_event(rev, 0) != NGX_OK) {
                n = -1;
                break;
            }

            //ngx_add_timer(rev, 1000);
        }

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

        ngx_php_debug("recv: %s, %d, %d", b->pos, (int)n, (int) size);
        
        if (n == NGX_ERROR) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 
                          "php socket recv error");
            n = -1;
            return NGX_ERROR;
        }

        if (n > 0) {
            b->last += n;
            b->start = NULL;

            ngx_php_debug("buf write in php var.");
            ZVAL_STRINGL(ctx->recv_buf, (char *)b->pos, b->last - b->pos);
            return NGX_AGAIN;
        }

        if (n == NGX_AGAIN) {
            //continue;
            break;
        }

        if (n == NGX_OK) {
            b->start = NULL;
            break;
        }

        b->last += n;
        b->start = NULL;
        break;

        /*if (n > 0) {
            b->last += n;

            continue;
        }*/

    }

    //ngx_php_debug("recv: %*s, %p, %p, %p, %p",(int)(b->last - b->pos),b->pos, b->pos, b->end, b->start, b->last);

    ctx->phase_status = NGX_AGAIN;

    ngx_php_debug("c->read->active:%d,c->read->timer_set:%d", rev->active, rev->timer_set);

#if 1
    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
        
        return NGX_ERROR;
    }
#endif
/*
    if (rev->active) {
        ngx_add_timer(rev, 5 * 1000);
    }else if (rev->timer_set) {
        ngx_del_timer(rev);
    }
*/
    return NGX_AGAIN;

}
static ngx_int_t 
ngx_http_php_socket_upstream_send(ngx_http_request_t *r, 
    ngx_http_php_socket_upstream_t *u)
{
    ngx_int_t           n;
    ngx_connection_t    *c;
    ngx_http_php_ctx_t  *ctx;
    ngx_buf_t           *b;

    c = u->peer.connection;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
                   "php socket send data");
    ngx_php_debug("php socket send data");

    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);
    if (ctx == NULL) {
        return NGX_ERROR;
    }

    b = u->request_bufs->buf;

    for (;;) {
        //ngx_php_debug("%s, %d", b->pos, (int)(b->last - b->pos));
        n = c->send(c, b->pos, b->last - b->pos);
    
        if (n >= 0) {
            b->pos += n;

            if (b->pos == b->last) {
                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, 
                               "php socket send all the data");
                ngx_php_debug("php socket send all the data");

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

                ngx_chain_update_chains(r->pool, &u->free_bufs, &u->busy_bufs, &u->request_bufs,
                    (ngx_buf_tag_t) &ngx_http_php_module);

                u->write_event_handler = (ngx_http_php_socket_upstream_handler_pt) ngx_http_php_socket_dummy_handler;

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

                //ngx_http_php_socket_handler(c->write);
                return NGX_OK;
            }

            /* keep sending more data */
            continue;
        }

        /* NGX_ERROR || NGX_AGAIN */
        break;
    }

    if (n == NGX_ERROR) {

        return NGX_ERROR;
    }

    /* n == NGX_AGAIN */

    ctx->phase_status = NGX_AGAIN;

    u->write_event_handler = (ngx_http_php_socket_upstream_handler_pt) ngx_http_php_socket_send_handler;

    ngx_add_timer(c->write, 5 * 1000);

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

    return NGX_AGAIN;


}
static void 
ngx_http_php_socket_connected_handler(ngx_http_request_t *r, 
    ngx_http_php_socket_upstream_t *u)
{
    ngx_php_debug("php socket connected handler");
}
static int 
ngx_http_php_socket_resolve_retval_handler(ngx_http_request_t *r, 
    ngx_http_php_socket_upstream_t *u)
{
    ngx_int_t                       rc;
    ngx_http_php_ctx_t              *ctx;
    ngx_peer_connection_t           *peer;
    ngx_connection_t                *c;
    ngx_http_upstream_resolved_t    *ur;

    ctx = ngx_http_get_module_ctx(r, ngx_http_php_module);

    peer = &u->peer;

    ngx_php_debug("%p", peer);

    ur = u->resolved;

    if (ur->sockaddr) {
        peer->sockaddr = ur->sockaddr;
        peer->socklen = ur->socklen;
        peer->name = &ur->host;
    }else {
        return NGX_ERROR;
    }

    peer->get = ngx_http_php_socket_get_peer;

    rc = ngx_event_connect_peer(peer);

    ngx_php_debug("rc: %d %p", (int)rc, ctx->generator_closure);

    if (rc == NGX_ERROR) {

        return NGX_ERROR;
    }

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

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

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

    //ctx->phase_status = NGX_AGAIN;

    c = peer->connection;
    c->data = u;
    u->request = r;

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

    u->write_event_handler = (ngx_http_php_socket_upstream_handler_pt )ngx_http_php_socket_connected_handler;
    u->read_event_handler = (ngx_http_php_socket_upstream_handler_pt )ngx_http_php_socket_connected_handler;

    c->sendfile &= r->connection->sendfile;

    if (c->pool == NULL) {

        /* we need separate pool here to be able to cache SSL connections */

        c->pool = ngx_create_pool(128, r->connection->log);
        if (c->pool == NULL) {
            return NGX_ERROR;
        }
    }

    c->log = r->connection->log;
    c->pool->log = c->log;
    c->read->log = c->log;
    c->write->log = c->log;

    /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */

    if (rc == NGX_OK) {
        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
                       "php socket connected: fd:%d", (int) c->fd);
        ngx_php_debug("php socket connected: fd:%d", (int) c->fd);

        ctx->phase_status = NGX_OK;

        if (ngx_handle_write_event(c->write, 0) != NGX_OK) {

            return NGX_ERROR;
        }

        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {

            return NGX_ERROR;
        }

        u->read_event_handler = (ngx_http_php_socket_upstream_handler_pt) ngx_http_php_socket_dummy_handler;
        u->write_event_handler = (ngx_http_php_socket_upstream_handler_pt) ngx_http_php_socket_dummy_handler;
    
        return NGX_OK;
    }

    // rc == NGX_AGAIN
    
    ctx->phase_status = NGX_AGAIN;
    
    ngx_add_timer(c->write, 5 * 1000);

    return NGX_AGAIN;
}
static void 
ngx_http_php_socket_resolve_handler(ngx_resolver_ctx_t *ctx)
{
    ngx_http_request_t              *r;
    //ngx_connection_t                *c;
    ngx_http_upstream_resolved_t    *ur;
    ngx_http_php_socket_upstream_t  *u;
    u_char                          *p;
    size_t                          len;
    //ngx_http_php_ctx_t              *php_ctx;

    socklen_t                        socklen;
    struct sockaddr                 *sockaddr;

    ngx_uint_t                      i;

    u = ctx->data;
    r = u->request;
    //c = r->connection;
    ur = u->resolved;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "php socket resolve handler");

    ngx_php_debug("php socket resolve handler");

    if (ctx->state) {
        return ;
    }

    ur->naddrs = ctx->naddrs;
    ur->addrs = ctx->addrs;

#if (NGX_DEBUG)
    {
    u_char      text[NGX_SOCKADDR_STRLEN];
    ngx_str_t   addr;
    ngx_uint_t  i;

    addr.data = text;

    for (i = 0; i < ctx->naddrs; i++ ) {
        addr.len = ngx_sock_ntop(ur->addrs[i].sockaddr, ur->addrs[i].socklen,
                                 text, NGX_SOCKADDR_STRLEN, 0);

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 
                       "name was resolved to %V", &addr);
    }
    }
#endif

    if (ur->naddrs == 1) {
        i = 0;
    }else {
        i = ngx_random() % ur->naddrs;
    }

    socklen = ur->addrs[i].socklen;

    sockaddr = ngx_palloc(r->pool, socklen);
    if (sockaddr == NULL) {

    }

    ngx_memcpy(sockaddr, ur->addrs[i].sockaddr, socklen);

    switch (sockaddr->sa_family) {
#if (NGX_HAVE_INET6)
    case AF_INET6:
        ((struct sockaddr_in6 *) sockaddr)->sin6_port = htons(ur->port);
        break;
#endif
    default: /* AF_INET */
        ((struct sockaddr_in *) sockaddr)->sin_port = htons(ur->port);
    }

    p = ngx_pnalloc(r->pool, NGX_SOCKADDR_STRLEN);
    if (p == NULL) {
        return ;
    }

    len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
    ur->sockaddr = sockaddr;
    ur->socklen = socklen;

    ur->host.data = p;
    ur->host.len = len;
    ur->naddrs = 1;

    ngx_resolve_name_done(ctx);
    ur->ctx = NULL;

    ngx_http_php_socket_resolve_retval_handler(r, u);

    return ;
}