diff --git a/CMakeLists.txt b/CMakeLists.txt index 8903a49e..47eed556 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1656,16 +1656,6 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS) set_source_files_properties( lib/event-libs/libev.c PROPERTIES COMPILE_FLAGS "-Wno-error" ) endif() - if (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-apps/test-server-libuv.c" - "" - "" - "" - "" - "") - endif() if (NOT ((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) AND LWS_WITH_LIBEVENT) create_test_app(test-server-libevent @@ -1714,20 +1704,6 @@ if ((LWS_ROLE_H1 OR LWS_ROLE_H2) AND NOT LWS_WITHOUT_TESTAPPS) "") endif() - # - # test-server-v2.0 - # - if (LWS_WITH_PLUGINS) - create_test_app( - test-server-v2.0 - "test-apps/test-server-v2.0.c" - "" - "" - "" - "" - "") - endif() - # Data files for running the test server. list(APPEND TEST_SERVER_DATA "${PROJECT_SOURCE_DIR}/test-apps/favicon.ico" diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index fb16dde3..a108da73 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -59,6 +59,8 @@ #cmakedefine LWS_WITHOUT_SERVER #cmakedefine LWS_WITHOUT_CLIENT +#cmakedefine LWS_WITH_POLL + /* Enable libev io loop */ #cmakedefine LWS_WITH_LIBEV diff --git a/lib/context.c b/lib/context.c index 33069988..75bf45aa 100644 --- a/lib/context.c +++ b/lib/context.c @@ -25,7 +25,7 @@ #define LWS_BUILD_HASH "unknown-build-hash" #endif -const struct lws_role_ops * available_roles[] = { +const struct lws_role_ops *available_roles[] = { #if defined(LWS_ROLE_H2) &role_ops_h2, #endif @@ -38,6 +38,22 @@ const struct lws_role_ops * available_roles[] = { NULL }; +const struct lws_event_loop_ops *available_event_libs[] = { +#if defined(LWS_WITH_POLL) + &event_loop_ops_poll, +#endif +#if defined(LWS_WITH_LIBUV) + &event_loop_ops_uv, +#endif +#if defined(LWS_WITH_LIBEVENT) + &event_loop_ops_event, +#endif +#if defined(LWS_WITH_LIBEV) + &event_loop_ops_ev, +#endif + NULL +}; + #if defined(LWS_WITH_TLS) static char alpn_discovered[32]; #endif @@ -985,10 +1001,7 @@ lws_create_context(const struct lws_context_creation_info *info) #else lwsl_info("IPV6 not compiled in\n"); #endif -#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_PLAT_ESP32) - lws_feature_status_libev(info); - lws_feature_status_libuv(info); -#endif + lwsl_info(" LWS_DEF_HEADER_LEN : %u\n", LWS_DEF_HEADER_LEN); lwsl_info(" LWS_MAX_PROTOCOLS : %u\n", LWS_MAX_PROTOCOLS); lwsl_info(" LWS_MAX_SMP : %u\n", LWS_MAX_SMP); @@ -1108,27 +1121,29 @@ lws_create_context(const struct lws_context_creation_info *info) context->event_loop_ops = &event_loop_ops_poll; #endif + if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV)) #if defined(LWS_WITH_LIBUV) - if (LWS_LIBUV_ENABLED(context)) { context->event_loop_ops = &event_loop_ops_uv; - } +#else + goto fail_event_libs; #endif + + if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV)) #if defined(LWS_WITH_LIBEV) - if (LWS_LIBEV_ENABLED(context)) { context->event_loop_ops = &event_loop_ops_ev; - } +#else + goto fail_event_libs; #endif + + if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT)) #if defined(LWS_WITH_LIBEVENT) - if (LWS_LIBEVENT_ENABLED(context)) { context->event_loop_ops = &event_loop_ops_event; - } +#else + goto fail_event_libs; #endif - if (!context->event_loop_ops) { - lwsl_err("no event loop possible\n"); - - goto bail; - } + if (!context->event_loop_ops) + goto fail_event_libs; lwsl_info("Using event loop: %s\n", context->event_loop_ops->name); @@ -1348,6 +1363,20 @@ lws_create_context(const struct lws_context_creation_info *info) bail: lws_context_destroy(context); + return NULL; + +fail_event_libs: + lwsl_err("Requested event library support not configured, available:\n"); + { + const struct lws_event_loop_ops **elops = available_event_libs; + + while (*elops) { + lwsl_err(" - %s\n", (*elops)->name); + elops++; + } + } + lws_free(context); + return NULL; } @@ -1694,9 +1723,13 @@ lws_context_destroy2(struct lws_context *context) uint32_t n; #endif - lwsl_info("%s: ctx %p\n", __func__, context); + context->being_destroyed2 = 1; + + if (context->pt[0].fds) + lws_free_set_NULL(context->pt[0].fds); + /* * free all the per-vhost allocations */ @@ -1776,6 +1809,8 @@ lws_context_destroy(struct lws_context *context) } if (context->being_destroyed1) { + if (!context->being_destroyed2) + return lws_context_destroy2(context); lwsl_info("%s: ctx %p: already being destroyed\n", __func__, context); return; @@ -1825,6 +1860,20 @@ lws_context_destroy(struct lws_context *context) lws_pt_mutex_destroy(pt); } + for (n = 0; n < context->count_threads; n++) { + pt = &context->pt[n]; + + if (context->event_loop_ops->destroy_pt) + context->event_loop_ops->destroy_pt(context, n); + + lws_free_set_NULL(context->pt[n].serv_buf); + +#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) + while (pt->http.ah_list) + _lws_destroy_ah(pt, pt->http.ah_list); +#endif + } + /* * inform all the protocols that they are done and will have no more * callbacks. @@ -1839,23 +1888,8 @@ lws_context_destroy(struct lws_context *context) vh = vhn; } - for (n = 0; n < context->count_threads; n++) { - pt = &context->pt[n]; - - if (context->event_loop_ops->destroy_pt) - context->event_loop_ops->destroy_pt(context, n); - - lws_free_set_NULL(context->pt[n].serv_buf); - -#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) - while (pt->http.ah_list) - _lws_destroy_ah(pt, pt->http.ah_list); -#endif - } lws_plat_context_early_destroy(context); - if (context->pt[0].fds) - lws_free_set_NULL(context->pt[0].fds); if (context->event_loop_ops->destroy_context1) { context->event_loop_ops->destroy_context1(context); diff --git a/lib/event-libs/README.md b/lib/event-libs/README.md new file mode 100644 index 00000000..3a7c377e --- /dev/null +++ b/lib/event-libs/README.md @@ -0,0 +1,126 @@ +## Information for new event lib implementers + +### Introduction + +By default lws has built-in support for POSIX poll() as the event loop. + +However either to get access to epoll() or other platform specific better +poll waits, or to integrate with existing applications already using a +specific event loop, it can be desirable for lws to use another external +event library, like libuv, libevent or libev. + +### Code placement + +The code specific to the event library should live in `./lib/event-libs/**lib name**` + +### Allowing control over enabling event libs + +All event libs should add a cmake define `LWS_WITH_**lib name**` and make its build +dependent on it in CMakeLists.txt. Export the cmakedefine in `./cmake/lws_config.h.in` +as well so user builds can understand if the event lib is available in the lws build it is +trying to bind to. + +If the event lib is disabled in cmake, nothing in its directory is built or referenced. + +### Event loop ops struct + +The event lib support is defined by `struct lws_event_loop_ops` in `lib/private/libwebsockets.h`, +each event lib support instantiates one of these and fills in the appropriate ops +callbacks to perform its job. By convention that lives in +`./lib/event-libs/**lib name**/**lib_name**.c`. + +### Private event lib declarations + +Truly private declarations for the event lib can go in the event-libs directory as you like. +However when the declarations must be accessible to other things in lws build, eg, +the event lib support adds members to `struct lws` when enabled, they should be in the +event lib supporr directory in a file `private.h`. + +Search for "bring in event libs private declarations" in `./lib/private-libwebsockets.h +and add your private event lib support file there following the style used for the other +event libs, eg, + +``` +#if defined(LWS_WITH_LIBUV) + #include "event-libs/libuv/private.h" +#else + #define LWS_LIBUV_ENABLED(context) (0) +#endif +``` + +If the event lib support is disabled at cmake, nothing from its private.h should be used anywhere. + +### Integrating event lib assets to lws + +If your event lib needs special storage in lws objects, that's no problem. But to keep +things sane, there are some rules. + + - declare a "container struct" in your private.h for everything, eg, the libuv event + lib support need to add its own assets in the perthread struct, it declares in its private.h + +``` +struct lws_pt_eventlibs_libuv { + uv_loop_t *io_loop; + uv_signal_t signals[8]; + uv_timer_t timeout_watcher; + uv_timer_t hrtimer; + uv_idle_t idle; +}; +``` + + - add your event lib content in one place in the related lws struct, protected by `#if defined(LWS_WITH_**lib name**)`, + eg, again for LWS_WITH_LIBUV + +``` +struct lws_context_per_thread { + +... + +#if defined(LWS_WITH_LIBUV) + struct lws_pt_eventlibs_libuv uv; +#endif + +... +``` + +### Adding to lws available event libs list + +Edit the NULL-terminated array `available_event_libs` at the top of `./lib/context.c` to include +a pointer to your new event lib support's ops struct, following the style already there. + +``` +const struct lws_event_loop_ops *available_event_libs[] = { +#if defined(LWS_WITH_POLL) + &event_loop_ops_poll, +#endif +#if defined(LWS_WITH_LIBUV) + &event_loop_ops_uv, +#endif +... +``` + +This is used to provide a list of avilable configured backends. + +### Enabling event lib adoption + +You need to add a `LWS_SERVER_OPTION...` flag as necessary in `./lib/libwebsockets.h` +`enum lws_context_options`, and follow the existing code in `lws_create_context()` +to convert the flag into binding your ops struct to the context. + +### Implementation of the event lib bindings + +Study eg libuv implementation, using the available ops in the struct lws_event_loop_ops +as a guide. + +### Destruction + +Ending the event loop is generally a bit tricky, because if the event loop is internal +to the lws context, you cannot destroy it while the event loop is running. + +Don't add special exports... we tried that, it's a huge mess. The same user code should be able +work with any of the event loops including poll. + +The solution we found was hide the different processing necessary for the different cases in +lws_destroy_context(). To help with that there are ops available at two different places in +the context destroy processing. + diff --git a/lib/event-libs/libev/libev.c b/lib/event-libs/libev/libev.c index 2ec6d6f5..06e812b0 100644 --- a/lib/event-libs/libev/libev.c +++ b/lib/event-libs/libev/libev.c @@ -19,18 +19,8 @@ * MA 02110-1301 USA */ -#define LWS_HIDE_LIBEVENT - #include "private-libwebsockets.h" -void lws_feature_status_libev(const struct lws_context_creation_info *info) -{ - if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEV)) - lwsl_info("libev support compiled in and enabled\n"); - else - lwsl_info("libev support compiled in but disabled\n"); -} - static void lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { @@ -81,11 +71,19 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) int status = 0; int backend; + lwsl_info("%s: loop %p\n", __func__, _loop); + if (!loop) loop = ev_loop_new(0); else context->pt[tsi].event_loop_foreign = 1; + if (!loop) { + lwsl_err("%s: creating event base failed\n", __func__); + + return -1; + } + context->pt[tsi].ev.io_loop = loop; /* @@ -149,9 +147,6 @@ elops_destroy_pt_ev(struct lws_context *context, int tsi) struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_vhost *vh = context->vhost_list; - if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV)) - return; - if (!pt->ev.io_loop) return; @@ -162,8 +157,7 @@ elops_destroy_pt_ev(struct lws_context *context, int tsi) } if (!pt->event_loop_foreign) ev_signal_stop(pt->ev.io_loop, &pt->w_sigint.ev.watcher); - if (!pt->event_loop_foreign) - ev_loop_destroy(pt->ev.io_loop); + } static int @@ -226,16 +220,75 @@ elops_io_ev(struct lws *wsi, int flags) static void elops_run_pt_ev(struct lws_context *context, int tsi) { - if (context->pt[tsi].ev.io_loop && LWS_LIBEV_ENABLED(context)) + if (context->pt[tsi].ev.io_loop) ev_run(context->pt[tsi].ev.io_loop, 0); } +static int +elops_destroy_context2_ev(struct lws_context *context) +{ + struct lws_context_per_thread *pt; + int n, m, internal = 0; + + lwsl_debug("%s\n", __func__); + + for (n = 0; n < context->count_threads; n++) { + int budget = 1000; + + pt = &context->pt[n]; + + /* only for internal loops... */ + + if (pt->event_loop_foreign || !pt->ev.io_loop) + continue; + + internal = 1; + if (!context->finalize_destroy_after_internal_loops_stopped) { + ev_break(pt->ev.io_loop, EVBREAK_ONE); + continue; + } + while (budget-- && + (m = ev_run(pt->ev.io_loop, 0))) + ; + + ev_loop_destroy(pt->ev.io_loop); + } + + return internal; +} + +static int +elops_init_vhost_listen_wsi_ev(struct lws *wsi) +{ + int fd; + + if (!wsi) { + assert(0); + return 0; + } + + wsi->w_read.context = wsi->context; + wsi->w_write.context = wsi->context; + + if (wsi->role_ops->file_handle) + fd = wsi->desc.filefd; + else + fd = wsi->desc.sockfd; + + ev_io_init(&wsi->w_read.ev.watcher, lws_accept_cb, fd, EV_READ); + ev_io_init(&wsi->w_write.ev.watcher, lws_accept_cb, fd, EV_WRITE); + + elops_io_ev(wsi, LWS_EV_START | LWS_EV_READ); + + return 0; +} + struct lws_event_loop_ops event_loop_ops_ev = { /* name */ "libev", /* init_context */ elops_init_context_ev, /* destroy_context1 */ NULL, - /* destroy_context2 */ NULL, - /* init_vhost_listen_wsi */ NULL, + /* destroy_context2 */ elops_destroy_context2_ev, + /* init_vhost_listen_wsi */ elops_init_vhost_listen_wsi_ev, /* init_pt */ elops_init_pt_ev, /* wsi_logical_close */ NULL, /* check_client_connect_ok */ NULL, diff --git a/lib/event-libs/libev/private.h b/lib/event-libs/libev/private.h index 12f1d9f6..6ff8ba17 100644 --- a/lib/event-libs/libev/private.h +++ b/lib/event-libs/libev/private.h @@ -39,12 +39,4 @@ struct lws_context_eventlibs_libev { int placeholder; }; -#define LWS_LIBEV_ENABLED(context) lws_check_opt(context->options, \ - LWS_SERVER_OPTION_LIBEV) - extern struct lws_event_loop_ops event_loop_ops_ev; - -LWS_EXTERN void -lws_libev_run(const struct lws_context *context, int tsi); -LWS_EXTERN void -lws_feature_status_libev(const struct lws_context_creation_info *info); diff --git a/lib/event-libs/libevent/libevent.c b/lib/event-libs/libevent/libevent.c index 53c4bf95..bd56ea97 100644 --- a/lib/event-libs/libevent/libevent.c +++ b/lib/event-libs/libevent/libevent.c @@ -21,14 +21,6 @@ #include "private-libwebsockets.h" -void lws_feature_status_libevent(const struct lws_context_creation_info *info) -{ - if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEVENT)) - lwsl_info("libevent support compiled in and enabled\n"); - else - lwsl_info("libevent support compiled in but disabled\n"); -} - static void lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx) { @@ -67,10 +59,11 @@ LWS_VISIBLE void lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx) { struct lws_context_per_thread *pt = ctx; + struct event *signal = (struct event *)ctx; if (pt->context->eventlib_signal_cb) { - pt->context->eventlib_signal_cb( - (void *)(lws_intptr_t)sock_fd, revents); + pt->context->eventlib_signal_cb((void *)(lws_intptr_t)sock_fd, + event_get_signal(signal)); return; } @@ -85,13 +78,21 @@ elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) struct lws_vhost *vh = context->vhost_list; struct event_base *loop = (struct event_base *)_loop; + lwsl_info("%s: loop %p\n", __func__, _loop); + if (!loop) - context->pt[tsi].event.io_loop = event_base_new(); - else { + loop = event_base_new(); + else context->pt[tsi].event_loop_foreign = 1; - context->pt[tsi].event.io_loop = loop; + + if (!loop) { + lwsl_err("%s: creating event base failed\n", __func__); + + return -1; } + context->pt[tsi].event.io_loop = loop; + /* * Initialize all events with the listening sockets * and register a callback for read operations @@ -153,18 +154,17 @@ elops_accept_event(struct lws *wsi) fd = wsi->desc.sockfd; wsi->w_read.event.watcher = event_new(pt->event.io_loop, fd, - (EV_READ | EV_PERSIST), lws_event_cb, &wsi->w_read); + (EV_READ | EV_PERSIST), lws_event_cb, &wsi->w_read); wsi->w_write.event.watcher = event_new(pt->event.io_loop, fd, - (EV_WRITE | EV_PERSIST), lws_event_cb, &wsi->w_write); + (EV_WRITE | EV_PERSIST), lws_event_cb, &wsi->w_write); } static void elops_io_event(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 (!pt->event.io_loop || context->being_destroyed) + if (!pt->event.io_loop || wsi->context->being_destroyed) return; assert((flags & (LWS_EV_START | LWS_EV_STOP)) && @@ -173,6 +173,7 @@ elops_io_event(struct lws *wsi, int flags) if (flags & LWS_EV_START) { if (flags & LWS_EV_WRITE) event_add(wsi->w_write.event.watcher, NULL); + if (flags & LWS_EV_READ) event_add(wsi->w_read.event.watcher, NULL); } else { @@ -188,8 +189,7 @@ static void elops_run_pt_event(struct lws_context *context, int tsi) { /* Run / Dispatch the event_base loop */ - if (context->pt[tsi].event.io_loop && - LWS_LIBEVENT_ENABLED(context)) + if (context->pt[tsi].event.io_loop) event_base_dispatch(context->pt[tsi].event.io_loop); } @@ -199,8 +199,7 @@ elops_destroy_pt_event(struct lws_context *context, int tsi) struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_vhost *vh = context->vhost_list; - if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT)) - return; + lwsl_info("%s\n", __func__); if (!pt->event.io_loop) return; @@ -212,14 +211,14 @@ elops_destroy_pt_event(struct lws_context *context, int tsi) if (vh->lserv_wsi) { event_free(vh->lserv_wsi->w_read.event.watcher); vh->lserv_wsi->w_read.event.watcher = NULL; + event_free(vh->lserv_wsi->w_write.event.watcher); + vh->lserv_wsi->w_write.event.watcher = NULL; } vh = vh->vhost_next; } if (!pt->event_loop_foreign) event_free(pt->w_sigint.event.watcher); - if (!pt->event_loop_foreign) - event_base_free(pt->event.io_loop); } static void @@ -235,13 +234,86 @@ elops_destroy_wsi_event(struct lws *wsi) event_free(wsi->w_write.event.watcher); } +static int +elops_init_vhost_listen_wsi_event(struct lws *wsi) +{ + struct lws_context_per_thread *pt; + int fd; + + if (!wsi) { + assert(0); + return 0; + } + + wsi->w_read.context = wsi->context; + wsi->w_write.context = wsi->context; + + pt = &wsi->context->pt[(int)wsi->tsi]; + + if (wsi->role_ops->file_handle) + fd = wsi->desc.filefd; + else + fd = wsi->desc.sockfd; + + wsi->w_read.event.watcher = event_new(pt->event.io_loop, fd, + (EV_READ | EV_PERSIST), + lws_event_cb, &wsi->w_read); + wsi->w_write.event.watcher = event_new(pt->event.io_loop, fd, + (EV_WRITE | EV_PERSIST), + lws_event_cb, &wsi->w_write); + + elops_io_event(wsi, LWS_EV_START | LWS_EV_READ); + + return 0; +} + +static int +elops_destroy_context2_event(struct lws_context *context) +{ + struct lws_context_per_thread *pt; + int n, m, internal = 0; + + lwsl_debug("%s\n", __func__); + + for (n = 0; n < context->count_threads; n++) { + int budget = 1000; + + pt = &context->pt[n]; + + /* only for internal loops... */ + + if (pt->event_loop_foreign || !pt->event.io_loop) + continue; + + internal = 1; + if (!context->finalize_destroy_after_internal_loops_stopped) { + event_base_loopexit(pt->event.io_loop, NULL); + continue; + } + while (budget-- && + (m = event_base_loop(pt->event.io_loop, EVLOOP_NONBLOCK))) + ; +#if 0 + if (m) { + lwsl_err("%s: tsi %d: NOT everything closed\n", + __func__, n); + event_base_dump_events(pt->event.io_loop, stderr); + } else + lwsl_debug("%s: %d: everything closed OK\n", __func__, n); +#endif + event_base_free(pt->event.io_loop); + + } + + return internal; +} struct lws_event_loop_ops event_loop_ops_event = { /* name */ "libevent", /* init_context */ elops_init_context_event, /* destroy_context1 */ NULL, - /* destroy_context2 */ NULL, - /* init_vhost_listen_wsi */ NULL, + /* destroy_context2 */ elops_destroy_context2_event, + /* init_vhost_listen_wsi */ elops_init_vhost_listen_wsi_event, /* init_pt */ elops_init_pt_event, /* wsi_logical_close */ NULL, /* check_client_connect_ok */ NULL, diff --git a/lib/event-libs/libevent/private.h b/lib/event-libs/libevent/private.h index 4715bc2a..2c4de3ea 100644 --- a/lib/event-libs/libevent/private.h +++ b/lib/event-libs/libevent/private.h @@ -39,11 +39,4 @@ struct lws_context_eventlibs_libevent { int placeholder; }; -#define LWS_LIBEVENT_ENABLED(context) lws_check_opt(context->options, \ - LWS_SERVER_OPTION_LIBEVENT) - extern struct lws_event_loop_ops event_loop_ops_event; - -LWS_EXTERN void -lws_feature_status_libevent(const struct lws_context_creation_info *info); - diff --git a/lib/event-libs/libuv/libuv.c b/lib/event-libs/libuv/libuv.c index b8990502..ecc7e2de 100644 --- a/lib/event-libs/libuv/libuv.c +++ b/lib/event-libs/libuv/libuv.c @@ -21,15 +21,6 @@ #include "private-libwebsockets.h" -void -lws_feature_status_libuv(const struct lws_context_creation_info *info) -{ - if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV)) - lwsl_info("libuv support compiled in and enabled\n"); - else - lwsl_info("libuv support compiled in but disabled\n"); -} - static void lws_uv_hrtimer_cb(uv_timer_t *timer #if UV_VERSION_MAJOR == 0 @@ -140,7 +131,7 @@ lws_io_cb(uv_poll_t *watcher, int status, int revents) * wsi, and set a flag; when all the wsi closures are finalized then we * actually stop the libuv event loops. */ -LWS_VISIBLE LWS_EXTERN void +static void lws_libuv_stop(struct lws_context *context) { struct lws_context_per_thread *pt; @@ -309,7 +300,7 @@ lws_close_all_handles_in_loop(uv_loop_t *loop) LWS_VISIBLE void lws_libuv_stop_without_kill(const struct lws_context *context, int tsi) { - if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context)) + if (context->pt[tsi].uv.io_loop) uv_stop(context->pt[tsi].uv.io_loop); } @@ -318,7 +309,7 @@ lws_libuv_stop_without_kill(const struct lws_context *context, int tsi) LWS_VISIBLE uv_loop_t * lws_uv_getloop(struct lws_context *context, int tsi) { - if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context)) + if (context->pt[tsi].uv.io_loop) return context->pt[tsi].uv.io_loop; return NULL; @@ -364,14 +355,14 @@ lws_plat_plugins_init(struct lws_context *context, const char * const *d) lib.errmsg = NULL; lib.handle = NULL; - uv_loop_init(&context->uv.pu_loop); + uv_loop_init(&context->uv.loop); lwsl_notice(" Plugins:\n"); while (d && *d) { lwsl_notice(" Scanning %s\n", *d); - m =uv_fs_scandir(&context->uv.pu_loop, &req, *d, 0, NULL); + m =uv_fs_scandir(&context->uv.loop, &req, *d, 0, NULL); if (m < 1) { lwsl_err("Scandir on %s failed\n", *d); return 1; @@ -495,7 +486,7 @@ lws_plat_plugins_destroy(struct lws_context *context) context->plugin_list = NULL; - while (uv_loop_close(&context->uv.pu_loop)) + while (uv_loop_close(&context->uv.loop)) ; return 0; @@ -709,7 +700,7 @@ elops_init_vhost_listen_wsi_uv(struct lws *wsi) static void elops_run_pt_uv(struct lws_context *context, int tsi) { - if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context)) + if (context->pt[tsi].uv.io_loop) uv_run(context->pt[tsi].uv.io_loop, 0); } diff --git a/lib/event-libs/libuv/private.h b/lib/event-libs/libuv/private.h index 5ea25183..c7b46bd8 100644 --- a/lib/event-libs/libuv/private.h +++ b/lib/event-libs/libuv/private.h @@ -49,7 +49,7 @@ struct lws_pt_eventlibs_libuv { }; struct lws_context_eventlibs_libuv { - uv_loop_t pu_loop; + uv_loop_t loop; }; struct lws_io_watcher_libuv { @@ -60,11 +60,5 @@ struct lws_signal_watcher_libuv { uv_signal_t watcher; }; -#define LWS_LIBUV_ENABLED(context) lws_check_opt(context->options, \ - LWS_SERVER_OPTION_LIBUV) - extern struct lws_event_loop_ops event_loop_ops_uv; -LWS_EXTERN void -lws_feature_status_libuv(const struct lws_context_creation_info *info); - diff --git a/lib/event-libs/poll/poll.c b/lib/event-libs/poll/poll.c index ad6b29b0..cfbec684 100644 --- a/lib/event-libs/poll/poll.c +++ b/lib/event-libs/poll/poll.c @@ -23,10 +23,16 @@ #include +static int +elops_destroy_context1_poll(struct lws_context *context) +{ + return 1; +} + struct lws_event_loop_ops event_loop_ops_poll = { /* name */ "poll", /* init_context */ NULL, - /* destroy_context1 */ NULL, + /* destroy_context1 */ elops_destroy_context1_poll, /* destroy_context2 */ NULL, /* init_vhost_listen_wsi */ NULL, /* init_pt */ NULL, diff --git a/lib/event-libs/poll/private.h b/lib/event-libs/poll/private.h index 2cd65b8d..ca313ebf 100644 --- a/lib/event-libs/poll/private.h +++ b/lib/event-libs/poll/private.h @@ -20,4 +20,4 @@ * */ -extern struct lws_event_loop_ops event_loop_ops_poll; \ No newline at end of file +extern struct lws_event_loop_ops event_loop_ops_poll; diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 4cbd4d0d..9f7ce8e2 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -275,11 +275,6 @@ __lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs) struct lws *wsi1; int bef = 0; - if (LWS_LIBEV_ENABLED(wsi->context)) - lwsl_warn("%s: lws hrtimer not implemented for libev\n", __func__); - if (LWS_LIBEVENT_ENABLED(wsi->context)) - lwsl_warn("%s: lws hrtimer not implemented for libevent\n", __func__); - lws_dll_lws_remove(&wsi->dll_hrtimer); if (usecs == LWS_SET_TIMER_USEC_CANCEL) diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 848b3f81..d97ca4a9 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -161,7 +161,7 @@ typedef unsigned long long lws_intptr_t; #include #endif #endif /* LWS_WITH_LIBUV */ -#if defined(LWS_WITH_LIBEVENT) && !defined(LWS_HIDE_LIBEVENT) +#if defined(LWS_WITH_LIBEVENT) #include #endif /* LWS_WITH_LIBEVENT */ @@ -4609,9 +4609,6 @@ lws_plat_recommended_rsa_bits(void); LWS_VISIBLE uv_loop_t * lws_uv_getloop(struct lws_context *context, int tsi); -LWS_VISIBLE LWS_EXTERN void -lws_libuv_stop(struct lws_context *context); - LWS_VISIBLE LWS_EXTERN void lws_libuv_static_refcount_add(uv_handle_t *, struct lws_context *context); diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 5a72047b..2aafdeb1 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -678,19 +678,23 @@ struct lws_event_loop_ops { unsigned int periodic_events_available:1; }; +/* bring in event libs private declarations */ + #if defined(LWS_WITH_POLL) #include "event-libs/poll/private.h" #endif -#if defined(LWS_WITH_LIBEV) -#include "event-libs/libev/private.h" -#endif + #if defined(LWS_WITH_LIBUV) #include "event-libs/libuv/private.h" #endif -#if defined(LWS_WITH_LIBEVENT) && !defined(LWS_HIDE_LIBEVENT) + +#if defined(LWS_WITH_LIBEVENT) #include "event-libs/libevent/private.h" #endif +#if defined(LWS_WITH_LIBEV) +#include "event-libs/libev/private.h" +#endif /* enums of socks version */ @@ -1180,6 +1184,7 @@ struct lws_context { unsigned int deprecated:1; unsigned int being_destroyed:1; unsigned int being_destroyed1:1; + unsigned int being_destroyed2:1; unsigned int requested_kill:1; unsigned int protocol_init_done:1; unsigned int ssl_gate_accepts:1; @@ -1246,37 +1251,6 @@ enum { LWS_EV_PREPARE_DELETION = (1 << 31), }; -#if !defined(LWS_WITH_LIBEV) -#define LWS_LIBEV_ENABLED(context) (0) -#if !defined(LWS_WITH_ESP32) -#define lws_feature_status_libev(_a) \ - lwsl_info("libev support not compiled in\n") -#else -#define lws_feature_status_libev(_a) -#endif -#endif - -#if !defined(LWS_WITH_LIBUV) -#define LWS_LIBUV_ENABLED(context) (0) -#if !defined(LWS_WITH_ESP32) -#define lws_feature_status_libuv(_a) \ - lwsl_info("libuv support not compiled in\n") -#else -#define lws_feature_status_libuv(_a) -#endif -#endif - -#if !defined(LWS_WITH_LIBEVENT) -#define lws_libevent_destroyloop(_a, _b) ((void) 0) -#define LWS_LIBEVENT_ENABLED(context) (0) -#if !defined(LWS_WITH_ESP32) -#define lws_feature_status_libevent(_a) \ - lwsl_info("libevent support not compiled in\n") -#else -#define lws_feature_status_libevent(_a) -#endif -#endif - #if defined(LWS_WITH_ESP32) LWS_EXTERN int diff --git a/lib/service.c b/lib/service.c index d9b82ab2..291995cf 100644 --- a/lib/service.c +++ b/lib/service.c @@ -790,6 +790,9 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws *wsi; + if (!context || context->being_destroyed1) + return -1; + /* the socket we came to service timed out, nothing to do */ if (lws_service_periodic_checks(context, pollfd, tsi) || !pollfd) return 0; @@ -862,13 +865,13 @@ close_and_handled: lwsl_debug("%p: Close and handled\n", wsi); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "close_and_handled"); -#if defined(_DEBUG) +#if defined(_DEBUG) && defined(LWS_WITH_LIBUV) /* * confirm close has no problem being called again while * it waits for libuv service to complete the first async * close */ - if (LWS_LIBUV_ENABLED(context)) + if (context->event_loop_ops == &event_loop_ops_uv) lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "close_and_handled uv repeat test"); #endif diff --git a/minimal-examples/http-server/README.md b/minimal-examples/http-server/README.md index 212d5ee4..d9ea25f3 100644 --- a/minimal-examples/http-server/README.md +++ b/minimal-examples/http-server/README.md @@ -2,11 +2,11 @@ ---|--- minimal-http-server-basicauth|Shows how to protect a mount using a password file and basic auth minimal-http-server-dynamic|Serves both static and dynamically generated http content +minimal-http-server-eventlib-foreign|Demonstrates integrating lws with a foreign event library +minimal-http-server-eventlib|Same as minimal-http-server but works with a supported event library minimal-http-server-form-get|Process a GET form minimal-http-server-form-post-file|Process a multipart POST form with file transfer minimal-http-server-form-post|Process a POST form (no file transfer) -minimal-http-server-libuv-foreign|Same as minimal-http-server but lws uses a foreign libuv event loop -minimal-http-server-libuv|Same as minimal-http-server but lws uses its own libuv event loop minimal-http-server-multivhost|Same as minimal-http-server but three different vhosts minimal-http-server-smp|Multiple service threads minimal-http-server-sse-ring|Server Side Events with ringbuffer and threaded event sources diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv-foreign/CMakeLists.txt rename to minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/README.md b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv-foreign/README.md rename to minimal-examples/http-server/minimal-http-server-eventlib-foreign/README.md diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.cert b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/localhost-100y.cert similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.cert rename to minimal-examples/http-server/minimal-http-server-eventlib-foreign/localhost-100y.cert diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.key b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/localhost-100y.key similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.key rename to minimal-examples/http-server/minimal-http-server-eventlib-foreign/localhost-100y.key diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/minimal-http-server-libuv-foreign.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-libuv-foreign.c similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv-foreign/minimal-http-server-libuv-foreign.c rename to minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-libuv-foreign.c diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/404.html b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/mount-origin/404.html similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/404.html rename to minimal-examples/http-server/minimal-http-server-eventlib-foreign/mount-origin/404.html diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/favicon.ico b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/mount-origin/favicon.ico similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/favicon.ico rename to minimal-examples/http-server/minimal-http-server-eventlib-foreign/mount-origin/favicon.ico diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/index.html b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/mount-origin/index.html similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/index.html rename to minimal-examples/http-server/minimal-http-server-eventlib-foreign/mount-origin/index.html diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/libwebsockets.org-logo.png b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/mount-origin/libwebsockets.org-logo.png similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv-foreign/mount-origin/libwebsockets.org-logo.png rename to minimal-examples/http-server/minimal-http-server-eventlib-foreign/mount-origin/libwebsockets.org-logo.png diff --git a/minimal-examples/http-server/minimal-http-server-libuv/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-eventlib/CMakeLists.txt similarity index 93% rename from minimal-examples/http-server/minimal-http-server-libuv/CMakeLists.txt rename to minimal-examples/http-server/minimal-http-server-eventlib/CMakeLists.txt index d95e7533..66a44523 100644 --- a/minimal-examples/http-server/minimal-http-server-libuv/CMakeLists.txt +++ b/minimal-examples/http-server/minimal-http-server-eventlib/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 2.8) include(CheckCSourceCompiles) -set(SAMP lws-minimal-http-server-libuv) -set(SRCS minimal-http-server-libuv.c) +set(SAMP lws-minimal-http-server-eventlib) +set(SRCS minimal-http-server-eventlib.c) # If we are being built as part of lws, confirm current build config supports # reqconfig, else skip building ourselves. @@ -64,7 +64,6 @@ ENDMACRO() set(requirements 1) require_lws_config(LWS_ROLE_H1 1 requirements) -require_lws_config(LWS_WITH_LIBUV 1 requirements) require_lws_config(LWS_WITHOUT_SERVER 0 requirements) if (requirements) diff --git a/minimal-examples/http-server/minimal-http-server-libuv/README.md b/minimal-examples/http-server/minimal-http-server-eventlib/README.md similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv/README.md rename to minimal-examples/http-server/minimal-http-server-eventlib/README.md diff --git a/minimal-examples/http-server/minimal-http-server-libuv/localhost-100y.cert b/minimal-examples/http-server/minimal-http-server-eventlib/localhost-100y.cert similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv/localhost-100y.cert rename to minimal-examples/http-server/minimal-http-server-eventlib/localhost-100y.cert diff --git a/minimal-examples/http-server/minimal-http-server-libuv/localhost-100y.key b/minimal-examples/http-server/minimal-http-server-eventlib/localhost-100y.key similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv/localhost-100y.key rename to minimal-examples/http-server/minimal-http-server-eventlib/localhost-100y.key diff --git a/minimal-examples/http-server/minimal-http-server-libuv/minimal-http-server-libuv.c b/minimal-examples/http-server/minimal-http-server-eventlib/minimal-http-server-libuv.c similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv/minimal-http-server-libuv.c rename to minimal-examples/http-server/minimal-http-server-eventlib/minimal-http-server-libuv.c diff --git a/minimal-examples/http-server/minimal-http-server-libuv/mount-origin/404.html b/minimal-examples/http-server/minimal-http-server-eventlib/mount-origin/404.html similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv/mount-origin/404.html rename to minimal-examples/http-server/minimal-http-server-eventlib/mount-origin/404.html diff --git a/minimal-examples/http-server/minimal-http-server-libuv/mount-origin/favicon.ico b/minimal-examples/http-server/minimal-http-server-eventlib/mount-origin/favicon.ico similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv/mount-origin/favicon.ico rename to minimal-examples/http-server/minimal-http-server-eventlib/mount-origin/favicon.ico diff --git a/minimal-examples/http-server/minimal-http-server-libuv/mount-origin/index.html b/minimal-examples/http-server/minimal-http-server-eventlib/mount-origin/index.html similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv/mount-origin/index.html rename to minimal-examples/http-server/minimal-http-server-eventlib/mount-origin/index.html diff --git a/minimal-examples/http-server/minimal-http-server-libuv/mount-origin/libwebsockets.org-logo.png b/minimal-examples/http-server/minimal-http-server-eventlib/mount-origin/libwebsockets.org-logo.png similarity index 100% rename from minimal-examples/http-server/minimal-http-server-libuv/mount-origin/libwebsockets.org-logo.png rename to minimal-examples/http-server/minimal-http-server-eventlib/mount-origin/libwebsockets.org-logo.png diff --git a/test-apps/test-server-libuv.c b/test-apps/test-server-libuv.c deleted file mode 100644 index f20cf8bc..00000000 --- a/test-apps/test-server-libuv.c +++ /dev/null @@ -1,510 +0,0 @@ -/* - * libwebsockets-test-server for libev - libwebsockets test implementation - * - * Copyright (C) 2010-2015 Andy Green - * - * 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 -#include -#include -#include -#include - -int close_testing; -int max_poll_elements; -int debug_level = 7; -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; - -#if defined(LWS_WITH_TLS) && defined(LWS_HAVE_SSL_CTX_set1_param) -char crl_path[1024] = ""; -#endif - -/* singlethreaded version --> no locks */ - -void test_server_lock(int care) -{ -} -void test_server_unlock(int care) -{ -} - -#define LWS_PLUGIN_STATIC -#if defined(LWS_ROLE_WS) -#include "../plugins/protocol_dumb_increment.c" -#include "../plugins/protocol_lws_mirror.c" -#include "../plugins/protocol_lws_status.c" -#include "../plugins/protocol_post_demo.c" -#endif - - -/* list of supported protocols and callbacks */ - -static struct lws_protocols protocols[] = { - /* first protocol must always be HTTP handler */ - - { "http-only", lws_callback_http_dummy, 0, 0, }, -#if defined(LWS_ROLE_WS) - LWS_PLUGIN_PROTOCOL_DUMB_INCREMENT, - LWS_PLUGIN_PROTOCOL_MIRROR, - LWS_PLUGIN_PROTOCOL_LWS_STATUS, - LWS_PLUGIN_PROTOCOL_POST_DEMO, -#endif - { 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" - }, - { NULL, NULL, NULL /* terminator */ } -}; - -void signal_cb(void *handle, int signum) -{ - uv_signal_t *watcher = (uv_signal_t *)handle; - - lwsl_err("Signal %d caught, exiting...\n", watcher->signum); - switch (watcher->signum) { - case SIGTERM: - case SIGINT: - break; - default: - signal(SIGABRT, SIG_DFL); - abort(); - break; - } - lws_context_destroy(context); -} - -/* - * mount handlers for sections of the URL space - */ - -static const struct lws_http_mount mount_ziptest = { - NULL, /* linked-list pointer to next*/ - "/ziptest", /* mountpoint in URL namespace on this vhost */ - LOCAL_RESOURCE_PATH"/candide.zip", /* handler */ - NULL, /* default filename if none given */ - NULL, - NULL, - NULL, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - LWSMPRO_FILE, /* origin points to a callback */ - 8, /* strlen("/ziptest"), ie length of the mountpoint */ - NULL, - - { NULL, NULL } // sentinel -}; - -static const struct lws_http_mount mount_post = { - (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/ - "/formtest", /* mountpoint in URL namespace on this vhost */ - "protocol-post-demo", /* handler */ - NULL, /* default filename if none given */ - NULL, - NULL, - NULL, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - LWSMPRO_CALLBACK, /* origin points to a callback */ - 9, /* strlen("/formtest"), ie length of the mountpoint */ - NULL, - - { NULL, NULL } // sentinel -}; - -/* - * mount a filesystem directory into the URL space at / - * point it to our /usr/share directory with our assets in - * stuff from here is autoserved by the library - */ - -static const struct lws_http_mount mount = { - (struct lws_http_mount *)&mount_post, /* linked-list pointer to next*/ - "/", /* mountpoint in URL namespace on this vhost */ - LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */ - "test.html", /* default filename if none given */ - NULL, - NULL, - NULL, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - LWSMPRO_FILE, /* mount type is a directory in a filesystem */ - 1, /* strlen("/"), ie length of the mountpoint */ - NULL, - - { NULL, NULL } // sentinel -}; - -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' }, - { "foreign", no_argument, NULL, 'f' }, -#ifndef LWS_NO_DAEMONIZE - { "daemonize", no_argument, NULL, 'D' }, -#endif - { "resource_path", required_argument, NULL, 'r' }, - { NULL, 0, 0, 0 } -}; - -#if UV_VERSION_MAJOR > 0 -/* ----- this code is only needed for foreign / external libuv tests -----*/ -struct counter -{ - int cur, lim; - int stop_loop; -}; - -static void timer_cb(uv_timer_t *t) -{ - struct counter *c = t->data; - - lwsl_notice(" timer %p cb, count %d, loop has %d handles\n", - t, c->cur, t->loop->active_handles); - - if (c->cur++ == c->lim) { - lwsl_debug("stop loop from timer\n"); - uv_timer_stop(t); - if (c->stop_loop) - uv_stop(t->loop); - } -} - -static void timer_test_cancel_cb(uv_timer_t *h) -{ - if (context) { - lwsl_notice("(doing cancel test)\n"); - lws_cancel_service(context); - } -} - - -static void timer_close_cb(uv_handle_t *h) -{ - lwsl_notice("timer close cb %p, loop has %d handles\n", - h, h->loop->active_handles); -} - -static void walk_cb(uv_handle_t *h, void *arg) -{ - lwsl_err("%s: handle %p: type %d\n", __func__, h, h->type); -} - -void outer_signal_cb(uv_signal_t *s, int signum) -{ - lwsl_notice("Foreign loop got signal %d\n", signum); - uv_signal_stop(s); - uv_stop(s->loop); -} - -/* --- end of foreign test code ---- */ -#endif - -int main(int argc, char **argv) -{ - struct lws_context_creation_info info; - char interface_name[128] = ""; -#if UV_VERSION_MAJOR > 0 -/* --- only needed for foreign loop test ---> */ - uv_loop_t loop; - uv_signal_t signal_outer; - uv_timer_t timer_outer; - struct counter ctr; - int foreign_libuv_loop = 0; - uv_timer_t timer_test_cancel; -/* <--- only needed for foreign loop test --- */ -#endif - const char *iface = NULL; - char cert_path[1024]; - char key_path[1024]; - void *foreign_loops[1]; - int use_ssl = 0; - int opts = 0; - int n = 0; -#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, "feci:hsap:d:Dr:", options, NULL); - if (n < 0) - continue; - switch (n) { - case 'f': -#if UV_VERSION_MAJOR > 0 - foreign_libuv_loop = 1; -#endif - break; - 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': - lws_strncpy(interface_name, optarg, sizeof interface_name); - 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=

] [--ssl] " - "[-d ] " - "[--resource_path ]\n"); - exit(1); - } - } - -#if !defined(WIN32) -#if !defined(LWS_NO_DAEMONIZE) - /* - * 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 -#endif - - /* tell the library what debug level to emit and to send it to stderr */ - lws_set_log_level(debug_level, NULL); - - lwsl_notice("libwebsockets test server libuv - license LGPL2.1+SLE\n"); - lwsl_notice("(C) Copyright 2010-2018 Andy Green \n"); - - lwsl_info("Using resource path \"%s\"\n", resource_path); - - info.iface = iface; - info.protocols = protocols; - info.extensions = exts; - info.mounts = &mount; - info.pcontext = &context; - - 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; - opts |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; - } - info.gid = -1; - info.uid = -1; - info.timeout_secs = 5; - info.options = opts | LWS_SERVER_OPTION_LIBUV; - -#if UV_VERSION_MAJOR > 0 - if (foreign_libuv_loop) { - /* create the foreign loop */ - uv_loop_init(&loop); - - /* run some timer on that loop just so loop is not 'clean' */ - - uv_signal_init(&loop, &signal_outer); - uv_signal_start(&signal_outer, outer_signal_cb, SIGINT); - - uv_timer_init(&loop, &timer_test_cancel); - uv_timer_start(&timer_test_cancel, timer_test_cancel_cb, 2000, 2000); - - uv_timer_init(&loop, &timer_outer); - timer_outer.data = &ctr; - ctr.cur = 0; - ctr.lim = ctr.cur + 5; - ctr.stop_loop = 1; - uv_timer_start(&timer_outer, timer_cb, 0, 1000); - lwsl_notice("running loop without libwebsockets for %d s\n", ctr.lim); - - uv_run(&loop, UV_RUN_DEFAULT); - - /* timer will stop loop and we will get here */ - - foreign_loops[0] = &loop; - info.foreign_loops = foreign_loops; - } else - info.signal_cb = signal_cb; -#endif - - context = lws_create_context(&info); - if (context == NULL) { - lwsl_err("libwebsocket init failed\n"); - return -1; - } - -#if UV_VERSION_MAJOR > 0 - if (foreign_libuv_loop) { - /* - * prepare inner timer on loop, to run along with lws. - * Will exit after 5s while lws keeps running - */ - struct counter ctr_inner = { 0, 3, 0 }; - int e; - uv_timer_t timer_inner; - uv_timer_init(&loop, &timer_inner); - timer_inner.data = &ctr_inner; - uv_timer_start(&timer_inner, timer_cb, 200, 1000); - - /* make this timer long-lived, should keep - * firing after lws exits */ - ctr.cur = 0; - ctr.lim = ctr.cur + 1000; - uv_timer_start(&timer_outer, timer_cb, 0, 1000); - - uv_run(&loop, UV_RUN_DEFAULT); - - /* we are here either because signal stopped us, - * or outer timer expired */ - - /* stop short timer */ - uv_timer_stop(&timer_inner); - - lwsl_notice("Destroying lws context\n"); - - /* detach lws */ - lws_context_destroy(context); - - lwsl_notice("Please wait while the outer libuv test continues for 10s\n"); - - ctr.lim = ctr.cur + 10; - - /* try and run outer timer for 10 more seconds, - * (or sigint outer handler) after lws has left the loop */ - uv_run(&loop, UV_RUN_DEFAULT); - - /* Clean up the foreign loop now */ - - /* PHASE 1: stop and close things we created - * outside of lws */ - - uv_timer_stop(&timer_outer); - uv_close((uv_handle_t*)&timer_outer, timer_close_cb); - uv_timer_stop(&timer_test_cancel); - uv_close((uv_handle_t*)&timer_test_cancel, timer_close_cb); - uv_timer_stop(&timer_inner); - uv_close((uv_handle_t*)&timer_inner, timer_close_cb); - uv_signal_stop(&signal_outer); - uv_close((uv_handle_t*)&signal_outer, NULL); - - e = 100; - while (e--) - uv_run(&loop, UV_RUN_NOWAIT); - - /* PHASE 2: close the UV loop itself */ - - e = uv_loop_close(&loop); - if (e) { - lwsl_notice("uv loop close rc %s\n", e ? uv_strerror(e) : "ok"); - - uv_walk(&loop, walk_cb, NULL); - } - - } else -#endif - { - lws_service(context, 0); - - /* - * we can't destroy the internal loops while they are running - */ - lws_context_destroy(context); - } - - lwsl_notice("libwebsockets-test-server exited cleanly\n"); - - context = NULL; - - return 0; -} diff --git a/test-apps/test-server-v2.0.c b/test-apps/test-server-v2.0.c deleted file mode 100644 index 8873d71b..00000000 --- a/test-apps/test-server-v2.0.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * libwebsockets-test-server-v2.0 - libwebsockets test implementation - * - * Copyright (C) 2010-2016 Andy Green - * - * 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 -#include -#include -#ifndef WIN32 -#include -#include -#include -#endif - -/* windows has no SIGUSR1 */ -#if !defined(WIN32) && !defined(_WIN32) -#define TEST_DYNAMIC_VHOST -#endif - -struct lws_context_creation_info info; -int debug_level = 7; -struct lws_context *context; - -#if defined(TEST_DYNAMIC_VHOST) -volatile int dynamic_vhost_enable = 0; -struct lws_vhost *dynamic_vhost; -uv_timer_t timeout_watcher; -#endif - -/* http server gets files from this path */ -#define LOCAL_RESOURCE_PATH INSTALL_DATADIR"/libwebsockets-test-server" -char *resource_path = LOCAL_RESOURCE_PATH; - -#if defined(LWS_WITH_TLS) && defined(LWS_HAVE_SSL_CTX_set1_param) -char crl_path[1024] = ""; -#endif - -/* - * This test server is ONLY this .c file, it's radically simpler than the - * pre-v2.0 test servers. For example it has no user callback content or - * defines any protocols. - * - * To achieve that, it uses the LWS protocol plugins. Those in turn - * use libuv. So you must configure with LWS_WITH_PLUGINS (which implies - * libuv) to get this to build. - * - * You can find the individual protocol plugin sources in ../plugins - */ - -#if defined(TEST_DYNAMIC_VHOST) - -/* - * to test dynamic vhost creation, fire a SIGUSR1 at the test server. - * It will toggle the existence of a second identical vhost at port + 1 - * - * To synchronize with the event loop, it uses a libuv timer with 0 delay - * to get the business end called as the next event. - */ - -static void -uv_timeout_dynamic_vhost_toggle(uv_timer_t *w -#if UV_VERSION_MAJOR == 0 - , int status -#endif -) -{ - if (dynamic_vhost_enable && !dynamic_vhost) { - lwsl_notice("creating dynamic vhost...\n"); - dynamic_vhost = lws_create_vhost(context, &info); - } else - if (!dynamic_vhost_enable && dynamic_vhost) { - lwsl_notice("destroying dynamic vhost...\n"); - lws_vhost_destroy(dynamic_vhost); - dynamic_vhost = NULL; - } -} - -void sighandler_USR1(int sig) -{ - dynamic_vhost_enable ^= 1; - lwsl_notice("SIGUSR1: dynamic_vhost_enable: %d\n", - dynamic_vhost_enable); - uv_timer_start(&timeout_watcher, - uv_timeout_dynamic_vhost_toggle, 0, 0); -} -#endif - -void sighandler(int sig) -{ - lws_cancel_service(context); -} - -static const struct lws_extension exts[] = { - { - "permessage-deflate", - lws_extension_callback_pm_deflate, - "permessage-deflate" - }, - { NULL, NULL, NULL /* terminator */ } -}; - -/* - * mount handlers for sections of the URL space - */ - -static const struct lws_http_mount mount_ziptest = { - NULL, /* linked-list pointer to next*/ - "/ziptest", /* mountpoint in URL namespace on this vhost */ - LOCAL_RESOURCE_PATH"/candide.zip", /* handler */ - NULL, /* default filename if none given */ - NULL, - NULL, - NULL, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - LWSMPRO_FILE, /* origin points to a callback */ - 8, /* strlen("/ziptest"), ie length of the mountpoint */ - NULL, - - { NULL, NULL } // sentinel -}; - -static const struct lws_http_mount mount_post = { - (struct lws_http_mount *)&mount_ziptest, /* linked-list pointer to next*/ - "/formtest", /* mountpoint in URL namespace on this vhost */ - "protocol-post-demo", /* handler */ - NULL, /* default filename if none given */ - NULL, - NULL, - NULL, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - LWSMPRO_CALLBACK, /* origin points to a callback */ - 9, /* strlen("/formtest"), ie length of the mountpoint */ - NULL, - - { NULL, NULL } // sentinel -}; - -/* - * mount a filesystem directory into the URL space at / - * point it to our /usr/share directory with our assets in - * stuff from here is autoserved by the library - */ - -static const struct lws_http_mount mount = { - (struct lws_http_mount *)&mount_post, /* linked-list pointer to next*/ - "/", /* mountpoint in URL namespace on this vhost */ - LOCAL_RESOURCE_PATH, /* where to go on the filesystem for that */ - "test.html", /* default filename if none given */ - NULL, - NULL, - NULL, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - LWSMPRO_FILE, /* mount type is a directory in a filesystem */ - 1, /* strlen("/"), ie length of the mountpoint */ - NULL, - - { NULL, NULL } // sentinel -}; - -/* - * this sets a per-vhost, per-protocol option name:value pair - * the effect is to set this protocol to be the default one for the vhost, - * ie, selected if no Protocol: header is sent with the ws upgrade. - */ -#if 0 -static const struct lws_protocol_vhost_options pvo_opt = { - NULL, - NULL, - "default", - "1" -}; -#endif - -static const struct lws_protocol_vhost_options pvo_opt4a = { - NULL, - NULL, - "raw", /* indicate we are the protocol that gets raw connections */ - "1" -}; - -static const struct lws_protocol_vhost_options pvo_opt4 = { - &pvo_opt4a, - NULL, - "fifo-path", /* tell the raw test plugin to open a raw file here */ - "/tmp/lws-test-raw" -}; - -/* - * We must enable the plugin protocols we want into our vhost with a - * linked-list. We can also give the plugin per-vhost options here. - */ - -static const struct lws_protocol_vhost_options pvo_5 = { - NULL, - NULL, - "lws-meta", - "" /* ignored, just matches the protocol name above */ -}; - -static const struct lws_protocol_vhost_options pvo_4 = { - &pvo_5, - &pvo_opt4, /* set us as the protocol who gets raw connections */ - "protocol-lws-raw-test", - "" /* ignored, just matches the protocol name above */ -}; - -static const struct lws_protocol_vhost_options pvo_3 = { - &pvo_4, - NULL, - "protocol-post-demo", - "" /* ignored, just matches the protocol name above */ -}; - -static const struct lws_protocol_vhost_options pvo_2 = { - &pvo_3, - NULL, - "lws-status", - "" /* ignored, just matches the protocol name above */ -}; - -static const struct lws_protocol_vhost_options pvo_1 = { - &pvo_2, - NULL, - "lws-mirror-protocol", - "" -}; - -static const struct lws_protocol_vhost_options pvo = { - &pvo_1, - NULL, // &pvo_opt, - "dumb-increment-protocol", - "" -}; - -static void signal_cb(void *handle, int signum) -{ - uv_signal_t *watcher = (uv_signal_t *)handle; - - lwsl_err("Signal %d caught, exiting...\n", watcher->signum); - switch (watcher->signum) { - case SIGTERM: - case SIGINT: - break; - default: - signal(SIGABRT, SIG_DFL); - abort(); - break; - } - lws_context_destroy(context); -} - -static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "debug", required_argument, NULL, 'd' }, - { "port", required_argument, NULL, 'p' }, - { "ssl", no_argument, NULL, 's' }, - { "ssl-alerts", no_argument, NULL, 'S' }, - { "allow-non-ssl", no_argument, NULL, 'a' }, - { "interface", required_argument, NULL, 'i' }, - { "ssl-cert", required_argument, NULL, 'C' }, - { "ssl-key", required_argument, NULL, 'K' }, - { "ssl-ca", required_argument, NULL, 'A' }, -#if defined(LWS_WITH_TLS) - { "ssl-verify-client", no_argument, NULL, 'v' }, -#if defined(LWS_HAVE_SSL_CTX_set1_param) - { "ssl-crl", required_argument, NULL, 'R' }, -#endif -#endif -#ifndef LWS_NO_DAEMONIZE - { "daemonize", no_argument, NULL, 'D' }, -#endif - { "resource_path", required_argument, NULL, 'r' }, - { NULL, 0, 0, 0 } -}; - -static const char * const plugin_dirs[] = { - INSTALL_DATADIR"/libwebsockets-test-server/plugins/", - NULL -}; - -int main(int argc, char **argv) -{ - struct lws_vhost *vhost; - char interface_name[128] = ""; - const char *iface = NULL; - char cert_path[1024] = ""; - char key_path[1024] = ""; - char ca_path[1024] = ""; - int uid = -1, gid = -1; - void *foreign_loops[1]; - int use_ssl = 0; - uv_loop_t loop; - int opts = 0; - int n = 0; -#ifndef _WIN32 - int syslog_options = LOG_PID | LOG_PERROR; -#endif -#ifndef LWS_NO_DAEMONIZE - int daemonize = 0; -#endif - - info.port = 7681; - - while (n >= 0) { - n = getopt_long(argc, argv, "i:hsap:d:Dr:C:K:A:R:vu:g:S", - (struct option *)options, NULL); - if (n < 0) - continue; - switch (n) { -#ifndef LWS_NO_DAEMONIZE - case 'D': - daemonize = 1; - #ifndef _WIN32 - syslog_options &= ~LOG_PERROR; - #endif - break; -#endif - case 'u': - uid = atoi(optarg); - break; - case 'g': - gid = atoi(optarg); - break; - case 'd': - debug_level = atoi(optarg); - break; - case 's': - use_ssl = 1; - break; - case 'S': -#if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS) - info.ssl_info_event_mask |= SSL_CB_ALERT; -#endif - break; - case 'a': - opts |= LWS_SERVER_OPTION_ALLOW_NON_SSL_ON_SSL_PORT; - break; - case 'p': - info.port = atoi(optarg); - break; - case 'i': - lws_strncpy(interface_name, optarg, sizeof interface_name); - iface = interface_name; - break; - case 'r': - resource_path = optarg; - printf("Setting resource path to \"%s\"\n", resource_path); - break; - case 'C': - lws_strncpy(cert_path, optarg, sizeof(cert_path)); - break; - case 'K': - lws_strncpy(key_path, optarg, sizeof(key_path)); - break; - case 'A': - lws_strncpy(ca_path, optarg, sizeof(ca_path)); - break; -#if defined(LWS_WITH_TLS) - case 'v': - use_ssl = 1; - opts |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT; - break; - -#if defined(LWS_HAVE_SSL_CTX_set1_param) - case 'R': - lws_strncpy(crl_path, optarg, sizeof(crl_path)); - break; -#endif -#endif - case 'h': - fprintf(stderr, "Usage: test-server " - "[--port=

] [--ssl] " - "[-d ] " - "[--resource_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 10; - } -#endif - - signal(SIGINT, sighandler); -#if defined(TEST_DYNAMIC_VHOST) - signal(SIGUSR1, sighandler_USR1); -#endif - -#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 */ - lws_set_log_level(debug_level, NULL); - - lwsl_notice("libwebsockets test server - license LGPL2.1+SLE\n"); - lwsl_notice("(C) Copyright 2010-2017 Andy Green \n"); - - lwsl_notice(" Using resource path \"%s\"\n", resource_path); - -#if UV_VERSION_MAJOR > 0 - uv_loop_init(&loop); -#endif -#if defined(TEST_DYNAMIC_VHOST) - uv_timer_init(&loop, &timeout_watcher); -#endif - info.iface = iface; - info.protocols = NULL; /* all protocols from lib / plugins */ - info.ssl_cert_filepath = NULL; - info.ssl_private_key_filepath = NULL; - info.gid = gid; - info.uid = uid; - info.max_http_header_pool = 16; - info.options = opts | LWS_SERVER_OPTION_EXPLICIT_VHOSTS | - LWS_SERVER_OPTION_FALLBACK_TO_RAW | - LWS_SERVER_OPTION_VALIDATE_UTF8 | - LWS_SERVER_OPTION_LIBUV; /* plugins require this */ - - if (use_ssl) { - if (strlen(resource_path) > sizeof(cert_path) - 32) { - lwsl_err("resource path too long\n"); - return -1; - } - if (!cert_path[0]) - 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; - } - if (!key_path[0]) - sprintf(key_path, "%s/libwebsockets-test-server.key.pem", - resource_path); - - info.ssl_cert_filepath = cert_path; - info.ssl_private_key_filepath = key_path; - if (ca_path[0]) - info.ssl_ca_filepath = ca_path; - - /* redirect guys coming on http */ - info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS; - } - - info.extensions = exts; - info.timeout_secs = 5; - info.ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:" - "ECDHE-RSA-AES256-GCM-SHA384:" - "DHE-RSA-AES256-GCM-SHA384:" - "ECDHE-RSA-AES256-SHA384:" - "HIGH:!aNULL:!eNULL:!EXPORT:" - "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:" - "!SHA1:!DHE-RSA-AES128-GCM-SHA256:" - "!DHE-RSA-AES128-SHA256:" - "!AES128-GCM-SHA256:" - "!AES128-SHA256:" - "!DHE-RSA-AES256-SHA256:" - "!AES256-GCM-SHA384:" - "!AES256-SHA256"; - - /* tell lws to look for protocol plugins here */ - info.plugin_dirs = plugin_dirs; - - /* tell lws about our mount we want */ - info.mounts = &mount; - /* - * give it our linked-list of Per-Vhost Options, these control - * which protocols (from plugins) are allowed to be enabled on - * our vhost - */ - info.pvo = &pvo; - info.signal_cb = signal_cb; - - foreign_loops[0] = &loop; - info.foreign_loops = foreign_loops; - - /* - * Since we used LWS_SERVER_OPTION_EXPLICIT_VHOSTS, this only creates - * the context. We can modify info and create as many vhosts as we - * like subsequently. - */ - context = lws_create_context(&info); - if (context == NULL) { - lwsl_err("libwebsocket init failed\n"); - return -1; - } - - /* - * normally we would adapt at least info.name to reflect the - * external hostname for this server. - */ - vhost = lws_create_vhost(context, &info); - if (!vhost) { - lwsl_err("vhost creation failed\n"); - return -1; - } - -#if defined(TEST_DYNAMIC_VHOST) - /* our dynamic vhost is on port + 1 */ - info.port++; -#endif - - lws_service(context, 0); - - /* when we decided to exit the event loop */ - lws_context_destroy(context); - - -#if defined(TEST_DYNAMIC_VHOST) - uv_timer_stop(&timeout_watcher); - uv_close((uv_handle_t *)&timeout_watcher, NULL); - - /* let it run until everything completed close */ - uv_run(&loop, UV_RUN_DEFAULT); -#endif - - /* nothing left in the foreign loop, destroy it */ -#if UV_VERSION_MAJOR > 0 - uv_loop_close(&loop); -#endif - lwsl_notice("libwebsockets-test-server exited cleanly\n"); - -#ifndef _WIN32 - closelog(); -#endif - - return 0; -}