void resume_in_waiting_get_connection(int loop_fd)
{
    int k = 0;

    for(k = 0; k < 64; k++) {
        if(waiting_get_connections[k]) {
            cosocket_t *c*k = ((cosocket_waiting_get_connection_t *)waiting_get_connections[k])->c*k;

            c*k->ptr = get_connection_in_pool(loop_fd, c*k->pool_key, c*k);

            if(c*k->ptr) {
                c*k->pool_wait = NULL;
                delete_in_waiting_get_connection(waiting_get_connections[k]);
                ((se_ptr_t *) c*k->ptr)->data = c*k;
                c*k->status = 2;
                c*k->inuse = 0;
                c*k->reusedtimes = 1;
                c*k->in_read_action = 0;
                c*k->fd = ((se_ptr_t *) c*k->ptr)->fd;
                //printf("reuse %d\n", c*k->fd);
                delete_timeout(c*k->timeout_ptr);
                c*k->timeout_ptr = NULL;
                se_be_pri(c*k->ptr, NULL);
                lua_pushboolean(c*k->L, 1);

                lua_f_lua_uthread_resume_in_c(c*k->L, 1);

                return;
            }

        }
    }
}
int cosocket_be_ssl_connected(se_ptr_t *ptr)
{
    cosocket_t *c*k = ptr->data;

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

    return 0;
}
Beispiel #3
0
static int network_be_read ( se_ptr_t *ptr )
{
    epdata_t *epd = ptr->data;

    if ( !epd ) {
        return 0;
    }

    int n = 0;

    update_timeout ( epd->timeout_ptr, STEP_READ_TIMEOUT );

    if ( epd->headers == NULL ) {
        epd->headers = &epd->iov;
        epd->buf_size = sizeof ( epd->iov );

    } else if ( epd->data_len == epd->buf_size ) {
        if ( epd->headers == &epd->iov ) {
            epd->headers = malloc ( 4096 * 2 );
            memcpy ( epd->headers, &epd->iov, sizeof ( epd->iov ) );
            epd->buf_size = 4096 * 2;

        } else {
            char *_t = ( char * ) realloc ( epd->headers, epd->buf_size + 4096 );

            if ( _t != NULL ) {
                epd->headers = _t;

            } else {
                epd->iov[0].iov_base = NULL;
                epd->iov[0].iov_len = 0;
                epd->iov[1].iov_base = NULL;
                epd->iov[1].iov_len = 0;
                network_send_error ( epd, 503, "memory error!" );
                close_client ( epd );
                serv_status.reading_counts--;
                return 0;
            }

            epd->buf_size += 4096;
        }
    }

    while ( ( n = recv ( epd->fd, epd->headers + epd->data_len,
                         epd->buf_size - epd->data_len, 0 ) ) >= 0 ) {
        if ( n == 0 ) {
            close_client ( epd );
            epd = NULL;
            break;
        }

        if ( epd->data_len + n >= epd->buf_size ) {
            if ( epd->headers == &epd->iov ) {
                epd->headers = malloc ( 4096 * 2 );
                memcpy ( epd->headers, &epd->iov, sizeof ( epd->iov ) );
                epd->buf_size = 4096 * 2;

            } else {
                char *_t = ( char * ) realloc ( epd->headers, epd->buf_size + 4096 );

                if ( _t != NULL ) {
                    epd->headers = _t;

                } else {
                    epd->iov[0].iov_base = NULL;
                    epd->iov[0].iov_len = 0;
                    epd->iov[1].iov_base = NULL;
                    epd->iov[1].iov_len = 0;
                    network_send_error ( epd, 503, "memory error!" );
                    close_client ( epd );
                    serv_status.reading_counts--;
                    return 0;
                }

                epd->buf_size += 4096;
            }
        }

        if ( epd->status != STEP_READ ) {
            serv_status.reading_counts++;
            epd->status = STEP_READ;
            epd->data_len = n;
            epd->start_time = longtime();

        } else {
            epd->data_len += n;
        }

        if ( epd->_header_length < 1 && epd->data_len >= 4 && epd->headers ) {
            int _get_content_length = 0;

            if ( epd->headers[epd->data_len - 1] == '\n' &&
                 ( epd->headers[epd->data_len - 2] == '\n' ||
                   ( epd->headers[epd->data_len - 4] == '\r' &&
                     epd->headers[epd->data_len - 2] == '\r' ) ) ) {
                epd->_header_length = epd->data_len;

            } else {
                _get_content_length = 1;
                unsigned char *fp2 = stristr ( epd->headers, "\r\n\r\n", epd->data_len );

                if ( fp2 ) {
                    epd->_header_length = ( fp2 - epd->headers ) + 4;

                } else {
                    fp2 = stristr ( epd->headers, "\n\n", epd->data_len );

                    if ( fp2 ) {
                        epd->_header_length = ( fp2 - epd->headers ) + 2;
                    }
                }
            }

            if ( epd->_header_length > 0 && epd->content_length < 0 ) {
                /// not POST or PUT request
                if ( _get_content_length == 0 && epd->headers[0] != 'P' && epd->headers[0] != 'p' ) {
                    epd->content_length = 0;

                } else {
                    int flag = 0;

                    unsigned char *fp = stristr ( epd->headers, "\ncontent-length:", epd->data_len );

                    if ( fp ) {
                        int fp_at = fp - epd->headers + 16;
                        int i = 0, _oc;

                        for ( i = fp_at; i < epd->data_len; i++ ) {
                            if ( epd->headers[i] == '\r' || epd->headers[i] == '\n' ) {
                                flag = 1;
                                fp = epd->headers + fp_at;
                                _oc = epd->headers[i];
                                epd->headers[i] = '\0';
                                break;
                            }
                        }

                        if ( flag ) {
                            epd->content_length = atoi ( fp );
                            epd->headers[i] = _oc;
                        }

                        if ( stristr ( epd->headers + ( epd->_header_length - 60 ), "100-continue",
                                       epd->_header_length ) ) {
                            network_raw_send ( epd->fd, "HTTP/1.1 100 Continue\r\n\r\n", 25 );
                        }
                    }
                }
            }

            if ( epd->_header_length > 0
                 && epd->_header_length < epd->data_len
                 && epd->content_length < 1 ) {
                epd->iov[0].iov_base = NULL;
                epd->iov[0].iov_len = 0;
                epd->iov[1].iov_base = NULL;
                epd->iov[1].iov_len = 0;
                network_send_error ( epd, 411, "" );
                close_client ( epd );
                epd = NULL;
                serv_status.reading_counts--;

                break;
            }
        }

        //printf("data_len = %d header_length = %d content_length = %d\n", epd->data_len, epd->_header_length, epd->content_length);

        if ( epd->_header_length > 0 && ( ( epd->content_length < 1
                                            && epd->_header_length > 0 ) ||
                                          epd->content_length <= epd->data_len - epd->_header_length ) ) {


            /// start job
            epd->header_len = epd->_header_length;
            epd->headers[epd->data_len] = '\0';
            epd->header_len -= 1;
            epd->headers[epd->header_len] = '\0';

            if ( epd->header_len + 1 < epd->data_len ) {
                epd->contents = epd->headers + epd->header_len + 1;

            } else {
                epd->content_length = 0;
            }


            if ( USE_KEEPALIVE == 1 && ( epd->keepalive == 1 ||
                                         ( stristr ( epd->headers, "keep-alive", epd->header_len ) ) )
               ) {
                epd->keepalive = 1;
            }

            epd->response_header_length = 0;
            epd->iov_buf_count = 0;
            epd->response_content_length = 0;

            epd->response_sendfile_fd = -1;

            /// output server status !!!!!!!!!!
            {
                int i, len;
                char *uri = NULL;
                uri = epd->headers;

                for ( i = 0; i < epd->header_len; i++ )
                    if ( uri[i] == ' ' ) {
                        break;
                    }

                for ( ; i < epd->header_len; i++ )
                    if ( uri[i] != ' ' ) {
                        break;
                    }

                uri = epd->headers + i;
                len = strlen ( uri );

                for ( i = 0; i < len; i++ ) {
                    if ( uri[i] == '\r' || uri[i] == '\n' || uri[i] == ' ' ) {
                        break;
                    }
                }

                if ( i > 11 && strncmp ( "/serv-status", uri, i ) == 0 ) {
                    epd->process_timeout = 0;

                    epd->iov[0].iov_base = NULL;
                    epd->iov[0].iov_len = 0;
                    epd->iov[1].iov_base = NULL;
                    epd->iov[1].iov_len = 0;

                    network_send_status ( epd );
                    serv_status.reading_counts--;
                    break;
                }
            }
            /// end.

            se_be_pri ( epd->se_ptr, NULL ); // be wait

            if ( epd->status == STEP_READ ) {
                serv_status.reading_counts--;
                epd->status = STEP_PROCESS;

                serv_status.sec_process_counts[ ( now ) % 5]++;
                serv_status.process_counts++;
                epd->method = NULL;
                epd->uri = NULL;
                epd->host = NULL;
                epd->query = NULL;
                epd->http_ver = NULL;
                epd->referer = NULL;
                epd->user_agent = NULL;

                if ( process_func ( epd, 0 ) != 0 ) {
                    close_client ( epd );
                    epd = NULL;
                }
            }

            break;
        }
    }

    if ( epd && n < 0 && errno != EAGAIN && errno != EWOULDBLOCK ) {
        //printf("error fd %d (%d) %s\n", epd->fd, errno, strerror(errno));
        close_client ( epd );
        epd = NULL;
        return 0;
    }

    return 1;
}
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;
}
Beispiel #7
0
static int network_be_read_request_body(se_ptr_t *ptr)
{
    //printf("network_be_read_request_body\n");
    epdata_t *epd = ptr->data;

    if(!epd) {
        return 0;
    }

    int n = 0, readed = 0;
    char *buf = malloc(65536);
    int buf_size = 65536;

    if(!buf) {
        serv_status.active_counts--;

        se_delete(epd->se_ptr);
        epd->se_ptr = NULL;
        close(epd->fd);
        epd->fd = -1;

        if(epd->status == STEP_READ) {
            serv_status.reading_counts--;
            epd->status = STEP_PROCESS;
        }

        lua_pushnil(epd->L);
        lua_pushstring(epd->L, "memory error");
        LOGF(ERR, "memory error!");

        lua_f_lua_uthread_resume_in_c(epd->L, 2);

        return 0;
    }

    while((n = recv(epd->fd, buf + readed, buf_size - readed, 0)) >= 0) {
        if(n == 0) {
            serv_status.active_counts--;

            se_delete(epd->se_ptr);
            epd->se_ptr = NULL;
            close(epd->fd);
            epd->fd = -1;

            if(epd->status == STEP_READ) {
                serv_status.reading_counts--;
                epd->status = STEP_PROCESS;
            }

            break;
        }

        epd->data_len += n;
        readed += n;

        //printf("readed: %d\n", n);
        if(readed >= buf_size) {
            char *p = realloc(buf, buf_size + 65536);

            if(p) {
                buf = p;
                buf_size += 65536;

            } else {
                break;
            }
        }
    }

    if(readed > 0) {
        if(epd->status == STEP_READ) {
            serv_status.reading_counts--;
            epd->status = STEP_PROCESS;
        }

        se_be_pri(epd->se_ptr, NULL); // be wait
        lua_pushlstring(epd->L, buf, readed);
        free(buf);

        lua_f_lua_uthread_resume_in_c(epd->L, 1);

    } else if(n == 0) {
        n = -1;
        errno = 1;
    }

    if(n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
        serv_status.active_counts--;

        se_delete(epd->se_ptr);
        epd->se_ptr = NULL;
        close(epd->fd);
        epd->fd = -1;

        if(epd->status == STEP_READ) {
            serv_status.reading_counts--;
            epd->status = STEP_PROCESS;
        }

        lua_pushnil(epd->L);
        lua_pushstring(epd->L, "socket closed");

        lua_f_lua_uthread_resume_in_c(epd->L, 2);

        return 0;
    }
}