Compare commits
5 commits
master
...
libuv-test
Author | SHA1 | Date | |
---|---|---|---|
![]() |
027fb683cc | ||
![]() |
86224b5093 | ||
![]() |
ba78cd36a6 | ||
![]() |
da408c0d2b | ||
![]() |
fa4619416e |
18 changed files with 824 additions and 80 deletions
|
@ -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}")
|
||||
|
|
|
@ -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.
|
||||
|
|
33
changelog
33
changelog
|
@ -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
|
||||
=======================
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
56
lib/libev.c
56
lib/libev.c
|
@ -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
176
lib/libuv.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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--) {
|
||||
|
|
20
lib/pollfd.c
20
lib/pollfd.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
373
test-server/test-server-libuv.c
Normal file
373
test-server/test-server-libuv.c
Normal 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;
|
||||
}
|
Loading…
Add table
Reference in a new issue