Beispiel #1
0
size_t api_stream_on_write(struct api_filter_t* filter,
                           const char* buffer, size_t length)
{
    api_stream_t* stream = filter->stream;
    api_stream_write_t write;
    api_timer_t timeout;
    struct timespec start, end, elapsed;
    uint64_t timeout_value = stream->write_timeout;

    if (length == 0)
        return length;

    if (stream->status.write_timeout ||
        stream->status.error != API__OK ||
        stream->status.closed ||
        stream->status.peer_closed ||
        stream->status.terminated)
        return -1;

    if (stream->loop->base.terminated)
        return -1;

    write.buffer = buffer;
    write.length = length;
    write.offset = 0;
    write.task = stream->loop->base.scheduler.current;

    stream->os_linux.reserved[1] = &write;

    if (timeout_value > 0)
    {
        memset(&timeout, 0, sizeof(timeout));
        timeout.task = write.task;

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

    clock_gettime(CLOCK_MONOTONIC, &start);

    api_loop_write_add(stream->loop, stream->fd, &stream->os_linux.e);

    do
    {
        api_task_sleep(write.task);

        if (stream->status.write_timeout ||
            stream->status.error != API__OK ||
            stream->status.closed ||
            stream->status.peer_closed ||
            stream->status.terminated)
            break;

        if (timeout_value > 0 && timeout.elapsed)
            break;
    }
    while (write.offset < write.length);

    api_loop_write_del(stream->loop, stream->fd, &stream->os_linux.e);

    clock_gettime(CLOCK_MONOTONIC, &end);

	if (end.tv_nsec - start.tv_nsec < 0)
    {
		elapsed.tv_sec = end.tv_sec - start.tv_sec - 1;
		elapsed.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
	}
    else
    {
		elapsed.tv_sec = end.tv_sec - start.tv_sec;
		elapsed.tv_nsec = end.tv_nsec - start.tv_nsec;
	}

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

    stream->os_linux.reserved[1] = 0;
    stream->write_bandwidth.sent += write.offset;
    stream->write_bandwidth.period += elapsed.tv_sec * 1000000 + elapsed.tv_nsec / 1000;

    if (timeout_value > 0 && timeout.elapsed)
    {
        stream->status.write_timeout = 1;
        stream->filter_head->on_write_timeout(stream->filter_head);
    }

    return write.offset;
}
Beispiel #2
0
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;
}