Esempio n. 1
0
SWINLINE static void swRingBuffer_collect(swRingBuffer *object)
{
    int i;
    swRingBuffer_head *item;

    swTraceLog(SW_TRACE_MEMORY, "collect_offset=%ld, free_n=%d", object->collect_offset, object->free_n);

    for(i = 0; i<SW_RINGBUFFER_COLLECT_N; i++)
    {
        item = (swRingBuffer_head *) (object->memory + object->collect_offset);

        swTraceLog(SW_TRACE_MEMORY, "collect_offset=%d, item_length=%d, lock=%d", object->collect_offset, item->length, item->lock);

        //can collect
        if (item->lock == 0)
        {
            object->collect_offset += (sizeof(swRingBuffer_head) + item->length);
            if (object->free_n > 0)
            {
                object->free_n --;
            }
            if (object->collect_offset >= object->size)
            {
                object->collect_offset = 0;
            }
        }
        else
        {
            break;
        }
    }
}
Esempio n. 2
0
int swReactorEpoll_add(swReactor *reactor, int fd, int fdtype)
{
    swReactorEpoll *object = reactor->object;
    struct epoll_event e;
    swFd fd_;
    int ret;
    bzero(&e, sizeof(struct epoll_event));

    fd_.fd = fd;
    fd_.fdtype = swReactor_fdtype(fdtype);
    e.events = swReactorEpoll_event_set(fdtype);

    memcpy(&(e.data.u64), &fd_, sizeof(fd_));
    ret = epoll_ctl(object->epfd, EPOLL_CTL_ADD, fd, &e);
    if (ret < 0)
    {
        swWarn("add event failed. Error: %s[%d]", strerror(errno), errno);
        return SW_ERR;
    }
    if (swReactor_add(reactor, fd, fdtype) < 0)
    {
        return SW_ERR;
    }
    swTraceLog(SW_TRACE_EVENT, "add event[reactor_id=%d|fd=%d]", reactor->id, fd);
    reactor->event_num++;
    return SW_OK;
}
Esempio n. 3
0
void swTimeWheel_forward(swTimeWheel *tw, swReactor *reactor)
{
    swHashMap *set = tw->wheel[tw->current];
    tw->current = tw->current == tw->size - 1 ? 0 : tw->current + 1;

    swTraceLog(SW_TRACE_REACTOR, "current=%d.", tw->current);

    swConnection *conn;
    uint64_t fd;

    while (1)
    {
        conn = swHashMap_each_int(set, &fd);
        if (conn == NULL)
        {
            break;
        }

        conn->close_force = 1;
        conn->close_notify = 1;
        conn->close_wait = 1;
        conn->close_actively = 1;

        //notify to reactor thread
        if (conn->removed)
        {
            reactor->close(reactor, (int) fd);
        }
        else
        {
            reactor->set(reactor, fd, SW_FD_TCP | SW_EVENT_WRITE);
        }
    }
}
Esempio n. 4
0
int swReactorEpoll_del(swReactor *reactor, int fd)
{
    swReactorEpoll *object = reactor->object;
    int ret;

    if (fd <= 0)
    {
        return SW_ERR;
    }
    ret = epoll_ctl(object->epfd, EPOLL_CTL_DEL, fd, NULL);
    if (ret < 0)
    {
        swWarn("epoll remove fd[=%d] failed. Error: %s[%d]", fd, strerror(errno), errno);
        return SW_ERR;
    }

    if (swReactor_del(reactor, fd) < 0)
    {
        return SW_ERR;
    }

    reactor->event_num = reactor->event_num <= 0 ? 0 : reactor->event_num - 1;
    swTraceLog(SW_TRACE_EVENT, "remove event[reactor_id=%d|fd=%d]", reactor->id, fd);
    return SW_OK;
}
Esempio n. 5
0
int swReactorEpoll_del(swReactor *reactor, int fd)
{
    swReactorEpoll *object = reactor->object;
    int ret;

    if (fd <= 0)
    {
        return SW_ERR;
    }
    ret = epoll_ctl(object->epfd, EPOLL_CTL_DEL, fd, NULL);
    if (ret < 0)
    {
        swWarn("epoll remove fd[=%d] failed. Error: %s[%d]", fd, strerror(errno), errno);
        return SW_ERR;
    }
    //close时会自动从epoll事件中移除
    //swoole中未使用dup
    ret = close(fd);
    if (ret >= 0)
    {
        (reactor->event_num <= 0) ? reactor->event_num = 0 : reactor->event_num--;
    }
    swTraceLog(SW_TRACE_EVENT, "remove event[reactor_id=%d|fd=%d]", reactor->id, fd);
    return SW_OK;
}
Esempio n. 6
0
void swTimeWheel_add(swTimeWheel *tw, swConnection *conn)
{
    uint16_t index = tw->current == 0 ? tw->size - 1 : tw->current - 1;
    swHashMap *new_set = tw->wheel[index];
    swHashMap_add_int(new_set, conn->fd, conn);

    conn->timewheel_index = index;

    swTraceLog(SW_TRACE_REACTOR, "current=%d, fd=%d, index=%d.", tw->current, conn->fd, index);
}
Esempio n. 7
0
void swTimeWheel_update(swTimeWheel *tw, swConnection *conn)
{
    uint16_t new_index = swTimeWheel_new_index(tw);
    swHashMap *new_set = tw->wheel[new_index];
    swHashMap_add_int(new_set, conn->fd, conn);

    swHashMap *old_set = tw->wheel[conn->timewheel_index];
    swHashMap_del_int(old_set, conn->fd);

    swTraceLog(SW_TRACE_REACTOR, "current=%d, fd=%d, old_index=%d, new_index=%d.", tw->current, conn->fd, new_index, conn->timewheel_index);

    conn->timewheel_index = new_index;
}
Esempio n. 8
0
int swReactor_add(swReactor *reactor, int fd, int fdtype)
{
    assert (fd <= SwooleG.max_sockets);

    swConnection *socket = swReactor_get(reactor, fd);

    socket->fdtype = swReactor_fdtype(fdtype);
    socket->events = swReactor_events(fdtype);
    socket->removed = 0;

    swTraceLog(SW_TRACE_REACTOR, "fd=%d, type=%d, events=%d", fd, socket->socket_type, socket->events);

    return SW_OK;
}
Esempio n. 9
0
/**
 * append to buffer queue
 */
int swBuffer_in(swBuffer *buffer, swSendData *send_data)
{
	swBuffer_trunk *trunk = swBuffer_new_trunk(buffer, SW_TRUNK_DATA, send_data->info.len);
	if (trunk == NULL)
	{
		return SW_ERR;
	}

	trunk->length = send_data->info.len;
	memcpy(trunk->data, send_data->data, trunk->length);

	swTraceLog(SW_TRACE_BUFFER, "trunk_n=%d|data_len=%d|trunk_len=%d|trunk=%p", buffer->trunk_num, send_data->info.len,
			trunk->length, trunk);

	return SW_OK;
}
Esempio n. 10
0
static int swReactorKqueue_add(swReactor *reactor, int fd, int fdtype)
{
    swReactorKqueue *this = reactor->object;
    struct kevent e;
    swFd fd_;
    int ret;
    bzero(&e, sizeof(e));

    int fflags = 0;
    fd_.fd = fd;
    fd_.fdtype = swReactor_fdtype(fdtype);

    swReactor_add(reactor, fd, fdtype);

    if (swReactor_event_read(fdtype))
    {
#ifdef NOTE_EOF
        fflags = NOTE_EOF;
#endif
        EV_SET(&e, fd, EVFILT_READ, EV_ADD, fflags, 0, NULL);
        memcpy(&e.udata, &fd_, sizeof(swFd));
        ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
        if (ret < 0)
        {
            swSysError("add events[fd=%d#%d, type=%d, events=read] failed.", fd, reactor->id, fd_.fdtype);
            swReactor_del(reactor, fd);
            return SW_ERR;
        }
    }

    if (swReactor_event_write(fdtype))
    {
        EV_SET(&e, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
        memcpy(&e.udata, &fd_, sizeof(swFd));
        ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
        if (ret < 0)
        {
            swSysError("add events[fd=%d#%d, type=%d, events=write] failed.", fd, reactor->id, fd_.fdtype);
            swReactor_del(reactor, fd);
            return SW_ERR;
        }
    }

    swTraceLog(SW_TRACE_EVENT, "[THREAD #%d]EP=%d|FD=%d, events=%d", SwooleTG.id, this->epfd, fd, fdtype);
    reactor->event_num++;
    return SW_OK;
}
Esempio n. 11
0
/**
 * append to buffer queue
 */
int swBuffer_append(swBuffer *buffer, void *data, uint32_t size)
{
    swBuffer_trunk *chunk = swBuffer_new_trunk(buffer, SW_CHUNK_DATA, size);
    if (chunk == NULL)
    {
        return SW_ERR;
    }

    buffer->length += size;
    chunk->length = size;

    memcpy(chunk->store.ptr, data, size);

    swTraceLog(SW_TRACE_BUFFER, "trunk_n=%d|size=%d|trunk_len=%d|trunk=%p", buffer->trunk_num, size,
            chunk->length, chunk);

    return SW_OK;
}
Esempio n. 12
0
void php_swoole_reactor_init()
{
    if (!SWOOLE_G(cli))
    {
        swoole_php_fatal_error(E_ERROR, "async-io must be used in PHP CLI mode.");
        return;
    }

    if (SwooleG.main_reactor == NULL)
    {
        swTraceLog(SW_TRACE_PHP, "init reactor");

        SwooleG.main_reactor = (swReactor *) sw_malloc(sizeof(swReactor));
        if (SwooleG.main_reactor == NULL)
        {
            swoole_php_fatal_error(E_ERROR, "malloc failed.");
            return;
        }
        if (swReactor_create(SwooleG.main_reactor, SW_REACTOR_MAXEVENTS) < 0)
        {
            swoole_php_fatal_error(E_ERROR, "failed to create reactor.");
            return;
        }

#ifdef SW_COROUTINE
        SwooleG.main_reactor->can_exit = php_coroutine_reactor_can_exit;
#endif

        //client, swoole_event_exit will set swoole_running = 0
        SwooleWG.in_client = 1;
        SwooleWG.reactor_wait_onexit = 1;
        SwooleWG.reactor_ready = 0;
        //only client side
        php_swoole_at_shutdown("swoole_event_wait");
    }

    SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_USER | SW_EVENT_READ, php_swoole_event_onRead);
    SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_USER | SW_EVENT_WRITE, php_swoole_event_onWrite);
    SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_USER | SW_EVENT_ERROR, php_swoole_event_onError);
    SwooleG.main_reactor->setHandle(SwooleG.main_reactor, SW_FD_WRITE, swReactor_onWrite);

    SwooleWG.reactor_init = 1;
}
Esempio n. 13
0
void swAio_handler_stream_get_line(swAio_event *event)
{
    int ret = -1;
    if (flock(event->fd, LOCK_SH) < 0)
    {
        swSysError("flock(%d, LOCK_SH) failed.", event->fd);
        event->ret = -1;
        event->error = errno;
        return;
    }

    off_t readpos = event->offset;
    off_t writepos = (long) event->req;
    size_t avail = 0;
    char *eol;
    char *tmp;

    char *read_buf = event->buf;
    int read_n = event->nbytes;

    while (1)
    {
        avail = writepos - readpos;

        swTraceLog(SW_TRACE_AIO, "readpos=%ld, writepos=%ld", (long)readpos, (long)writepos);

        if (avail > 0)
        {
            tmp = event->buf + readpos;
            eol = find_eol(tmp, avail);
            if (eol)
            {
                event->buf = tmp;
                event->ret = (eol - tmp) + 1;
                readpos += event->ret;
                goto _return;
            }
            else if (readpos == 0)
            {
                if (writepos == event->nbytes)
                {
                    writepos = 0;
                    event->ret = event->nbytes;
                    goto _return;
                }
                else
                {
                    event->flags = SW_AIO_EOF;
                    ((char*) event->buf)[writepos] = '\0';
                    event->ret = writepos;
                    writepos = 0;
                    goto _return;
                }
            }
            else
            {
                memmove(event->buf, event->buf + readpos, avail);
                writepos = avail;
                read_buf = event->buf + writepos;
                read_n = event->nbytes - writepos;
                readpos = 0;
                goto _readfile;
            }
        }
        else
        {
            _readfile: while (1)
            {
                ret = read(event->fd, read_buf, read_n);
                if (ret < 0 && (errno == EINTR || errno == EAGAIN))
                {
                    continue;
                }
                break;
            }
            if (ret > 0)
            {
                writepos += ret;
            }
            else if (ret == 0)
            {
                event->flags = SW_AIO_EOF;
                if (writepos > 0)
                {
                    event->ret = writepos;
                }
                else
                {
                    ((char*) event->buf)[0] = '\0';
                    event->ret = 0;
                }
                readpos = writepos = 0;
                goto _return;
            }
        }
    }

    _return:
    if (flock(event->fd, LOCK_UN) < 0)
    {
        swSysError("flock(%d, LOCK_UN) failed.", event->fd);
    }
    event->offset = readpos;
    event->req = (void *) (long) writepos;
}
Esempio n. 14
0
static int swReactorKqueue_set(swReactor *reactor, int fd, int fdtype)
{
    swReactorKqueue *this = reactor->object;
    struct kevent e;
    swFd fd_;
    int ret;
    bzero(&e, sizeof(e));

    int fflags = 0;
    fd_.fd = fd;
    fd_.fdtype = swReactor_fdtype(fdtype);

    if (swReactor_event_read(fdtype))
    {
#ifdef NOTE_EOF
        fflags = NOTE_EOF;
#endif
        EV_SET(&e, fd, EVFILT_READ, EV_ADD, fflags, 0, NULL);
        memcpy(&e.udata, &fd_, sizeof(swFd));
        ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
        if (ret < 0)
        {
            swSysError("kqueue->set(%d, SW_EVENT_READ) failed.", fd);
            return SW_ERR;
        }
    }
    else
    {
        EV_SET(&e, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
        memcpy(&e.udata, &fd_, sizeof(swFd));
        ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
        if (ret < 0)
        {
            swSysError("kqueue->del(%d, SW_EVENT_READ) failed.", fd);
            return SW_ERR;
        }
    }

    if (swReactor_event_write(fdtype))
    {
        EV_SET(&e, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
        memcpy(&e.udata, &fd_, sizeof(swFd));
        ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
        if (ret < 0)
        {
            swSysError("kqueue->set(%d, SW_EVENT_WRITE) failed.", fd);
            return SW_ERR;
        }
    }
    else
    {
        EV_SET(&e, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
        memcpy(&e.udata, &fd_, sizeof(swFd));
        ret = kevent(this->epfd, &e, 1, NULL, 0, NULL);
        if (ret < 0)
        {
            swSysError("kqueue->del(%d, SW_EVENT_WRITE) failed.", fd);
            return SW_ERR;
        }
    }
    swTraceLog(SW_TRACE_EVENT, "[THREAD #%d]EP=%d|FD=%d, events=%d", SwooleTG.id, this->epfd, fd, fdtype);
    //execute parent method
    swReactor_set(reactor, fd, fdtype);
    return SW_OK;
}
Esempio n. 15
0
static void* swRingBuffer_alloc(swMemoryPool *pool, uint32_t size)
{
    swRingBuffer *object = pool->object;
    swRingBuffer_head *item;
    size_t n;
    uint8_t try_collect = 0;
    void *ret_mem = NULL;

    swTraceLog(SW_TRACE_MEMORY, "[0] alloc_offset=%ld|collect_offset=%ld", object->alloc_offset, object->collect_offset);

start_alloc:

    if (object->alloc_offset < object->collect_offset)
    {
head_alloc:
        item = object->memory + object->alloc_offset;
        /**
         * 剩余内存的长度
         */
        n = object->collect_offset - object->alloc_offset;
        /**
         * 剩余内存可供本次分配,必须是>size
         */
        if ((n - sizeof(swRingBuffer_head)) > size)
        {
            goto do_alloc;
        }
        /**
         * 内存不足,已尝试回收过
         */
        else if (try_collect == 1)
        {
            swWarn("alloc_offset=%ld|collect_offset=%ld", object->alloc_offset, object->collect_offset);
            return NULL;
        }
        //try collect memory, then try head_alloc
        else
        {
            try_collect = 1;
            swRingBuffer_collect(object);
            goto start_alloc;
        }
    }
    else
    {
        //tail_alloc:
        n = object->size - object->alloc_offset;
        item = object->memory + object->alloc_offset;

        swTraceLog(SW_TRACE_MEMORY, "[1] size=%ld, ac_size=%d, n_size=%ld", object->size, size, n);

        if ((n - sizeof(swRingBuffer_head)) >= size)
        {
            goto do_alloc;
        }
        else
        {
            //unlock
            item->lock = 0;
            item->length = n - sizeof(swRingBuffer_head);

            //goto head
            object->alloc_offset = 0;

            swTraceLog(SW_TRACE_MEMORY, "switch to head_alloc. ac_size=%d, n_size=%ld", size, n);

            goto head_alloc;
        }
    }

do_alloc:
    item->lock = 1;
    item->length = size;
    ret_mem = (void*) (object->memory + object->alloc_offset + sizeof(swRingBuffer_head));

    /**
     * 内存游标向后移动
     */
    object->alloc_offset += size + sizeof(swRingBuffer_head);

    if (object->free_n > 0)
    {
        swRingBuffer_collect(object);
    }

    return ret_mem;
}
Esempio n. 16
0
static int swReactorKqueue_wait(swReactor *reactor, struct timeval *timeo)
{
    swEvent event;
    swFd fd_;
    swReactorKqueue *object = reactor->object;
    swReactor_handle handle;

    int i, n, ret;
    struct timespec t;
    struct timespec *t_ptr;
    bzero(&t, sizeof(t));

    if (reactor->timeout_msec == 0)
    {
        if (timeo == NULL)
        {
            reactor->timeout_msec = -1;
        }
        else
        {
            reactor->timeout_msec = timeo->tv_sec * 1000 + timeo->tv_usec / 1000;
        }
    }

    reactor->start = 1;

    while (reactor->running > 0)
    {
        if (reactor->onBegin != NULL)
        {
            reactor->onBegin(reactor);
        }
        if (reactor->timeout_msec > 0)
        {
            t.tv_sec = reactor->timeout_msec / 1000;
            t.tv_nsec = (reactor->timeout_msec - t.tv_sec * 1000) * 1000;
            t_ptr = &t;
        }
        else
        {
            t_ptr = NULL;
        }

        n = kevent(object->epfd, NULL, 0, object->events, object->event_max, t_ptr);
        if (n < 0)
        {
            swTrace("kqueue error.EP=%d | Errno=%d\n", object->epfd, errno);
            if (swReactor_error(reactor) < 0)
            {
                swWarn("Kqueue[#%d] Error: %s[%d]", reactor->id, strerror(errno), errno);
                return SW_ERR;
            }
            else
            {
                continue;
            }
        }
        else if (n == 0)
        {
            if (reactor->onTimeout != NULL)
            {
                reactor->onTimeout(reactor);
            }
            continue;
        }

        for (i = 0; i < n; i++)
        {
            swTraceLog(SW_TRACE_EVENT, "n %d events.", n);
            if (object->events[i].udata)
            {
                memcpy(&fd_, &(object->events[i].udata), sizeof(fd_));
                event.fd = fd_.fd;
                event.from_id = reactor->id;
                event.type = fd_.fdtype;
                event.socket = swReactor_get(reactor, event.fd);

                //read
                if (object->events[i].filter == EVFILT_READ)
                {
                    if (event.socket->removed)
                    {
                        continue;
                    }
                    handle = swReactor_getHandle(reactor, SW_EVENT_READ, event.type);
                    ret = handle(reactor, &event);
                    if (ret < 0)
                    {
                        swSysError("kqueue event read socket#%d handler failed.", event.fd);
                    }
                }
                //write
                else if (object->events[i].filter == EVFILT_WRITE)
                {
                    if (event.socket->removed)
                    {
                        continue;
                    }
                    handle = swReactor_getHandle(reactor, SW_EVENT_WRITE, event.type);
                    ret = handle(reactor, &event);
                    if (ret < 0)
                    {
                        swSysError("kqueue event write socket#%d handler failed.", event.fd);
                    }
                }
                else
                {
                    swWarn("unknown event filter[%d].", object->events[i].filter);
                }
            }
        }

        if (reactor->onFinish != NULL)
        {
            reactor->onFinish(reactor);
        }
        if (reactor->once)
        {
            break;
        }
    }
    return 0;
}
Esempio n. 17
0
void swTimeWheel_remove(swTimeWheel *tw, swConnection *conn)
{
    swHashMap *set = tw->wheel[conn->timewheel_index];
    swHashMap_del_int(set, conn->fd);
    swTraceLog(SW_TRACE_REACTOR, "current=%d, fd=%d.", tw->current, conn->fd);
}
Esempio n. 18
0
static sw_inline int swProtocol_split_package_by_eof(swProtocol *protocol, swConnection *conn, swString *buffer)
{
#ifdef SW_LOG_TRACE_OPEN
    static int count;
    count++;
#endif

    int eof_pos;
    if (buffer->length - buffer->offset < protocol->package_eof_len)
    {
        eof_pos = -1;
    }
    else
    {
        eof_pos = swoole_strnpos(buffer->str + buffer->offset, buffer->length - buffer->offset, protocol->package_eof, protocol->package_eof_len);
    }

    swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[0] count=%d, length=%ld, size=%ld, offset=%ld.", count, buffer->length, buffer->size, (long)buffer->offset);

    //waiting for more data
    if (eof_pos < 0)
    {
        buffer->offset = buffer->length - protocol->package_eof_len;
        return SW_CONTINUE;
    }

    uint32_t length = buffer->offset + eof_pos + protocol->package_eof_len;
    swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[4] count=%d, length=%d", count, length);
    if (protocol->onPackage(conn, buffer->str, length) < 0)
    {
        return SW_CLOSE;
    }
    if (conn->removed)
    {
        return SW_OK;
    }

    //there are remaining data
    if (length < buffer->length)
    {
        uint32_t remaining_length = buffer->length - length;
        char *remaining_data = buffer->str + length;
        swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[5] count=%d, remaining_length=%d", count, remaining_length);

        while (1)
        {
            if (remaining_length < protocol->package_eof_len)
            {
                goto wait_more_data;
            }
            eof_pos = swoole_strnpos(remaining_data, remaining_length, protocol->package_eof, protocol->package_eof_len);
            if (eof_pos < 0)
            {
                wait_more_data:
                swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[1] count=%d, remaining_length=%d, length=%d", count, remaining_length, length);
                memmove(buffer->str, remaining_data, remaining_length);
                buffer->length = remaining_length;
                buffer->offset = 0;
#ifdef SW_USE_OPENSSL
                if (conn->ssl)
                {
                    return SW_CONTINUE;
                }
                else
#endif
                {
                    return SW_OK;
                }
            }
            else
            {
                length = eof_pos + protocol->package_eof_len;
                if (protocol->onPackage(conn, remaining_data, length) < 0)
                {
                    return SW_CLOSE;
                }
                if (conn->removed)
                {
                    return SW_OK;
                }
                swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[2] count=%d, remaining_length=%d, length=%d", count, remaining_length, length);
                remaining_data += length;
                remaining_length -= length;
            }
        }
    }
    swTraceLog(SW_TRACE_EOF_PROTOCOL, "#[3] length=%ld, size=%ld, offset=%ld", buffer->length, buffer->size, (long)buffer->offset);
    swString_clear(buffer);
#ifdef SW_USE_OPENSSL
    if (conn->ssl)
    {
        return SW_CONTINUE;
    }
#endif
    return SW_OK;
}
Esempio n. 19
0
/**
 * For Http Protocol
 */
static int swPort_onRead_http(swReactor *reactor, swListenPort *port, swEvent *event)
{
    swConnection *conn = event->socket;
    swServer *serv = reactor->ptr;

    if (conn->websocket_status >= WEBSOCKET_STATUS_HANDSHAKE)
    {
        if (conn->http_upgrade == 0)
        {
            swHttpRequest_free(conn);
            conn->websocket_status = WEBSOCKET_STATUS_ACTIVE;
            conn->http_upgrade = 1;
        }
        return swPort_onRead_check_length(reactor, port, event);
    }

#ifdef SW_USE_HTTP2
    if (conn->http2_stream)
    {
        _parse_frame: return swPort_onRead_check_length(reactor, port, event);
    }
#endif

    int n = 0;
    char *buf;
    int buf_len;

    swHttpRequest *request = NULL;
    swProtocol *protocol = &port->protocol;

    //new http request
    if (conn->object == NULL)
    {
        request = sw_malloc(sizeof(swHttpRequest));
        bzero(request, sizeof(swHttpRequest));
        conn->object = request;
    }
    else
    {
        request = (swHttpRequest *) conn->object;
    }

    if (!request->buffer)
    {
        request->buffer = swString_new(SW_HTTP_HEADER_MAX_SIZE);
        //alloc memory failed.
        if (!request->buffer)
        {
            swReactorThread_onClose(reactor, event);
            return SW_ERR;
        }
    }

    swString *buffer = request->buffer;

    recv_data:
    buf = buffer->str + buffer->length;
    buf_len = buffer->size - buffer->length;

    n = swConnection_recv(conn, buf, buf_len, 0);
    if (n < 0)
    {
        switch (swConnection_error(errno))
        {
        case SW_ERROR:
            swSysError("recv from connection#%d failed.", event->fd);
            return SW_OK;
        case SW_CLOSE:
            conn->close_errno = errno;
            goto close_fd;
        default:
            return SW_OK;
        }
    }
    else if (n == 0)
    {
        close_fd:
        swHttpRequest_free(conn);
        swReactorThread_onClose(reactor, event);
        return SW_OK;
    }
    else
    {
        buffer->length += n;

        if (request->method == 0 && swHttpRequest_get_protocol(request) < 0)
        {
            if (request->excepted == 0 && request->buffer->length < SW_HTTP_HEADER_MAX_SIZE)
            {
                return SW_OK;
            }
            swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "get protocol failed.");
#ifdef SW_HTTP_BAD_REQUEST_TIP
            if (swConnection_send(conn, SW_STRL(SW_HTTP_BAD_REQUEST_TIP), 0) < 0)
            {
                swSysError("send() failed.");
            }
#endif
            goto close_fd;
        }

        if (request->method > HTTP_PRI)
        {
            swWarn("method no support");
            goto close_fd;
        }
#ifdef SW_USE_HTTP2
        else if (request->method == HTTP_PRI)
        {
            conn->http2_stream = 1;
            swHttp2_send_setting_frame(protocol, conn);
            if (n == sizeof(SW_HTTP2_PRI_STRING) - 1)
            {
                swHttpRequest_free(conn);
                return SW_OK;
            }
            swString *buffer = swServer_get_buffer(serv, event->fd);
            if (!buffer)
            {
                goto close_fd;
            }
            swString_append_ptr(buffer, buf + (sizeof(SW_HTTP2_PRI_STRING) - 1), n - (sizeof(SW_HTTP2_PRI_STRING) - 1));
            swHttpRequest_free(conn);
            conn->skip_recv = 1;
            goto _parse_frame;
        }
#endif
        //http header is not the end
        if (request->header_length == 0)
        {
            if (swHttpRequest_get_header_length(request) < 0)
            {
                if (buffer->size == buffer->length)
                {
                    swWarn("[2]http header is too long.");
                    goto close_fd;
                }
                else
                {
                    goto recv_data;
                }
            }
        }

        //http body
        if (request->content_length == 0)
        {
            swTraceLog(SW_TRACE_SERVER, "content-length=%u, keep-alive=%d", request->content_length, request->keep_alive);
            // content length field not found
            if (swHttpRequest_get_header_info(request) < 0)
            {
                /* the request is really no body */
                if (buffer->length == request->header_length)
                {
                    /**
                     * send static file content directly in the reactor thread
                     */
                    if (!(serv->enable_static_handler && swPort_http_static_handler(request, conn)))
                    {
                        /**
                         * dynamic request, dispatch to worker
                         */
                        swReactorThread_dispatch(conn, buffer->str, buffer->length);
                    }
                    swHttpRequest_free(conn);
                    return SW_OK;
                }
                else if (buffer->size == buffer->length)
                {
                    swWarn("[0]http header is too long.");
                    goto close_fd;
                }
                /* wait more data */
                else
                {
                    goto recv_data;
                }
            }
            else if (request->content_length > (protocol->package_max_length - request->header_length))
            {
                swWarn("Content-Length is too big, MaxSize=[%d].", protocol->package_max_length - request->header_length);
                goto close_fd;
            }
        }

        //total length
        uint32_t request_size = request->header_length + request->content_length;
        if (request_size > buffer->size && swString_extend(buffer, request_size) < 0)
        {
            goto close_fd;
        }

        //discard the redundant data
        if (buffer->length > request_size)
        {
            buffer->length = request_size;
        }

        if (buffer->length == request_size)
        {
            swReactorThread_dispatch(conn, buffer->str, buffer->length);
            swHttpRequest_free(conn);
        }
        else
        {
#ifdef SW_HTTP_100_CONTINUE
            //Expect: 100-continue
            if (swHttpRequest_has_expect_header(request))
            {
                swSendData _send;
                _send.data = "HTTP/1.1 100 Continue\r\n\r\n";
                _send.length = strlen(_send.data);

                int send_times = 0;
                direct_send:
                n = swConnection_send(conn, _send.data, _send.length, 0);
                if (n < _send.length)
                {
                    _send.data += n;
                    _send.length -= n;
                    send_times++;
                    if (send_times < 10)
                    {
                        goto direct_send;
                    }
                    else
                    {
                        swWarn("send http header failed");
                    }
                }
            }
            else
            {
                swTrace("PostWait: request->content_length=%d, buffer->length=%zd, request->header_length=%d\n",
                        request->content_length, buffer->length, request->header_length);
            }
#endif
            goto recv_data;
        }
    }
    return SW_OK;
}