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); }
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; }
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; }
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; }
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; }
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); }