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:
parent
566cd7c2c6
commit
2970d38a7f
3 changed files with 94 additions and 6 deletions
|
@ -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,
|
||||
|
|
14
lib/output.c
14
lib/output.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue