From 36c5c9e89f295907b425129bb8a9139c2f2123a2 Mon Sep 17 00:00:00 2001 From: Manoj Ampalam Date: Tue, 12 Jan 2016 14:38:05 -0800 Subject: [PATCH] 1-12 C1 --- .../win32posix/Tests/Tests.vcxproj | 10 +- .../win32posix/Tests/Tests.vcxproj.filters | 13 +- .../{unittest1.cpp => socketiotests.cpp} | 59 ++- .../win32posix/win32posix/signal.c | 50 ++ .../win32posix/win32posix/socketio.c | 465 +++++++++++------- .../win32posix/win32posix/w32fd.c | 120 ++--- .../win32posix/win32posix/w32fd.h | 10 +- .../win32posix/win32posix/win32posix.vcxproj | 1 + .../win32posix/win32posix.vcxproj.filters | 3 + 9 files changed, 447 insertions(+), 284 deletions(-) rename contrib/win32/w32-posix-prototype/win32posix/Tests/{unittest1.cpp => socketiotests.cpp} (66%) create mode 100644 contrib/win32/w32-posix-prototype/win32posix/win32posix/signal.c diff --git a/contrib/win32/w32-posix-prototype/win32posix/Tests/Tests.vcxproj b/contrib/win32/w32-posix-prototype/win32posix/Tests/Tests.vcxproj index 41d872c..97d9ce6 100644 --- a/contrib/win32/w32-posix-prototype/win32posix/Tests/Tests.vcxproj +++ b/contrib/win32/w32-posix-prototype/win32posix/Tests/Tests.vcxproj @@ -83,15 +83,7 @@ - - - - - - Create - Create - - + diff --git a/contrib/win32/w32-posix-prototype/win32posix/Tests/Tests.vcxproj.filters b/contrib/win32/w32-posix-prototype/win32posix/Tests/Tests.vcxproj.filters index 5d0d136..471a8f0 100644 --- a/contrib/win32/w32-posix-prototype/win32posix/Tests/Tests.vcxproj.filters +++ b/contrib/win32/w32-posix-prototype/win32posix/Tests/Tests.vcxproj.filters @@ -15,18 +15,7 @@ - - Header Files - - - Header Files - - - - - Source Files - - + Source Files diff --git a/contrib/win32/w32-posix-prototype/win32posix/Tests/unittest1.cpp b/contrib/win32/w32-posix-prototype/win32posix/Tests/socketiotests.cpp similarity index 66% rename from contrib/win32/w32-posix-prototype/win32posix/Tests/unittest1.cpp rename to contrib/win32/w32-posix-prototype/win32posix/Tests/socketiotests.cpp index f9f573f..011c373 100644 --- a/contrib/win32/w32-posix-prototype/win32posix/Tests/unittest1.cpp +++ b/contrib/win32/w32-posix-prototype/win32posix/Tests/socketiotests.cpp @@ -5,11 +5,68 @@ extern "C" { using namespace Microsoft::VisualStudio::CppUnitTestFramework; +#define DEFAULT_PORT "27015" + namespace UnitTests { - TEST_CLASS(UnitTest1) + TEST_CLASS(SocketIOTests) { + public: + + struct addrinfo *result = NULL; + struct addrinfo hints; + int ListenSocket = -1; + + + TEST_METHOD_INITIALIZE(TestMethodInitialize) + { + int iResult; + + w32posix_initialize(); + ZeroMemory(&hints, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE; + + iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result); + if (iResult != 0) { + printf("getaddrinfo failed with error: %d\n", iResult); + return; + } + + ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + if (ListenSocket == -1) { + printf("socket failed with error: %ld\n", errno); + return; + } + + // Setup the TCP listening socket + iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen); + if (iResult == -1) { + printf("bind failed with error: %d\n", errno); + return ; + } + + iResult = listen(ListenSocket, SOMAXCONN); + if (iResult == -1) { + printf("listen failed with error: %d\n", errno); + return; + } + freeaddrinfo(result); + + } + + TEST_METHOD_CLEANUP(TestMethodCleanup) + { + if (result) + freeaddrinfo(result); + if (ListenSocket != -1) + close(ListenSocket); + w32posix_done(); + + } TEST_METHOD(TestMethod1) { diff --git a/contrib/win32/w32-posix-prototype/win32posix/win32posix/signal.c b/contrib/win32/w32-posix-prototype/win32posix/win32posix/signal.c new file mode 100644 index 0000000..eb34310 --- /dev/null +++ b/contrib/win32/w32-posix-prototype/win32posix/win32posix/signal.c @@ -0,0 +1,50 @@ +#include "w32fd.h" +#include + +//signal handlers + +//signal queue + +//wakes on +// - any signals (errno = EINTR ) +// - any of the supplied events set +// - any APCs caused by IO completions +int wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) +{ + //todo - implement signal catching and handling + if (num_events) + { + DWORD ret = WaitForMultipleObjectsEx(num_events, events, FALSE, milli_seconds, TRUE); + if ((ret >= WAIT_OBJECT_0) && (ret <= WAIT_OBJECT_0 + num_events - 1)) { + //woken up by event signalled + return 0; + } + else if (ret == WAIT_IO_COMPLETION) { + return 0; + } + else if (ret == WAIT_TIMEOUT) { + errno = ETIMEDOUT; + return -1; + } + else { //some other error + errno = EOTHER; + return -1; + } + } + else + { + DWORD ret = SleepEx(milli_seconds, TRUE); + if (ret == WAIT_IO_COMPLETION) { + return 0; + } + else if (ret == 0) { + //timed out + errno = ETIMEDOUT; + return -1; + } + else { //some other error + errno = EOTHER; + return -1; + } + } +} \ No newline at end of file diff --git a/contrib/win32/w32-posix-prototype/win32posix/win32posix/socketio.c b/contrib/win32/w32-posix-prototype/win32posix/win32posix/socketio.c index e0d5216..153236b 100644 --- a/contrib/win32/w32-posix-prototype/win32posix/win32posix/socketio.c +++ b/contrib/win32/w32-posix-prototype/win32posix/win32posix/socketio.c @@ -7,6 +7,8 @@ #define INTERNAL_BUFFER_SIZE 100*1024 //100KB +#define INTERNAL_RECV_BUFFER_SIZE 70*1024 //70KB + static int getWSAErrno() { int wsaerrno = WSAGetLastError(); @@ -47,6 +49,153 @@ int socketio_done() { return 0; } +struct acceptEx_context { + char lpOutputBuf[1024]; + SOCKET accept_socket; + LPFN_ACCEPTEX lpfnAcceptEx; + DWORD bytes_received; +}; + + +int socketio_acceptEx(struct w32_io* pio) { + struct acceptEx_context *context; + + if (pio->context == NULL) { + GUID GuidAcceptEx = WSAID_ACCEPTEX; + DWORD dwBytes; + + context = (struct acceptEx_context*)malloc(sizeof(struct acceptEx_context)); + if (context == NULL) { + errno = ENOMEM; + return -1; + } + + if (SOCKET_ERROR == WSAIoctl(pio->sock, SIO_GET_EXTENSION_FUNCTION_POINTER, + &GuidAcceptEx, sizeof (GuidAcceptEx), + &context->lpfnAcceptEx, sizeof (context->lpfnAcceptEx), + &dwBytes, NULL, NULL)) + { + free(context); + errno = getWSAErrno(); + return -1; + } + + context->accept_socket = INVALID_SOCKET; + pio->context = context; + } + else + context = (struct acceptEx_context *)pio->context; + + //init overlapped event + if (pio->read_overlapped.hEvent == NULL) { + if ((pio->read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) { + errno = ENOMEM; + return -1; + } + } + ResetEvent(pio->read_overlapped.hEvent); + + //create accepting socket + //todo - get socket parameters from listening socket + context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (context->accept_socket == INVALID_SOCKET) { + errno = getWSAErrno(); + return -1; + } + + if (TRUE == context->lpfnAcceptEx(pio->sock, + context->accept_socket, + context->lpOutputBuf, + 0, + sizeof(struct sockaddr_in) + 16, + sizeof(struct sockaddr_in) + 16, + &context->bytes_received, + &pio->read_overlapped)) + { + //we are already connected. Set event so subsequent select will catch + SetEvent(pio->read_overlapped.hEvent); + } + else { + //if overlapped io is in progress, we are good + if (WSAGetLastError() != ERROR_IO_PENDING) { + errno = getWSAErrno(); + return -1; + } + } + + pio->read_details.pending = TRUE; + return 0; +} + +#define RECV_CONNECTION_CLOSED 1234 + +void CALLBACK WSARecvCompletionRoutine( + IN DWORD dwError, + IN DWORD cbTransferred, + IN LPWSAOVERLAPPED lpOverlapped, + IN DWORD dwFlags + ) +{ + struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped)); + if (!dwError && !cbTransferred) + dwError = RECV_CONNECTION_CLOSED; + pio->read_details.error = dwError; + pio->read_details.remaining = cbTransferred; + pio->read_details.completed = 0; + pio->read_details.pending = FALSE; +} + +int socketio_WSARecv(struct w32_io* pio, BOOL* completed) { + int ret = 0; + WSABUF wsabuf; + DWORD recv_flags = 0; + + if (completed) + *completed = FALSE; + + //initialize recv buffers if needed + wsabuf.len = INTERNAL_RECV_BUFFER_SIZE; + if (pio->read_details.buf == NULL) + { + wsabuf.buf = malloc(wsabuf.len); + + if (!wsabuf.buf) + { + errno = ENOMEM; + return -1; + } + + pio->read_details.buf = wsabuf.buf; + pio->read_details.buf_size = wsabuf.len; + } + else + wsabuf.buf = pio->read_details.buf; + + + //TODO - implement flags if any needed for OpenSSH + ret = WSARecv(pio->sock, &wsabuf, 1, NULL, &recv_flags, &pio->read_overlapped, &WSARecvCompletionRoutine); + if (ret == 0) + { + pio->read_details.pending = TRUE; + //receive has completed but APC is pending to be scheduled + if (completed) + *completed = TRUE; + } + else { //(ret == SOCKET_ERROR) + if (WSAGetLastError() == WSA_IO_PENDING) + { + //io is initiated and pending + pio->read_details.pending = TRUE; + } + else { //failed + errno = getWSAErrno(); + return -1; + } + } + + return 0; +} + struct w32_io* socketio_socket(int domain, int type, int protocol) { struct w32_io *pio = (struct w32_io*)malloc(sizeof(struct w32_io)); if (!pio) { @@ -95,51 +244,21 @@ int socketio_connect(struct w32_io* pio, const struct sockaddr* name, int namele return set_errno_on_error(connect(pio->sock, name, namelen)); } -void CALLBACK WSARecvCompletionRoutine( - IN DWORD dwError, - IN DWORD cbTransferred, - IN LPWSAOVERLAPPED lpOverlapped, - IN DWORD dwFlags - ) -{ - struct w32_io* pio = (struct w32_io*)((char*)lpOverlapped - offsetof(struct w32_io, read_overlapped)); - pio->read_details.error = dwError; - pio->read_details.remaining = cbTransferred; - pio->read_details.completed = 0; - pio->read_details.pending = FALSE; -} - int socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { - int ret = 0; - WSABUF wsabuf; - DWORD recv_flags = 0; + BOOL completed = FALSE; + if ((buf == NULL) || (len == 0)){ + errno = EPERM; + return -1; + } + //if io is already pending - if (pio->read_details.pending) - { + if (pio->read_details.pending) { errno = EAGAIN; return -1; } - //initialize recv buffers if needed - wsabuf.len = INTERNAL_BUFFER_SIZE; - if (pio->read_details.buf == NULL) - { - wsabuf.buf = malloc(wsabuf.len); - - if (!wsabuf.buf) - { - errno = ENOMEM; - return -1; - } - - pio->read_details.buf = wsabuf.buf; - pio->read_details.buf_size = wsabuf.len; - } - else - wsabuf.buf = pio->read_details.buf; - - //if we have some buffer copy it and retun #bytes copied + //if we have some buffer copy it and return #bytes copied if (pio->read_details.remaining) { int num_bytes_copied = min(len, pio->read_details.remaining); @@ -147,41 +266,46 @@ int socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { pio->read_details.remaining -= num_bytes_copied; pio->read_details.completed += num_bytes_copied; return num_bytes_copied; + } + + //if there was an error on async call, return + if (pio->read_details.error) { + if (pio->read_details.error == RECV_CONNECTION_CLOSED) { + //connection is closed + return 0; + } + else { + //todo - get qualified error + errno = EOTHER; + pio->read_details.error = 0; + return -1; + } } - //TODO - implement flags if any needed for OpenSSH - ret = WSARecv(pio->sock, &wsabuf, 1, NULL, &recv_flags, &pio->read_overlapped, &WSARecvCompletionRoutine); - if (ret == 0) - { - //receive has completed and APC is scheduled, let it run - pio->read_details.pending = TRUE; + if (0 != socketio_WSARecv(pio, &completed)) + return -1; + + if (completed) { + //Let APC be scheduled SleepEx(1, TRUE); if (pio->read_details.pending) { - //unexpected internal error + //this shouldn't be happening errno = EOTHER; return -1; } - } - else { //(ret == SOCKET_ERROR) - if (WSAGetLastError() == WSA_IO_PENDING) - { - //io is initiated and pending - pio->read_details.pending = TRUE; - if (w32_io_is_blocking(pio)) - { - //wait until io is done - while (pio->read_details.pending) - SleepEx(INFINITE, TRUE); - } - else { - errno = EAGAIN; + if (w32_io_is_blocking(pio)) + { + //wait until io is done + while (socketio_is_io_available(pio, TRUE) == FALSE) { + if (0 != wait_for_any_event(NULL, 0, INFINITE)) return -1; - } - } - else { //failed - errno = getWSAErrno(); + } + } + else { + if (socketio_is_io_available(pio, TRUE) == FALSE) { + errno = EAGAIN; return -1; } } @@ -189,8 +313,16 @@ int socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { //by this time we should have some bytes in internal buffer or an error from callback if (pio->read_details.error) { - errno = EOTHER; - return -1; + if (pio->read_details.error == RECV_CONNECTION_CLOSED) { + //connection is closed + return 0; + } + else { + //todo - get qualified error + errno = EOTHER; + pio->read_details.error = 0; + return -1; + } } if (pio->read_details.remaining) { @@ -199,11 +331,13 @@ int socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { pio->read_details.remaining -= num_bytes_copied; pio->read_details.completed = num_bytes_copied; return num_bytes_copied; - } - else { //connection is closed - return 0; } - + else { + //this should not happen + errno = EOTHER; + return -1; + } + } void CALLBACK WSASendCompletionRoutine( @@ -231,6 +365,11 @@ int socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { return -1; } + if (pio->write_details.error) { + errno = EOTHER; + return -1; + } + //initialize buffers if needed wsabuf.len = INTERNAL_BUFFER_SIZE; if (pio->write_details.buf == NULL) @@ -299,6 +438,9 @@ int socketio_shutdown(struct w32_io* pio, int how) { int socketio_close(struct w32_io* pio) { closesocket(pio->sock); + //todo- wait for pending io to abort + SleepEx(1, TRUE); + if (pio->type == LISTEN_FD) { if (pio->read_overlapped.hEvent) CloseHandle(pio->read_overlapped.hEvent); @@ -313,21 +455,46 @@ int socketio_close(struct w32_io* pio) { free(pio->write_details.buf); } - //todo- wait for pending io to abort free(pio); return 0; } -struct acceptEx_context { - char lpOutputBuf[1024]; - SOCKET accept_socket; - LPFN_ACCEPTEX lpfnAcceptEx; - DWORD bytes_received; -}; - - struct w32_io* socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen) { struct w32_io *accept_io = NULL; + int iResult = 0; + struct acceptEx_context* context = (struct acceptEx_context*)pio->context; + + //start io if not already started + if (pio->read_details.pending == FALSE) { + if (socketio_acceptEx(pio) != 0) { + return NULL; + } + } + + if (w32_io_is_blocking(pio)) { + // block until accept io is complete + while (FALSE == socketio_is_io_available(pio, TRUE)) + { + if (0 != wait_for_any_event(&pio->read_overlapped.hEvent, 1, INFINITE)) + { + return NULL; + } + } + } + else { + //if i/o is not ready + if (FALSE == socketio_is_io_available(pio, TRUE)) { + errno = EAGAIN; + return NULL; + } + + } + + if (0 != setsockopt(context->accept_socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&pio->sock, sizeof(pio->sock))) + { + errno = getWSAErrno(); + return NULL; + } accept_io = (struct w32_io*)malloc(sizeof(struct w32_io)); if (!accept_io) @@ -337,40 +504,17 @@ struct w32_io* socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* a } memset(accept_io, 0, sizeof(struct w32_io)); - if (w32_io_is_blocking(pio)) { - accept_io->sock = accept(pio->sock, addr, addrlen); - if (accept_io->sock == INVALID_SOCKET) { - errno = getWSAErrno(); - free(accept_io); - return NULL; - } - } - else { - //ensure i/o is ready - if (FALSE == socketio_is_ioready(pio, TRUE)) { - free(accept_io); - errno = EAGAIN; - return NULL; - } - - struct acceptEx_context* context = (struct acceptEx_context*)pio->context; - - accept_io->sock = context->accept_socket; - context->accept_socket = INVALID_SOCKET; - pio->read_details.pending = FALSE; - ResetEvent(pio->read_overlapped.hEvent); - } - - pio->type = SOCK_FD; + accept_io->sock = context->accept_socket; + accept_io->type = SOCK_FD; + context->accept_socket = INVALID_SOCKET; + pio->read_details.pending = FALSE; + ResetEvent(pio->read_overlapped.hEvent); return accept_io; } -BOOL socketio_is_ioready(struct w32_io* pio, BOOL rd) { +BOOL socketio_is_io_available(struct w32_io* pio, BOOL rd) { struct acceptEx_context* context = (struct acceptEx_context*)pio->context; - if (w32_io_is_blocking(pio)) - return FALSE; - if (pio->type == LISTEN_FD) { DWORD numBytes = 0; DWORD flags; @@ -384,95 +528,38 @@ BOOL socketio_is_ioready(struct w32_io* pio, BOOL rd) { return FALSE; } } - else { //regular socket - //todo - return FALSE; + else if (rd){ + if (pio->read_details.remaining || pio->read_details.error) + return TRUE; + else + return FALSE; + } + else { //write + return (pio->write_details.pending == FALSE)? TRUE : FALSE; } } -int socketio_start_asyncio(struct w32_io* pio, BOOL rd) { +int socketio_on_select(struct w32_io* pio, BOOL rd) { - if (w32_io_is_blocking(pio)) { - errno = EPERM; - return -1; - } + if (rd && pio->read_details.pending) + return 0; + + if (!rd && pio->write_details.pending) + return 0; if (pio->type == LISTEN_FD) { - if (!pio->read_details.pending) { - struct acceptEx_context *context; - - if (pio->context == NULL) { - GUID GuidAcceptEx = WSAID_ACCEPTEX; - DWORD dwBytes; - - context = (struct acceptEx_context*)malloc(sizeof(struct acceptEx_context)); - if (context == NULL) { - errno = ENOMEM; - return -1; - } - - if (SOCKET_ERROR == WSAIoctl(pio->sock, SIO_GET_EXTENSION_FUNCTION_POINTER, - &GuidAcceptEx, sizeof (GuidAcceptEx), - &context->lpfnAcceptEx, sizeof (context->lpfnAcceptEx), - &dwBytes, NULL, NULL)) - { - free(context); - errno = getWSAErrno(); - return -1; - } - - context->accept_socket = INVALID_SOCKET; - pio->context = context; - } - else - context = (struct acceptEx_context *)pio->context; - - //init overlapped event - if (pio->read_overlapped.hEvent == NULL) { - if ((pio->read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL) { - errno = ENOMEM; - return -1; - } - } - ResetEvent(pio->read_overlapped.hEvent); - - //create accepting socket - //todo - get socket parameters from listening socket - context->accept_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (context->accept_socket == INVALID_SOCKET) { - errno = getWSAErrno(); - return -1; - } - - if (TRUE == context->lpfnAcceptEx(pio->sock, - context->accept_socket, - context->lpOutputBuf, - 0, - sizeof(struct sockaddr_in) + 16, - sizeof(struct sockaddr_in) + 16, - &context->bytes_received, - &pio->read_overlapped)) - { - //we are already connected. Set event so subsequent select will catch - SetEvent(pio->read_overlapped.hEvent); - } - else { - //if overlapped io is in progress, we are good - if (WSAGetLastError() != ERROR_IO_PENDING) { - errno = getWSAErrno(); - return -1; - } - } - - pio->read_details.pending = TRUE; - return 0; - } - else //io is already pending - return 0; - + if (socketio_acceptEx(pio) != 0) + return -1; + return 0; } - else { //type == SOCK_FD - return -1; + else if (rd) { + if (socketio_WSARecv(pio, NULL) != 0) + return -1; + return 0; + } + else { + //nothing to start for write + return 0; } } \ No newline at end of file diff --git a/contrib/win32/w32-posix-prototype/win32posix/win32posix/w32fd.c b/contrib/win32/w32-posix-prototype/win32posix/win32posix/w32fd.c index b837c0a..0cf5a49 100644 --- a/contrib/win32/w32-posix-prototype/win32posix/win32posix/w32fd.c +++ b/contrib/win32/w32-posix-prototype/win32posix/win32posix/w32fd.c @@ -70,9 +70,9 @@ BOOL w32_io_is_blocking(struct w32_io* pio) return (pio->fd_status_flags & O_NONBLOCK) ? FALSE : TRUE; } -BOOL w32_io_is_ioready(struct w32_io* pio, BOOL rd) { +BOOL w32_io_is_io_available(struct w32_io* pio, BOOL rd) { if ((pio->type == LISTEN_FD) || (pio->type == SOCK_FD)) { - return socketio_is_ioready(pio, rd); + return socketio_is_io_available(pio, rd); } else { //return fileio_is_ready(pio); @@ -81,13 +81,13 @@ BOOL w32_io_is_ioready(struct w32_io* pio, BOOL rd) { } -int w32_io_start_asyncio(struct w32_io* pio, BOOL rd) +int w32_io_on_select(struct w32_io* pio, BOOL rd) { if ((pio->type == LISTEN_FD) || (pio->type == SOCK_FD)) { - return socketio_start_asyncio(pio, rd); + return socketio_on_select(pio, rd); } else { - //return fileio_is_ready(pio); + //return fileio_start_io(pio); return -1; } @@ -214,30 +214,36 @@ int w32_select(int fds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, co return -1; } + if (!readfds && !writefds && !exceptfds) { + errno = EPERM; + return -1; + } + + //see if any io is ready for (int i = 0; i <= fds; i++) { - if FD_ISSET(i, readfds) { + if (readfds && FD_ISSET(i, readfds)) { if (fd_table.w32_ios[i] == NULL) { errno = EPERM; return -1; } in_ready_fds++; - if (w32_io_is_ioready(fd_table.w32_ios[i], TRUE)) { + if (w32_io_is_io_available(fd_table.w32_ios[i], TRUE)) { FD_SET(i, &read_ready_fds); out_ready_fds++; } } - if FD_ISSET(i, writefds) { + if (writefds && FD_ISSET(i, writefds)) { if (fd_table.w32_ios[i] == NULL) { errno = EPERM; return -1; } in_ready_fds++; - if (w32_io_is_ioready(fd_table.w32_ios[i], FALSE)) { + if (w32_io_is_io_available(fd_table.w32_ios[i], FALSE)) { FD_SET(i, &write_ready_fds); out_ready_fds++; } @@ -254,94 +260,68 @@ int w32_select(int fds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, co //if some fds are already ready, return if (out_ready_fds) { - *readfds = read_ready_fds; - *writefds = write_ready_fds; + if (readfds) + *readfds = read_ready_fds; + if (writefds) + *writefds = write_ready_fds; return out_ready_fds; } //start async io on selected fds for (int i = 0; i <= fds; i++) { - if FD_ISSET(i, readfds) { - if (w32_io_start_asyncio(fd_table.w32_ios[i], TRUE) == -1) + if (readfds && FD_ISSET(i, readfds)) { + if (w32_io_on_select(fd_table.w32_ios[i], TRUE) == -1) return -1; if (fd_table.w32_ios[i]->type == LISTEN_FD) { events[num_events++] = fd_table.w32_ios[i]->read_overlapped.hEvent; } } - if FD_ISSET(i, writefds) { - if (w32_io_start_asyncio(fd_table.w32_ios[i], FALSE) == -1) + if (writefds && FD_ISSET(i, writefds)) { + if (w32_io_on_select(fd_table.w32_ios[i], FALSE) == -1) return -1; } } - //wait for any io to complete - if (num_events) - { - DWORD ret = WaitForMultipleObjectsEx(num_events, events, FALSE, ((timeout->tv_sec) * 1000) + ((timeout->tv_usec) / 1000), TRUE); - if ((ret >= WAIT_OBJECT_0) && (ret <= WAIT_OBJECT_0 + num_events - 1)) { - //woken up by event signalled - } - else if (ret == WAIT_IO_COMPLETION) { - //woken up by APC from IO completion - } - else if (ret == WAIT_TIMEOUT) { - errno = ETIMEDOUT; + do { + //to-do cut down wait time on subsequent waits + if (0 != wait_for_any_event(events, num_events, ((timeout->tv_sec) * 1000) + ((timeout->tv_usec) / 1000))) { return -1; } - else { //some other error - errno = EOTHER; - return -1; - } - } - else - { - DWORD ret = SleepEx(((timeout->tv_sec) * 1000) + ((timeout->tv_usec) / 1000), TRUE); - if (ret == WAIT_IO_COMPLETION) { - //worken up by APC from IO completion - } - else if (ret == 0) { - //timed out - errno = ETIMEDOUT; - return -1; - } - else { //some other error - errno = EOTHER; - return -1; - } - } - //check on fd status - out_ready_fds = 0; - for (int i = 0; i <= fds; i++) { + //check on fd status + out_ready_fds = 0; + for (int i = 0; i <= fds; i++) { - if FD_ISSET(i, readfds) { - in_ready_fds++; - if (w32_io_is_ioready(fd_table.w32_ios[i], TRUE)) { - FD_SET(i, &read_ready_fds); - out_ready_fds++; + if (readfds && FD_ISSET(i, readfds)) { + in_ready_fds++; + if (w32_io_is_io_available(fd_table.w32_ios[i], TRUE)) { + FD_SET(i, &read_ready_fds); + out_ready_fds++; + } + } + + if (writefds && FD_ISSET(i, writefds)) { + in_ready_fds++; + if (w32_io_is_io_available(fd_table.w32_ios[i], FALSE)) { + FD_SET(i, &write_ready_fds); + out_ready_fds++; + } } } - if FD_ISSET(i, writefds) { - in_ready_fds++; - if (w32_io_is_ioready(fd_table.w32_ios[i], FALSE)) { - FD_SET(i, &write_ready_fds); - out_ready_fds++; - } - } + if (out_ready_fds) + break; - } + } while (1); - if (out_ready_fds) - { + if (readfds) *readfds = read_ready_fds; + if (writefds) *writefds = write_ready_fds; - return out_ready_fds; - } + + return out_ready_fds; - errno = EOTHER; - return -1; } diff --git a/contrib/win32/w32-posix-prototype/win32posix/win32posix/w32fd.h b/contrib/win32/w32-posix-prototype/win32posix/win32posix/w32fd.h index 1abbbd0..3601c80 100644 --- a/contrib/win32/w32-posix-prototype/win32posix/win32posix/w32fd.h +++ b/contrib/win32/w32-posix-prototype/win32posix/win32posix/w32fd.h @@ -51,12 +51,16 @@ struct w32_io { }; BOOL w32_io_is_blocking(struct w32_io*); -BOOL w32_io_is_ioready(struct w32_io* pio, BOOL rd); +BOOL w32_io_is_io_available(struct w32_io* pio, BOOL rd); +//signal +int wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds); + +//socket io int socketio_initialize(); int socketio_done(); -BOOL socketio_is_ioready(struct w32_io* pio, BOOL rd); -int socketio_start_asyncio(struct w32_io* pio, BOOL rd); +BOOL socketio_is_io_available(struct w32_io* pio, BOOL rd); +int socketio_on_select(struct w32_io* pio, BOOL rd); struct w32_io* socketio_socket(int domain, int type, int protocol); struct w32_io* socketio_accept(struct w32_io* pio, struct sockaddr* addr, int* addrlen); int socketio_setsockopt(struct w32_io* pio, int level, int optname, const char* optval, int optlen); diff --git a/contrib/win32/w32-posix-prototype/win32posix/win32posix/win32posix.vcxproj b/contrib/win32/w32-posix-prototype/win32posix/win32posix/win32posix.vcxproj index 3c6ce0e..f3184fe 100644 --- a/contrib/win32/w32-posix-prototype/win32posix/win32posix/win32posix.vcxproj +++ b/contrib/win32/w32-posix-prototype/win32posix/win32posix/win32posix.vcxproj @@ -74,6 +74,7 @@ + diff --git a/contrib/win32/w32-posix-prototype/win32posix/win32posix/win32posix.vcxproj.filters b/contrib/win32/w32-posix-prototype/win32posix/win32posix/win32posix.vcxproj.filters index 68fd9c8..2f47450 100644 --- a/contrib/win32/w32-posix-prototype/win32posix/win32posix/win32posix.vcxproj.filters +++ b/contrib/win32/w32-posix-prototype/win32posix/win32posix/win32posix.vcxproj.filters @@ -24,6 +24,9 @@ Source Files + + Source Files +