コード例 #1
0
ファイル: api_stream.c プロジェクト: angrygorilla/libapi
int api_stream_attach(api_stream_t* stream, api_loop_t* loop)
{
    int error = API__OK;

    if (loop->base.terminated)
    {
        stream->status.terminated = 1;
        return API__TERMINATE;
    }

    if (stream->type == STREAM_Tcp)
    {
        stream->os_linux.e.events = EPOLLERR | EPOLLHUP | EPOLLRDHUP;
        error = epoll_ctl(loop->epoll, EPOLL_CTL_ADD, stream->fd,
                            &stream->os_linux.e);
    }
    
    if (!error)
    {
        stream->loop = loop;
        api_loop_ref(loop);
        return API__OK;
    }

    return api_error_translate(errno);
}
コード例 #2
0
ファイル: api_tcp.c プロジェクト: KoushikDasika/libapi
int api_tcp_listen(api_tcp_listener_t* listener, api_loop_t* loop,
                           const char* ip, int port, int backlog)
{
    struct sockaddr_in* addr_in = 
        (struct sockaddr_in*)&listener->address.address;
    struct sockaddr_in6* addr_in6 = 
        (struct sockaddr_in6*)&listener->address.address;
    struct sockaddr* a = (struct sockaddr*)&listener->address.address;
    HANDLE handle;
    DWORD sys_error = 0;
    int error;

    if (loop->terminated)
    {
        listener->status.terminated = 1;
        return API__TERMINATE;
    }

    memset(listener, 0, sizeof(*listener));

    if (strchr(ip, ':') == 0)
    {
        // ipv4
        listener->fd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
                                NULL, 0, WSA_FLAG_OVERLAPPED);

        listener->address.length = sizeof(struct sockaddr_in);
        addr_in->sin_family = AF_INET;
        addr_in->sin_addr.s_addr = inet_addr(ip);
        addr_in->sin_port = htons(port);

        listener->os_win.af = AF_INET;
    }
    else
    {
        // ipv6
        listener->fd = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, 
                                NULL, 0, WSA_FLAG_OVERLAPPED);

        listener->address.length = sizeof(struct sockaddr_in6);
        addr_in6->sin6_family = AF_INET6;
        addr_in6->sin6_addr = in6addr_any;
        addr_in6->sin6_port = htons(port);

        inet_pton(AF_INET6, ip, (void*)&addr_in6->sin6_addr);

        listener->os_win.af = AF_INET6;
    }

    error = api_socket_non_block(listener->fd, 1);
    error = api_socket_recv_buffer_size(listener->fd, 0);
    error = api_socket_send_buffer_size(listener->fd, 0);
    error = api_tcp_nodelay(listener->fd, 1);

    if (0 != bind(listener->fd, a, listener->address.length))
        return api_error_translate(WSAGetLastError());

    if (0 != listen(listener->fd, backlog))
        return api_error_translate(WSAGetLastError());

    listener->loop = loop;
    listener->os_win.processor = api_tcp_listener_processor;

    listener->on_closed = api_tcp_listener_on_closed;
    listener->on_error = api_tcp_listener_on_error;
    listener->on_terminate = api_tcp_listener_on_terminate;
    listener->on_accept = api_tcp_listener_on_accept;

    handle = CreateIoCompletionPort((HANDLE)listener->fd, loop->iocp, 
                                (ULONG_PTR)&listener->os_win, 0);
    if (handle == NULL)
    {
        sys_error = GetLastError();
        closesocket(listener->fd);
        error = api_error_translate(sys_error);
    }

    if (API__OK != error)
    {
        listener->loop = loop;
        api_loop_ref(loop);
        return API__OK;
    }
    else
    {
        SetFileCompletionNotificationModes((HANDLE)listener->fd,
                    FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
    }

    return error;
}
コード例 #3
0
ファイル: api_tcp.c プロジェクト: KoushikDasika/libapi
int api_tcp_connect(api_tcp_t* tcp,
                    api_loop_t* loop,
                    const char* ip, int port, uint64_t tmeout)
{
    struct sockaddr_in* addr_in = 
        (struct sockaddr_in*)&tcp->address.address;
    struct sockaddr_in6* addr_in6 = 
        (struct sockaddr_in6*)&tcp->address.address;
    struct sockaddr* a = (struct sockaddr*)&tcp->address.address;
    api_timer_t timeout;
    uint64_t timeout_value = tmeout;
    HANDLE handle;
    DWORD dwSent = 0;
    DWORD sys_error = 0;
    BOOL result;
    BOOL completed = FALSE;
    int af;
    int error = API__OK;

    memset(tcp, 0, sizeof(*tcp));

    if (loop->terminated)
    {
        tcp->stream.status.terminated = 1;
        return API__TERMINATE;
    }

    tcp->stream.os_win.processor = api_tcp_connect_processor;
    tcp->stream.os_win.reserved[0] = loop->scheduler.current;

    if (strchr(ip, ':') == 0)
    {
        // ipv4
        tcp->stream.fd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
                                NULL, 0, WSA_FLAG_OVERLAPPED);

        af = AF_INET;

        tcp->address.length = sizeof(struct sockaddr_in);
        addr_in->sin_family = AF_INET;
        addr_in->sin_addr.s_addr = INADDR_ANY;
        addr_in->sin_port = 0;
    }
    else
    {
        // ipv6
        tcp->stream.fd = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, 
                                NULL, 0, WSA_FLAG_OVERLAPPED);

        af = AF_INET6;

        tcp->address.length = sizeof(struct sockaddr_in6);
        addr_in6->sin6_family = AF_INET6;
        addr_in6->sin6_addr = in6addr_any;
        addr_in6->sin6_port = 0;
    }

    error = api_socket_non_block(tcp->stream.fd, 1);
    error = api_socket_recv_buffer_size(tcp->stream.fd, 0);
    error = api_socket_send_buffer_size(tcp->stream.fd, 0);
    error = api_tcp_nodelay(tcp->stream.fd, 1);

    if (0 != bind(tcp->stream.fd, a, tcp->address.length))
    {
        error = api_error_translate(WSAGetLastError());
        closesocket(tcp->stream.fd);
        return error;
    }

    handle = CreateIoCompletionPort((HANDLE)tcp->stream.fd, loop->iocp, 
        (ULONG_PTR)&tcp->stream.os_win, 0);
    if (handle == NULL)
    {
        sys_error = GetLastError();
        closesocket(tcp->stream.fd);
        return api_error_translate(sys_error);
    }

    SetFileCompletionNotificationModes((HANDLE)tcp->stream.fd,
                    FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);

    if (af == AF_INET)
    {
        addr_in->sin_family = AF_INET;
        addr_in->sin_addr.s_addr = inet_addr(ip);
        addr_in->sin_port = htons(port);
    }
    else
    {
        addr_in6->sin6_family = AF_INET6;
        addr_in6->sin6_addr = in6addr_any;
        addr_in6->sin6_port = htons(port);

        inet_pton(AF_INET6, ip, (void*)&addr_in6->sin6_addr);
    }

    if (timeout_value > 0)
    {
        memset(&timeout, 0, sizeof(timeout));
        timeout.task = loop->scheduler.current;

        api_timeout_exec(&loop->timeouts, &timeout, timeout_value);
    }

    result = lpfnConnectEx(tcp->stream.fd, a, tcp->address.length,
                        NULL, 0,
                        &dwSent, (LPOVERLAPPED)&tcp->stream.os_win.read);

    if (!result)
    {
        sys_error = WSAGetLastError();
        if (sys_error == ERROR_SUCCESS)
        {
            completed = TRUE;
        }
        else
        if (sys_error != WSA_IO_PENDING)
        {
            completed = TRUE;
            error = api_error_translate(sys_error);
            tcp->stream.status.error = error;
        }
    }
    else
    {
        completed = TRUE;
    }

    if (!completed)
        api_task_sleep(loop->scheduler.current);

    if (timeout_value > 0)
        api_timeout_exec(&loop->timeouts, &timeout, 0);

    if (timeout_value > 0 && timeout.elapsed)
    {
        tcp->stream.status.read_timeout = 1;

        if (API__OK != error)
            error = api_error_translate(ERROR_TIMEOUT);
    }

    if (API__OK == error)
    {
        api_stream_init(&tcp->stream, STREAM_Tcp, tcp->stream.fd);
        tcp->stream.loop = loop;
        
        api_loop_ref(loop);
        return API__OK;
    }
    else
    {
        closesocket(tcp->stream.fd);
    }

    return error;
}
コード例 #4
0
ファイル: api_loop.c プロジェクト: cmilan/libapi
int api_loop_run_internal(api_loop_t* loop)
{
    BOOL status;
    DWORD transfered;
    ULONG_PTR key;
    OVERLAPPED* overlapped;
    DWORD error;
    BOOL failed;
    os_win_t* win;

    api_scheduler_init(&loop->base.scheduler);
    loop->base.scheduler.pool = &loop->base.pool;
	
    loop->base.now = api_time_current();
    loop->base.last_activity = loop->base.now;

    api_loop_ref(loop);

    do
    {
        if (0 < api_timer_process(&loop->base.sleeps, TIMER_Sleep, loop->base.now))
        {
            loop->base.now = api_time_current();
            loop->base.last_activity = loop->base.now;
        }

        failed = 0;
        error = 0;
        status = GetQueuedCompletionStatus(loop->iocp, &transfered, &key,
            &overlapped, (DWORD)api_loop_calculate_wait_timeout(&loop->base));

        loop->base.now = api_time_current();

        if (status == FALSE)
        {
            failed = 1;
            error = GetLastError();

            if (overlapped == NULL)
            {
                /*
                 * Completion port closed, propably by api_loop_stop
                 */
                if (error == ERROR_ABANDONED_WAIT_0)
                {
                    loop->iocp = NULL;
                    failed = 1;
                    break;
                }

                if (error == WAIT_TIMEOUT)
                {
                    failed = 0;
                    key = 0;

                    if (0 < api_timer_process(&loop->base.idles, TIMER_Idle,
                                        loop->base.now - loop->base.last_activity))
                    {
                        loop->base.now = api_time_current();
                        loop->base.last_activity = loop->base.now;
                    }
                }
            }

            if (overlapped != NULL)
            {
                /*
                 * Eof or Connection was closed
                 */
                if (transfered == 0)
                {
                    failed = 0;
                }
            }
        }

        if (!failed && key != 0)
        {
            win = (os_win_t*)key;
            win->processor(win, transfered, overlapped, loop, error);
            loop->base.now = api_time_current();
            loop->base.last_activity = loop->base.now;
        }

        api_timer_process(&loop->base.timeouts, TIMER_Timeout,
                loop->base.now - loop->base.last_activity);

        loop->base.now = api_time_current();
    }
    while (!failed);

    if (API__OK != api_loop_cleanup(loop))
    {
        /* handle error */
    }

    if (loop->iocp != NULL)
    {
        if (!CloseHandle(loop->iocp))
        {
            /* handle error when eopll not closed already */
        }
    }

    return API__OK;
}
コード例 #5
0
ファイル: api_tcp.c プロジェクト: KoushikDasika/libapi
int api_tcp_connect(api_tcp_t* tcp,
                    api_loop_t* loop,
                    const char* ip, int port, uint64_t tmeout)
{
    struct sockaddr_in* addr_in =
        (struct sockaddr_in*)&tcp->address.address;
    struct sockaddr_in6* addr_in6 =
        (struct sockaddr_in6*)&tcp->address.address;
    struct sockaddr* a = (struct sockaddr*)&tcp->address.address;
    int error = API__OK;
    api_timer_t timeout;
    uint64_t timeout_value = tmeout;

    memset(tcp, 0, sizeof(*tcp));

    if (loop->terminated)
    {
        tcp->stream.status.terminated = 1;
        return API__TERMINATE;
    }

    tcp->stream.os_linux.processor = api_tcp_connect_processor;
    tcp->stream.os_linux.reserved[0] = loop->scheduler.current;
    tcp->stream.os_linux.e.data.ptr = &tcp->stream.os_linux;

    if (strchr(ip, ':') == 0)
    {
        // ipv4
        tcp->stream.fd = 
            socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

        tcp->address.length = sizeof(struct sockaddr_in);
        addr_in->sin_family = AF_INET;
        addr_in->sin_addr.s_addr = inet_addr(ip);
        addr_in->sin_port = htons(port);
    }
    else
    {
        // ipv6
        tcp->stream.fd =
            socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

        tcp->address.length = sizeof(struct sockaddr_in6);
        addr_in6->sin6_family = AF_INET6;
        addr_in6->sin6_addr = in6addr_any;
        addr_in6->sin6_port = htons(port);

        inet_pton(AF_INET6, ip, (void*)&addr_in6->sin6_addr.__in6_u);
    }

    error = api_socket_non_block(tcp->stream.fd, 1);
    error = api_socket_recv_buffer_size(tcp->stream.fd, 0);
    error = api_socket_send_buffer_size(tcp->stream.fd, 0);
    error = api_tcp_nodelay(tcp->stream.fd, 1);

    if (0 != connect(tcp->stream.fd, a, tcp->address.length))
    {
        if (errno != EINPROGRESS)
        {
            error = api_error_translate(errno);
        }
        else
        {
            // wait needed

            tcp->stream.os_linux.e.events = 
                EPOLLERR | EPOLLHUP | EPOLLRDHUP | EPOLLOUT;

            error = epoll_ctl(loop->epoll, EPOLL_CTL_ADD, tcp->stream.fd,
                                        &tcp->stream.os_linux.e);

            error = api_error_translate(error);
            if (API__OK == error)
            {
                error = api_loop_write_add(loop, tcp->stream.fd, 
                                        &tcp->stream.os_linux.e);

                if (API__OK != error)
                {
                    epoll_ctl(loop->epoll, EPOLL_CTL_DEL, tcp->stream.fd,
                        &tcp->stream.os_linux.e);
                }
                else
                {
                    if (timeout_value > 0)
                    {
                        memset(&timeout, 0, sizeof(timeout));
                        timeout.task = loop->scheduler.current;

                        api_timeout_exec(&loop->timeouts, &timeout,
                                                    timeout_value);
                    }

                    api_task_sleep(loop->scheduler.current);

                    if (timeout_value > 0)
                        api_timeout_exec(&loop->timeouts, &timeout, 0);

                    if (timeout_value > 0 && timeout.elapsed)
                    {
                        tcp->stream.status.read_timeout = 1;
                        error = api_error_translate(ETIMEDOUT);
                    }

                    if (tcp->stream.status.closed ||
                        tcp->stream.status.terminated ||
                        tcp->stream.status.error != API__OK)
                    {
                        epoll_ctl(loop->epoll, EPOLL_CTL_DEL, tcp->stream.fd,
                                                &tcp->stream.os_linux.e);
                    }
                    else
                    {
                        api_loop_write_del(loop, tcp->stream.fd,
                                            &tcp->stream.os_linux.e);
                    }
                }
            }
        }
    }
    else
    {
        // completed immediately
    }

    if (API__OK == error &&
        tcp->stream.status.closed == 0 &&
        tcp->stream.status.terminated == 0 &&
        tcp->stream.status.error == API__OK)
    {
        api_stream_init(&tcp->stream, STREAM_Tcp, tcp->stream.fd);
        tcp->stream.loop = loop;
        api_loop_ref(loop);
        return API__OK;
    }

    close(tcp->stream.fd);

    if (API__OK != error)
        return error;

    if (API__OK != tcp->stream.status.error)
        return tcp->stream.status.error;

    return -1;
}
コード例 #6
0
ファイル: api_tcp.c プロジェクト: KoushikDasika/libapi
int api_tcp_listen(api_tcp_listener_t* listener, api_loop_t* loop,
                           const char* ip, int port, int backlog)
{
    struct sockaddr_in* addr_in =
        (struct sockaddr_in*)&listener->address.address;
    struct sockaddr_in6* addr_in6 =
        (struct sockaddr_in6*)&listener->address.address;
    struct sockaddr* a = (struct sockaddr*)&listener->address.address;
    int error;

    if (loop->terminated)
    {
        listener->status.terminated = 1;
        return API__TERMINATE;
    }

    memset(listener, 0, sizeof(*listener));

    if (strchr(ip, ':') == 0)
    {
        // ipv4
        listener->fd = 
            socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

        listener->address.length = sizeof(struct sockaddr_in);
        addr_in->sin_family = AF_INET;
        addr_in->sin_addr.s_addr = inet_addr(ip);
        addr_in->sin_port = htons(port);

        listener->os_linux.af = AF_INET;
    }
    else
    {
        // ipv6
        listener->fd =
            socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);

        listener->address.length = sizeof(struct sockaddr_in6);
        addr_in6->sin6_family = AF_INET6;
        addr_in6->sin6_addr = in6addr_any;
        addr_in6->sin6_port = htons(port);

        inet_pton(AF_INET6, ip, (void*)&addr_in6->sin6_addr.__in6_u);

        listener->os_linux.af = AF_INET6;
    }

    error = api_socket_non_block(listener->fd, 1);
    error = api_socket_recv_buffer_size(listener->fd, 0);
    error = api_socket_send_buffer_size(listener->fd, 0);
    error = api_tcp_nodelay(listener->fd, 1);

    if (0 != bind(listener->fd, a, listener->address.length))
        return api_error_translate(errno);

    if (0 != listen(listener->fd, backlog))
        return api_error_translate(errno);

    listener->loop = loop;
    listener->os_linux.processor = api_tcp_listener_processor;
    listener->os_linux.e.data.ptr = listener;

    listener->on_closed = api_tcp_listener_on_closed;
    listener->on_error = api_tcp_listener_on_error;
    listener->on_terminate = api_tcp_listener_on_terminate;
    listener->on_accept = api_tcp_listener_on_accept;

    listener->os_linux.e.events = EPOLLERR | EPOLLHUP | EPOLLRDHUP;
    error = epoll_ctl(loop->epoll, EPOLL_CTL_ADD, listener->fd,
                        &listener->os_linux.e);

    if (!error)
    {
        listener->loop == loop;
        api_loop_ref(loop);
    }

    return api_error_translate(error);
}