Windows: use new error handling API

This commit is contained in:
Bert Belder 2011-04-20 22:26:28 +02:00
parent 97f9404ac0
commit 183c1de112

130
oio-win.c
View File

@ -28,7 +28,6 @@
#include "oio.h"
#include "tree.h"
/*
* Guids and typedefs for winsock extension functions
* Mingw32 doesn't have these :-(
@ -99,7 +98,6 @@
DWORD dwFlags);
#endif
/*
* MinGW is missing this too
*/
@ -107,6 +105,13 @@
# define SO_UPDATE_CONNECT_CONTEXT 0x7010
#endif
/*
* Described in MSDN but apparently not defined in the SDK.
*/
#ifndef ERROR_SUCCESS
# define ERROR_SUCCESS 0
#endif
/*
* Pointers to winsock extension functions to be retrieved dynamically
@ -166,7 +171,8 @@ static HANDLE oio_iocp_;
/* Global error code */
static int oio_errno_;
static const oio_err oio_ok_ = { OIO_OK, ERROR_SUCCESS };
static oio_err oio_last_error_ = { OIO_OK, ERROR_SUCCESS };
/* Reference count that keeps the event loop alive */
@ -211,6 +217,38 @@ static void oio_fatal_error(const int errorno, const char *syscall) {
}
oio_err oio_last_error() {
return oio_last_error_;
}
static oio_err_code oio_translate_sys_error(int sys_errno) {
switch (sys_errno) {
case ERROR_SUCCESS: return OIO_OK;
case ERROR_TOO_MANY_OPEN_FILES: return OIO_EMFILE;
case WSAEMFILE: return OIO_EMFILE;
case WSAEINVAL: return OIO_EINVAL;
case WSAEALREADY: return OIO_EALREADY;
case ERROR_OUTOFMEMORY: return OIO_ENOMEM;
default: return OIO_UNKNOWN;
}
}
static oio_err oio_new_sys_error(int sys_errno) {
oio_err e;
e.code = oio_translate_sys_error(sys_errno);
e.sys_errno_ = sys_errno;
return e;
}
static void oio_set_sys_error(int sys_errno) {
oio_last_error_.code = oio_translate_sys_error(sys_errno);
oio_last_error_.sys_errno_ = sys_errno;
}
/*
* Retrieves the pointer to a winsock extension function.
*/
@ -324,7 +362,7 @@ static int oio_set_socket_options(SOCKET socket) {
/* Make the socket non-inheritable */
if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
oio_errno_ = GetLastError();
oio_set_sys_error(GetLastError());
return -1;
}
@ -334,7 +372,7 @@ static int oio_set_socket_options(SOCKET socket) {
oio_iocp_,
(ULONG_PTR)socket,
0) == NULL) {
oio_errno_ = GetLastError();
oio_set_sys_error(GetLastError());
return -1;
}
@ -349,13 +387,13 @@ int oio_tcp_init(oio_handle *handle, oio_close_cb close_cb,
handle->type = OIO_TCP;
handle->flags = 0;
handle->reqs_pending = 0;
handle->error = 0;
handle->error = oio_ok_;
handle->accept_reqs = NULL;
handle->accepted_socket = INVALID_SOCKET;
handle->socket = socket(AF_INET, SOCK_STREAM, 0);
if (handle->socket == INVALID_SOCKET) {
oio_errno_ = WSAGetLastError();
oio_set_sys_error(WSAGetLastError());
return -1;
}
@ -373,7 +411,7 @@ int oio_tcp_init(oio_handle *handle, oio_close_cb close_cb,
int oio_accept(oio_handle* server, oio_handle* client,
oio_close_cb close_cb, void* data) {
if (!server->accepted_socket == INVALID_SOCKET) {
oio_errno_ = WSAENOTCONN;
oio_set_sys_error(WSAENOTCONN);
return -1;
}
@ -383,7 +421,7 @@ int oio_accept(oio_handle* server, oio_handle* client,
client->socket = server->accepted_socket;
client->flags = 0;
client->reqs_pending = 0;
client->error = 0;
client->error = oio_ok_;
client->accepted_socket = INVALID_SOCKET;
client->accept_reqs = NULL;
@ -397,9 +435,9 @@ int oio_accept(oio_handle* server, oio_handle* client,
static int oio_close_error(oio_handle* handle, oio_err e) {
oio_req *req;
if (handle->flags & OIO_HANDLE_CLOSING)
if (handle->flags & OIO_HANDLE_CLOSING) {
return 0;
}
handle->error = e;
@ -436,7 +474,7 @@ static int oio_close_error(oio_handle* handle, oio_err e) {
int oio_close(oio_handle* handle) {
return oio_close_error(handle, 0);
return oio_close_error(handle, oio_ok_);
}
@ -464,7 +502,7 @@ int oio_bind(oio_handle* handle, struct sockaddr* addr) {
}
if (bind(handle->socket, addr, addrsize) == SOCKET_ERROR) {
oio_errno_ = WSAGetLastError();
oio_set_sys_error(WSAGetLastError());
return -1;
}
@ -480,13 +518,13 @@ static void oio_queue_accept(oio_accept_req *areq, oio_handle *handle) {
areq->socket = socket(AF_INET, SOCK_STREAM, 0);
if (areq->socket == INVALID_SOCKET) {
oio_close_error(handle, WSAGetLastError());
oio_close_error(handle, oio_new_sys_error(WSAGetLastError()));
return;
}
if (oio_set_socket_options(areq->socket) != 0) {
closesocket(areq->socket);
oio_close_error(handle, oio_errno_);
oio_close_error(handle, oio_last_error_);
return;
}
@ -505,11 +543,11 @@ static void oio_queue_accept(oio_accept_req *areq, oio_handle *handle) {
&areq->req.overlapped);
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
oio_errno_ = WSAGetLastError();
oio_set_sys_error(WSAGetLastError());
/* destroy the preallocated client handle */
closesocket(areq->socket);
/* destroy ourselves */
oio_close_error(handle, oio_errno_);
oio_close_error(handle, oio_last_error_);
return;
}
@ -527,18 +565,18 @@ int oio_listen(oio_handle* handle, int backlog, oio_accept_cb cb) {
if (handle->accept_reqs != NULL) {
/* Already listening. */
oio_errno_ = WSAEALREADY;
oio_set_sys_error(WSAEALREADY);
return -1;
}
reqs = (oio_accept_req*)malloc(sizeof(oio_accept_req) * backlog);
if (!reqs) {
oio_errno_ = WSAENOBUFS;
oio_set_sys_error(ERROR_OUTOFMEMORY);
return -1;
}
if (listen(handle->socket, backlog) == SOCKET_ERROR) {
oio_errno_ = WSAGetLastError();
oio_set_sys_error(WSAGetLastError());
free(reqs);
return -1;
}
@ -590,7 +628,7 @@ int oio_connect(oio_req* req, struct sockaddr* addr) {
&req->overlapped);
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
oio_errno_ = WSAGetLastError();
oio_set_sys_error(WSAGetLastError());
return -1;
}
@ -619,7 +657,7 @@ int oio_write(oio_req *req, oio_buf* bufs, int bufcnt) {
&req->overlapped,
NULL);
if (result != 0 && WSAGetLastError() != ERROR_IO_PENDING) {
oio_errno_ = WSAGetLastError();
oio_set_sys_error(WSAGetLastError());
return -1;
}
@ -649,7 +687,7 @@ int oio_read(oio_req *req, oio_buf* bufs, int bufcnt) {
&req->overlapped,
NULL);
if (result != 0 && WSAGetLastError() != ERROR_IO_PENDING) {
oio_errno_ = WSAGetLastError();
oio_set_sys_error(WSAGetLastError());
return -1;
}
@ -660,11 +698,6 @@ int oio_read(oio_req *req, oio_buf* bufs, int bufcnt) {
}
oio_err oio_last_error() {
return oio_errno_;
}
static int oio_timer_compare(oio_req *a, oio_req* b) {
if (a->due < b->due)
return -1;
@ -688,7 +721,7 @@ int oio_timeout(oio_req* req, int64_t timeout) {
req->due = oio_now_ + timeout;
if (RB_INSERT(oio_timer_s, &oio_timers_, req) != NULL) {
oio_errno_ = EINVAL;
oio_set_sys_error(ERROR_INVALID_DATA);
return -1;
}
@ -759,7 +792,7 @@ static void oio_poll() {
RB_REMOVE(oio_timer_s, &oio_timers_, req);
req->flags &= ~OIO_REQ_PENDING;
oio_refs_--;
((oio_timer_cb)req->cb)(req, req->due - oio_now_);
((oio_timer_cb)req->cb)(req, req->due - oio_now_, 0);
}
/* Quit if there were no io requests dequeued. */
@ -790,7 +823,8 @@ static void oio_poll() {
free(handle->accept_reqs);
}
if (handle->close_cb) {
handle->close_cb(handle, handle->error);
oio_last_error_ = handle->error;
handle->close_cb(handle, handle->error.code == OIO_OK ? 0 : 1);
}
oio_refs_--;
}
@ -801,18 +835,22 @@ static void oio_poll() {
case OIO_WRITE:
success = GetOverlappedResult(handle->handle, overlapped, &bytes, FALSE);
if (!success) {
oio_close_error(handle, GetLastError());
} else if (req->cb) {
((oio_write_cb)req->cb)(req);
oio_set_sys_error(GetLastError());
oio_close_error(handle, oio_last_error_);
}
if (req->cb) {
((oio_write_cb)req->cb)(req, success ? 0 : -1);
}
return;
case OIO_READ:
success = GetOverlappedResult(handle->handle, overlapped, &bytes, FALSE);
if (!success) {
oio_close_error(handle, GetLastError());
} else if (req->cb) {
((oio_read_cb)req->cb)(req, bytes);
oio_set_sys_error(GetLastError());
oio_close_error(handle, oio_last_error_);
}
if (req->cb) {
((oio_read_cb)req->cb)(req, bytes, success ? 0 : -1);
}
return;
@ -826,21 +864,19 @@ static void oio_poll() {
success = GetOverlappedResult(handle->handle, overlapped, &bytes, FALSE);
if (success) {
if (setsockopt(handle->accepted_socket,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
(char*)&handle->socket,
sizeof(handle->socket)) == 0) {
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
(char*)&handle->socket,
sizeof(handle->socket)) == 0) {
if (req->cb) {
((oio_accept_cb)req->cb)(handle);
}
} else {
oio_fatal_error(WSAGetLastError(), "setsockopt");
}
}
/* accept_cb should call oio_accept_handle which sets data->socket */
/* to INVALID_SOCKET. */
/* Just ignore failed accept if the listen socket is still healthy. */
/* Errorneous accept is ignored if the listen socket is still healthy. */
if (handle->accepted_socket != INVALID_SOCKET) {
closesocket(handle->accepted_socket);
handle->accepted_socket = INVALID_SOCKET;
@ -864,10 +900,12 @@ static void oio_poll() {
0) == 0) {
((oio_connect_cb)req->cb)(req, 0);
} else {
((oio_connect_cb)req->cb)(req, WSAGetLastError());
oio_set_sys_error(WSAGetLastError());
((oio_connect_cb)req->cb)(req, -1);
}
} else {
((oio_connect_cb)req->cb)(req, GetLastError());
oio_set_sys_error(WSAGetLastError());
((oio_connect_cb)req->cb)(req, -1);
}
}
return;