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>
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)
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)
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")
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()
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)
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.
#
"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()
#
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}")
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.
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
----------------
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
=======================
*/
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
goto failed;
- lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
return wsi;
}
}
lwsl_client("lws_client_connect: direct conn\n");
+ wsi->context->count_wsi_allocated++;
+
return lws_client_connect_2(wsi);
bail1:
*/
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 */
* 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) +
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;
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++) {
+ pt = &context->pt[n];
+
+ lws_libev_destroyloop(context, n);
+ lws_libuv_destroyloop(context, 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);
+ 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);
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;
}
}
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;
}
}
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:
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);
}
--- /dev/null
+/*
+ * 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);
+}
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);
}
* 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)
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);
}
/* 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);
#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
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 ---^ ******/
};
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);
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;
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;
}
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--) {
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
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);
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);
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
return -1;
- lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
-
return 1;
}
#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 */
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)
#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;
unsigned long count_conns;
#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;
#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];
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;
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
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))
/* 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 */
if (insert_wsi_socket_into_fds(context, wsi))
goto bail;
+ context->count_wsi_allocated++;
context->pt[m].lserv_fd = sockfd;
#if LWS_POSIX
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
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 */
}
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))
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,
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
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,
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;
}
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",
/* 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
/* 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
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;
{ 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]);
}
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;
}
#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);
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;
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;
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, loop, 0);
+ lws_uv_initloop(context, NULL, signal_cb, 0);
- uv_timer_init(loop, &timeout_watcher);
- uv_timer_start(&timeout_watcher, uv_timeout_cb, 0.05, 0.05);
+ uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher);
+ uv_timer_start(&timeout_watcher, uv_timeout_cb, 50, 50);
- 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;
}