Windows: use new error handling API
This commit is contained in:
parent
97f9404ac0
commit
183c1de112
130
oio-win.c
130
oio-win.c
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user