static void be_connect(void *data, int fd)
{
    cosocket_t *c*k = data;

    if(fd < 0) {
        connection_pool_counter_operate(c*k->pool_key, -1);

        lua_pushnil(c*k->L);

        if(se_errno == SE_DNS_QUERY_TIMEOUT) {
            lua_pushstring(c*k->L, "Connect error!(dns query timeout)");

        } else if(se_errno == SE_CONNECT_TIMEOUT) {
            lua_pushstring(c*k->L, "Connect error!(timeout)");

        } else {
            lua_pushstring(c*k->L, "Connect error!(unknow)");
        }

        c*k->status = 0;
        c*k->inuse = 0;

        lua_f_lua_uthread_resume_in_c(c*k->L, 2);
        return;
    }

    int ret = _be_connect(c*k, fd, 1);

    if(ret == -2) {
        return;
    }

    lua_f_lua_uthread_resume_in_c(c*k->L, ret);
}
static int cosocket_be_close(se_ptr_t *ptr)
{
    //printf("cosocket_be_close %d\n", ptr->fd);
    int fd = ptr->fd;

    cosocket_connection_pool_t *n = ptr->data;
    int k = n->pool_key % 64;

    if(n == connect_pool_p[0][k]) {
        connect_pool_p[0][k] = n->next;

        if(n->next) {
            ((cosocket_connection_pool_t *) n->next)->uper = NULL;
        }

    } else if(n == connect_pool_p[1][k]) {
        connect_pool_p[1][k] = n->next;

        if(n->next) {
            ((cosocket_connection_pool_t *) n->next)->uper = NULL;
        }

    } else {
        ((cosocket_connection_pool_t *) n->uper)->next = n->next;

        if(n->next) {
            ((cosocket_connection_pool_t *) n->next)->uper = n->uper;
        }
    }

    se_delete(n->ptr);
    n->ptr = NULL;

    if(n->ssl) {
        SSL_free(n->ssl);
        n->ssl = NULL;
        SSL_CTX_free(n->ctx);
        n->ctx = NULL;
    }

    connection_pool_counter_operate(n->pool_key, -1);
    close(fd);

    free(n);

    return 1;
}
static int _lua_co_close(lua_State *L, cosocket_t *c*k)
{
    if(c*k->read_buf) {
        cosocket_link_buf_t *fr = c*k->read_buf;
        cosocket_link_buf_t *nb = NULL;

        while(fr) {
            nb = fr->next;
            free(fr->buf);
            free(fr);
            fr = nb;
        }

        c*k->read_buf = NULL;
    }

    if(c*k->send_buf_need_free) {
        free(c*k->send_buf_need_free);
        c*k->send_buf_need_free = NULL;
    }

    if(c*k->pool_wait) {
        delete_in_waiting_get_connection(c*k->pool_wait);
        c*k->pool_wait = NULL;
    }

    delete_timeout(c*k->timeout_ptr);
    c*k->timeout_ptr = NULL;

    c*k->status = 0;

    if(c*k->fd > -1) {
        ((se_ptr_t *) c*k->ptr)->fd = c*k->fd;

        if(c*k->pool_size < 1
           || add_connection_to_pool(_loop_fd, c*k->pool_key, c*k->pool_size, c*k->ptr, c*k->ssl,
                                     c*k->ctx, c*k->ssl_pw) == 0) {
            se_delete(c*k->ptr);
            c*k->ptr = NULL;

            connection_pool_counter_operate(c*k->pool_key, -1);
            close(c*k->fd);

            if(c*k->ssl) {
                SSL_free(c*k->ssl);
                c*k->ssl = NULL;
            }

            if(c*k->ctx) {
                SSL_CTX_free(c*k->ctx);
                c*k->ctx = NULL;
            }

            if(c*k->ssl_pw) {
                free(c*k->ssl_pw);
                c*k->ssl_pw = NULL;
            }

        }

        c*k->ssl = NULL;
        c*k->ctx = NULL;
        c*k->ssl_pw = NULL;

        c*k->ptr = NULL;
        c*k->fd = -1;
    }
}
static void timeout_handle(void *ptr)
{
    cosocket_t *c*k = ptr;
    delete_timeout(c*k->timeout_ptr);
    c*k->timeout_ptr = NULL;

    if(c*k->pool_wait) {
        delete_in_waiting_get_connection(c*k->pool_wait);
        c*k->pool_wait = NULL;
    }

    lua_pushnil(c*k->L);

    if(c*k->ptr) {
        if(c*k->status == 3) {
            lua_pushstring(c*k->L, "Connect error!(wait pool timeout)");

        } else if(((se_ptr_t *) c*k->ptr)->wfunc == cosocket_be_ssl_connected) {
            lua_pushstring(c*k->L, "SSL Connect timeout!");

        } else if(((se_ptr_t *) c*k->ptr)->wfunc == cosocket_be_write) {
            lua_pushstring(c*k->L, "Send timeout!");

        } else if(((se_ptr_t *) c*k->ptr)->rfunc == cosocket_be_read) {
            lua_pushstring(c*k->L, "Read timeout!");

        } else {
            lua_pushstring(c*k->L, "Timeout!");
        }

    } else {
        if(c*k->status == 3) {
            lua_pushstring(c*k->L, "Connect error!(wait pool timeout)");

        } else {
            lua_pushstring(c*k->L, "Timeout!");
        }
    }

    {
        se_delete(c*k->ptr);
        c*k->ptr = NULL;

        if(c*k->fd > -1) {
            connection_pool_counter_operate(c*k->pool_key, -1);
            close(c*k->fd);
            c*k->fd = -1;
        }

        c*k->status = 0;
    }

    if(c*k->ssl) {
        SSL_shutdown(c*k->ssl);
        SSL_free(c*k->ssl);
        c*k->ssl = NULL;
        SSL_CTX_free(c*k->ctx);
        c*k->ctx = NULL;
    }

    if(c*k->read_buf) {
        cosocket_link_buf_t *fr = c*k->read_buf;
        cosocket_link_buf_t *nb = NULL;

        while(fr) {
            nb = fr->next;
            free(fr->buf);
            free(fr);
            fr = nb;
        }

        c*k->read_buf = NULL;
    }

    if(c*k->send_buf_need_free) {
        free(c*k->send_buf_need_free);
        c*k->send_buf_need_free = NULL;
    }


    c*k->inuse = 0;

    lua_f_lua_uthread_resume_in_c(c*k->L, 2);
}
int cosocket_be_read(se_ptr_t *ptr)
{
    cosocket_t *c*k = ptr->data;
    int n = 0, ret = 0;

init_read_buf:

    if(!c*k->read_buf
       || (c*k->last_buf->buf_len >= c*k->last_buf->buf_size)) {    /// init read buf
        cosocket_link_buf_t *nbuf = NULL;
        nbuf = malloc(sizeof(cosocket_link_buf_t));

        if(nbuf == NULL) {
            LOGF(ERR, "malloc error @%s:%d\n", __FILE__, __LINE__);
            exit(1);
        }

        nbuf->buf = large_malloc(4096);

        if(!nbuf->buf) {
            LOGF(ERR, "malloc error @%s:%d\n", __FILE__, __LINE__);
            exit(1);
        }

        nbuf->buf_size = 4096;
        nbuf->buf_len = 0;
        nbuf->next = NULL;

        if(c*k->read_buf) {
            c*k->last_buf->next = nbuf;

        } else {
            c*k->read_buf = nbuf;
        }

        c*k->last_buf = nbuf;
    }

    if(!c*k->ssl) {
        while((n = recv(c*k->fd, c*k->last_buf->buf + c*k->last_buf->buf_len,
                        c*k->last_buf->buf_size - c*k->last_buf->buf_len, 0)) > 0) {
            c*k->last_buf->buf_len += n;
            c*k->total_buf_len += n;

            if(c*k->last_buf->buf_len >= c*k->last_buf->buf_size) {
                goto init_read_buf;
            }
        }

    } else {
        while((n = SSL_read(c*k->ssl, c*k->last_buf->buf + c*k->last_buf->buf_len,
                            c*k->last_buf->buf_size - c*k->last_buf->buf_len)) > 0) {
            c*k->last_buf->buf_len += n;
            c*k->total_buf_len += n;

            if(c*k->last_buf->buf_len >= c*k->last_buf->buf_size) {
                goto init_read_buf;
            }
        }

    }

    if(n == 0 || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
        int rfd = c*k->fd;
        /// socket closed
        delete_timeout(c*k->timeout_ptr);
        c*k->timeout_ptr = NULL;
        {
            c*k->status = 0;

            se_delete(c*k->ptr);
            c*k->ptr = NULL;
            connection_pool_counter_operate(c*k->pool_key, -1);
            close(c*k->fd);
            c*k->fd = -1;
            c*k->status = 0;
        }

        if(c*k->in_read_action == 1) {
            c*k->in_read_action = 0;
            int rt = lua_co_read_(c*k);
            c*k->inuse = 0;

            if(rt > 0) {
                ret = lua_f_lua_uthread_resume_in_c(c*k->L, rt);

            } else if(n == 0) {
                lua_pushnil(c*k->L);
                ret = lua_f_lua_uthread_resume_in_c(c*k->L, 1);
            }

            if(ret == LUA_ERRRUN) {
                se_delete(c*k->ptr);
                c*k->ptr = NULL;
                connection_pool_counter_operate(c*k->pool_key, -1);
                close(c*k->fd);
                c*k->fd = -1;
                c*k->status = 0;
            }
        }

    } else {
        if(c*k->in_read_action == 1) {
            int rt = lua_co_read_(c*k);

            if(rt > 0) {
                c*k->in_read_action = 0;
                delete_timeout(c*k->timeout_ptr);
                c*k->timeout_ptr = NULL;
                c*k->inuse = 0;

                ret = lua_f_lua_uthread_resume_in_c(c*k->L, rt);

                if(ret == LUA_ERRRUN) {
                    se_delete(c*k->ptr);
                    c*k->ptr = NULL;
                    connection_pool_counter_operate(c*k->pool_key, -1);
                    close(c*k->fd);
                    c*k->fd = -1;
                    c*k->status = 0;
                }
            }
        }
    }

    return 0;
}
int cosocket_be_write(se_ptr_t *ptr)
{
    cosocket_t *c*k = ptr->data;
    int n = 0, ret = 0;
    c*k->in_read_action = 0;

    if(!c*k->ssl) {
        while((n = send(c*k->fd, c*k->send_buf + c*k->send_buf_ed, c*k->send_buf_len - c*k->send_buf_ed, MSG_DONTWAIT)) > 0) {
            c*k->send_buf_ed += n;
        }

    } else {
        while((n = SSL_write(c*k->ssl, c*k->send_buf + c*k->send_buf_ed, c*k->send_buf_len - c*k->send_buf_ed)) > 0) {
            c*k->send_buf_ed += n;
        }
    }

    if(c*k->send_buf_ed == c*k->send_buf_len || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
        if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
            se_delete(c*k->ptr);
            c*k->ptr = NULL;
            connection_pool_counter_operate(c*k->pool_key, -1);
            close(c*k->fd);
            c*k->fd = -1;
            c*k->status = 0;
            c*k->send_buf_ed = 0;

        }

        /* else {
            se_be_pri(c*k->ptr, NULL);
        }*/

        if(c*k->send_buf_need_free) {
            free(c*k->send_buf_need_free);
            c*k->send_buf_need_free = NULL;
        }

        delete_timeout(c*k->timeout_ptr);
        c*k->timeout_ptr = NULL;

        int rc = 1;

        if(c*k->send_buf_ed >= c*k->send_buf_len) {
            lua_pushnumber(c*k->L, c*k->send_buf_ed);

        } else if(c*k->fd == -1) {
            lua_pushnil(c*k->L);
            lua_pushstring(c*k->L, "connection closed!");
            rc = 2;

        } else {
            lua_pushboolean(c*k->L, 0);
        }

        if(c*k->inuse == 1) {
            se_be_pri(c*k->ptr, NULL);
            c*k->inuse = 0;
            lua_f_lua_uthread_resume_in_c(c*k->L, rc);
            return 0;

        } else {
            return 0 - rc;
        }
    }

    return c*k->send_buf_len - c*k->send_buf_ed;
}
static int lua_co_connect(lua_State *L)
{
    cosocket_t *c*k = NULL;
    {
        if(!lua_isuserdata(L, 1) || !lua_isstring(L, 2)) {
            lua_pushnil(L);
            lua_pushstring(L, "Error params!");
            return 2;
        }

        c*k = (cosocket_t *) lua_touserdata(L, 1);

        if(c*k->status > 0) {
            lua_pushnil(L);
            lua_pushstring(L, "Aleady connected!");
            return 2;
        }

        if(c*k->inuse == 1) {
            lua_pushnil(L);
            lua_pushstring(L, "socket busy!");
            return 2;
        }

        //printf(" 0x%p connect to %s\n", L, lua_tostring(L, 2));
        size_t host_len = 0;
        const char *host = lua_tolstring(L, 2, &host_len);

        if(host_len > (host[0] == '/' ? 108 : 60)) {
            lua_pushnil(L);
            lua_pushstring(L, "hostname length must be <= 60!");
            return 2;
        }

        int port = 0;
        int pn = 3;

        if(host[0] != '/') {
            port = lua_tonumber(L, 3);

            if(port < 1) {
                lua_pushnil(L);
                lua_pushstring(L, "port must be > 0");
                return 2;
            }

            pn = 4;
        }

        if(lua_gettop(L) >= pn) { /// set keepalive options
            if(lua_isnumber(L, pn)) {
                c*k->pool_size = lua_tonumber(L, pn);

                if(c*k->pool_size < 0) {
                    c*k->pool_size = 0;

                } else if(c*k->pool_size > 4096) {
                    c*k->pool_size = 4096;
                }

                pn++;
            }

            if(c*k->pool_size > 0) {
                size_t len = 0;

                if(lua_gettop(L) == pn && lua_isstring(L, pn)) {
                    const char *key = lua_tolstring(L, pn, &len);
                    c*k->pool_key = fnv1a_32(key, len);
                }
            }
        }

        if(c*k->pool_key == 0) { /// create a normal key
            int len = snprintf(temp_buf, 4096, "%s%s:%d:%ld", port > 0 ? "tcp://" : "unix://", host, port, c*k->ssl_sign);
            c*k->pool_key = fnv1a_32(temp_buf, len);
        }

        c*k->status = 1;
        c*k->L = L;
        c*k->read_buf = NULL;
        c*k->last_buf = NULL;
        c*k->total_buf_len = 0;
        c*k->buf_read_len = 0;

        /// check pool count
        cosocket_connection_pool_counter_t *pool_counter = get_connection_pool_counter(c*k->pool_key);

        if(pool_counter->size > c*k->pool_size) {
            c*k->pool_size = pool_counter->size;
        }

        if(c*k->pool_size > 0) {
            c*k->ptr = get_connection_in_pool(_loop_fd, c*k->pool_key, c*k);

            if(c*k->ptr) {
                ((se_ptr_t *) c*k->ptr)->data = c*k;
                c*k->status = 2;
                c*k->reusedtimes = 1;
                c*k->fd = ((se_ptr_t *) c*k->ptr)->fd;
                //printf("reuse %d\n", c*k->fd);
                se_be_pri(c*k->ptr, NULL);
                lua_pushboolean(L, 1);

                return 1;
            }

            if(pool_counter->count > 0 && pool_counter->count >= c*k->pool_size / _process_count) {
                /// pool full
                if((c*k->pool_wait = add_waiting_get_connection(c*k))) {
                    c*k->status = 3;
                    c*k->timeout_ptr = add_timeout(c*k, c*k->timeout, timeout_handle);
                    //printf("wait %d\n", c*k->fd);
                    c*k->inuse = 1;
                    return lua_yield(L, 0);

                } else {
                    lua_pushnil(L);
                    lua_pushstring(L, "pool error");
                    return 2;
                }
            }
        }

        int fd = se_connect(_loop_fd, host, port, c*k->timeout > 0 ? c*k->timeout : 30000, be_connect, c*k);

        if(fd != -2) {
            if(fd > -1) {
                connection_pool_counter_operate(c*k->pool_key, 1);
                int ret = _be_connect(c*k, fd, 0);

                if(ret == -2) {
                    return lua_yield(L, 0);
                }

                return ret;

            } else {
                lua_pushnil(L);
                lua_pushstring(L, strerror(errno));
                return 2;
            }
        }

        connection_pool_counter_operate(c*k->pool_key, 1);
    }

    return lua_yield(L, 0);
}
static int _be_connect(cosocket_t *c*k, int fd, int yielded)
{
    int flag = 1;
    int ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));

    c*k->fd = fd;
    c*k->ptr = se_add(_loop_fd, fd, c*k);

    c*k->status = 2;
    c*k->in_read_action = 0;

    if(c*k->use_ssl) {
        if(c*k->ctx == NULL) {
            c*k->ctx = SSL_CTX_new(SSLv23_client_method());

            if(c*k->ctx == NULL) {
                connection_pool_counter_operate(c*k->pool_key, -1);
                se_delete(c*k->ptr);
                close(c*k->fd);

                c*k->ptr = NULL;
                c*k->fd = -1;
                c*k->status = 0;

                lua_pushnil(c*k->L);
                lua_pushstring(c*k->L, "SSL_CTX_new Error");
                return 2;
            }
        }

        c*k->ssl = SSL_new(c*k->ctx);

        if(c*k->ssl == NULL) {
            connection_pool_counter_operate(c*k->pool_key, -1);
            se_delete(c*k->ptr);
            close(c*k->fd);

            c*k->ptr = NULL;
            c*k->fd = -1;
            c*k->status = 0;

            SSL_CTX_free(c*k->ctx);
            c*k->ctx = NULL;

            lua_pushnil(c*k->L);
            lua_pushstring(c*k->L, "SSL_new Error");
            return 2;
        }

        SSL_set_fd(c*k->ssl, c*k->fd);
        se_be_read(c*k->ptr, cosocket_be_ssl_connected);

        if(SSL_connect(c*k->ssl) == 1) {
            se_be_pri(c*k->ptr, NULL);
            lua_pushboolean(c*k->L, 1);
            c*k->inuse = 0;
            return 1;
        }

        c*k->timeout_ptr = add_timeout(c*k, c*k->timeout, timeout_handle);

        return -2;
    }

    se_be_pri(c*k->ptr, NULL);
    lua_pushboolean(c*k->L, 1);
    c*k->inuse = 0;

    return 1;
}
se_ptr_t *get_connection_in_pool(int loop_fd, unsigned long pool_key, cosocket_t *c*k)
{
    int k = pool_key % 64;
    int p = (now / connect_pool_ttl) % 2;
    cosocket_connection_pool_t  *n = NULL,
                                 *m = NULL,
                                  *nn = NULL;
    se_ptr_t *ptr = NULL;

    /// clear old caches
    int q = (p + 1) % 2;
    int i = 0;

    for(i = 0; i < 64; i++) {
        n = connect_pool_p[q][i];

        while(n) {
            m = n;
            n = n->next;

            ptr = m->ptr;

            if(m->z == 0) {
                m->z = 1;
                nn = connect_pool_p[p][m->pool_key % 64];

                if(nn == NULL) {
                    connect_pool_p[p][m->pool_key % 64] = m;
                    m->next = NULL;
                    m->uper = NULL;

                } else {
                    m->uper = NULL;
                    m->next = nn;
                    nn->uper = m;
                    connect_pool_p[p][m->pool_key % 64] = m;
                }

            } else {
                int fd = ptr->fd;
                se_delete(ptr);
                connection_pool_counter_operate(m->pool_key, -1);
                close(fd);
                free(m);
            }
        }

        connect_pool_p[q][i] = NULL;
    }

    /// end
    if(pool_key == 0) {
        resume_in_waiting_get_connection(loop_fd);
        return NULL; /// only do clear job
    }

regetfd:
    n = connect_pool_p[p][k];

    while(n != NULL) {
        if(n->pool_key == pool_key) {
            break;
        }

        n = (cosocket_connection_pool_t *) n->next;
    }

    if(n) {
        if(n == connect_pool_p[p][k]) {    /// at top
            m = n->next;

            if(m) {
                m->uper = NULL;
                connect_pool_p[p][k] = m;

            } else {
                connect_pool_p[p][k] = NULL;
            }

        } else {
            ((cosocket_connection_pool_t *) n->uper)->next = n->next;

            if(n->next) {
                ((cosocket_connection_pool_t *) n->next)->uper = n->uper;
            }
        }

        ptr = n->ptr;

        if(c*k) {
            if(c*k->ctx) {
                SSL_CTX_free(c*k->ctx);
            }

            if(c*k->ssl_pw) {
                free(c*k->ssl_pw);
            }

            c*k->ctx = n->ctx;
            c*k->ssl = n->ssl;
            c*k->ssl_pw = n->ssl_pw;
        }

        free(n);
        //printf ( "get fd in pool%d %d key:%d\n", p, ptr->fd, k );
        return ptr;
    }

    if(p != q) {
        p = q;
        goto regetfd;
    }

    return NULL;
}