1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-16 00:00:07 +01:00

Use WSAWaitForMultipleEvents in libwebsocket_service() on Windows

Using this function instead of poll() alows us to cancel
the function call by signalign an event object.
This commit is contained in:
Patrick Gansterer 2014-03-28 17:46:11 +01:00
parent 566cd7c2c6
commit 2970d38a7f
3 changed files with 94 additions and 6 deletions

View file

@ -187,6 +187,7 @@ insert_wsi_socket_into_fds(struct libwebsocket_context *context,
context->fds[context->fds_count++].revents = 0;
#ifdef _WIN32
context->events[context->fds_count] = WSACreateEvent();
WSAEventSelect(wsi->sock, context->events[context->fds_count], LWS_POLLIN);
#endif
/* external POLL support via protocol 0 */
@ -1481,8 +1482,15 @@ LWS_VISIBLE int
libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
{
int n;
#ifdef _WIN32
int i;
DWORD ev;
WSANETWORKEVENTS networkevents;
struct pollfd *pfd;
#else
int m;
char buf;
#endif
/* stay dead once we are dead */
@ -1495,6 +1503,53 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
#endif /* LWS_USE_LIBEV */
context->service_tid = context->protocols[0].callback(context, NULL,
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
#ifdef _WIN32
for (i = 0; i < context->fds_count; ++i) {
pfd = &context->fds[i];
if (pfd->fd == context->listen_service_fd)
continue;
if (pfd->events & POLLOUT) {
if (context->lws_lookup[pfd->fd]->sock_send_blocking)
continue;
pfd->revents = POLLOUT;
n = libwebsocket_service_fd(context, pfd);
if (n < 0)
return n;
}
}
ev = WSAWaitForMultipleEvents(context->fds_count + 1, context->events, FALSE, timeout_ms, FALSE);
if (ev == WSA_WAIT_TIMEOUT) {
libwebsocket_service_fd(context, NULL);
return 0;
}
if (ev == WSA_WAIT_EVENT_0) {
WSAResetEvent(context->events[0]);
return 0;
}
if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + context->fds_count)
return -1;
pfd = &context->fds[ev - WSA_WAIT_EVENT_0 - 1];
if (WSAEnumNetworkEvents(pfd->fd, context->events[ev - WSA_WAIT_EVENT_0],
&networkevents) == SOCKET_ERROR) {
lwsl_err("WSAEnumNetworkEvents() failed with error %d\n", LWS_ERRNO);
return -1;
}
pfd->revents = (networkevents.lNetworkEvents & LWS_POLLIN) ? POLLIN : 0;
if (networkevents.lNetworkEvents & LWS_POLLOUT) {
context->lws_lookup[pfd->fd]->sock_send_blocking = FALSE;
pfd->revents |= POLLOUT;
}
return libwebsocket_service_fd(context, pfd);
#else
n = poll(context->fds, context->fds_count, timeout_ms);
context->service_tid = 0;
@ -1515,13 +1570,13 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
for (n = 0; n < context->fds_count; n++) {
if (!context->fds[n].revents)
continue;
#ifndef _WIN32
if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
if (read(context->fds[n].fd, &buf, 1) != 1)
lwsl_err("Cannot read from dummy pipe.");
continue;
}
#endif
m = libwebsocket_service_fd(context, &context->fds[n]);
if (m < 0)
return -1;
@ -1531,6 +1586,7 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
}
return 0;
#endif
}
/**
@ -1539,13 +1595,13 @@ libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
*
* This function let a call to libwebsocket_service() waiting for a timeout
* immediately return.
*
* At the moment this functionality cannot be used on Windows.
*/
LWS_VISIBLE void
libwebsocket_cancel_service(struct libwebsocket_context *context)
{
#ifndef _WIN32
#ifdef _WIN32
WSASetEvent(context->events[0]);
#else
char buf = 0;
if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
lwsl_err("Cannot write to dummy pipe.");
@ -1664,6 +1720,9 @@ lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or)
int sampled_tid;
struct pollfd *pfd;
struct libwebsocket_pollargs pa;
#ifdef _WIN32
long networkevents = FD_WRITE;
#endif
pfd = &context->fds[wsi->position_in_fds_table];
pa.fd = wsi->sock;
@ -1688,6 +1747,17 @@ lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or)
* then cancel it to force a restart with our changed events
*/
if (pa.prev_events != pa.events) {
#ifdef _WIN32
if ((pfd->events & POLLIN))
networkevents |= LWS_POLLIN;
if (WSAEventSelect(wsi->sock,
context->events[wsi->position_in_fds_table + 1],
networkevents) == SOCKET_ERROR) {
lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO);
}
#endif
sampled_tid = context->service_tid;
if (sampled_tid) {
tid = context->protocols[0].callback(context, NULL,

View file

@ -86,6 +86,13 @@ LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len)
#endif
static void lws_set_blocking_send(struct libwebsocket *wsi)
{
#ifdef _WIN32
wsi->sock_send_blocking = TRUE;
#endif
}
/*
* notice this returns number of bytes consumed, or -1
*/
@ -160,6 +167,8 @@ int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
n = SSL_get_error(wsi->ssl, n);
if (n == SSL_ERROR_WANT_READ ||
n == SSL_ERROR_WANT_WRITE) {
if (n == SSL_ERROR_WANT_WRITE)
lws_set_blocking_send(wsi);
n = 0;
goto handle_truncated_send;
@ -172,7 +181,10 @@ int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
n = send(wsi->sock, buf, len, MSG_NOSIGNAL);
lws_latency(context, wsi, "send lws_issue_raw", n, n == len);
if (n < 0) {
if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EINTR) {
if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK
|| LWS_ERRNO == LWS_EINTR) {
if (LWS_ERRNO == LWS_EWOULDBLOCK)
lws_set_blocking_send(wsi);
n = 0;
goto handle_truncated_send;
}

View file

@ -68,6 +68,8 @@
#define LWS_EINTR WSAEINTR
#define LWS_EISCONN WSAEISCONN
#define LWS_EWOULDBLOCK WSAEWOULDBLOCK
#define LWS_POLLIN (FD_READ | FD_ACCEPT)
#define LWS_POLLOUT (FD_WRITE)
#define compatible_close(fd) closesocket(fd);
#ifdef __MINGW64__
@ -503,6 +505,10 @@ struct libwebsocket {
BIO *client_bio;
unsigned int use_ssl:2;
#endif
#ifdef _WIN32
BOOL sock_send_blocking;
#endif
};
LWS_EXTERN void