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
+