plugins
This adds support for dynamically loaded plugins at runtime, which can expose their own protocols or extensions transparently. With these changes lwsws defaults to OFF in cmake, and if enabled it automatically enables plugins and libuv support. Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
parent
09998e3ad8
commit
020770566e
23 changed files with 1247 additions and 71 deletions
|
@ -4,6 +4,7 @@ env:
|
|||
global:
|
||||
- secure: "KhAdQ9ja+LBObWNQTYO7Df5J4DyOih6S+eerDMu8UPSO+CoWV2pWoQzbOfocjyOscGOwC+2PrrHDNZyGfqkCLDXg1BxynXPCFerHC1yc2IajvKpGXmAAygNIvp4KACDfGv/dkXrViqIzr/CdcNaU4vIMHSVb5xkeLi0W1dPnQOI="
|
||||
matrix:
|
||||
- LWS_METHOD=lwsws CMAKE_ARGS="-DLWS_WITH_LWSWS=ON"
|
||||
- LWS_METHOD=default
|
||||
- LWS_METHOD=noserver CMAKE_ARGS="-DLWS_WITHOUT_SERVER=ON"
|
||||
- LWS_METHOD=noclient CMAKE_ARGS="-DLWS_WITHOUT_CLIENT=ON"
|
||||
|
@ -18,16 +19,18 @@ env:
|
|||
os:
|
||||
- linux
|
||||
- osx
|
||||
language: c
|
||||
language: generic
|
||||
install:
|
||||
- ./travis_install.sh
|
||||
script:
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then mkdir build && cd build && cmake $CMAKE_ARGS .. && cmake --build .; fi
|
||||
sudo: required
|
||||
dist: trusty
|
||||
addons:
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "warmcat/libwebsockets"
|
||||
notification_email: andy.green@linaro.org
|
||||
notification_email: andy@warmcat.com
|
||||
build_command_prepend: "mkdir build && cd build && cmake .."
|
||||
build_command: "cmake --build ."
|
||||
branch_pattern: coverity_scan
|
||||
|
|
|
@ -91,7 +91,14 @@ option(LWS_MBED3 "Platform is MBED3" OFF)
|
|||
option(LWS_SSL_SERVER_WITH_ECDH_CERT "Include SSL server use ECDH certificate" OFF)
|
||||
option(LWS_WITH_CGI "Include CGI (spawn process with network-connected stdin/out/err) APIs" OFF)
|
||||
option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying" OFF)
|
||||
option(LWS_WITH_LWSWS "Libwebsockets Webserver" ON)
|
||||
option(LWS_WITH_LWSWS "Libwebsockets Webserver" OFF)
|
||||
option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions" OFF)
|
||||
|
||||
if (LWS_WITH_LWSWS)
|
||||
message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV")
|
||||
set(LWS_WITH_PLUGINS 1)
|
||||
set(LWS_WITH_LIBUV 1)
|
||||
endif()
|
||||
|
||||
if (DEFINED YOTTA_WEBSOCKETS_VERSION_STRING)
|
||||
|
||||
|
@ -101,6 +108,7 @@ set(LWS_WITH_ZLIB OFF)
|
|||
set(LWS_WITHOUT_CLIENT ON)
|
||||
set(LWS_WITHOUT_TESTAPPS ON)
|
||||
set(LWS_WITHOUT_EXTENSIONS ON)
|
||||
set(LWS_WITH_PLUGINS OFF)
|
||||
set(LWS_MBED3 ON)
|
||||
# this implies no pthreads in the lib
|
||||
set(LWS_MAX_SMP 1)
|
||||
|
@ -110,6 +118,9 @@ endif()
|
|||
if (WIN32)
|
||||
# this implies no pthreads in the lib
|
||||
set(LWS_MAX_SMP 1)
|
||||
|
||||
# plugin stuff not implemented in win32 plat
|
||||
set (LWS_WITH_PLUGINS OFF)
|
||||
endif()
|
||||
|
||||
|
||||
|
@ -926,6 +937,10 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
|||
message("OpenSSL executable: ${OPENSSL_EXECUTABLE}")
|
||||
endif()
|
||||
|
||||
if (UNIX AND LWS_WITH_PLUGINS)
|
||||
set(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
|
||||
target_link_libraries(websockets dl)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_SERVER)
|
||||
#
|
||||
|
@ -1115,6 +1130,54 @@ if (NOT LWS_WITHOUT_TESTAPPS)
|
|||
endif()
|
||||
|
||||
endif(NOT LWS_WITHOUT_CLIENT)
|
||||
|
||||
|
||||
if (LWS_WITH_PLUGINS AND LWS_WITH_SHARED)
|
||||
macro(create_plugin PLUGIN_NAME MAIN_SRC)
|
||||
|
||||
set(PLUGIN_SRCS ${MAIN_SRC})
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND PLUGIN_SRCSset_property
|
||||
${WIN32_HELPERS_PATH}/getopt.c
|
||||
${WIN32_HELPERS_PATH}/getopt_long.c
|
||||
${WIN32_HELPERS_PATH}/gettimeofday.c
|
||||
)
|
||||
|
||||
list(APPEND PLUGIN_HDR
|
||||
${WIN32_HELPERS_PATH}/getopt.h
|
||||
${WIN32_HELPERS_PATH}/gettimeofday.h
|
||||
)
|
||||
endif(WIN32)
|
||||
|
||||
source_group("Headers Private" FILES ${PLUGIN_HDR})
|
||||
source_group("Sources" FILES ${PLUGIN_SRCS})
|
||||
add_library(${PLUGIN_NAME} SHARED ${PLUGIN_SRCS} ${PLUGIN_HDR})
|
||||
|
||||
target_link_libraries(${PLUGIN_NAME} websockets)
|
||||
add_dependencies(${PLUGIN_NAME} websockets)
|
||||
|
||||
# Set test app specific defines.
|
||||
set_property(TARGET ${PLUGIN_NAME}
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/plugins"
|
||||
)
|
||||
|
||||
# set_target_properties(${PLUGIN_NAME}
|
||||
# PROPERTIES
|
||||
# OUTPUT_NAME ${PLUGIN_NAME})
|
||||
|
||||
list(APPEND PLUGINS_LIST ${PLUGIN_NAME})
|
||||
endmacro()
|
||||
|
||||
|
||||
create_plugin(protocol_dumb_increment
|
||||
"plugins/protocol_dumb_increment.c")
|
||||
create_plugin(protocol_lws_mirror
|
||||
"plugins/protocol_lws_mirror.c")
|
||||
create_plugin(protocol_lws_status
|
||||
"plugins/protocol_lws_status.c")
|
||||
endif(LWS_WITH_PLUGINS AND LWS_WITH_SHARED)
|
||||
|
||||
#
|
||||
# Copy OpenSSL dlls to the output directory on Windows.
|
||||
|
@ -1318,6 +1381,15 @@ if (LWS_WITH_CGI)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
# plugins
|
||||
|
||||
if (LWS_WITH_PLUGINS)
|
||||
install(TARGETS ${PLUGINS_LIST}
|
||||
PERMISSIONS OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ
|
||||
DESTINATION share/libwebsockets-test-server/plugins
|
||||
COMPONENT plugins)
|
||||
endif()
|
||||
|
||||
# Install the LibwebsocketsConfig.cmake and LibwebsocketsConfigVersion.cmake
|
||||
install(FILES
|
||||
"${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LibwebsocketsConfig.cmake"
|
||||
|
@ -1379,6 +1451,7 @@ message(" LWS_WITH_CGI = ${LWS_WITH_CGI}")
|
|||
message(" LWS_HAVE_OPENSSL_ECDH_H = ${LWS_HAVE_OPENSSL_ECDH_H}")
|
||||
message(" LWS_WITH_HTTP_PROXY = ${LWS_WITH_HTTP_PROXY}")
|
||||
message(" LIBHUBBUB_LIBRARIES = ${LIBHUBBUB_LIBRARIES}")
|
||||
message(" PLUGINS = ${PLUGINS_LIST}")
|
||||
message("---------------------------------------------------------------------")
|
||||
|
||||
# These will be available to parent projects including libwebsockets using add_subdirectory()
|
||||
|
|
|
@ -4,6 +4,14 @@ Libwebsockets Web Server
|
|||
lwsws is an implementation of a very lightweight, ws-capable generic web
|
||||
server, which uses libwebsockets to implement everything underneath.
|
||||
|
||||
Build
|
||||
-----
|
||||
|
||||
Just enable -DLWS_WITH_LWSWS=1 at cmake-time.
|
||||
|
||||
It enables libuv and plugin support automatically.
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
|
@ -94,10 +102,12 @@ The vhost name field is used to match on incoming SNI or Host: header, so it
|
|||
must always be the host name used to reach the vhost externally.
|
||||
|
||||
Vhosts may have the same name and different ports, these will each create a
|
||||
listening socket on the appropriate port, and they may have the same port and
|
||||
different name: these will be treated as true vhosts on one listening socket
|
||||
and the active vhost decided at SSL negotiation time (via SNI) or if no SSL,
|
||||
then after the Host: header from the client has been parsed.
|
||||
listening socket on the appropriate port.
|
||||
|
||||
They may also have the same port and different name: these will be treated as
|
||||
true vhosts on one listening socket and the active vhost decided at SSL
|
||||
negotiation time (via SNI) or if no SSL, then after the Host: header from
|
||||
the client has been parsed.
|
||||
|
||||
|
||||
Mounts
|
||||
|
@ -107,4 +117,34 @@ Where mounts are given in the vhost definition, then directory contents may
|
|||
be auto-served if it matches the mountpoint.
|
||||
|
||||
Currently only file:// mount protocol and a fixed set of mimetypes are
|
||||
supported.
|
||||
supported.
|
||||
|
||||
|
||||
Plugins
|
||||
-------
|
||||
|
||||
Protcols and extensions may also be provided from "plugins", these are
|
||||
lightweight dynamic libraries. They are scanned for at init time, and
|
||||
any protocols and extensions found are added to the list given at context
|
||||
creation time.
|
||||
|
||||
Protocols receive init (LWS_CALLBACK_PROTOCOL_INIT) and destruction
|
||||
(LWS_CALLBACK_PROTOCOL_DESTROY) callbacks per-vhost, and there are arrangements
|
||||
they can make per-vhost allocations and get hold of the correct pointer from
|
||||
the wsi at the callback.
|
||||
|
||||
This allows a protocol to choose to strictly segregate data on a per-vhost
|
||||
basis, and also allows the plugin to handle its own initialization and
|
||||
context storage.
|
||||
|
||||
To help that happen conveniently, there are some new apis
|
||||
|
||||
- lws_vhost_get(wsi)
|
||||
- lws_protocol_get(wsi)
|
||||
- lws_callback_on_writable_all_protocol_vhost(vhost, protocol)
|
||||
- lws_protocol_vh_priv_zalloc(vhost, protocol, size)
|
||||
- lws_protocol_vh_priv_get(vhost, protocol)
|
||||
|
||||
dumb increment, mirror and status protocol plugins are provided as examples.
|
||||
|
||||
|
||||
|
|
213
lib/context.c
213
lib/context.c
|
@ -86,6 +86,86 @@ lws_write_http_mount(struct lws_http_mount *next, struct lws_http_mount **res,
|
|||
return ((char *)store + sizeof(*m)) - (char *)orig;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void *
|
||||
lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, const struct lws_protocols *prot,
|
||||
int size)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
/* allocate the vh priv array only on demand */
|
||||
if (!vhost->protocol_vh_privs) {
|
||||
vhost->protocol_vh_privs = (void **)lws_zalloc(
|
||||
vhost->count_protocols * sizeof(void *));
|
||||
if (!vhost->protocol_vh_privs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
|
||||
n++;
|
||||
|
||||
if (n == vhost->count_protocols)
|
||||
return NULL;
|
||||
|
||||
vhost->protocol_vh_privs[n] = lws_zalloc(size);
|
||||
return vhost->protocol_vh_privs[n];
|
||||
}
|
||||
|
||||
LWS_VISIBLE void *
|
||||
lws_protocol_vh_priv_get(struct lws_vhost *vhost, const struct lws_protocols *prot)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if (!vhost->protocol_vh_privs)
|
||||
return NULL;
|
||||
|
||||
while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
|
||||
n++;
|
||||
|
||||
if (n == vhost->count_protocols) {
|
||||
lwsl_err("%s: unknown protocol %p\n", __func__, prot);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vhost->protocol_vh_privs[n];
|
||||
}
|
||||
|
||||
int
|
||||
lws_protocol_init(struct lws_context *context)
|
||||
{
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
struct lws wsi;
|
||||
int n;
|
||||
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.context = context;
|
||||
|
||||
while (vh) {
|
||||
wsi.vhost = vh;
|
||||
|
||||
/* initialize supported protocols on this vhost */
|
||||
|
||||
for (n = 0; n < vh->count_protocols; n++) {
|
||||
wsi.protocol = &vh->protocols[n];
|
||||
|
||||
/*
|
||||
* inform all the protocols that they are doing their one-time
|
||||
* initialization if they want to.
|
||||
*
|
||||
* NOTE the wsi is all zeros except for the context, vh and
|
||||
* protocol ptrs so lws_get_context(wsi) etc can work
|
||||
*/
|
||||
vh->protocols[n].callback(&wsi,
|
||||
LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
context->protocol_init_done = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE struct lws_vhost *
|
||||
lws_create_vhost(struct lws_context *context,
|
||||
struct lws_context_creation_info *info,
|
||||
|
@ -93,9 +173,12 @@ lws_create_vhost(struct lws_context *context,
|
|||
{
|
||||
struct lws_vhost *vh = lws_zalloc(sizeof(*vh)),
|
||||
**vh1 = &context->vhost_list;
|
||||
struct lws wsi;
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
struct lws_plugin *plugin = context->plugin_list;
|
||||
struct lws_protocols *lwsp;
|
||||
int m;
|
||||
#endif
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
if (!vh)
|
||||
return NULL;
|
||||
|
@ -107,11 +190,38 @@ lws_create_vhost(struct lws_context *context,
|
|||
vh->name = info->vhost_name;
|
||||
|
||||
vh->iface = info->iface;
|
||||
vh->protocols = info->protocols;
|
||||
for (vh->count_protocols = 0;
|
||||
info->protocols[vh->count_protocols].callback;
|
||||
vh->count_protocols++)
|
||||
;
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (plugin) {
|
||||
/*
|
||||
* give the vhost a unified list of protocols including the
|
||||
* ones that came from plugins
|
||||
*/
|
||||
lwsp = lws_zalloc(sizeof(struct lws_protocols) *
|
||||
(vh->count_protocols +
|
||||
context->plugin_protocol_count + 1));
|
||||
if (!lwsp)
|
||||
return NULL;
|
||||
|
||||
m = vh->count_protocols;
|
||||
memcpy(lwsp, info->protocols,
|
||||
sizeof(struct lws_protocols) * m);
|
||||
while (plugin) {
|
||||
memcpy(&lwsp[m], plugin->caps.protocols,
|
||||
sizeof(struct lws_protocols) *
|
||||
plugin->caps.count_protocols);
|
||||
m += plugin->caps.count_protocols;
|
||||
vh->count_protocols += plugin->caps.count_protocols;
|
||||
plugin = plugin->list;
|
||||
}
|
||||
vh->protocols = lwsp;
|
||||
} else
|
||||
#endif
|
||||
vh->protocols = info->protocols;
|
||||
|
||||
|
||||
vh->mount_list = mounts;
|
||||
|
||||
|
@ -126,7 +236,35 @@ lws_create_vhost(struct lws_context *context,
|
|||
}
|
||||
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
vh->extensions = info->extensions;
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (context->plugin_extension_count) {
|
||||
|
||||
m = 0;
|
||||
while (info->extensions && info->extensions[m].callback)
|
||||
m++;
|
||||
|
||||
/*
|
||||
* give the vhost a unified list of extensions including the
|
||||
* ones that came from plugins
|
||||
*/
|
||||
vh->extensions = lws_zalloc(sizeof(struct lws_extension) *
|
||||
(m +
|
||||
context->plugin_extension_count + 1));
|
||||
if (!vh->extensions)
|
||||
return NULL;
|
||||
|
||||
memcpy((struct lws_extension *)vh->extensions, info->extensions,
|
||||
sizeof(struct lws_extension) * m);
|
||||
while (plugin) {
|
||||
memcpy((struct lws_extension *)&vh->extensions[m], plugin->caps.extensions,
|
||||
sizeof(struct lws_extension) *
|
||||
plugin->caps.count_extensions);
|
||||
m += plugin->caps.count_extensions;
|
||||
plugin = plugin->list;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
vh->extensions = info->extensions;
|
||||
#endif
|
||||
|
||||
vh->listen_port = info->port;
|
||||
|
@ -148,23 +286,6 @@ lws_create_vhost(struct lws_context *context,
|
|||
#endif
|
||||
}
|
||||
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.context = context;
|
||||
wsi.vhost = vh;
|
||||
|
||||
/* initialize supported protocols */
|
||||
|
||||
for (n = 0; n < vh->count_protocols; n++)
|
||||
/*
|
||||
* inform all the protocols that they are doing their one-time
|
||||
* initialization if they want to.
|
||||
*
|
||||
* NOTE the wsi is all zeros except for the context & vh ptrs
|
||||
* so lws_get_context(wsi) can work in the callback.
|
||||
*/
|
||||
info->protocols[n].callback(&wsi,
|
||||
LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);
|
||||
|
||||
vh->ka_time = info->ka_time;
|
||||
vh->ka_interval = info->ka_interval;
|
||||
vh->ka_probes = info->ka_probes;
|
||||
|
@ -467,7 +588,7 @@ lws_context_destroy(struct lws_context *context)
|
|||
{
|
||||
const struct lws_protocols *protocol = NULL;
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_vhost *vh;
|
||||
struct lws_vhost *vh, *vh1;
|
||||
struct lws wsi;
|
||||
int n, m;
|
||||
|
||||
|
@ -514,18 +635,25 @@ lws_context_destroy(struct lws_context *context)
|
|||
|
||||
/*
|
||||
* inform all the protocols that they are done and will have no more
|
||||
* callbacks
|
||||
* callbacks.
|
||||
*
|
||||
* We can't free things until after the event loop shuts down.
|
||||
*/
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
wsi.vhost = vh;
|
||||
protocol = vh->protocols;
|
||||
if (protocol)
|
||||
while (protocol->callback) {
|
||||
if (protocol) {
|
||||
n = 0;
|
||||
while (n < vh->count_protocols) {
|
||||
wsi.protocol = protocol;
|
||||
protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
|
||||
NULL, NULL, 0);
|
||||
protocol++;
|
||||
n++;
|
||||
}
|
||||
lws_ssl_SSL_CTX_destroy(vh);
|
||||
}
|
||||
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
|
@ -547,6 +675,39 @@ lws_context_destroy(struct lws_context *context)
|
|||
if (context->pt[0].fds)
|
||||
lws_free_set_NULL(context->pt[0].fds);
|
||||
|
||||
/* free all the vhost allocations */
|
||||
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
protocol = vh->protocols;
|
||||
if (protocol) {
|
||||
n = 0;
|
||||
while (n < vh->count_protocols) {
|
||||
if (vh->protocol_vh_privs &&
|
||||
vh->protocol_vh_privs[n]) {
|
||||
lws_free(vh->protocol_vh_privs[n]);
|
||||
vh->protocol_vh_privs[n] = NULL;
|
||||
}
|
||||
protocol++;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (vh->protocol_vh_privs)
|
||||
lws_free(vh->protocol_vh_privs);
|
||||
lws_ssl_SSL_CTX_destroy(vh);
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (context->plugin_list)
|
||||
lws_free((void *)vh->protocols);
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
if (context->plugin_extension_count)
|
||||
lws_free((void *)vh->extensions);
|
||||
#endif
|
||||
#endif
|
||||
vh1 = vh->vhost_next;
|
||||
lws_free(vh);
|
||||
vh = vh1;
|
||||
}
|
||||
|
||||
lws_plat_context_late_destroy(context);
|
||||
|
||||
lws_free(context);
|
||||
|
|
|
@ -32,7 +32,7 @@ void lws_feature_status_libev(struct lws_context_creation_info *info)
|
|||
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 *lws_io = lws_container_of(watcher,
|
||||
struct lws_io_watcher, ev_watcher);
|
||||
struct lws_context *context = lws_io->context;
|
||||
struct lws_pollfd eventfd;
|
||||
|
|
30
lib/libuv.c
30
lib/libuv.c
|
@ -31,9 +31,13 @@ lws_feature_status_libuv(struct lws_context_creation_info *info)
|
|||
}
|
||||
|
||||
static void
|
||||
lws_uv_idle(uv_idle_t *handle)
|
||||
lws_uv_idle(uv_idle_t *handle
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct lws_context_per_thread *pt = container_of(handle,
|
||||
struct lws_context_per_thread *pt = lws_container_of(handle,
|
||||
struct lws_context_per_thread, uv_idle);
|
||||
|
||||
lwsl_debug("%s\n", __func__);
|
||||
|
@ -57,9 +61,9 @@ lws_uv_idle(uv_idle_t *handle)
|
|||
static void
|
||||
lws_io_cb(uv_poll_t *watcher, int status, int revents)
|
||||
{
|
||||
struct lws_io_watcher *lws_io = container_of(watcher,
|
||||
struct lws_io_watcher *lws_io = lws_container_of(watcher,
|
||||
struct lws_io_watcher, uv_watcher);
|
||||
struct lws *wsi = container_of(lws_io, struct lws, w_read);
|
||||
struct lws *wsi = lws_container_of(lws_io, struct lws, w_read);
|
||||
struct lws_context *context = lws_io->context;
|
||||
struct lws_pollfd eventfd;
|
||||
|
||||
|
@ -117,9 +121,13 @@ lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
|
|||
}
|
||||
|
||||
static void
|
||||
lws_uv_timeout_cb(uv_timer_t *timer)
|
||||
lws_uv_timeout_cb(uv_timer_t *timer
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct lws_context_per_thread *pt = container_of(timer,
|
||||
struct lws_context_per_thread *pt = lws_container_of(timer,
|
||||
struct lws_context_per_thread, uv_timeout_watcher);
|
||||
|
||||
lwsl_debug("%s\n", __func__);
|
||||
|
@ -138,7 +146,12 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)
|
|||
|
||||
if (!loop) {
|
||||
loop = lws_malloc(sizeof(*loop));
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
uv_loop_init(loop);
|
||||
#else
|
||||
lwsl_err("This libuv is too old to work...\n");
|
||||
return 1;
|
||||
#endif
|
||||
pt->ev_loop_foreign = 0;
|
||||
} else
|
||||
pt->ev_loop_foreign = 1;
|
||||
|
@ -217,9 +230,11 @@ lws_libuv_destroyloop(struct lws_context *context, int tsi)
|
|||
uv_stop(pt->io_loop_uv);
|
||||
uv_walk(pt->io_loop_uv, lws_uv_walk_cb, NULL);
|
||||
while (uv_run(pt->io_loop_uv, UV_RUN_NOWAIT));
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
m = uv_loop_close(pt->io_loop_uv);
|
||||
if (m == UV_EBUSY)
|
||||
lwsl_debug("%s: uv_loop_close: UV_EBUSY\n", __func__);
|
||||
#endif
|
||||
lws_free(pt->io_loop_uv);
|
||||
}
|
||||
}
|
||||
|
@ -298,9 +313,8 @@ lws_libuv_init_fd_table(struct lws_context *context)
|
|||
if (!LWS_LIBUV_ENABLED(context))
|
||||
return 0;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
context->pt[n].w_sigint.context = context;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -707,6 +707,18 @@ lws_context_user(struct lws_context *context)
|
|||
return context->user_space;
|
||||
}
|
||||
|
||||
LWS_VISIBLE struct lws_vhost *
|
||||
lws_vhost_get(struct lws *wsi)
|
||||
{
|
||||
return wsi->vhost;
|
||||
}
|
||||
|
||||
LWS_VISIBLE const struct lws_protocols *
|
||||
lws_protocol_get(struct lws *wsi)
|
||||
{
|
||||
return wsi->protocol;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* lws_callback_all_protocol() - Callback all connections using
|
||||
|
@ -739,6 +751,39 @@ lws_callback_all_protocol(struct lws_context *context,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* lws_callback_all_protocol_vhost() - Callback all connections using
|
||||
* the given protocol with the given reason
|
||||
*
|
||||
* @vh: Vhost whose connections will get callbacks
|
||||
* @protocol: Which protocol to match
|
||||
* @reason: Callback reason index
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
|
||||
const struct lws_protocols *protocol, int reason)
|
||||
{
|
||||
struct lws_context *context = vh->context;
|
||||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
unsigned int n, m = context->count_threads;
|
||||
struct lws *wsi;
|
||||
|
||||
while (m--) {
|
||||
for (n = 0; n < pt->fds_count; n++) {
|
||||
wsi = wsi_from_fd(context, pt->fds[n].fd);
|
||||
if (!wsi)
|
||||
continue;
|
||||
if (wsi->vhost == vh && wsi->protocol == protocol)
|
||||
protocol->callback(wsi, reason, wsi->user_space,
|
||||
NULL, 0);
|
||||
}
|
||||
pt++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LWS_POSIX
|
||||
|
||||
/**
|
||||
|
|
|
@ -280,6 +280,14 @@ LWS_VISIBLE LWS_EXTERN void lwsl_hexdump(void *buf, size_t len);
|
|||
#define lwsl_hexdump(a, b)
|
||||
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef lws_container_of
|
||||
#define lws_container_of(P,T,M) ((T *)((char *)(P) - offsetof(T, M)))
|
||||
#endif
|
||||
|
||||
|
||||
struct lws;
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
|
@ -1293,6 +1301,26 @@ struct lws_extension {
|
|||
* This is part of the ABI, don't needlessly break compatibility */
|
||||
};
|
||||
|
||||
#define LWS_PLUGIN_API_MAGIC 180
|
||||
|
||||
struct lws_plugin_capability {
|
||||
unsigned int api_magic; /* caller fills this in, plugin fills rest */
|
||||
const struct lws_protocols *protocols;
|
||||
int count_protocols;
|
||||
const struct lws_extension *extensions;
|
||||
int count_extensions;
|
||||
};
|
||||
|
||||
typedef int (*lws_plugin_init_func)(struct lws_context *,
|
||||
struct lws_plugin_capability *);
|
||||
typedef int (*lws_plugin_destroy_func)(struct lws_context *);
|
||||
struct lws_plugin {
|
||||
struct lws_plugin *list;
|
||||
void *l;
|
||||
char name[64];
|
||||
struct lws_plugin_capability caps;
|
||||
};
|
||||
|
||||
/*
|
||||
* The internal exts are part of the public abi
|
||||
* If we add more extensions, publish the callback here ------v
|
||||
|
@ -1414,6 +1442,7 @@ struct lws_context_creation_info {
|
|||
unsigned int timeout_secs; /* VH */
|
||||
const char *ecdh_curve; /* VH */
|
||||
const char *vhost_name; /* VH */
|
||||
const char *plugins_dir; /* context */
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility
|
||||
|
@ -1505,6 +1534,18 @@ lws_create_vhost(struct lws_context *context,
|
|||
struct lws_context_creation_info *info,
|
||||
struct lws_http_mount *mounts);
|
||||
|
||||
LWS_VISIBLE struct lws_vhost *
|
||||
lws_vhost_get(struct lws *wsi);
|
||||
|
||||
LWS_VISIBLE const struct lws_protocols *
|
||||
lws_protocol_get(struct lws *wsi);
|
||||
|
||||
LWS_VISIBLE void *
|
||||
lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost, const struct lws_protocols *prot,
|
||||
int size);
|
||||
LWS_VISIBLE void *
|
||||
lws_protocol_vh_priv_get(struct lws_vhost *vhost, const struct lws_protocols *prot);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_finalize_startup(struct lws_context *context);
|
||||
|
||||
|
@ -1740,10 +1781,18 @@ LWS_VISIBLE LWS_EXTERN int
|
|||
lws_callback_on_writable_all_protocol(const struct lws_context *context,
|
||||
const struct lws_protocols *protocol);
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
|
||||
const struct lws_protocols *protocol);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_callback_all_protocol(struct lws_context *context,
|
||||
const struct lws_protocols *protocol, int reason);
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_all_protocol_vhost(struct lws_vhost *vh,
|
||||
const struct lws_protocols *protocol, int reason);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_get_socket_fd(struct lws *wsi);
|
||||
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
|
||||
|
||||
/*
|
||||
* included from libwebsockets.c for unix builds
|
||||
*/
|
||||
|
@ -294,6 +298,141 @@ lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
|
||||
static int filter(const struct dirent *ent)
|
||||
{
|
||||
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_plugins_init(struct lws_context * context, const char *d)
|
||||
{
|
||||
struct lws_plugin_capability lcaps;
|
||||
struct lws_plugin *plugin;
|
||||
lws_plugin_init_func initfunc;
|
||||
struct dirent **namelist;
|
||||
int n, i, m, ret = 0;
|
||||
char path[256];
|
||||
void *l;
|
||||
|
||||
|
||||
n = scandir(d, &namelist, filter, alphasort);
|
||||
if (n < 0) {
|
||||
lwsl_err("Scandir on %d failed\n", d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_notice(" Plugins:\n");
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (strlen(namelist[i]->d_name) < 7)
|
||||
goto inval;
|
||||
|
||||
lwsl_notice(" %s\n", namelist[i]->d_name);
|
||||
|
||||
snprintf(path, sizeof(path) - 1, "%s/%s", d,
|
||||
namelist[i]->d_name);
|
||||
l = dlopen(path, RTLD_NOW);
|
||||
if (!l) {
|
||||
lwsl_err("Error loading DSO: %s\n", dlerror());
|
||||
while (i++ < n)
|
||||
free(namelist[i]);
|
||||
goto bail;
|
||||
}
|
||||
/* we could open it, can we get his init function? */
|
||||
m = snprintf(path, sizeof(path) - 1, "init_%s",
|
||||
namelist[i]->d_name + 3 /* snip lib... */);
|
||||
path[m - 3] = '\0'; /* snip the .so */
|
||||
initfunc = dlsym(l, path);
|
||||
if (!initfunc) {
|
||||
lwsl_err("Failed to get init on %s: %s",
|
||||
namelist[i]->d_name, dlerror());
|
||||
dlclose(l);
|
||||
}
|
||||
lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
|
||||
m = initfunc(context, &lcaps);
|
||||
if (m) {
|
||||
lwsl_err("Initializing %s failed %d\n",
|
||||
namelist[i]->d_name, m);
|
||||
dlclose(l);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
plugin = lws_malloc(sizeof(*plugin));
|
||||
if (!plugin) {
|
||||
lwsl_err("OOM\n");
|
||||
goto bail;
|
||||
}
|
||||
plugin->list = context->plugin_list;
|
||||
context->plugin_list = plugin;
|
||||
strncpy(plugin->name, namelist[i]->d_name, sizeof(plugin->name) - 1);
|
||||
plugin->name[sizeof(plugin->name) - 1] = '\0';
|
||||
plugin->l = l;
|
||||
plugin->caps = lcaps;
|
||||
context->plugin_protocol_count += lcaps.count_protocols;
|
||||
context->plugin_extension_count += lcaps.count_extensions;
|
||||
|
||||
free(namelist[i]);
|
||||
continue;
|
||||
|
||||
skip:
|
||||
dlclose(l);
|
||||
inval:
|
||||
free(namelist[i]);
|
||||
}
|
||||
|
||||
bail:
|
||||
free(namelist);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_plugins_destroy(struct lws_context * context)
|
||||
{
|
||||
struct lws_plugin *plugin = context->plugin_list, *p;
|
||||
lws_plugin_destroy_func func;
|
||||
char path[256];
|
||||
int m;
|
||||
|
||||
if (!plugin)
|
||||
return 0;
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
while (plugin) {
|
||||
p = plugin;
|
||||
m = snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
|
||||
path[m - 3] = '\0';
|
||||
func = dlsym(plugin->l, path);
|
||||
if (!func) {
|
||||
lwsl_err("Failed to get destroy on %s: %s",
|
||||
plugin->name, dlerror());
|
||||
goto next;
|
||||
}
|
||||
m = func(context);
|
||||
if (m)
|
||||
lwsl_err("Initializing %s failed %d\n",
|
||||
plugin->name, m);
|
||||
next:
|
||||
dlclose(p->l);
|
||||
plugin = p->list;
|
||||
p->list = NULL;
|
||||
free(p);
|
||||
}
|
||||
|
||||
context->plugin_list = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
sigpipe_handler(int x)
|
||||
{
|
||||
|
@ -326,6 +465,11 @@ lws_plat_context_late_destroy(struct lws_context *context)
|
|||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
int m = context->count_threads;
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (context->plugin_list)
|
||||
lws_plat_plugins_destroy(context);
|
||||
#endif
|
||||
|
||||
if (context->lws_lookup)
|
||||
lws_free(context->lws_lookup);
|
||||
|
||||
|
@ -513,6 +657,7 @@ _lws_plat_file_write(struct lws *wsi, lws_filefd_type fd, unsigned long *amount,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_plat_init(struct lws_context *context,
|
||||
struct lws_context_creation_info *info)
|
||||
|
@ -565,5 +710,10 @@ lws_plat_init(struct lws_context *context,
|
|||
context->fops.read = _lws_plat_file_read;
|
||||
context->fops.write = _lws_plat_file_write;
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (info->plugins_dir)
|
||||
lws_plat_plugins_init(context, info->plugins_dir);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
34
lib/pollfd.c
34
lib/pollfd.c
|
@ -374,3 +374,37 @@ lws_callback_on_writable_all_protocol(const struct lws_context *context,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* lws_callback_on_writable_all_protocol_vhost() - Request a callback for
|
||||
* all connections using the given protocol when it
|
||||
* becomes possible to write to each socket without
|
||||
* blocking in turn.
|
||||
*
|
||||
* @vhost: Only consider connections on this lws_vhost
|
||||
* @protocol: Protocol whose connections will get callbacks
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
|
||||
const struct lws_protocols *protocol)
|
||||
{
|
||||
const struct lws_context *context = vhost->context;
|
||||
const struct lws_context_per_thread *pt = &context->pt[0];
|
||||
unsigned int n, m = context->count_threads;
|
||||
struct lws *wsi;
|
||||
|
||||
while (m--) {
|
||||
for (n = 0; n < pt->fds_count; n++) {
|
||||
wsi = wsi_from_fd(context, pt->fds[n].fd);
|
||||
if (!wsi)
|
||||
continue;
|
||||
if (wsi->vhost == vhost && wsi->protocol == protocol)
|
||||
lws_callback_on_writable(wsi);
|
||||
}
|
||||
pt++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -261,12 +261,6 @@ typedef unsigned __int64 u_int64_t;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(P,T,M) ((T *)((char *)(P) - offsetof(T, M)))
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
@ -283,11 +277,6 @@ typedef unsigned __int64 u_int64_t;
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(P,T,M) ((T *)((char *)(P) - offsetof(T, M)))
|
||||
#endif
|
||||
|
||||
#if defined(__QNX__)
|
||||
#include <gulliver.h>
|
||||
|
@ -664,6 +653,7 @@ struct lws_vhost {
|
|||
const char *name;
|
||||
const char *iface;
|
||||
const struct lws_protocols *protocols;
|
||||
void **protocol_vh_privs;
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL_CTX *ssl_client_ctx;
|
||||
|
@ -704,6 +694,7 @@ struct lws_context {
|
|||
struct lws **lws_lookup; /* fd to wsi */
|
||||
#endif
|
||||
struct lws_vhost *vhost_list;
|
||||
struct lws_plugin *plugin_list;
|
||||
const struct lws_token_limits *token_limits;
|
||||
void *user_space;
|
||||
|
||||
|
@ -755,9 +746,12 @@ struct lws_context {
|
|||
short max_http_header_data;
|
||||
short max_http_header_pool;
|
||||
short count_threads;
|
||||
short plugin_protocol_count;
|
||||
short plugin_extension_count;
|
||||
|
||||
unsigned int being_destroyed:1;
|
||||
unsigned int requested_kill:1;
|
||||
unsigned int protocol_init_done:1;
|
||||
};
|
||||
|
||||
#define lws_get_context_protocol(ctx, x) ctx->vhost_list->protocols[x]
|
||||
|
@ -1671,6 +1665,9 @@ lws_get_addresses(struct lws_context *context, void *ads, char *name,
|
|||
LWS_EXTERN int
|
||||
lws_cgi_kill_terminated(struct lws_context_per_thread *pt);
|
||||
|
||||
int
|
||||
lws_protocol_init(struct lws_context *context);
|
||||
|
||||
/*
|
||||
* custom allocator
|
||||
*/
|
||||
|
|
|
@ -194,6 +194,9 @@ static const char * get_mimetype(const char *file)
|
|||
if (!strcmp(&file[n - 4], ".png"))
|
||||
return "image/png";
|
||||
|
||||
if (!strcmp(&file[n - 4], ".jpg"))
|
||||
return "image/jpeg";
|
||||
|
||||
if (!strcmp(&file[n - 5], ".html"))
|
||||
return "text/html";
|
||||
|
||||
|
@ -220,7 +223,7 @@ int lws_http_serve(struct lws *wsi, char *uri, const char *origin)
|
|||
}
|
||||
|
||||
n = lws_serve_http_file(wsi, path, mimetype, NULL, 0);
|
||||
if (n < 0)
|
||||
|
||||
if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
|
||||
return -1; /* error or can't reuse connection: close the socket */
|
||||
|
||||
|
|
|
@ -637,6 +637,9 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, int t
|
|||
int n = 0, m;
|
||||
int more;
|
||||
|
||||
if (!context->protocol_init_done)
|
||||
lws_protocol_init(context);
|
||||
|
||||
/*
|
||||
* you can call us with pollfd = NULL to just allow the once-per-second
|
||||
* global timeout checks; if less than a second since the last check
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#cmakedefine LWS_USE_MBEDTLS
|
||||
#cmakedefine LWS_USE_POLARSSL
|
||||
|
||||
#cmakedefine LWS_WITH_PLUGINS
|
||||
|
||||
/* The Libwebsocket version */
|
||||
#cmakedefine LWS_LIBRARY_VERSION "${LWS_LIBRARY_VERSION}"
|
||||
|
||||
|
|
14
lwsws/etc-lwsws-conf-EXAMPLE
Normal file
14
lwsws/etc-lwsws-conf-EXAMPLE
Normal file
|
@ -0,0 +1,14 @@
|
|||
# these are the server global settings
|
||||
# stuff related to vhosts should go in one
|
||||
# file per vhost in ../conf.d/
|
||||
|
||||
{
|
||||
"global": {
|
||||
"uid": "99",
|
||||
"gid": "99",
|
||||
"interface": "eth0",
|
||||
"count-threads": "1",
|
||||
"init-ssl": "yes"
|
||||
}
|
||||
}
|
||||
|
50
lwsws/etc-lwsws-conf.d-libwebsockets.org-EXAMPLE
Normal file
50
lwsws/etc-lwsws-conf.d-libwebsockets.org-EXAMPLE
Normal file
|
@ -0,0 +1,50 @@
|
|||
# comment
|
||||
|
||||
{
|
||||
"vhosts": [ {
|
||||
"name": "libwebsockets.org",
|
||||
"port": "443",
|
||||
"host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key",
|
||||
"host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt",
|
||||
"host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer",
|
||||
"mounts": [{
|
||||
"mountpoint": "/",
|
||||
"origin": "file:///var/www/libwebsockets.org",
|
||||
"default": "index.html"
|
||||
}, {
|
||||
"mountpoint": "/git",
|
||||
"origin": "http://git.warmcat.com",
|
||||
"default": "/"
|
||||
}, {
|
||||
"mountpoint": "/mailman",
|
||||
"origin": "cgi://usr/lib/mailman/cgi-bin/",
|
||||
"default": "/list-info"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "libwebsockets.org", # disambiguated by port, must be same for SNI
|
||||
"port": "7681",
|
||||
"host-ssl-key": "/etc/pki/tls/private/libwebsockets.org.key",
|
||||
"host-ssl-cert": "/etc/pki/tls/certs/libwebsockets.org.crt",
|
||||
"host-ssl-ca": "/etc/pki/tls/certs/libwebsockets.org.cer",
|
||||
"ws-protocols": [{
|
||||
"wsprotocol": "dumb-increment-protocol",
|
||||
"wsprotocol": "lws-mirror-protocol",
|
||||
"wsprotocol": "lws-status"
|
||||
}],
|
||||
"ws-extensions": [{
|
||||
"extension": "permessage-deflate"
|
||||
}],
|
||||
"mounts": [{
|
||||
"mountpoint": "/",
|
||||
"origin": "file:///usr/local/share/libwebsockets-test-server",
|
||||
"default": "test.html"
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "libwebsockets.org",
|
||||
"port": "80",
|
||||
"global-redirect": "https://libwebsockets.org"
|
||||
}]
|
||||
}
|
||||
|
|
@ -47,6 +47,9 @@ const char * get_mimetype(const char *file)
|
|||
if (!strcmp(&file[n - 4], ".png"))
|
||||
return "image/png";
|
||||
|
||||
if (!strcmp(&file[n - 4], ".jpg"))
|
||||
return "image/jpeg";
|
||||
|
||||
if (!strcmp(&file[n - 5], ".html"))
|
||||
return "text/html";
|
||||
|
||||
|
@ -190,7 +193,7 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
|||
return 0;
|
||||
|
||||
/* check for the "send a big file by hand" example case */
|
||||
|
||||
lwsl_notice("%s\n", in);
|
||||
if (!strcmp((const char *)in, "/leaf.jpg")) {
|
||||
if (strlen(resource_path) > sizeof(leaf_path) - 10)
|
||||
return -1;
|
||||
|
|
21
lwsws/main.c
21
lwsws/main.c
|
@ -62,6 +62,7 @@ static struct lws_protocols protocols[] = {
|
|||
sizeof (struct per_session_data__http), /* per_session_data_size */
|
||||
0, /* max frame size / rx buffer */
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
void sighandler(int sig)
|
||||
|
@ -177,17 +178,16 @@ int main(int argc, char **argv)
|
|||
|
||||
info.max_http_header_pool = 16;
|
||||
info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 |
|
||||
LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
|
||||
#ifdef LWS_USE_LIBUV
|
||||
info.options |= LWS_SERVER_OPTION_LIBUV;
|
||||
#endif
|
||||
LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
|
||||
LWS_SERVER_OPTION_LIBUV;
|
||||
|
||||
info.plugins_dir = INSTALL_DATADIR"/libwebsockets-test-server/plugins/";
|
||||
|
||||
lwsl_notice("Using config dir: \"%s\"\n", config_dir);
|
||||
|
||||
/*
|
||||
* first go through the config for creating the outer context
|
||||
*/
|
||||
|
||||
if (lwsws_get_config_globals(&info, config_dir, &cs, &cs_len))
|
||||
goto bail;
|
||||
|
||||
|
@ -214,21 +214,14 @@ int main(int argc, char **argv)
|
|||
if (lwsws_get_config_vhosts(context, &info, config_dir, &cs, &cs_len))
|
||||
goto bail;
|
||||
|
||||
#ifdef LWS_USE_LIBUV
|
||||
lws_uv_sigint_cfg(context, 1, signal_cb);
|
||||
lws_uv_initloop(context, NULL, 0);
|
||||
lws_libuv_run(context, 0);
|
||||
#else
|
||||
|
||||
n = 0;
|
||||
while (n >= 0 && !force_exit) {
|
||||
n = lws_service(context, 50);
|
||||
}
|
||||
#endif
|
||||
lws_libuv_run(context, 0);
|
||||
|
||||
bail:
|
||||
lws_context_destroy(context);
|
||||
lwsl_notice("lwsws exited cleanly\n");
|
||||
fprintf(stderr, "lwsws exited cleanly\n");
|
||||
|
||||
#ifndef _WIN32
|
||||
closelog();
|
||||
|
|
141
plugins/protocol_dumb_increment.c
Normal file
141
plugins/protocol_dumb_increment.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* ws protocol handler plugin for "dumb increment"
|
||||
*
|
||||
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* The person who associated a work with this deed has dedicated
|
||||
* the work to the public domain by waiving all of his or her rights
|
||||
* to the work worldwide under copyright law, including all related
|
||||
* and neighboring rights, to the extent allowed by law. You can copy,
|
||||
* modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
*
|
||||
* These test plugins are intended to be adapted for use in your code, which
|
||||
* may be proprietary. So unlike the library itself, they are licensed
|
||||
* Public Domain.
|
||||
*/
|
||||
#include "../lib/libwebsockets.h"
|
||||
|
||||
struct per_vhost_data__dumb_increment {
|
||||
uv_timer_t timeout_watcher;
|
||||
struct lws_context *context;
|
||||
struct lws_vhost *vhost;
|
||||
const struct lws_protocols *protocol;
|
||||
};
|
||||
|
||||
struct per_session_data__dumb_increment {
|
||||
int number;
|
||||
};
|
||||
|
||||
static void
|
||||
uv_timeout_cb_dumb_increment(uv_timer_t *w
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct per_vhost_data__dumb_increment *vhd = lws_container_of(w,
|
||||
struct per_vhost_data__dumb_increment, timeout_watcher);
|
||||
lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
|
||||
}
|
||||
|
||||
static int
|
||||
callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__dumb_increment *pss =
|
||||
(struct per_session_data__dumb_increment *)user;
|
||||
struct per_vhost_data__dumb_increment *vhd =
|
||||
(struct per_vhost_data__dumb_increment *)
|
||||
lws_protocol_vh_priv_get(lws_vhost_get(wsi),
|
||||
lws_protocol_get(wsi));
|
||||
unsigned char buf[LWS_PRE + 512];
|
||||
unsigned char *p = &buf[LWS_PRE];
|
||||
int n, m;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
vhd = lws_protocol_vh_priv_zalloc(lws_vhost_get(wsi),
|
||||
lws_protocol_get(wsi),
|
||||
sizeof(struct per_vhost_data__dumb_increment));
|
||||
vhd->context = lws_get_context(wsi);
|
||||
vhd->protocol = lws_protocol_get(wsi);
|
||||
vhd->vhost = lws_vhost_get(wsi);
|
||||
uv_timer_init(lws_uv_getloop(vhd->context, 0),
|
||||
&vhd->timeout_watcher);
|
||||
uv_timer_start(&vhd->timeout_watcher,
|
||||
uv_timeout_cb_dumb_increment, 50, 50);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY:
|
||||
uv_timer_stop(&vhd->timeout_watcher);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
pss->number = 0;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
n = sprintf((char *)p, "%d", pss->number++);
|
||||
m = lws_write(wsi, p, n, LWS_WRITE_TEXT);
|
||||
if (m < n) {
|
||||
lwsl_err("ERROR %d writing to di socket\n", n);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
if (len < 6)
|
||||
break;
|
||||
if (strcmp((const char *)in, "reset\n") == 0)
|
||||
pss->number = 0;
|
||||
if (strcmp((const char *)in, "closeme\n") == 0) {
|
||||
lwsl_notice("dumb_inc: closing as requested\n");
|
||||
lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY,
|
||||
(unsigned char *)"seeya", 5);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lws_protocols protocols[] = {
|
||||
{
|
||||
"dumb-increment-protocol",
|
||||
callback_dumb_increment,
|
||||
sizeof(struct per_session_data__dumb_increment),
|
||||
10, /* rx buf size must be >= permessage-deflate rx size */
|
||||
},
|
||||
};
|
||||
|
||||
LWS_VISIBLE int
|
||||
init_protocol_dumb_increment(struct lws_context *context,
|
||||
struct lws_plugin_capability *c)
|
||||
{
|
||||
if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
|
||||
lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
|
||||
c->api_magic);
|
||||
return 1;
|
||||
}
|
||||
|
||||
c->protocols = protocols;
|
||||
c->count_protocols = ARRAY_SIZE(protocols);
|
||||
c->extensions = NULL;
|
||||
c->count_extensions = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
destroy_protocol_dumb_increment(struct lws_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
177
plugins/protocol_lws_mirror.c
Normal file
177
plugins/protocol_lws_mirror.c
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* libwebsockets-test-server - libwebsockets test implementation
|
||||
*
|
||||
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* The person who associated a work with this deed has dedicated
|
||||
* the work to the public domain by waiving all of his or her rights
|
||||
* to the work worldwide under copyright law, including all related
|
||||
* and neighboring rights, to the extent allowed by law. You can copy,
|
||||
* modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
*
|
||||
* The test apps are intended to be adapted for use in your code, which
|
||||
* may be proprietary. So unlike the library itself, they are licensed
|
||||
* Public Domain.
|
||||
*/
|
||||
#include "../lib/libwebsockets.h"
|
||||
|
||||
/* lws-mirror_protocol */
|
||||
|
||||
#define MAX_MESSAGE_QUEUE 512
|
||||
|
||||
struct per_session_data__lws_mirror {
|
||||
struct lws *wsi;
|
||||
int ringbuffer_tail;
|
||||
};
|
||||
|
||||
struct a_message {
|
||||
void *payload;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct per_vhost_data__lws_mirror {
|
||||
struct a_message ringbuffer[MAX_MESSAGE_QUEUE];
|
||||
int ringbuffer_head;
|
||||
};
|
||||
|
||||
static int
|
||||
callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__lws_mirror *pss =
|
||||
(struct per_session_data__lws_mirror *)user;
|
||||
struct per_vhost_data__lws_mirror *v =
|
||||
(struct per_vhost_data__lws_mirror *)
|
||||
lws_protocol_vh_priv_get(lws_vhost_get(wsi),
|
||||
lws_protocol_get(wsi));
|
||||
int n, m;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
|
||||
pss->ringbuffer_tail = v->ringbuffer_head;
|
||||
pss->wsi = wsi;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */
|
||||
lws_protocol_vh_priv_zalloc(lws_vhost_get(wsi),
|
||||
lws_protocol_get(wsi),
|
||||
sizeof(struct per_vhost_data__lws_mirror));
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
|
||||
lwsl_info("%s: mirror protocol cleaning up %p\n", __func__, v);
|
||||
for (n = 0; n < ARRAY_SIZE(v->ringbuffer); n++)
|
||||
if (v->ringbuffer[n].payload) {
|
||||
free(v->ringbuffer[n].payload);
|
||||
v->ringbuffer[n].payload = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
while (pss->ringbuffer_tail != v->ringbuffer_head) {
|
||||
m = v->ringbuffer[pss->ringbuffer_tail].len;
|
||||
n = lws_write(wsi, (unsigned char *)
|
||||
v->ringbuffer[pss->ringbuffer_tail].payload +
|
||||
LWS_PRE, m, LWS_WRITE_TEXT);
|
||||
if (n < 0) {
|
||||
lwsl_err("ERROR %d writing to mirror socket\n", n);
|
||||
return -1;
|
||||
}
|
||||
if (n < m)
|
||||
lwsl_err("mirror partial write %d vs %d\n", n, m);
|
||||
|
||||
if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
|
||||
pss->ringbuffer_tail = 0;
|
||||
else
|
||||
pss->ringbuffer_tail++;
|
||||
|
||||
if (((v->ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 15))
|
||||
lws_rx_flow_allow_all_protocol(lws_get_context(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
|
||||
if (lws_send_pipe_choked(wsi)) {
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RECEIVE:
|
||||
if (((v->ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) == (MAX_MESSAGE_QUEUE - 1)) {
|
||||
lwsl_err("dropping!\n");
|
||||
goto choke;
|
||||
}
|
||||
|
||||
if (v->ringbuffer[v->ringbuffer_head].payload)
|
||||
free(v->ringbuffer[v->ringbuffer_head].payload);
|
||||
|
||||
v->ringbuffer[v->ringbuffer_head].payload = malloc(LWS_PRE + len);
|
||||
v->ringbuffer[v->ringbuffer_head].len = len;
|
||||
memcpy((char *)v->ringbuffer[v->ringbuffer_head].payload +
|
||||
LWS_PRE, in, len);
|
||||
if (v->ringbuffer_head == (MAX_MESSAGE_QUEUE - 1))
|
||||
v->ringbuffer_head = 0;
|
||||
else
|
||||
v->ringbuffer_head++;
|
||||
|
||||
if (((v->ringbuffer_head - pss->ringbuffer_tail) &
|
||||
(MAX_MESSAGE_QUEUE - 1)) != (MAX_MESSAGE_QUEUE - 2))
|
||||
goto done;
|
||||
|
||||
choke:
|
||||
lwsl_debug("LWS_CALLBACK_RECEIVE: throttling %p\n", wsi);
|
||||
lws_rx_flow_control(wsi, 0);
|
||||
|
||||
done:
|
||||
lws_callback_on_writable_all_protocol(lws_get_context(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lws_protocols protocols[] = {
|
||||
{
|
||||
"lws-mirror-protocol",
|
||||
callback_lws_mirror,
|
||||
sizeof(struct per_session_data__lws_mirror),
|
||||
128, /* rx buf size must be >= permessage-deflate rx size */
|
||||
},
|
||||
};
|
||||
|
||||
LWS_VISIBLE int
|
||||
init_protocol_lws_mirror(struct lws_context *context,
|
||||
struct lws_plugin_capability *c)
|
||||
{
|
||||
if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
|
||||
lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
|
||||
c->api_magic);
|
||||
return 1;
|
||||
}
|
||||
|
||||
c->protocols = protocols;
|
||||
c->count_protocols = ARRAY_SIZE(protocols);
|
||||
c->extensions = NULL;
|
||||
c->count_extensions = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
destroy_protocol_lws_mirror(struct lws_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
208
plugins/protocol_lws_status.c
Normal file
208
plugins/protocol_lws_status.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* libwebsockets-test-server - libwebsockets test implementation
|
||||
*
|
||||
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* The person who associated a work with this deed has dedicated
|
||||
* the work to the public domain by waiving all of his or her rights
|
||||
* to the work worldwide under copyright law, including all related
|
||||
* and neighboring rights, to the extent allowed by law. You can copy,
|
||||
* modify, distribute and perform the work, even for commercial purposes,
|
||||
* all without asking permission.
|
||||
*
|
||||
* The test apps are intended to be adapted for use in your code, which
|
||||
* may be proprietary. So unlike the library itself, they are licensed
|
||||
* Public Domain.
|
||||
*/
|
||||
#include "../lib/libwebsockets.h"
|
||||
#include <time.h>
|
||||
|
||||
struct per_session_data__lws_status {
|
||||
struct per_session_data__lws_status *list;
|
||||
struct timeval tv_established;
|
||||
int last;
|
||||
char ip[270];
|
||||
char user_agent[512];
|
||||
const char *pos;
|
||||
int len;
|
||||
};
|
||||
|
||||
|
||||
static unsigned char server_info[1024];
|
||||
static int server_info_len;
|
||||
static int current;
|
||||
static char cache[16384];
|
||||
static int cache_len;
|
||||
static struct per_session_data__lws_status *list;
|
||||
static int live_wsi;
|
||||
|
||||
|
||||
static void
|
||||
update_status(struct lws *wsi, struct per_session_data__lws_status *pss)
|
||||
{
|
||||
struct per_session_data__lws_status **pp = &list;
|
||||
int subsequent = 0;
|
||||
char *p = cache + LWS_PRE, *start = p;
|
||||
char date[128];
|
||||
time_t t;
|
||||
struct tm *ptm;
|
||||
#ifndef WIN32
|
||||
struct tm tm;
|
||||
#endif
|
||||
|
||||
p += snprintf(p, 512, " { %s, \"wsi\":\"%d\", \"conns\":[",
|
||||
server_info, live_wsi);
|
||||
|
||||
/* render the list */
|
||||
while (*pp) {
|
||||
t = (*pp)->tv_established.tv_sec;
|
||||
#ifdef WIN32
|
||||
ptm = localtime(&t);
|
||||
if (!ptm)
|
||||
#else
|
||||
ptm = &tm;
|
||||
if (!localtime_r(&t, &tm))
|
||||
#endif
|
||||
strcpy(date, "unknown");
|
||||
else
|
||||
strftime(date, sizeof(date), "%F %H:%M %Z", ptm);
|
||||
if ((p - start) > (sizeof(cache) - 512))
|
||||
break;
|
||||
if (subsequent)
|
||||
*p++ = ',';
|
||||
subsequent = 1;
|
||||
p += snprintf(p, sizeof(cache) - (p - start) - 1,
|
||||
"{\"peer\":\"%s\",\"time\":\"%s\","
|
||||
"\"ua\":\"%s\"}",
|
||||
(*pp)->ip, date, (*pp)->user_agent);
|
||||
pp = &((*pp)->list);
|
||||
}
|
||||
|
||||
p += sprintf(p, "]}");
|
||||
cache_len = p - start;
|
||||
lwsl_err("cache_len %d\n", cache_len);
|
||||
*p = '\0';
|
||||
|
||||
/* since we changed the list, increment the 'version' */
|
||||
current++;
|
||||
/* update everyone */
|
||||
lws_callback_on_writable_all_protocol(lws_get_context(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
}
|
||||
|
||||
|
||||
/* lws-status protocol */
|
||||
|
||||
int
|
||||
callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
struct per_session_data__lws_status *pss =
|
||||
(struct per_session_data__lws_status *)user,
|
||||
**pp;
|
||||
char name[128], rip[128];
|
||||
int m;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_INIT:
|
||||
/*
|
||||
* Prepare the static server info
|
||||
*/
|
||||
server_info_len = sprintf((char *)server_info,
|
||||
"\"version\":\"%s\","
|
||||
" \"hostname\":\"%s\"",
|
||||
lws_get_library_version(),
|
||||
lws_canonical_hostname(
|
||||
lws_get_context(wsi)));
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
/*
|
||||
* we keep a linked list of live pss, so we can walk it
|
||||
*/
|
||||
pss->last = 0;
|
||||
pss->list = list;
|
||||
list = pss;
|
||||
live_wsi++;
|
||||
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name,
|
||||
sizeof(name), rip, sizeof(rip));
|
||||
sprintf(pss->ip, "%s (%s)", name, rip);
|
||||
gettimeofday(&pss->tv_established, NULL);
|
||||
strcpy(pss->user_agent, "unknown");
|
||||
lws_hdr_copy(wsi, pss->user_agent, sizeof(pss->user_agent),
|
||||
WSI_TOKEN_HTTP_USER_AGENT);
|
||||
update_status(wsi, pss);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_SERVER_WRITEABLE:
|
||||
m = lws_write(wsi, (unsigned char *)cache + LWS_PRE, cache_len,
|
||||
LWS_WRITE_TEXT);
|
||||
if (m < server_info_len) {
|
||||
lwsl_err("ERROR %d writing to di socket\n", m);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_CLOSED:
|
||||
/*
|
||||
* remove ourselves from live pss list
|
||||
*/
|
||||
lwsl_err("CLOSING pss %p ********\n", pss);
|
||||
|
||||
pp = &list;
|
||||
while (*pp) {
|
||||
if (*pp == pss) {
|
||||
*pp = pss->list;
|
||||
pss->list = NULL;
|
||||
live_wsi--;
|
||||
break;
|
||||
}
|
||||
pp = &((*pp)->list);
|
||||
}
|
||||
|
||||
update_status(wsi, pss);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lws_protocols protocols[] = {
|
||||
{
|
||||
"lws-status",
|
||||
callback_lws_status,
|
||||
sizeof(struct per_session_data__lws_status),
|
||||
128, /* rx buf size must be >= permessage-deflate rx size */
|
||||
},
|
||||
};
|
||||
|
||||
LWS_VISIBLE int
|
||||
init_protocol_lws_status(struct lws_context *context,
|
||||
struct lws_plugin_capability *c)
|
||||
{
|
||||
if (c->api_magic != LWS_PLUGIN_API_MAGIC) {
|
||||
lwsl_err("Plugin API %d, library API %d", LWS_PLUGIN_API_MAGIC,
|
||||
c->api_magic);
|
||||
return 1;
|
||||
}
|
||||
|
||||
c->protocols = protocols;
|
||||
c->count_protocols = ARRAY_SIZE(protocols);
|
||||
c->extensions = NULL;
|
||||
c->count_extensions = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
destroy_protocol_lws_status(struct lws_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -128,7 +128,11 @@ void signal_cb(uv_signal_t *watcher, int signum)
|
|||
}
|
||||
|
||||
static void
|
||||
uv_timeout_cb_dumb_increment(uv_timer_t *w)
|
||||
uv_timeout_cb_dumb_increment(uv_timer_t *w
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
{
|
||||
lws_callback_on_writable_all_protocol(context,
|
||||
&protocols[PROTOCOL_DUMB_INCREMENT]);
|
||||
|
|
|
@ -10,6 +10,12 @@ then
|
|||
then
|
||||
sudo apt-get install -y -qq libev-dev;
|
||||
fi
|
||||
|
||||
if [ "$LWS_METHOD" == "libuv" -o "$LWS_METHOD" == "lwsws" ];
|
||||
then
|
||||
sudo apt-get install -y -qq libuv-dev;
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ];
|
||||
|
@ -18,6 +24,12 @@ then
|
|||
then
|
||||
brew install libev;
|
||||
fi
|
||||
|
||||
if [ "$LWS_METHOD" == "libuv" -o "$LWS_METHOD" == "lwsws" ];
|
||||
then
|
||||
brew install libuv;
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue