libuv integration

This gets the libuv stuff plumbed in and working.

Currently it's only workable for some service thread, and there
is an isolated valgrind problem left

==28425== 128 bytes in 1 blocks are definitely lost in loss record 3 of 3
==28425==    at 0x4C28C50: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==28425==    by 0x4C2AB1E: realloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==28425==    by 0x58BBB27: maybe_resize (core.c:748)
==28425==    by 0x58BBB27: uv__io_start (core.c:787)
==28425==    by 0x58C1B80: uv__signal_loop_once_init (signal.c:225)
==28425==    by 0x58C1B80: uv_signal_init (signal.c:260)
==28425==    by 0x58BF7A6: uv_loop_init (loop.c:66)
==28425==    by 0x4157F5: lws_uv_initloop (libuv.c:89)
==28425==    by 0x405536: main (test-server-libuv.c:284)

libuv wants to sign off on all libuv 'handles' that will close, and
callback to do the close confirmation asynchronously.  The wsi close function
is adapted when libuv is in use to work with libuv accordingly and exit the uv
loop the number of remaining wsi is zero.

Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
Andy Green 2016-02-14 09:27:41 +08:00
parent 19bb09133d
commit 86ed65ff00
20 changed files with 705 additions and 206 deletions

View file

@ -54,6 +54,7 @@ option(LWS_USE_CYASSL "Use CyaSSL replacement for OpenSSL. When setting this, yo
option(LWS_USE_WOLFSSL "Use wolfSSL replacement for OpenSSL. When setting this, you also need to specify LWS_WOLFSSL_LIBRARIES and LWS_WOLFSSL_INCLUDE_DIRS" OFF)
option(LWS_WITH_ZLIB "Include zlib support (required for extensions)" ON)
option(LWS_WITH_LIBEV "Compile with support for libev" OFF)
option(LWS_WITH_LIBUV "Compile with support for libuv" OFF)
option(LWS_USE_BUNDLED_ZLIB "Use bundled zlib version (Windows only)" ${LWS_USE_BUNDLED_ZLIB_DEFAULT})
option(LWS_SSL_CLIENT_USE_OS_CA_CERTS "SSL support should make use of the OS-installed CA root certs" ON)
option(LWS_WITHOUT_BUILTIN_GETIFADDRS "Don't use the BSD getifaddrs implementation from libwebsockets if it is missing (this will result in a compilation error) ... The default is to assume that your libc provides it. On some systems such as uclibc it doesn't exist." OFF)
@ -135,6 +136,8 @@ set(LWS_WOLFSSL_LIBRARIES CACHE PATH "Path to the wolfSSL library")
set(LWS_WOLFSSL_INCLUDE_DIRS CACHE PATH "Path to the wolfSSL include directory")
set(LWS_LIBEV_LIBRARIES CACHE PATH "Path to the libev library")
set(LWS_LIBEV_INCLUDE_DIRS CACHE PATH "Path to the libev include directory")
set(LWS_LIBUV_LIBRARIES CACHE PATH "Path to the libuv library")
set(LWS_LIBUV_INCLUDE_DIRS CACHE PATH "Path to the libuv include directory")
if (NOT LWS_WITH_SSL)
set(LWS_WITHOUT_BUILTIN_SHA1 OFF)
@ -187,6 +190,15 @@ if (LWS_WITH_LIBEV)
endif()
endif()
if (LWS_WITH_LIBUV)
if ("${LWS_LIBUV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBUV_INCLUDE_DIRS}" STREQUAL "")
else()
set(LIBUV_LIBRARIES ${LWS_LIBUV_LIBRARIES})
set(LIBUV_INCLUDE_DIRS ${LWS_LIBUV_INCLUDE_DIRS})
set(LIBUV_FOUND 1)
endif()
endif()
# FIXME: This must be runtime-only option.
# The base dir where the test-apps look for the SSL certs.
set(LWS_OPENSSL_CLIENT_CERTS ../share CACHE PATH "Server SSL certificate directory")
@ -233,6 +245,10 @@ if (LWS_WITH_LIBEV)
set(LWS_USE_LIBEV 1)
endif()
if (LWS_WITH_LIBUV)
set(LWS_USE_LIBUV 1)
endif()
if (LWS_IPV6)
set(LWS_USE_IPV6 1)
endif()
@ -461,7 +477,12 @@ endif()
if (LWS_WITH_LIBEV)
list(APPEND SOURCES
lib/libev.c)
endif(LWS_WITH_LIBEV)
endif()
if (LWS_WITH_LIBUV)
list(APPEND SOURCES
lib/libuv.c)
endif()
# Add helper files for Windows.
if (WIN32)
@ -676,6 +697,20 @@ if (LWS_WITH_LIBEV)
list(APPEND LIB_LIST ${LIBEV_LIBRARIES})
endif(LWS_WITH_LIBEV)
if (LWS_WITH_LIBUV)
if (NOT LIBUV_FOUND)
find_path(LIBUV_INCLUDE_DIRS NAMES uv.h)
find_library(LIBUV_LIBRARIES NAMES uv)
if(LIBUV_INCLUDE_DIRS AND LIBUV_LIBRARIES)
set(LIBUV_FOUND 1)
endif()
endif()
message("libuv include dir: ${LIBUV_INCLUDE_DIRS}")
message("libuv libraries: ${LIBUV_LIBRARIES}")
include_directories("${LIBUV_INCLUDE_DIRS}")
list(APPEND LIB_LIST ${LIBUV_LIBRARIES})
endif()
#
# Platform specific libs.
#
@ -808,6 +843,15 @@ if (NOT LWS_WITHOUT_TESTAPPS)
"test-server/test-server-mirror.c"
"test-server/test-server-echogen.c")
endif()
if (UNIX AND NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
AND LWS_WITH_LIBUV)
create_test_app(test-server-libuv
"test-server/test-server-libuv.c"
"test-server/test-server-http.c"
"test-server/test-server-dumb-increment.c"
"test-server/test-server-mirror.c"
"test-server/test-server-echogen.c")
endif()
endif()
#
@ -1134,6 +1178,7 @@ message(" LWS_WITHOUT_EXTENSIONS = ${LWS_WITHOUT_EXTENSIONS}")
message(" LWS_WITH_LATENCY = ${LWS_WITH_LATENCY}")
message(" LWS_WITHOUT_DAEMONIZE = ${LWS_WITHOUT_DAEMONIZE}")
message(" LWS_USE_LIBEV = ${LWS_USE_LIBEV}")
message(" LWS_USE_LIBUV = ${LWS_USE_LIBUV}")
message(" LWS_IPV6 = ${LWS_IPV6}")
message(" LWS_WITH_HTTP2 = ${LWS_WITH_HTTP2}")
message(" LWS_MBED3 = ${LWS_MBED3}")

View file

@ -378,3 +378,19 @@ libwebsockets-test-server-pthread does it, for the FD locking callbacks.
There is no knowledge or dependency in lws itself about pthreads. How the
locking is implemented is entirely up to the user code.
Libev / Libuv support
---------------------
You can select either or both
-DLWS_WITH_LIBEV=1
-DLWS_WITH_LIBUV=1
at cmake configure-time. The user application may use one of the
context init options flags
LWS_SERVER_OPTION_LIBEV
LWS_SERVER_OPTION_LIBUV
to indicate it will use either of the event libraries.

View file

@ -222,6 +222,24 @@ had just been accepted by lws' own listen socket.
9) X-Real-IP: header has been added as WSI_TOKEN_HTTP_X_REAL_IP
10) Libuv support is added, there are new related user apis
typedef void (lws_uv_signal_cb_t)(uv_loop_t *l, uv_signal_t *w, int revents);
LWS_VISIBLE LWS_EXTERN int
lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
lws_uv_signal_cb_t *cb);
LWS_VISIBLE LWS_EXTERN int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi);
LWS_VISIBLE void
lws_uv_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents);
and CMAKE option
LWS_WITH_LIBUV
User api changes
----------------
@ -262,6 +280,21 @@ the library.
of value 73. That's now corrected and WSI_TOKEN_PROXY moved to his own place at
77.
9) With the addition of libuv support, libev is not the only event loop
library in town and his api names must be elaborated with _ev_
Callback typedef: lws_signal_cb ---> lws_ev_signal_cb_t
lws_sigint_cfg --> lws_ev_sigint_cfg
lws_initloop --> lws_ev_initloop
lws_sigint_cb --> lws_ev_sigint_cb
10) Libev support is made compatible with multithreaded service,
lws_ev_initloop (was lws_initloop) gets an extra argument for the
thread service index (use 0 if you will just have 1 service thread).
LWS_VISIBLE LWS_EXTERN int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi);
v1.6.0-chrome48-firefox42
=======================

View file

@ -233,7 +233,6 @@ lws_client_connect_2(struct lws *wsi)
*/
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
goto failed;
lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
return wsi;
}
@ -461,6 +460,8 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
}
lwsl_client("lws_client_connect: direct conn\n");
wsi->context->count_wsi_allocated++;
return lws_client_connect_2(wsi);
bail1:

View file

@ -144,7 +144,6 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
*/
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
return -1;
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
#ifdef LWS_OPENSSL_SUPPORT
/* we can retry this... just cook the SSL BIO the first time */

View file

@ -199,8 +199,18 @@ lws_create_context(struct lws_context_creation_info *info)
* before invoking lws_initloop:
*/
context->use_ev_sigint = 1;
context->lws_ev_sigint_cb = &lws_sigint_cb;
context->lws_ev_sigint_cb = &lws_ev_sigint_cb;
#endif /* LWS_USE_LIBEV */
#ifdef LWS_USE_LIBUV
/* (Issue #264) In order to *avoid breaking backwards compatibility*, we
* enable libev mediated SIGINT handling with a default handler of
* lws_sigint_cb. The handler can be overridden or disabled
* by invoking lws_sigint_cfg after creating the context, but
* before invoking lws_initloop:
*/
context->use_ev_sigint = 1;
context->lws_uv_sigint_cb = &lws_uv_sigint_cb;
#endif
lwsl_info(" mem: context: %5u bytes (%d ctx + (%d thr x %d))\n",
sizeof(struct lws_context) +
@ -324,6 +334,7 @@ LWS_VISIBLE void
lws_context_destroy(struct lws_context *context)
{
const struct lws_protocols *protocol = NULL;
struct lws_context_per_thread *pt;
struct lws wsi;
int n, m;
@ -343,59 +354,59 @@ lws_context_destroy(struct lws_context *context)
lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
#endif
while (m--)
while (m--) {
pt = &context->pt[m];
for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
struct lws *wsi = wsi_from_fd(context, context->pt[m].fds[n].fd);
struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
if (!wsi)
continue;
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
lws_close_free_wsi(wsi,
LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
/* no protocol close */);
n--;
}
}
/*
* give all extensions a chance to clean up any per-context
* allocations they might have made
*/
n = lws_ext_cb_all_exts(context, NULL,
LWS_EXT_CB_SERVER_CONTEXT_DESTRUCT, NULL, 0);
LWS_EXT_CB_SERVER_CONTEXT_DESTRUCT, NULL, 0);
n = lws_ext_cb_all_exts(context, NULL,
LWS_EXT_CB_CLIENT_CONTEXT_DESTRUCT, NULL, 0);
LWS_EXT_CB_CLIENT_CONTEXT_DESTRUCT, NULL, 0);
/*
* inform all the protocols that they are done and will have no more
* callbacks
*/
protocol = context->protocols;
if (protocol) {
if (protocol)
while (protocol->callback) {
protocol->callback(&wsi,
LWS_CALLBACK_PROTOCOL_DESTROY,
protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
NULL, NULL, 0);
protocol++;
}
}
#ifdef LWS_USE_LIBEV
uv_poll_stop(&context->w_accept.watcher);
//ev_io_stop(context->io_loop, &context->w_accept.watcher);
//if (context->use_ev_sigint)
//ev_signal_stop(context->io_loop, &context->w_sigint.watcher);
#endif /* LWS_USE_LIBEV */
for (n = 0; n < context->count_threads; n++) {
lws_free_set_NULL(context->pt[n].serv_buf);
if (context->pt[n].ah_pool)
lws_free(context->pt[n].ah_pool);
if (context->pt[n].http_header_data)
lws_free(context->pt[n].http_header_data);
}
pt = &context->pt[n];
lws_libev_destroyloop(context, n);
lws_libuv_destroyloop(context, n);
lws_free_set_NULL(context->pt[n].serv_buf);
if (pt->ah_pool)
lws_free(pt->ah_pool);
if (pt->http_header_data)
lws_free(pt->http_header_data);
}
lws_plat_context_early_destroy(context);
lws_ssl_context_destroy(context);
if (context->pt[0].fds)
lws_free(context->pt[0].fds);
lws_free_set_NULL(context->pt[0].fds);
lws_plat_context_late_destroy(context);

View file

@ -171,6 +171,9 @@ int lws_ext_cb_active(struct lws *wsi, int reason, void *arg, int len)
wsi->active_extensions[n]->name, reason);
return -1;
}
/* valgrind... */
if (reason == LWS_EXT_CB_DESTROY)
wsi->act_ext_user[n] = NULL;
if (m > handled)
handled = m;
}

View file

@ -30,24 +30,24 @@ void lws_feature_status_libev(struct lws_context_creation_info *info)
}
static void
lws_accept_cb(uv_poll_t *watcher, int status, int revents)
lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
struct lws_io_watcher *lws_io = container_of(watcher,
struct lws_io_watcher, watcher);
struct lws_io_watcher, ev_watcher);
struct lws_context *context = lws_io->context;
struct lws_pollfd eventfd;
if (status < 0/*revents & EV_ERROR*/)
return;
if (revents & EV_ERROR)
return;
eventfd.fd = watcher->io_watcher.fd;
eventfd.fd = watcher->fd;
eventfd.events = 0;
eventfd.revents = 0;//EV_NONE;
if (revents & UV_READABLE) {
eventfd.revents = EV_NONE;
if (revents & EV_READ) {
eventfd.events |= LWS_POLLIN;
eventfd.revents |= LWS_POLLIN;
}
if (revents & UV_WRITABLE) {
if (revents & EV_WRITE) {
eventfd.events |= LWS_POLLOUT;
eventfd.revents |= LWS_POLLOUT;
}
@ -55,54 +55,51 @@ lws_accept_cb(uv_poll_t *watcher, int status, int revents)
}
LWS_VISIBLE void
lws_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents)
lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)
{
//ev_break(loop, EVBREAK_ALL);
ev_break(loop, EVBREAK_ALL);
}
LWS_VISIBLE int
lws_sigint_cfg(struct lws_context *context, int use_ev_sigint,
lws_ev_signal_cb* cb)
lws_ev_sigint_cfg(struct lws_context *context, int use_ev_sigint,
lws_ev_signal_cb_t *cb)
{
context->use_ev_sigint = use_ev_sigint;
if (cb)
context->lws_ev_sigint_cb = cb;
else
context->lws_ev_sigint_cb = &lws_sigint_cb;
context->lws_ev_sigint_cb = &lws_ev_sigint_cb;
return 0;
}
LWS_VISIBLE int
lws_initloop(struct lws_context *context, uv_loop_t *loop)
lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
{
//uv_signal_t *w_sigint = &context->w_sigint.watcher;
uv_poll_t *w_accept = &context->w_accept.watcher;
//const char * backend_name;
struct ev_signal *w_sigint = &context->pt[tsi].w_sigint.ev_watcher;
struct ev_io *w_accept = &context->pt[tsi].w_accept.ev_watcher;
const char * backend_name;
int status = 0;
//int backend;
int m = 0; /* !!! TODO add pt support */
int backend;
if (!loop)
loop = uv_default_loop();
loop = ev_loop_new(0);
context->io_loop = loop;
context->pt[tsi].io_loop_ev = loop;
/*
* Initialize the accept w_accept with the listening socket
* and register a callback for read operations
*/
uv_poll_init(context->io_loop, w_accept, context->pt[m].lserv_fd);
uv_poll_start(w_accept, UV_READABLE, lws_accept_cb);
//ev_io_init(w_accept, lws_accept_cb, context->pt[m].lserv_fd, UV_READABLE);
//ev_io_start(context->io_loop,w_accept);
ev_io_init(w_accept, lws_accept_cb, context->pt[tsi].lserv_fd, EV_READ);
ev_io_start(context->pt[tsi].io_loop_ev, w_accept);
/* Register the signal watcher unless the user says not to */
if (context->use_ev_sigint) {
//ev_signal_init(w_sigint, context->lws_ev_sigint_cb, SIGINT);
//ev_signal_start(context->io_loop,w_sigint);
ev_signal_init(w_sigint, context->lws_ev_sigint_cb, SIGINT);
ev_signal_start(context->pt[tsi].io_loop_ev, w_sigint);
}
/*backend = ev_backend(loop);
backend = ev_backend(loop);
switch (backend) {
case EVBACKEND_SELECT:
@ -128,82 +125,90 @@ lws_initloop(struct lws_context *context, uv_loop_t *loop)
break;
}
lwsl_notice(" libev backend: %s\n", backend_name);*/
lwsl_notice(" libev backend: %s\n", backend_name);
return status;
}
void
lws_libev_destroyloop(struct lws_context *context, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
if (!(context->options & LWS_SERVER_OPTION_LIBEV))
return;
ev_io_stop(pt->io_loop_ev, &pt->w_accept.ev_watcher);
if (context->use_ev_sigint)
ev_signal_stop(pt->io_loop_ev,
&pt->w_sigint.ev_watcher);
if (!pt->ev_loop_foreign)
ev_loop_destroy(pt->io_loop_ev);
}
LWS_VISIBLE void
lws_libev_accept(struct lws *new_wsi, int accept_fd)
{
struct lws_context *context = lws_get_context(new_wsi);
uv_poll_t *r = &new_wsi->w_read.watcher;
//uv_poll_t *w = &new_wsi->w_write.watcher;
struct ev_io *r = &new_wsi->w_read.ev_watcher;
struct ev_io *w = &new_wsi->w_write.ev_watcher;
if (!LWS_LIBEV_ENABLED(context))
return;
new_wsi->w_read.context = context;
new_wsi->w_write.context = context;
uv_poll_init(context->io_loop, r, accept_fd);
//ev_io_init(r, lws_accept_cb, accept_fd, UV_READABLE);
//ev_io_init(w, lws_accept_cb, accept_fd, UV_WRITABLE);
ev_io_init(r, lws_accept_cb, accept_fd, EV_READ);
ev_io_init(w, lws_accept_cb, accept_fd, EV_WRITE);
}
LWS_VISIBLE void
lws_libev_io(struct lws *wsi, int flags)
{
struct lws_context *context = lws_get_context(wsi);
int current_events = wsi->w_read.watcher.io_watcher.pevents & (UV_READABLE | UV_WRITABLE);
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
if (!LWS_LIBEV_ENABLED(context))
return;
if (!context->io_loop)
if (!pt->io_loop_ev || context->being_destroyed)
return;
assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
(flags & (LWS_EV_READ | LWS_EV_WRITE)));
if (flags & LWS_EV_START) {
if (flags & LWS_EV_WRITE)
current_events |= UV_WRITABLE;
//ev_io_start(context->io_loop, &wsi->w_write.watcher);
if (flags & LWS_EV_READ)
current_events |= UV_READABLE;
//ev_io_start(context->io_loop, &wsi->w_read.watcher);
uv_poll_start(&wsi->w_read.watcher, current_events, lws_accept_cb);
if (flags & LWS_EV_WRITE)
ev_io_start(pt->io_loop_ev, &wsi->w_write.ev_watcher);
if (flags & LWS_EV_READ)
ev_io_start(pt->io_loop_ev, &wsi->w_read.ev_watcher);
} else {
if (flags & LWS_EV_WRITE)
current_events &= ~UV_WRITABLE;
//ev_io_stop(context->io_loop, &wsi->w_write.watcher);
if (flags & LWS_EV_READ)
current_events &= ~UV_READABLE;
//ev_io_stop(context->io_loop, &wsi->w_read.watcher);
if (!(current_events & (UV_READABLE | UV_WRITABLE)))
uv_poll_stop(&wsi->w_read.watcher);
else
uv_poll_start(&wsi->w_read.watcher, current_events, lws_accept_cb);
if (flags & LWS_EV_WRITE)
ev_io_stop(pt->io_loop_ev, &wsi->w_write.ev_watcher);
if (flags & LWS_EV_READ)
ev_io_stop(pt->io_loop_ev, &wsi->w_read.ev_watcher);
}
}
LWS_VISIBLE int
lws_libev_init_fd_table(struct lws_context *context)
{
int n;
if (!LWS_LIBEV_ENABLED(context))
return 0;
context->w_accept.context = context;
context->w_sigint.context = context;
for (n = 0; n < context->count_threads; n++) {
context->pt[n].w_accept.context = context;
context->pt[n].w_sigint.context = context;
}
return 1;
}
LWS_VISIBLE void
lws_libev_run(const struct lws_context *context)
lws_libev_run(const struct lws_context *context, int tsi)
{
if (context->io_loop && LWS_LIBEV_ENABLED(context))
uv_run(context->io_loop, 0);
if (context->pt[tsi].io_loop_ev && LWS_LIBEV_ENABLED(context))
ev_run(context->pt[tsi].io_loop_ev, 0);
}

301
lib/libuv.c Normal file
View file

@ -0,0 +1,301 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
void
lws_feature_status_libuv(struct lws_context_creation_info *info)
{
if (info->options & LWS_SERVER_OPTION_LIBUV)
lwsl_notice("libuv support compiled in and enabled\n");
else
lwsl_notice("libuv support compiled in but disabled\n");
}
static void
lws_accept_cb(uv_poll_t *watcher, int status, int revents)
{
struct lws_io_watcher *lws_io = container_of(watcher,
struct lws_io_watcher, uv_watcher);
struct lws_context *context = lws_io->context;
struct lws_pollfd eventfd;
if (status < 0)
return;
eventfd.fd = watcher->io_watcher.fd;
eventfd.events = 0;
eventfd.revents = 0;//EV_NONE;
if (revents & UV_READABLE) {
eventfd.events |= LWS_POLLIN;
eventfd.revents |= LWS_POLLIN;
}
if (revents & UV_WRITABLE) {
eventfd.events |= LWS_POLLOUT;
eventfd.revents |= LWS_POLLOUT;
}
lws_service_fd(context, &eventfd);
}
LWS_VISIBLE void
lws_uv_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents)
{
//ev_break(loop, EVBREAK_ALL);
}
LWS_VISIBLE int
lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
lws_uv_signal_cb_t *cb)
{
context->use_ev_sigint = use_uv_sigint;
if (cb)
context->lws_uv_sigint_cb = cb;
else
context->lws_uv_sigint_cb = &lws_uv_sigint_cb;
return 0;
}
static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE };
LWS_VISIBLE int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, uv_signal_cb cb,
int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws *wsi = wsi_from_fd(context, pt->lserv_fd);
int status = 0, n;
if (!loop) {
loop = lws_malloc(sizeof(*loop));
uv_loop_init(loop);
pt->ev_loop_foreign = 0;
} else
pt->ev_loop_foreign = 1;
pt->io_loop_uv = loop;
assert(ARRAY_SIZE(sigs) <= ARRAY_SIZE(pt->signals));
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
uv_signal_init(loop, &pt->signals[n]);
uv_signal_start(&pt->signals[n], cb, sigs[n]);
}
/*
* Initialize the accept wsi read watcher with the listening socket
* and register a callback for read operations
*
* We have to do it here because the uv loop(s) are not
* initialized until after context creation.
*/
if (wsi) {
wsi->w_read.context = context;
uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher, pt->lserv_fd);
uv_poll_start(&wsi->w_read.uv_watcher, UV_READABLE, lws_accept_cb);
}
return status;
}
void
lws_libuv_destroyloop(struct lws_context *context, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
int m;
if (!(context->options & LWS_SERVER_OPTION_LIBUV))
return;
if (context->use_ev_sigint)
uv_signal_stop(&pt->w_sigint.uv_watcher);
for (m = 0; m < ARRAY_SIZE(sigs); m++)
uv_signal_stop(&pt->signals[m]);
if (!pt->ev_loop_foreign) {
m = uv_loop_close(pt->io_loop_uv);
lwsl_debug("%s: uv_loop_close: %d\n", __func__, m);
lws_free(pt->io_loop_uv);
}
}
void
lws_libuv_accept(struct lws *wsi, int accept_fd)
{
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
if (!LWS_LIBUV_ENABLED(context))
return;
lwsl_debug("%s: new wsi %p\n", __func__, wsi);
wsi->w_read.context = context;
uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher, accept_fd);
}
void
lws_libuv_io(struct lws *wsi, int flags)
{
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
int current_events = wsi->w_read.uv_watcher.io_watcher.pevents &
(UV_READABLE | UV_WRITABLE);
struct lws_io_watcher *w = &wsi->w_read;
if (!LWS_LIBUV_ENABLED(context))
return;
lwsl_debug("%s: wsi: %p, flags:%d\n", __func__, wsi, flags);
if (!pt->io_loop_uv) {
lwsl_info("%s: no io loop yet\n", __func__);
return;
}
assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
(flags & (LWS_EV_READ | LWS_EV_WRITE)));
if (flags & LWS_EV_START) {
if (flags & LWS_EV_WRITE)
current_events |= UV_WRITABLE;
if (flags & LWS_EV_READ)
current_events |= UV_READABLE;
uv_poll_start(&w->uv_watcher, current_events, lws_accept_cb);
} else {
if (flags & LWS_EV_WRITE)
current_events &= ~UV_WRITABLE;
if (flags & LWS_EV_READ)
current_events &= ~UV_READABLE;
if (!(current_events & (UV_READABLE | UV_WRITABLE)))
uv_poll_stop(&w->uv_watcher);
else
uv_poll_start(&w->uv_watcher, current_events,
lws_accept_cb);
}
}
int
lws_libuv_init_fd_table(struct lws_context *context)
{
int n;
if (!LWS_LIBUV_ENABLED(context))
return 0;
for (n = 0; n < context->count_threads; n++) {
context->pt[n].w_sigint.context = context;
}
return 1;
}
LWS_VISIBLE void
lws_libuv_run(const struct lws_context *context, int tsi)
{
if (context->pt[tsi].io_loop_uv && LWS_LIBUV_ENABLED(context))
uv_run(context->pt[tsi].io_loop_uv, 0);
}
static void
lws_libuv_kill(const struct lws_context *context)
{
int n;
for (n = 0; n < context->count_threads; n++)
if (context->pt[n].io_loop_uv && LWS_LIBUV_ENABLED(context))
uv_stop(context->pt[n].io_loop_uv);
}
/*
* This does not actually stop the event loop. The reason is we have to pass
* libuv handle closures through its event loop. So this tries to close all
* wsi, and set a flag; when all the wsi closures are finalized then we
* actually stop the libuv event loops.
*/
LWS_VISIBLE void
lws_libuv_stop(struct lws_context *context)
{
struct lws_context_per_thread *pt;
int n, m;
context->requested_kill = 1;
m = context->count_threads;
context->being_destroyed = 1;
while (m--) {
pt = &context->pt[m];
for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
if (!wsi)
continue;
lws_close_free_wsi(wsi,
LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
/* no protocol close */);
n--;
}
}
if (context->count_wsi_allocated == 0)
lws_libuv_kill(context);
}
LWS_VISIBLE uv_loop_t *
lws_uv_getloop(struct lws_context *context, int tsi)
{
if (context->pt[tsi].io_loop_uv && LWS_LIBUV_ENABLED(context))
return context->pt[tsi].io_loop_uv;
return NULL;
}
static void
lws_libuv_closewsi(uv_handle_t* handle)
{
struct lws *n = NULL, *wsi = (struct lws *)(((void *)handle) -
(void *)(&n->w_read.uv_watcher));
struct lws_context *context = lws_get_context(wsi);
lws_close_free_wsi_final(wsi);
if (context->requested_kill && context->count_wsi_allocated == 0)
lws_libuv_kill(context);
}
void
lws_libuv_closehandle(struct lws *wsi)
{
struct lws_context *context = lws_get_context(wsi);
/* required to defer actual deletion until libuv has processed it */
uv_close((uv_handle_t*)&wsi->w_read.uv_watcher, lws_libuv_closewsi);
if (context->requested_kill && context->count_wsi_allocated == 0)
lws_libuv_kill(context);
}

View file

@ -65,6 +65,10 @@ lws_free_wsi(struct lws *wsi)
wsi->mode != LWSCM_WS_SERVING)
lws_free_header_table(wsi);
wsi->context->count_wsi_allocated--;
lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
wsi->context->count_wsi_allocated);
lws_free(wsi);
}
@ -294,7 +298,9 @@ just_kill_connection:
* for the POLLIN to show a zero-size rx before coming back and doing
* the actual close.
*/
if (wsi->state != LWSS_SHUTDOWN) {
if (wsi->state != LWSS_SHUTDOWN &&
reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY &&
!wsi->socket_is_permanently_unusable) {
lwsl_info("%s: shutting down connection: %p\n", __func__, wsi);
n = shutdown(wsi->sock, SHUT_WR);
if (n)
@ -404,6 +410,21 @@ just_kill_connection:
wsi->socket_is_permanently_unusable = 1;
#ifdef LWS_USE_LIBUV
/* libuv has to do his own close handle processing asynchronously */
lws_libuv_closehandle(wsi);
return;
#endif
lws_close_free_wsi_final(wsi);
}
void
lws_close_free_wsi_final(struct lws *wsi)
{
int n;
if (!lws_ssl_close(wsi) && lws_socket_is_valid(wsi->sock)) {
#if LWS_POSIX
n = compatible_close(wsi->sock);
@ -417,7 +438,7 @@ just_kill_connection:
}
/* outermost destroy notification for wsi (user_space still intact) */
context->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY,
wsi->context->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY,
wsi->user_space, NULL, 0);
lws_free_wsi(wsi);

View file

@ -170,8 +170,11 @@ struct sockaddr_in;
#endif
#ifdef LWS_USE_LIBEV
#include <uv.h>
#include <ev.h>
#endif /* LWS_USE_LIBEV */
#ifdef LWS_USE_LIBUV
#include <uv.h>
#endif /* LWS_USE_LIBUV */
#ifndef LWS_EXTERN
#define LWS_EXTERN extern
@ -281,6 +284,7 @@ enum lws_context_options {
LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED = (1 << 7),
LWS_SERVER_OPTION_VALIDATE_UTF8 = (1 << 8),
LWS_SERVER_OPTION_SSL_ECDH = (1 << 9),
LWS_SERVER_OPTION_LIBUV = (1 << 10),
/****** add new things just above ---^ ******/
};
@ -1457,19 +1461,42 @@ LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
lws_http_transaction_completed(struct lws *wsi);
#ifdef LWS_USE_LIBEV
typedef void (lws_ev_signal_cb)(uv_loop_t *l, uv_signal_t *w, int revents);
typedef void (lws_ev_signal_cb_t)(EV_P_ struct ev_signal *w, int revents);
LWS_VISIBLE LWS_EXTERN int
lws_sigint_cfg(struct lws_context *context, int use_ev_sigint,
lws_ev_signal_cb *cb);
lws_ev_sigint_cfg(struct lws_context *context, int use_ev_sigint,
lws_ev_signal_cb_t *cb);
LWS_VISIBLE LWS_EXTERN int
lws_initloop(struct lws_context *context, uv_loop_t *loop);
lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi);
LWS_VISIBLE void
lws_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents);
lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents);
#endif /* LWS_USE_LIBEV */
#ifdef LWS_USE_LIBUV
typedef void (lws_uv_signal_cb_t)(uv_loop_t *l, uv_signal_t *w, int revents);
LWS_VISIBLE LWS_EXTERN int
lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
lws_uv_signal_cb_t *cb);
LWS_VISIBLE LWS_EXTERN void
lws_libuv_run(const struct lws_context *context, int tsi);
LWS_VISIBLE void
lws_libuv_stop(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, uv_signal_cb cb, int tsi);
LWS_VISIBLE LWS_EXTERN uv_loop_t *
lws_uv_getloop(struct lws_context *context, int tsi);
LWS_VISIBLE void
lws_uv_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents);
#endif /* LWS_USE_LIBUV */
LWS_VISIBLE LWS_EXTERN int
lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd);

View file

@ -134,7 +134,8 @@ lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
if (!context)
return 1;
lws_libev_run(context);
lws_libev_run(context, tsi);
lws_libuv_run(context, tsi);
if (!context->service_tid_detected) {
struct lws _lws;
@ -455,6 +456,8 @@ lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
pt->fds[pt->fds_count++].revents = 0;
}
@ -579,7 +582,8 @@ lws_plat_init(struct lws_context *context,
return 1;
}
if (!lws_libev_init_fd_table(context)) {
if (!lws_libev_init_fd_table(context) &&
!lws_libuv_init_fd_table(context)) {
/* otherwise libev handled it instead */
while (n--) {

View file

@ -49,6 +49,23 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
goto bail;
}
if (_and & LWS_POLLIN) {
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ);
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ);
}
if (_or & LWS_POLLIN) {
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
}
if (_and & LWS_POLLOUT) {
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
}
if (_or & LWS_POLLOUT) {
lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_WRITE);
}
/*
* if we changed something in this pollfd...
* ... and we're running in a different thread context
@ -167,7 +184,8 @@ remove_wsi_socket_from_fds(struct lws *wsi)
wsi->user_space, (void *)&pa, 1))
return -1;
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE | LWS_EV_PREPARE_DELETION);
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE | LWS_EV_PREPARE_DELETION);
lws_pt_lock(pt);
@ -199,9 +217,10 @@ remove_wsi_socket_from_fds(struct lws *wsi)
wsi->user_space, (void *) &pa, 0))
ret = -1;
#ifndef LWS_NO_SERVER
/* if this made some room, accept connects on this thread */
if ((unsigned int)pt->fds_count < context->fd_limit_per_thread - 1)
_lws_change_pollfd(pt->wsi_listening, 0, LWS_POLLIN, &pa1);
if (!context->being_destroyed)
/* if this made some room, accept connects on this thread */
if ((unsigned int)pt->fds_count < context->fd_limit_per_thread - 1)
_lws_change_pollfd(pt->wsi_listening, 0, LWS_POLLIN, &pa1);
#endif
lws_pt_unlock(pt);
@ -314,8 +333,6 @@ network_sock:
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
return -1;
lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
return 1;
}

View file

@ -117,8 +117,11 @@
#include <arpa/inet.h>
#include <poll.h>
#ifdef LWS_USE_LIBEV
#include <ev.h>
#endif
#ifdef LWS_USE_LIBUV
#include <uv.h>
#endif /* LWS_USE_LIBEV */
#endif
#include <sys/mman.h>
#endif /* MBED */
@ -437,17 +440,28 @@ enum {
struct lws_protocols;
struct lws;
#ifdef LWS_USE_LIBEV
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
struct lws_io_watcher {
uv_poll_t watcher;
struct lws_context* context;
#ifdef LWS_USE_LIBEV
ev_io ev_watcher;
#endif
#ifdef LWS_USE_LIBUV
uv_poll_t uv_watcher;
#endif
struct lws_context *context;
};
struct lws_signal_watcher {
uv_signal_t watcher;
struct lws_context* context;
#ifdef LWS_USE_LIBEV
ev_signal ev_watcher;
#endif
#ifdef LWS_USE_LIBUV
uv_signal_t uv_watcher;
#endif
struct lws_context *context;
};
#endif /* LWS_USE_LIBEV */
#endif
#ifdef _WIN32
#define LWS_FD_HASH(fd) ((fd ^ (fd >> 8) ^ (fd >> 16)) % FD_HASHTABLE_MODULUS)
@ -520,6 +534,20 @@ struct lws_context_per_thread {
#endif
#ifndef LWS_NO_SERVER
struct lws *wsi_listening;
#endif
#if defined(LWS_USE_LIBEV)
struct ev_loop *io_loop_ev;
#endif
#if defined(LWS_USE_LIBUV)
uv_loop_t *io_loop_uv;
uv_signal_t signals[8];
#endif
#if defined(LWS_USE_LIBEV)
struct lws_io_watcher w_accept;
#endif
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
struct lws_signal_watcher w_sigint;
unsigned char ev_loop_foreign:1;
#endif
lws_sockfd_type lserv_fd;
@ -559,12 +587,6 @@ struct lws_context {
#else
struct lws **lws_lookup; /* fd to wsi */
#endif
#ifdef LWS_USE_LIBEV
uv_loop_t *io_loop;
struct lws_io_watcher w_accept;
struct lws_signal_watcher w_sigint;
lws_ev_signal_cb* lws_ev_sigint_cb;
#endif /* LWS_USE_LIBEV */
const char *iface;
const struct lws_token_limits *token_limits;
void *user_space;
@ -578,7 +600,12 @@ struct lws_context {
#ifndef LWS_NO_EXTENSIONS
const struct lws_extension *extensions;
#endif
#if defined(LWS_USE_LIBEV)
lws_ev_signal_cb_t * lws_ev_sigint_cb;
#endif
#if defined(LWS_USE_LIBUV)
lws_uv_signal_cb_t * lws_uv_sigint_cb;
#endif
char http_proxy_address[128];
char proxy_basic_auth_token[128];
char canonical_hostname[128];
@ -589,13 +616,14 @@ struct lws_context {
int max_fds;
int listen_port;
#ifdef LWS_USE_LIBEV
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
int use_ev_sigint;
#endif
int started_with_parent;
int fd_random;
int lserv_mod;
int count_wsi_allocated;
unsigned int http_proxy_port;
unsigned int options;
unsigned int fd_limit_per_thread;
@ -634,18 +662,24 @@ struct lws_context {
short count_threads;
unsigned int being_destroyed:1;
unsigned int requested_kill:1;
};
LWS_EXTERN void
lws_close_free_wsi_final(struct lws *wsi);
LWS_EXTERN void
lws_libuv_closehandle(struct lws *wsi);
enum {
LWS_EV_READ = (1 << 0),
LWS_EV_WRITE = (1 << 1),
LWS_EV_START = (1 << 2),
LWS_EV_STOP = (1 << 3),
LWS_EV_PREPARE_DELETION = (1 << 31),
};
#ifdef LWS_USE_LIBEV
#define LWS_LIBEV_ENABLED(context) (context->options & LWS_SERVER_OPTION_LIBEV)
LWS_EXTERN void lws_feature_status_libev(struct lws_context_creation_info *info);
#if defined(LWS_USE_LIBEV)
LWS_EXTERN void
lws_libev_accept(struct lws *new_wsi, lws_sockfd_type accept_fd);
LWS_EXTERN void
@ -653,21 +687,55 @@ lws_libev_io(struct lws *wsi, int flags);
LWS_EXTERN int
lws_libev_init_fd_table(struct lws_context *context);
LWS_EXTERN void
lws_libev_run(const struct lws_context *context);
lws_libev_destroyloop(struct lws_context *context, int tsi);
LWS_EXTERN void
lws_libev_run(const struct lws_context *context, int tsi);
#define LWS_LIBEV_ENABLED(context) (context->options & LWS_SERVER_OPTION_LIBEV)
LWS_EXTERN void lws_feature_status_libev(struct lws_context_creation_info *info);
#else
#define lws_libev_accept(_a, _b) ((void) 0)
#define lws_libev_io(_a, _b) ((void) 0)
#define lws_libev_init_fd_table(_a) (0)
#define lws_libev_run(_a, _b) ((void) 0)
#define lws_libev_destroyloop(_a, _b) ((void) 0)
#define LWS_LIBEV_ENABLED(context) (0)
#ifdef LWS_POSIX
#if LWS_POSIX
#define lws_feature_status_libev(_a) \
lwsl_notice("libev support not compiled in\n")
#else
#define lws_feature_status_libev(_a)
#endif
#define lws_libev_accept(_a, _b) ((void) 0)
#define lws_libev_io(_a, _b) ((void) 0)
#define lws_libev_init_fd_table(_a) (0)
#define lws_libev_run(_a) ((void) 0)
#endif
#if defined(LWS_USE_LIBUV)
LWS_EXTERN void
lws_libuv_accept(struct lws *new_wsi, lws_sockfd_type accept_fd);
LWS_EXTERN void
lws_libuv_io(struct lws *wsi, int flags);
LWS_EXTERN int
lws_libuv_init_fd_table(struct lws_context *context);
LWS_EXTERN void
lws_libuv_run(const struct lws_context *context, int tsi);
LWS_EXTERN void
lws_libuv_destroyloop(struct lws_context *context, int tsi);
#define LWS_LIBUV_ENABLED(context) (context->options & LWS_SERVER_OPTION_LIBUV)
LWS_EXTERN void lws_feature_status_libuv(struct lws_context_creation_info *info);
#else
#define lws_libuv_accept(_a, _b) ((void) 0)
#define lws_libuv_io(_a, _b) ((void) 0)
#define lws_libuv_init_fd_table(_a) (0)
#define lws_libuv_run(_a, _b) ((void) 0)
#define lws_libuv_destroyloop(_a, _b) ((void) 0)
#define LWS_LIBUV_ENABLED(context) (0)
#if LWS_POSIX
#define lws_feature_status_libuv(_a) \
lwsl_notice("libuv support not compiled in\n")
#else
#define lws_feature_status_libuv(_a)
#endif
#endif
#ifdef LWS_USE_IPV6
#define LWS_IPV6_ENABLED(context) \
(!(context->options & LWS_SERVER_OPTION_DISABLE_IPV6))
@ -933,10 +1001,12 @@ struct lws {
/* lifetime members */
#ifdef LWS_USE_LIBEV
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
struct lws_io_watcher w_read;
#endif
#if defined(LWS_USE_LIBEV)
struct lws_io_watcher w_write;
#endif /* LWS_USE_LIBEV */
#endif
time_t pending_timeout_limit;
/* pointers */

View file

@ -143,6 +143,7 @@ lws_context_init_server(struct lws_context_creation_info *info,
if (insert_wsi_socket_into_fds(context, wsi))
goto bail;
context->count_wsi_allocated++;
context->pt[m].lserv_fd = sockfd;
#if LWS_POSIX
@ -665,7 +666,7 @@ lws_create_new_server_wsi(struct lws_context *context)
new_wsi->user_space = NULL;
new_wsi->ietf_spec_revision = 0;
new_wsi->sock = LWS_SOCK_INVALID;
context->count_wsi_allocated++;
/*
* outermost create notification for wsi
@ -752,6 +753,8 @@ lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
return NULL;
}
lwsl_debug("%s: new wsi %p\n", __func__, new_wsi);
new_wsi->sock = accept_fd;
/* the transport is accepted... give him time to negotiate */
@ -775,6 +778,7 @@ lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
}
lws_libev_accept(new_wsi, new_wsi->sock);
lws_libuv_accept(new_wsi, new_wsi->sock);
if (!LWS_SSL_ENABLED(context)) {
if (insert_wsi_socket_into_fds(context, new_wsi))
@ -908,8 +912,6 @@ try_pollout:
goto fail;
}
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
if (wsi->state != LWSS_HTTP_ISSUING_FILE) {
n = user_callback_handle_rxflow(wsi->protocol->callback,
wsi, LWS_CALLBACK_HTTP_WRITEABLE,

View file

@ -231,15 +231,12 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
user_service:
/* one shot */
if (pollfd) {
if (pollfd)
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
lwsl_info("failed at set pollfd\n");
return 1;
}
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
}
#ifdef LWS_USE_HTTP2
/*
* we are the 'network wsi' for potentially many muxed child wsi with

View file

@ -664,8 +664,6 @@ lws_server_socket_service_ssl(struct lws *wsi, lws_sockfd_type accept_fd)
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
goto fail;
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
lws_latency_pre(context, wsi);
n = recv(wsi->sock, (char *)pt->serv_buf, LWS_MAX_SOCKET_IO_BUF,
@ -732,8 +730,6 @@ go_again:
if (lws_change_pollfd(wsi, 0, LWS_POLLIN))
goto fail;
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
lwsl_info("SSL_ERROR_WANT_READ\n");
break;
}
@ -741,7 +737,6 @@ go_again:
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
goto fail;
lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
break;
}
lwsl_debug("SSL_accept failed skt %u: %s\n",

View file

@ -41,6 +41,9 @@
/* Enable libev io loop */
#cmakedefine LWS_USE_LIBEV
/* Enable libuv io loop */
#cmakedefine LWS_USE_LIBUV
/* Build with support for ipv6 */
#cmakedefine LWS_USE_IPV6

View file

@ -350,17 +350,13 @@ int main(int argc, char **argv)
/* override the active fops */
lws_get_fops(context)->open = test_server_fops_open;
lws_initloop(context, loop);
lws_ev_initloop(context, loop, 0);
_ev_timer_init(&timeout_watcher, ev_timeout_cb, 0.05, 0.05);
ev_timer_start(loop, &timeout_watcher);
while (!force_exit)
ev_run(loop, 0);
ev_run(loop, 0);
lws_context_destroy(context);
ev_loop_destroy(loop);
lwsl_notice("libwebsockets-test-server exited cleanly\n");
#ifndef _WIN32

View file

@ -24,7 +24,6 @@
int close_testing;
int max_poll_elements;
int debug_level = 7;
volatile int force_exit = 0;
struct lws_context *context;
struct lws_plat_file_ops fops_plat;
@ -107,44 +106,25 @@ static const struct lws_extension exts[] = {
{ NULL, NULL, NULL /* terminator */ }
};
/* this shows how to override the lws file operations. You don't need
* to do any of this unless you have a reason (eg, want to serve
* compressed files without decompressing the whole archive)
*/
static lws_filefd_type
test_server_fops_open(struct lws *wsi, const char *filename,
unsigned long *filelen, int flags)
{
lws_filefd_type n;
/* call through to original platform implementation */
n = fops_plat.open(wsi, filename, filelen, flags);
lwsl_notice("%s: opening %s, ret %ld, len %lu\n", __func__, filename,
(long)n, *filelen);
return n;
}
void signal_cb(uv_signal_t *watcher, int revents)
{
lwsl_notice("Signal caught, exiting...\n");
force_exit = 1;
lwsl_err("Signal %d caught, exiting...\n", watcher->signum);
switch (watcher->signum) {
case SIGTERM:
case SIGINT:
uv_stop(uv_default_loop()); /* Note: we assume default loop! */
break;
default:
signal(SIGABRT, SIG_DFL);
abort();
break;
}
lws_libuv_stop(context);
}
static void
uv_timeout_cb (uv_timer_t *w)
uv_timeout_cb(uv_timer_t *w)
{
lwsl_info("%s\n", __func__);
lws_callback_on_writable_all_protocol(context,
&protocols[PROTOCOL_DUMB_INCREMENT]);
}
@ -167,13 +147,10 @@ static struct option options[] = {
int main(int argc, char **argv)
{
int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
uv_signal_t signals[ARRAY_SIZE(sigs)];
uv_loop_t *loop = uv_default_loop();
struct lws_context_creation_info info;
char interface_name[128] = "";
const char *iface = NULL;
uv_timer_t timeout_watcher;
const char *iface = NULL;
char cert_path[1024];
char key_path[1024];
int use_ssl = 0;
@ -257,16 +234,9 @@ int main(int argc, char **argv)
}
#endif
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
uv_signal_init(loop, &signals[n]);
uv_signal_start(&signals[n], signal_cb, sigs[n]);
}
#ifndef _WIN32
/* we will only try to log things according to our debug_level */
setlogmask(LOG_UPTO (LOG_DEBUG));
openlog("lwsts", syslog_options, LOG_DAEMON);
#endif
/* tell the library what debug level to emit and to send it to syslog */
lws_set_log_level(debug_level, lwsl_emit_syslog);
@ -274,7 +244,7 @@ int main(int argc, char **argv)
lwsl_notice("libwebsockets test server libuv - license LGPL2.1+SLE\n");
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
printf("Using resource path \"%s\"\n", resource_path);
lwsl_info("Using resource path \"%s\"\n", resource_path);
info.iface = iface;
info.protocols = protocols;
@ -289,13 +259,13 @@ int main(int argc, char **argv)
return -1;
}
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
resource_path);
resource_path);
if (strlen(resource_path) > sizeof(key_path) - 32) {
lwsl_err("resource path too long\n");
return -1;
}
sprintf(key_path, "%s/libwebsockets-test-server.key.pem",
resource_path);
resource_path);
info.ssl_cert_filepath = cert_path;
info.ssl_private_key_filepath = key_path;
@ -311,32 +281,15 @@ int main(int argc, char **argv)
return -1;
}
/*
* this shows how to override the lws file operations. You don't need
* to do any of this unless you have a reason (eg, want to serve
* compressed files without decompressing the whole archive)
*/
/* stash original platform fops */
fops_plat = *(lws_get_fops(context));
/* override the active fops */
lws_get_fops(context)->open = test_server_fops_open;
lws_uv_initloop(context, NULL, signal_cb, 0);
lws_uv_initloop(context, loop, 0);
uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher);
uv_timer_start(&timeout_watcher, uv_timeout_cb, 50, 50);
uv_timer_init(loop, &timeout_watcher);
uv_timer_start(&timeout_watcher, uv_timeout_cb, 0.05, 0.05);
while (!force_exit)
uv_run(loop, 0);
lws_libuv_run(context, 0);
lws_context_destroy(context);
uv_stop(loop);
lwsl_notice("libwebsockets-test-server exited cleanly\n");
#ifndef _WIN32
closelog();
#endif
return 0;
}