Compare commits

...
Sign in to create a new pull request.

5 commits

Author SHA1 Message Date
Andy Green
027fb683cc libuv only cleanup if in use
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-03 07:07:31 +08:00
Andy Green
86224b5093 libuv test server update for deprecated apis
We have to set a good example everywhere now
lws_get_internal_extensions() blows a warning / error

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-03 07:07:31 +08:00
Andy Green
ba78cd36a6 lib_v move start stop handling into change_pollfd
The existing lib_v handling copied around to each change_pollfd instance
can be easily missed off if new change_pollfd uses are added.  Instead
migrate it directly into change_pollfd to guarantee it is handled and
simplify the code.

Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-03 07:07:31 +08:00
Andy Green
da408c0d2b libuv libev abstraction
Signed-off-by: Andy Green <andy.green@linaro.org>
2016-02-03 07:07:31 +08:00
Alex Hultman
fa4619416e libuv initial replace libev version 2016-02-03 07:07:31 +08:00
18 changed files with 824 additions and 80 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;
}

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) +
@ -377,13 +387,21 @@ lws_context_destroy(struct lws_context *context)
protocol++;
}
}
#ifdef LWS_USE_LIBEV
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++) {
#ifdef LWS_USE_LIBEV
if (context->options & LWS_SERVER_OPTION_LIBEV) {
ev_io_stop(context->pt[n].io_loop_ev,
&context->pt[n].w_accept.ev_watcher);
if (context->use_ev_sigint)
ev_signal_stop(context->pt[n].io_loop_ev,
&context->pt[n].w_sigint.ev_watcher);
}
#endif /* LWS_USE_LIBEV */
#ifdef LWS_USE_LIBUV
if (context->options & LWS_SERVER_OPTION_LIBUV)
uv_poll_stop(&context->pt[n].w_accept.uv_watcher);
#endif
lws_free_set_NULL(context->pt[n].serv_buf);
if (context->pt[n].ah_pool)
lws_free(context->pt[n].ah_pool);

View file

@ -33,7 +33,7 @@ static void
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;
@ -55,50 +55,49 @@ lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
}
LWS_VISIBLE void
lws_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)
lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)
{
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, struct ev_loop *loop)
lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
{
struct ev_signal *w_sigint = &context->w_sigint.watcher;
struct ev_io *w_accept = &context->w_accept.watcher;
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 */
if (!loop)
loop = ev_default_loop(0);
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
*/
ev_io_init(w_accept, lws_accept_cb, context->pt[m].lserv_fd, EV_READ);
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_start(context->pt[tsi].io_loop_ev, w_sigint);
}
backend = ev_backend(loop);
@ -135,8 +134,8 @@ LWS_VISIBLE void
lws_libev_accept(struct lws *new_wsi, int accept_fd)
{
struct lws_context *context = lws_get_context(new_wsi);
struct ev_io *r = &new_wsi->w_read.watcher;
struct ev_io *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;
@ -151,11 +150,12 @@ LWS_VISIBLE void
lws_libev_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];
if (!LWS_LIBEV_ENABLED(context))
return;
if (!context->io_loop)
if (!pt->io_loop_ev)
return;
assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
@ -163,32 +163,36 @@ lws_libev_io(struct lws *wsi, int flags)
if (flags & LWS_EV_START) {
if (flags & LWS_EV_WRITE)
ev_io_start(context->io_loop, &wsi->w_write.watcher);
ev_io_start(pt->io_loop_ev, &wsi->w_write.ev_watcher);
if (flags & LWS_EV_READ)
ev_io_start(context->io_loop, &wsi->w_read.watcher);
ev_io_start(pt->io_loop_ev, &wsi->w_read.ev_watcher);
} else {
if (flags & LWS_EV_WRITE)
ev_io_stop(context->io_loop, &wsi->w_write.watcher);
ev_io_stop(pt->io_loop_ev, &wsi->w_write.ev_watcher);
if (flags & LWS_EV_READ)
ev_io_stop(context->io_loop, &wsi->w_read.watcher);
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))
ev_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);
}

176
lib/libuv.c Normal file
View file

@ -0,0 +1,176 @@
/*
* 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;
}
LWS_VISIBLE int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)
{
uv_poll_t *w_accept = &context->pt[tsi].w_accept.uv_watcher;
int status = 0;
if (!loop)
loop = uv_loop_new();
context->pt[tsi].io_loop_uv = loop;
/*
* Initialize the accept w_accept with the listening socket
* and register a callback for read operations
*/
uv_poll_init(context->pt[tsi].io_loop_uv, w_accept,
context->pt[tsi].lserv_fd);
uv_poll_start(w_accept, UV_READABLE, lws_accept_cb);
return status;
}
LWS_VISIBLE void
lws_libuv_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.uv_watcher;
if (!LWS_LIBUV_ENABLED(context))
return;
new_wsi->w_read.context = context;
new_wsi->w_write.context = context;
uv_poll_init(context->pt[(int)new_wsi->tsi].io_loop_uv, r, accept_fd);
}
LWS_VISIBLE 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);
if (!LWS_LIBUV_ENABLED(context))
return;
if (!pt->io_loop_uv)
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(&wsi->w_read.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(&wsi->w_read.uv_watcher);
else
uv_poll_start(&wsi->w_read.uv_watcher, current_events,
lws_accept_cb);
}
}
LWS_VISIBLE 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_accept.context = context;
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);
}

View file

@ -171,6 +171,9 @@ struct sockaddr_in;
#ifdef LWS_USE_LIBEV
#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
@ -280,6 +283,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 ---^ ******/
};
@ -1456,19 +1460,33 @@ 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)(EV_P_ struct ev_signal *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, struct ev_loop *loop);
lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi);
LWS_VISIBLE void
lws_sigint_cb(struct ev_loop *loop, struct ev_signal *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 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);
#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
@ -168,6 +185,7 @@ remove_wsi_socket_from_fds(struct lws *wsi)
return -1;
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
lws_pt_lock(pt);
@ -314,8 +332,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

@ -118,7 +118,10 @@
#include <poll.h>
#ifdef LWS_USE_LIBEV
#include <ev.h>
#endif /* LWS_USE_LIBEV */
#endif
#ifdef LWS_USE_LIBUV
#include <uv.h>
#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 {
struct ev_io watcher;
#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 {
struct ev_signal watcher;
#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,16 @@ 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;
#endif
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
struct lws_io_watcher w_accept;
struct lws_signal_watcher w_sigint;
#endif
lws_sockfd_type lserv_fd;
@ -559,12 +583,6 @@ struct lws_context {
#else
struct lws **lws_lookup; /* fd to wsi */
#endif
#ifdef LWS_USE_LIBEV
struct ev_loop* 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 +596,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,7 +612,7 @@ 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;
@ -643,9 +666,7 @@ enum {
LWS_EV_STOP = (1 << 3),
};
#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 +674,49 @@ 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_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_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);
#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_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 +982,10 @@ struct lws {
/* lifetime members */
#ifdef LWS_USE_LIBEV
#if defined(LWS_USE_LIBEV) || defined(LWS_USE_LIBUV)
struct lws_io_watcher w_read;
struct lws_io_watcher w_write;
#endif /* LWS_USE_LIBEV */
#endif
time_t pending_timeout_limit;
/* pointers */

View file

@ -767,6 +767,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))
@ -900,8 +901,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

@ -352,7 +352,7 @@ 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);

View file

@ -0,0 +1,373 @@
/*
* libwebsockets-test-server for libev - libwebsockets test implementation
*
* Copyright (C) 2010-2015 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 "test-server.h"
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;
/* http server gets files from this path */
#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server"
char *resource_path = LOCAL_RESOURCE_PATH;
/*
* libev dumps their hygeine problems on their users blaming compiler
* http://lists.schmorp.de/pipermail/libev/2008q4/000442.html
*/
#if EV_MINPRI == EV_MAXPRI
# define _ev_set_priority(ev, pri) ((ev), (pri))
#else
# define _ev_set_priority(ev, pri) { \
ev_watcher *evw = (ev_watcher *)(void *)ev; \
evw->priority = pri; \
}
#endif
#define _ev_init(ev,cb_) { \
ev_watcher *evw = (ev_watcher *)(void *)ev; \
\
evw->active = evw->pending = 0; \
_ev_set_priority((ev), 0); \
ev_set_cb((ev), cb_); \
}
#define _ev_timer_init(ev, cb, after, _repeat) { \
ev_watcher_time *evwt = (ev_watcher_time *)(void *)ev; \
\
_ev_init(ev, cb); \
evwt->at = after; \
(ev)->repeat = _repeat; \
}
/* singlethreaded version --> no locks */
void test_server_lock(int care)
{
}
void test_server_unlock(int care)
{
}
/*
* This demo server shows how to use libwebsockets for one or more
* websocket protocols in the same server
*
* It defines the following websocket protocols:
*
* dumb-increment-protocol: once the socket is opened, an incrementing
* ascii string is sent down it every 50ms.
* If you send "reset\n" on the websocket, then
* the incrementing number is reset to 0.
*
* lws-mirror-protocol: copies any received packet to every connection also
* using this protocol, including the sender
*/
enum demo_protocols {
/* always first */
PROTOCOL_HTTP = 0,
PROTOCOL_DUMB_INCREMENT,
PROTOCOL_LWS_MIRROR,
/* always last */
DEMO_PROTOCOL_COUNT
};
/* list of supported protocols and callbacks */
static struct lws_protocols protocols[] = {
/* first protocol must always be HTTP handler */
{
"http-only", /* name */
callback_http, /* callback */
sizeof (struct per_session_data__http), /* per_session_data_size */
0, /* max frame size / rx buffer */
},
{
"dumb-increment-protocol",
callback_dumb_increment,
sizeof(struct per_session_data__dumb_increment),
10,
},
{
"lws-mirror-protocol",
callback_lws_mirror,
sizeof(struct per_session_data__lws_mirror),
128,
},
{ NULL, NULL, 0, 0 } /* terminator */
};
static const struct lws_extension exts[] = {
{
"permessage-deflate",
lws_extension_callback_pm_deflate,
"permessage-deflate; client_no_context_takeover; client_max_window_bits"
},
{
"deflate-frame",
lws_extension_callback_pm_deflate,
"deflate_frame"
},
{ 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(struct ev_loop *loop, struct ev_signal* watcher, int revents)
{
lwsl_notice("Signal caught, exiting...\n");
force_exit = 1;
switch (watcher->signum) {
case SIGTERM:
case SIGINT:
ev_break(loop, EVBREAK_ALL);
break;
default:
signal(SIGABRT, SIG_DFL);
abort();
break;
}
}
static void
ev_timeout_cb (EV_P_ ev_timer *w, int revents)
{
lws_callback_on_writable_all_protocol(context,
&protocols[PROTOCOL_DUMB_INCREMENT]);
}
static struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "debug", required_argument, NULL, 'd' },
{ "port", required_argument, NULL, 'p' },
{ "ssl", no_argument, NULL, 's' },
{ "allow-non-ssl", no_argument, NULL, 'a' },
{ "interface", required_argument, NULL, 'i' },
{ "closetest", no_argument, NULL, 'c' },
{ "libev", no_argument, NULL, 'e' },
#ifndef LWS_NO_DAEMONIZE
{ "daemonize", no_argument, NULL, 'D' },
#endif
{ "resource_path", required_argument, NULL, 'r' },
{ NULL, 0, 0, 0 }
};
int main(int argc, char **argv)
{
int sigs[] = { SIGINT, SIGKILL, SIGTERM, SIGSEGV, SIGFPE };
struct ev_signal signals[ARRAY_SIZE(sigs)];
struct ev_loop *loop = ev_default_loop(0);
struct lws_context_creation_info info;
char interface_name[128] = "";
const char *iface = NULL;
ev_timer timeout_watcher;
char cert_path[1024];
char key_path[1024];
int use_ssl = 0;
int opts = 0;
int n = 0;
#ifndef _WIN32
int syslog_options = LOG_PID | LOG_PERROR;
#endif
#ifndef LWS_NO_DAEMONIZE
int daemonize = 0;
#endif
/*
* take care to zero down the info struct, he contains random garbaage
* from the stack otherwise
*/
memset(&info, 0, sizeof info);
info.port = 7681;
while (n >= 0) {
n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
if (n < 0)
continue;
switch (n) {
case 'e':
opts |= LWS_SERVER_OPTION_LIBEV;
break;
#ifndef LWS_NO_DAEMONIZE
case 'D':
daemonize = 1;
#ifndef _WIN32
syslog_options &= ~LOG_PERROR;
#endif
break;
#endif
case 'd':
debug_level = atoi(optarg);
break;
case 's':
use_ssl = 1;
break;
case 'a':
opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT;
break;
case 'p':
info.port = atoi(optarg);
break;
case 'i':
strncpy(interface_name, optarg, sizeof interface_name);
interface_name[(sizeof interface_name) - 1] = '\0';
iface = interface_name;
break;
case 'c':
close_testing = 1;
fprintf(stderr, " Close testing mode -- closes on "
"client after 50 dumb increments"
"and suppresses lws_mirror spam\n");
break;
case 'r':
resource_path = optarg;
printf("Setting resource path to \"%s\"\n", resource_path);
break;
case 'h':
fprintf(stderr, "Usage: test-server "
"[--port=<p>] [--ssl] "
"[-d <log bitfield>] "
"[--resource_path <path>]\n");
exit(1);
}
}
#if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
/*
* normally lock path would be /var/lock/lwsts or similar, to
* simplify getting started without having to take care about
* permissions or running as root, set to /tmp/.lwsts-lock
*/
if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
fprintf(stderr, "Failed to daemonize\n");
return 1;
}
#endif
for (n = 0; n < ARRAY_SIZE(sigs); n++) {
_ev_init(&signals[n], signal_cb);
ev_signal_set(&signals[n], sigs[n]);
ev_signal_start(loop, &signals[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);
info.iface = iface;
info.protocols = protocols;
info.extensions = exts;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
if (use_ssl) {
if (strlen(resource_path) > sizeof(cert_path) - 32) {
lwsl_err("resource path too long\n");
return -1;
}
sprintf(cert_path, "%s/libwebsockets-test-server.pem",
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);
info.ssl_cert_filepath = cert_path;
info.ssl_private_key_filepath = key_path;
}
info.gid = -1;
info.uid = -1;
info.max_http_header_pool = 1;
info.options = opts | LWS_SERVER_OPTION_LIBUV;
context = lws_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
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_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);
lws_context_destroy(context);
ev_loop_destroy(loop);
lwsl_notice("libwebsockets-test-server exited cleanly\n");
#ifndef _WIN32
closelog();
#endif
return 0;
}