libuv/oio-win.c

682 lines
17 KiB
C
Raw Normal View History

2011-03-30 03:03:56 +00:00
2011-04-07 09:02:54 +00:00
#include "oio.h"
2011-03-30 03:03:56 +00:00
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
/*
* Guids and typedefs for winsock extension functions
* Mingw32 doesn't have these :-(
*/
#ifndef WSAID_ACCEPTEX
# define WSAID_ACCEPTEX \
{0xb5367df1, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}};
# define WSAID_CONNECTEX \
{0x25a207b9, 0xddf3, 0x4660, {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}};
# define WSAID_GETACCEPTEXSOCKADDRS \
{0xb5367df2, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}};
# define WSAID_DISCONNECTEX \
{0x7fda2e11, 0x8630, 0x436f, {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}};
# define WSAID_TRANSMITFILE \
{0xb5367df0, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}};
typedef BOOL(*LPFN_ACCEPTEX)
(SOCKET sListenSocket,
SOCKET sAcceptSocket,
PVOID lpOutputBuffer,
DWORD dwReceiveDataLength,
DWORD dwLocalAddressLength,
DWORD dwRemoteAddressLength,
LPDWORD lpdwBytesReceived,
LPOVERLAPPED lpOverlapped);
typedef BOOL(*LPFN_CONNECTEX)
(SOCKET s,
const struct sockaddr *name,
int namelen,
PVOID lpSendBuffer,
DWORD dwSendDataLength,
LPDWORD lpdwBytesSent,
LPOVERLAPPED lpOverlapped);
typedef void(*LPFN_GETACCEPTEXSOCKADDRS)
(PVOID lpOutputBuffer,
DWORD dwReceiveDataLength,
DWORD dwLocalAddressLength,
DWORD dwRemoteAddressLength,
LPSOCKADDR *LocalSockaddr,
LPINT LocalSockaddrLength,
LPSOCKADDR *RemoteSockaddr,
LPINT RemoteSockaddrLength);
typedef BOOL(*LPFN_DISCONNECTEX)
(SOCKET hSocket,
LPOVERLAPPED lpOverlapped,
DWORD dwFlags,
DWORD reserved);
typedef BOOL(*LPFN_TRANSMITFILE)
(SOCKET hSocket,
HANDLE hFile,
DWORD nNumberOfBytesToWrite,
DWORD nNumberOfBytesPerSend,
LPOVERLAPPED lpOverlapped,
LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
DWORD dwFlags);
#endif
2011-03-30 05:19:17 +00:00
/*
2011-04-07 09:02:54 +00:00
* Private oio_handle flags
2011-04-04 23:41:53 +00:00
*/
2011-04-07 09:02:54 +00:00
#define OIO_HANDLE_CLOSING 0x01
#define OIO_HANDLE_CLOSED 0x03
2011-04-04 23:41:53 +00:00
/*
2011-04-07 09:02:54 +00:00
* Private oio_req flags.
2011-03-30 05:19:17 +00:00
*/
/* The request is currently queued. */
2011-04-07 09:02:54 +00:00
#define OIO_REQ_PENDING 0x01
2011-03-30 03:03:56 +00:00
/*
* Pointers to winsock extension functions that have to be retrieved dynamically
*/
LPFN_CONNECTEX pConnectEx;
LPFN_ACCEPTEX pAcceptEx;
LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs;
LPFN_DISCONNECTEX pDisconnectEx;
LPFN_TRANSMITFILE pTransmitFile;
/*
2011-04-04 23:41:53 +00:00
* Global I/O completion port
2011-03-30 03:03:56 +00:00
*/
2011-04-07 09:02:54 +00:00
HANDLE oio_iocp_;
2011-03-30 03:03:56 +00:00
2011-03-30 05:19:17 +00:00
2011-03-30 03:03:56 +00:00
/* Global error code */
2011-04-07 09:02:54 +00:00
int oio_errno_;
2011-03-30 03:03:56 +00:00
2011-03-30 05:19:17 +00:00
2011-04-04 23:41:53 +00:00
/* Reference count that keeps the event loop alive */
2011-04-07 09:02:54 +00:00
int oio_refs_ = 0;
2011-04-04 23:41:53 +00:00
2011-03-30 03:03:56 +00:00
/*
* Display an error message and abort the event loop.
*/
2011-04-07 09:02:54 +00:00
void oio_fatal_error(const int errorno, const char *syscall) {
2011-03-30 03:03:56 +00:00
char *buf = NULL;
const char *errmsg;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
if (buf) {
errmsg = buf;
} else {
errmsg = "Unknown error";
}
2011-04-04 23:41:53 +00:00
2011-03-30 03:03:56 +00:00
/* FormatMessage messages include a newline character already, */
/* so don't add another. */
if (syscall) {
fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
} else {
fprintf(stderr, "(%d) %s", errorno, errmsg);
}
if (buf) {
LocalFree(buf);
}
*((char*)NULL) = 0xff; /* Force debug break */
abort();
}
/*
* Retrieves the pointer to a winsock extension function.
*/
2011-04-07 09:02:54 +00:00
void oio_get_extension_function(SOCKET socket, GUID guid, void **target) {
2011-03-30 03:03:56 +00:00
DWORD result, bytes;
result = WSAIoctl(socket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid,
sizeof(guid),
(void*)target,
sizeof(*target),
&bytes,
NULL,
NULL);
if (result == SOCKET_ERROR) {
*target = NULL;
2011-04-07 09:02:54 +00:00
oio_fatal_error(WSAGetLastError(), "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)");
2011-03-30 03:03:56 +00:00
}
}
2011-04-07 09:02:54 +00:00
void oio_init() {
2011-03-30 03:03:56 +00:00
const GUID wsaid_connectex = WSAID_CONNECTEX;
2011-03-30 06:57:46 +00:00
const GUID wsaid_acceptex = WSAID_ACCEPTEX;
2011-03-30 03:03:56 +00:00
const GUID wsaid_getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
const GUID wsaid_disconnectex = WSAID_DISCONNECTEX;
const GUID wsaid_transmitfile = WSAID_TRANSMITFILE;
WSADATA wsa_data;
int errorno;
SOCKET dummy;
/* Initialize winsock */
errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (errorno != 0) {
2011-04-07 09:02:54 +00:00
oio_fatal_error(errorno, "WSAStartup");
2011-03-30 03:03:56 +00:00
}
/* Retrieve the needed winsock extension function pointers. */
dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (dummy == INVALID_SOCKET) {
2011-04-07 09:02:54 +00:00
oio_fatal_error(WSAGetLastError(), "socket");
2011-03-30 03:03:56 +00:00
}
2011-04-07 09:02:54 +00:00
oio_get_extension_function(dummy, wsaid_connectex, (void**)&pConnectEx );
oio_get_extension_function(dummy, wsaid_acceptex, (void**)&pAcceptEx );
oio_get_extension_function(dummy, wsaid_getacceptexsockaddrs, (void**)&pGetAcceptExSockAddrs);
oio_get_extension_function(dummy, wsaid_disconnectex, (void**)&pDisconnectEx );
oio_get_extension_function(dummy, wsaid_transmitfile, (void**)&pTransmitFile );
2011-03-30 03:03:56 +00:00
if (closesocket(dummy) == SOCKET_ERROR) {
2011-04-07 09:02:54 +00:00
oio_fatal_error(WSAGetLastError(), "closesocket");
2011-03-30 03:03:56 +00:00
}
/* Create an I/O completion port */
2011-04-07 09:02:54 +00:00
oio_iocp_ = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
if (oio_iocp_ == NULL) {
oio_fatal_error(GetLastError(), "CreateIoCompletionPort");
2011-03-30 03:03:56 +00:00
}
}
2011-04-07 09:02:54 +00:00
void oio_req_init(oio_req* req, oio_handle* handle, void *cb) {
req->type = OIO_UNKNOWN_REQ;
2011-04-07 02:51:59 +00:00
req->flags = 0;
req->handle = handle;
req->cb = cb;
}
2011-04-07 09:02:54 +00:00
oio_req* oio_overlapped_to_req(OVERLAPPED* overlapped) {
return CONTAINING_RECORD(overlapped, oio_req, overlapped);
2011-03-30 03:03:56 +00:00
}
2011-04-07 09:02:54 +00:00
int oio_set_socket_options(SOCKET socket) {
2011-03-30 05:19:17 +00:00
DWORD yes = 1;
2011-03-30 03:03:56 +00:00
2011-03-30 05:19:17 +00:00
/* Set the SO_REUSEADDR option on the socket */
/* If it fails, soit. */
2011-04-07 02:51:59 +00:00
setsockopt(socket,
2011-04-04 23:41:53 +00:00
SOL_SOCKET,
SO_REUSEADDR,
(char*)&yes,
2011-03-30 05:19:17 +00:00
sizeof(int));
2011-03-30 03:03:56 +00:00
2011-03-30 05:19:17 +00:00
/* Make the socket non-inheritable */
2011-04-07 02:51:59 +00:00
if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
2011-04-07 09:02:54 +00:00
oio_errno_ = GetLastError();
2011-03-30 05:19:17 +00:00
return -1;
2011-03-30 03:03:56 +00:00
}
2011-03-30 05:19:17 +00:00
/* Associate it with the I/O completion port. */
2011-04-07 09:02:54 +00:00
/* Use oio_handle pointer as completion key. */
2011-04-07 02:51:59 +00:00
if (CreateIoCompletionPort((HANDLE)socket,
2011-04-07 09:02:54 +00:00
oio_iocp_,
2011-04-07 02:51:59 +00:00
(ULONG_PTR)socket,
2011-03-30 05:19:17 +00:00
0) == NULL) {
2011-04-07 09:02:54 +00:00
oio_errno_ = GetLastError();
2011-03-30 05:19:17 +00:00
return -1;
2011-03-30 03:03:56 +00:00
}
2011-03-30 05:19:17 +00:00
2011-03-30 03:03:56 +00:00
return 0;
}
2011-03-30 05:19:17 +00:00
2011-04-07 09:02:54 +00:00
int oio_tcp_handle_init(oio_handle *handle, oio_close_cb close_cb, void* data) {
2011-03-30 03:03:56 +00:00
handle->close_cb = close_cb;
handle->data = data;
2011-04-07 09:02:54 +00:00
handle->type = OIO_TCP;
2011-04-07 02:51:59 +00:00
handle->flags = 0;
handle->reqs_pending = 0;
handle->error = 0;
handle->accept_data = NULL;
2011-03-30 03:03:56 +00:00
2011-04-07 02:51:59 +00:00
handle->socket = socket(AF_INET, SOCK_STREAM, 0);
if (handle->socket == INVALID_SOCKET) {
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAGetLastError();
2011-04-07 02:51:59 +00:00
return -1;
}
2011-04-07 09:02:54 +00:00
if (oio_set_socket_options(handle->socket) != 0) {
2011-04-07 02:51:59 +00:00
closesocket(handle->socket);
return -1;
2011-03-30 03:03:56 +00:00
}
2011-04-07 09:02:54 +00:00
oio_refs_++;
2011-04-07 02:51:59 +00:00
return 0;
}
2011-04-07 09:02:54 +00:00
int oio_tcp_handle_accept(oio_handle* server, oio_handle* client, oio_close_cb close_cb, void* data) {
2011-04-07 02:51:59 +00:00
if (!server->accept_data ||
server->accept_data->socket == INVALID_SOCKET) {
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAENOTCONN;
2011-04-07 02:51:59 +00:00
return -1;
2011-03-30 03:03:56 +00:00
}
2011-04-04 23:41:53 +00:00
2011-04-07 02:51:59 +00:00
client->close_cb = close_cb;
client->data = data;
2011-04-07 09:02:54 +00:00
client->type = OIO_TCP;
2011-04-07 02:51:59 +00:00
client->socket = server->accept_data->socket;
client->flags = 0;
client->reqs_pending = 0;
client->error = 0;
client->accept_data = NULL;
server->accept_data->socket = INVALID_SOCKET;
2011-04-07 09:02:54 +00:00
oio_refs_++;
2011-04-04 23:41:53 +00:00
2011-04-07 02:51:59 +00:00
return 0;
2011-03-30 03:03:56 +00:00
}
2011-04-07 09:02:54 +00:00
int oio_close_error(oio_handle* handle, oio_err e) {
oio_req *req;
2011-04-07 09:02:54 +00:00
if (handle->flags & OIO_HANDLE_CLOSING)
2011-04-04 23:41:53 +00:00
return 0;
2011-04-07 02:51:59 +00:00
handle->error = e;
2011-04-04 23:41:53 +00:00
switch (handle->type) {
2011-04-07 09:02:54 +00:00
case OIO_TCP:
2011-04-07 02:51:59 +00:00
closesocket(handle->socket);
if (handle->reqs_pending == 0) {
/* If there are no operations queued for this socket, queue one */
2011-04-07 09:02:54 +00:00
/* manually, so oio_poll will call close_cb. */
req = (oio_req*)malloc(sizeof(*req));
req->handle = handle;
2011-04-07 09:02:54 +00:00
req->type = OIO_CLOSE;
2011-04-07 02:51:59 +00:00
req->flags = 0;
2011-04-07 09:02:54 +00:00
if (!PostQueuedCompletionStatus(oio_iocp_, 0, (ULONG_PTR)handle, &req->overlapped))
oio_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
req->flags |= OIO_REQ_PENDING;
2011-04-07 02:51:59 +00:00
handle->reqs_pending++;
}
2011-04-07 09:02:54 +00:00
/* After all packets to come out, oio_poll will call close_cb. */
handle->flags |= OIO_HANDLE_CLOSING;
return 0;
default:
/* Not supported */
assert(0);
return -1;
}
}
2011-04-07 09:02:54 +00:00
int oio_close(oio_handle* handle) {
return oio_close_error(handle, 0);
}
2011-04-07 09:02:54 +00:00
struct sockaddr_in oio_ip4_addr(char *ip, int port) {
2011-03-30 05:19:17 +00:00
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);
return addr;
}
2011-04-07 09:02:54 +00:00
int oio_bind(oio_handle* handle, struct sockaddr* addr) {
2011-03-30 03:03:56 +00:00
int addrsize;
if (addr->sa_family == AF_INET) {
addrsize = sizeof(struct sockaddr_in);
} else if (addr->sa_family == AF_INET6) {
addrsize = sizeof(struct sockaddr_in6);
} else {
assert(0);
return -1;
}
2011-04-07 02:51:59 +00:00
if (bind(handle->socket, addr, addrsize) == SOCKET_ERROR) {
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAGetLastError();
2011-03-30 03:03:56 +00:00
return -1;
}
return 0;
}
2011-04-07 09:02:54 +00:00
void oio_queue_accept(oio_handle *handle) {
oio_accept_data* data;
2011-04-04 23:41:53 +00:00
BOOL success;
2011-03-30 05:19:17 +00:00
DWORD bytes;
2011-04-07 02:51:59 +00:00
data = handle->accept_data;
assert(data != NULL);
data->socket = socket(AF_INET, SOCK_STREAM, 0);
if (data->socket == INVALID_SOCKET) {
2011-04-07 09:02:54 +00:00
oio_close_error(handle, WSAGetLastError());
return;
2011-03-30 05:19:17 +00:00
}
2011-04-07 09:02:54 +00:00
if (oio_set_socket_options(data->socket) != 0) {
2011-04-07 02:51:59 +00:00
closesocket(data->socket);
2011-04-07 09:02:54 +00:00
oio_close_error(handle, oio_errno_);
2011-04-07 02:51:59 +00:00
return;
}
2011-03-30 05:19:17 +00:00
2011-04-07 09:02:54 +00:00
/* Prepare the oio_req and OVERLAPPED structures. */
assert(!(data->req.flags & OIO_REQ_PENDING));
data->req.flags |= OIO_REQ_PENDING;
2011-04-07 02:51:59 +00:00
memset(&data->req.overlapped, 0, sizeof(data->req.overlapped));
success = pAcceptEx(handle->socket,
data->socket,
(void*)&data->buffer,
2011-04-04 23:41:53 +00:00
0,
sizeof(struct sockaddr_storage),
sizeof(struct sockaddr_storage),
&bytes,
2011-04-07 02:51:59 +00:00
&data->req.overlapped);
2011-04-04 23:41:53 +00:00
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAGetLastError();
2011-04-04 23:41:53 +00:00
/* destroy the preallocated client handle */
2011-04-07 02:51:59 +00:00
closesocket(data->socket);
2011-04-04 23:41:53 +00:00
/* destroy ourselves */
2011-04-07 09:02:54 +00:00
oio_close_error(handle, oio_errno_);
2011-04-04 23:41:53 +00:00
return;
2011-03-30 05:19:17 +00:00
}
2011-04-07 02:51:59 +00:00
handle->reqs_pending++;
2011-04-07 09:02:54 +00:00
data->req.flags |= OIO_REQ_PENDING;
2011-03-30 05:19:17 +00:00
}
2011-04-07 09:02:54 +00:00
int oio_listen(oio_handle* handle, int backlog, oio_accept_cb cb) {
oio_accept_data *data;
2011-03-30 05:19:17 +00:00
2011-04-07 02:51:59 +00:00
if (handle->accept_data != NULL) {
/* Already listening. */
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAEALREADY;
2011-03-30 05:19:17 +00:00
return -1;
2011-04-07 02:51:59 +00:00
}
2011-03-30 05:19:17 +00:00
2011-04-07 09:02:54 +00:00
data = (oio_accept_data*)malloc(sizeof(*data));
2011-04-07 02:51:59 +00:00
if (!data) {
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAENOBUFS;
2011-04-07 02:51:59 +00:00
return -1;
}
data->socket = INVALID_SOCKET;
2011-04-07 09:02:54 +00:00
oio_req_init(&data->req, handle, (void*)cb);
data->req.type = OIO_ACCEPT;
2011-04-07 02:51:59 +00:00
if (listen(handle->socket, backlog) == SOCKET_ERROR) {
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAGetLastError();
2011-04-07 02:51:59 +00:00
free(data);
return -1;
}
2011-04-04 23:41:53 +00:00
2011-04-07 02:51:59 +00:00
handle->accept_data = data;
2011-04-07 09:02:54 +00:00
oio_queue_accept(handle);
2011-03-30 06:57:46 +00:00
return 0;
}
2011-04-07 09:02:54 +00:00
int oio_connect(oio_req* req, struct sockaddr* addr) {
2011-04-04 23:41:53 +00:00
int addrsize;
BOOL success;
2011-03-30 20:36:41 +00:00
DWORD bytes;
2011-04-07 09:02:54 +00:00
oio_handle* handle = req->handle;
2011-03-30 20:36:41 +00:00
2011-04-07 09:02:54 +00:00
assert(!(req->flags & OIO_REQ_PENDING));
2011-03-30 20:36:41 +00:00
if (addr->sa_family == AF_INET) {
addrsize = sizeof(struct sockaddr_in);
} else if (addr->sa_family == AF_INET6) {
addrsize = sizeof(struct sockaddr_in6);
} else {
assert(0);
return -1;
}
2011-04-07 02:51:59 +00:00
memset(&req->overlapped, 0, sizeof(req->overlapped));
2011-04-07 09:02:54 +00:00
req->type = OIO_CONNECT;
2011-03-30 20:36:41 +00:00
2011-04-07 02:51:59 +00:00
success = pConnectEx(handle->socket,
2011-04-04 23:41:53 +00:00
addr,
addrsize,
NULL,
0,
&bytes,
2011-04-07 02:51:59 +00:00
&req->overlapped);
2011-03-30 20:36:41 +00:00
2011-04-04 23:41:53 +00:00
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAGetLastError();
2011-03-30 20:36:41 +00:00
return -1;
}
2011-04-07 09:02:54 +00:00
req->flags |= OIO_REQ_PENDING;
2011-04-07 02:51:59 +00:00
handle->reqs_pending++;
2011-03-30 20:36:41 +00:00
return 0;
}
2011-04-07 09:02:54 +00:00
int oio_write(oio_req *req, oio_buf* bufs, int bufcnt) {
2011-03-30 06:57:46 +00:00
int result;
DWORD bytes;
2011-04-07 09:02:54 +00:00
oio_handle* handle = req->handle;
2011-03-30 06:57:46 +00:00
2011-04-07 09:02:54 +00:00
assert(!(req->flags & OIO_REQ_PENDING));
2011-04-07 02:51:59 +00:00
memset(&req->overlapped, 0, sizeof(req->overlapped));
2011-04-07 09:02:54 +00:00
req->type = OIO_WRITE;
2011-03-30 06:57:46 +00:00
2011-04-07 02:51:59 +00:00
result = WSASend(handle->socket,
2011-04-04 23:41:53 +00:00
(WSABUF*)bufs,
bufcnt,
&bytes,
0,
2011-04-07 02:51:59 +00:00
&req->overlapped,
2011-03-30 06:57:46 +00:00
NULL);
if (result != 0 && WSAGetLastError() != ERROR_IO_PENDING) {
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAGetLastError();
2011-03-30 06:57:46 +00:00
return -1;
}
2011-04-07 09:02:54 +00:00
req->flags |= OIO_REQ_PENDING;
2011-04-07 02:51:59 +00:00
handle->reqs_pending++;
2011-03-30 06:57:46 +00:00
return 0;
}
2011-04-04 23:41:53 +00:00
2011-04-07 09:02:54 +00:00
int oio_read(oio_req *req, oio_buf* bufs, int bufcnt) {
2011-03-30 06:57:46 +00:00
int result;
DWORD bytes, flags;
2011-04-07 09:02:54 +00:00
oio_handle* handle = req->handle;
2011-03-30 06:57:46 +00:00
2011-04-07 09:02:54 +00:00
assert(!(req->flags & OIO_REQ_PENDING));
2011-04-07 02:51:59 +00:00
memset(&req->overlapped, 0, sizeof(req->overlapped));
2011-04-07 09:02:54 +00:00
req->type = OIO_READ;
2011-04-04 23:41:53 +00:00
2011-03-30 06:57:46 +00:00
flags = 0;
2011-04-07 02:51:59 +00:00
result = WSARecv(handle->socket,
2011-04-04 23:41:53 +00:00
(WSABUF*)bufs,
bufcnt,
&bytes,
&flags,
2011-04-07 02:51:59 +00:00
&req->overlapped,
2011-03-30 06:57:46 +00:00
NULL);
if (result != 0 && WSAGetLastError() != ERROR_IO_PENDING) {
2011-04-07 09:02:54 +00:00
oio_errno_ = WSAGetLastError();
2011-03-30 06:57:46 +00:00
return -1;
}
2011-04-07 09:02:54 +00:00
req->flags |= OIO_REQ_PENDING;
2011-04-07 02:51:59 +00:00
handle->reqs_pending++;
2011-03-30 06:57:46 +00:00
return 0;
2011-03-30 06:57:46 +00:00
}
2011-04-07 09:02:54 +00:00
int oio_write2(oio_req *req, const char* msg) {
oio_buf buf;
oio_handle* handle = req->handle;
2011-03-30 06:57:46 +00:00
buf.base = (char*)msg;
buf.len = strlen(msg);
2011-04-04 23:41:53 +00:00
2011-04-07 09:02:54 +00:00
return oio_write(req, &buf, 1);
2011-03-30 05:19:17 +00:00
}
2011-04-07 09:02:54 +00:00
oio_err oio_last_error() {
return oio_errno_;
2011-04-04 23:41:53 +00:00
}
2011-04-07 09:02:54 +00:00
void oio_poll() {
2011-03-30 05:19:17 +00:00
BOOL success;
DWORD bytes;
ULONG_PTR key;
OVERLAPPED* overlapped;
2011-04-07 09:02:54 +00:00
oio_req* req;
oio_handle* handle;
oio_accept_data *data;
2011-04-04 23:41:53 +00:00
2011-04-07 09:02:54 +00:00
success = GetQueuedCompletionStatus(oio_iocp_,
2011-03-30 05:19:17 +00:00
&bytes,
&key,
&overlapped,
INFINITE);
if (!success && !overlapped)
2011-04-07 09:02:54 +00:00
oio_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
2011-03-30 05:19:17 +00:00
2011-04-07 09:02:54 +00:00
req = oio_overlapped_to_req(overlapped);
2011-04-04 23:41:53 +00:00
handle = req->handle;
2011-03-30 05:19:17 +00:00
/* Mark the request non-pending */
2011-04-07 09:02:54 +00:00
req->flags &= ~OIO_REQ_PENDING;
2011-04-07 02:51:59 +00:00
handle->reqs_pending--;
/* If the related socket got closed in the meantime, disregard this */
2011-04-07 02:51:59 +00:00
/* result. If this is the last request pending, call the handle's close callback. */
2011-04-07 09:02:54 +00:00
if (handle->flags & OIO_HANDLE_CLOSING) {
2011-04-07 02:51:59 +00:00
if (handle->reqs_pending == 0) {
2011-04-07 09:02:54 +00:00
handle->flags |= OIO_HANDLE_CLOSED;
2011-04-07 02:51:59 +00:00
if (handle->accept_data) {
if (handle->accept_data) {
if (handle->accept_data->socket) {
closesocket(handle->accept_data->socket);
}
free(handle->accept_data);
handle->accept_data = NULL;
}
}
if (handle->close_cb) {
handle->close_cb(handle, handle->error);
}
2011-04-07 09:02:54 +00:00
oio_refs_--;
2011-04-04 23:41:53 +00:00
}
return;
}
2011-03-30 05:19:17 +00:00
switch (req->type) {
2011-04-07 09:02:54 +00:00
case OIO_WRITE:
2011-04-07 02:51:59 +00:00
success = GetOverlappedResult(handle->handle, overlapped, &bytes, FALSE);
if (!success) {
2011-04-07 09:02:54 +00:00
oio_close_error(handle, GetLastError());
} else if (req->cb) {
2011-04-07 09:02:54 +00:00
((oio_write_cb)req->cb)(req);
2011-04-04 23:41:53 +00:00
}
2011-03-30 06:57:46 +00:00
return;
2011-04-07 09:02:54 +00:00
case OIO_READ:
2011-04-07 02:51:59 +00:00
success = GetOverlappedResult(handle->handle, overlapped, &bytes, FALSE);
if (!success) {
2011-04-07 09:02:54 +00:00
oio_close_error(handle, GetLastError());
} else if (req->cb) {
2011-04-07 09:02:54 +00:00
((oio_read_cb)req->cb)(req, bytes);
2011-03-30 06:57:46 +00:00
}
break;
2011-03-30 05:19:17 +00:00
2011-04-07 09:02:54 +00:00
case OIO_ACCEPT:
2011-04-07 02:51:59 +00:00
data = handle->accept_data;
assert(data != NULL);
assert(data->socket != INVALID_SOCKET);
success = GetOverlappedResult(handle->handle, overlapped, &bytes, FALSE);
if (success && req->cb) {
2011-04-07 09:02:54 +00:00
((oio_accept_cb)req->cb)(handle);
2011-04-07 02:51:59 +00:00
}
2011-04-07 09:02:54 +00:00
/* accept_cb should call oio_accept_handle which sets data->socket */
2011-04-07 02:51:59 +00:00
/* to INVALID_SOCKET. */
/* Just ignore failed accept if the listen socket is still healthy. */
if (data->socket != INVALID_SOCKET) {
closesocket(handle->socket);
data->socket = INVALID_SOCKET;
2011-03-30 05:19:17 +00:00
}
/* Queue another accept */
2011-04-07 09:02:54 +00:00
oio_queue_accept(handle);
2011-03-30 05:19:17 +00:00
return;
2011-03-30 20:36:41 +00:00
2011-04-07 09:02:54 +00:00
case OIO_CONNECT:
2011-03-30 20:36:41 +00:00
if (req->cb) {
2011-04-07 02:51:59 +00:00
success = GetOverlappedResult(handle->handle, overlapped, &bytes, FALSE);
2011-03-30 20:36:41 +00:00
if (success) {
2011-04-07 09:02:54 +00:00
((oio_connect_cb)req->cb)(req, 0);
2011-03-30 20:36:41 +00:00
} else {
2011-04-07 09:02:54 +00:00
((oio_connect_cb)req->cb)(req, GetLastError());
2011-03-30 20:36:41 +00:00
}
}
return;
2011-04-07 09:02:54 +00:00
case OIO_CLOSE:
/* Should never get here */
assert(0);
2011-03-30 05:19:17 +00:00
}
}
2011-04-07 09:02:54 +00:00
int oio_run() {
while (oio_refs_ > 0) {
oio_poll();
2011-03-30 05:19:17 +00:00
}
2011-04-07 09:02:54 +00:00
assert(oio_refs_ == 0);
2011-03-30 05:19:17 +00:00
return 0;
}