refactor: apply ops structs to event loop handlers
This commit is contained in:
parent
d05b408cde
commit
d37b383edc
38 changed files with 1470 additions and 1147 deletions
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -1,4 +1,12 @@
|
|||
#Ignore build files
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
build
|
||||
cmake_install.cmake
|
||||
lws-minimal*
|
||||
Makefile
|
||||
.cproject
|
||||
.project
|
||||
config.h
|
||||
config.log
|
||||
config.status
|
||||
|
@ -38,4 +46,4 @@ ar-lib
|
|||
libwebsockets.pc
|
||||
build/
|
||||
*.swp
|
||||
doc
|
||||
doc
|
||||
|
|
|
@ -11,6 +11,7 @@ if(WIN32)
|
|||
endif()
|
||||
|
||||
set(LWS_ROLE_RAW 1)
|
||||
set(LWS_WITH_POLL 1)
|
||||
|
||||
#
|
||||
# Select features recommended for PC distro packaging
|
||||
|
@ -947,9 +948,9 @@ if (LWS_WITH_HTTP_PROXY)
|
|||
lib/roles/http/server/rewrite.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
if (LWS_WITH_POLL)
|
||||
list(APPEND SOURCES
|
||||
lib/event-libs/libev/libev.c)
|
||||
lib/event-libs/poll/poll.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBUV)
|
||||
|
@ -962,6 +963,11 @@ if (LWS_WITH_LIBEVENT)
|
|||
lib/event-libs/libevent/libevent.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
list(APPEND SOURCES
|
||||
lib/event-libs/libev/libev.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LEJP)
|
||||
list(APPEND SOURCES
|
||||
lib/misc/lejp.c)
|
||||
|
|
335
lib/context.c
335
lib/context.c
|
@ -817,7 +817,7 @@ lws_create_vhost(struct lws_context *context,
|
|||
goto bail1;
|
||||
}
|
||||
lws_context_lock(context);
|
||||
n = _lws_context_init_server(info, vh);
|
||||
n = _lws_vhost_init_server(info, vh);
|
||||
lws_context_unlock(context);
|
||||
if (n < 0) {
|
||||
lwsl_err("init server failed\n");
|
||||
|
@ -926,26 +926,34 @@ lws_create_event_pipes(struct lws_context *context)
|
|||
|
||||
context->pt[n].pipe_wsi = wsi;
|
||||
|
||||
lws_libuv_accept(wsi, wsi->desc);
|
||||
lws_libev_accept(wsi, wsi->desc);
|
||||
lws_libevent_accept(wsi, wsi->desc);
|
||||
if (context->event_loop_ops->accept)
|
||||
context->event_loop_ops->accept(wsi);
|
||||
|
||||
if (__insert_wsi_socket_into_fds(context, wsi))
|
||||
return 1;
|
||||
|
||||
lws_change_pollfd(context->pt[n].pipe_wsi, 0, LWS_POLLIN);
|
||||
//lws_change_pollfd(context->pt[n].pipe_wsi, 0, LWS_POLLIN);
|
||||
context->count_wsi_allocated++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
lws_destroy_event_pipe(struct lws *wsi)
|
||||
{
|
||||
lws_plat_pipe_close(wsi);
|
||||
lwsl_info("%s\n", __func__);
|
||||
__remove_wsi_socket_from_fds(wsi);
|
||||
lws_libevent_destroy(wsi);
|
||||
|
||||
if (wsi->context->event_loop_ops->wsi_logical_close) {
|
||||
wsi->context->event_loop_ops->wsi_logical_close(wsi);
|
||||
lws_plat_pipe_close(wsi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wsi->context->event_loop_ops->destroy_wsi)
|
||||
wsi->context->event_loop_ops->destroy_wsi(wsi);
|
||||
lws_plat_pipe_close(wsi);
|
||||
wsi->context->count_wsi_allocated--;
|
||||
lws_free(wsi);
|
||||
}
|
||||
|
@ -1056,6 +1064,7 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
info->external_baggage_free_on_destroy;
|
||||
|
||||
context->time_up = time(NULL);
|
||||
context->pcontext_finalize = info->pcontext;
|
||||
|
||||
context->simultaneous_ssl_restriction =
|
||||
info->simultaneous_ssl_restriction;
|
||||
|
@ -1089,6 +1098,40 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
|
||||
context->options = info->options;
|
||||
|
||||
/*
|
||||
* set the context event loops ops struct
|
||||
*
|
||||
* after this, all event_loop actions use the generic ops
|
||||
*/
|
||||
|
||||
#if defined(LWS_WITH_POLL)
|
||||
context->event_loop_ops = &event_loop_ops_poll;
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_LIBUV)
|
||||
if (LWS_LIBUV_ENABLED(context)) {
|
||||
context->event_loop_ops = &event_loop_ops_uv;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_WITH_LIBEV)
|
||||
if (LWS_LIBEV_ENABLED(context)) {
|
||||
context->event_loop_ops = &event_loop_ops_ev;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_WITH_LIBEVENT)
|
||||
if (LWS_LIBEVENT_ENABLED(context)) {
|
||||
context->event_loop_ops = &event_loop_ops_event;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!context->event_loop_ops) {
|
||||
lwsl_err("no event loop possible\n");
|
||||
|
||||
goto bail;
|
||||
}
|
||||
|
||||
lwsl_info("Using event loop: %s\n", context->event_loop_ops->name);
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
if (info->alpn)
|
||||
context->alpn_default = info->alpn;
|
||||
|
@ -1135,6 +1178,12 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
else
|
||||
context->max_http_header_pool = context->max_fds;
|
||||
|
||||
if (info->fd_limit_per_thread)
|
||||
context->fd_limit_per_thread = info->fd_limit_per_thread;
|
||||
else
|
||||
context->fd_limit_per_thread = context->max_fds /
|
||||
context->count_threads;
|
||||
|
||||
/*
|
||||
* Allocate the per-thread storage for scratchpad buffers,
|
||||
* and header data pool
|
||||
|
@ -1147,10 +1196,9 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_LIBUV
|
||||
context->pt[n].context = context;
|
||||
#endif
|
||||
context->pt[n].tid = n;
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
context->pt[n].http.ah_list = NULL;
|
||||
context->pt[n].http.ah_pool_length = 0;
|
||||
|
@ -1158,12 +1206,6 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
lws_pt_mutex_init(&context->pt[n]);
|
||||
}
|
||||
|
||||
if (info->fd_limit_per_thread)
|
||||
context->fd_limit_per_thread = info->fd_limit_per_thread;
|
||||
else
|
||||
context->fd_limit_per_thread = context->max_fds /
|
||||
context->count_threads;
|
||||
|
||||
lwsl_info(" Threads: %d each %d fds\n", context->count_threads,
|
||||
context->fd_limit_per_thread);
|
||||
|
||||
|
@ -1172,24 +1214,6 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_LIBEV
|
||||
if (LWS_LIBEV_ENABLED(context)) {
|
||||
context->use_event_loop_sigint = 1;
|
||||
context->ev.sigint_cb = &lws_ev_sigint_cb;
|
||||
}
|
||||
#endif /* LWS_WITH_LIBEV */
|
||||
#ifdef LWS_WITH_LIBUV
|
||||
if (LWS_LIBUV_ENABLED(context)) {
|
||||
context->use_event_loop_sigint = 1;
|
||||
context->uv.sigint_cb = &lws_uv_sigint_cb;
|
||||
}
|
||||
#endif
|
||||
#ifdef LWS_WITH_LIBEVENT
|
||||
if (LWS_LIBEVENT_ENABLED(context)) {
|
||||
context->use_event_loop_sigint = 1;
|
||||
context->event.sigint_cb = &lws_event_sigint_cb;
|
||||
}
|
||||
#endif /* LWS_WITH_LIBEVENT */
|
||||
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
/* scale the peer hash table according to the max fds for the process,
|
||||
|
@ -1245,6 +1269,25 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
if (lws_plat_init(context, info))
|
||||
goto bail;
|
||||
|
||||
if (context->event_loop_ops->init_context)
|
||||
if (context->event_loop_ops->init_context(context, info))
|
||||
goto bail;
|
||||
|
||||
|
||||
if (context->event_loop_ops->init_pt)
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
void *lp = NULL;
|
||||
|
||||
if (info->foreign_loops)
|
||||
lp = info->foreign_loops[n];
|
||||
|
||||
if (context->event_loop_ops->init_pt(context, lp, n))
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (lws_create_event_pipes(context))
|
||||
goto bail;
|
||||
|
||||
lws_context_init_ssl_library(info);
|
||||
|
||||
context->user_space = info->user;
|
||||
|
@ -1283,16 +1326,6 @@ lws_create_context(const struct lws_context_creation_info *info)
|
|||
context->count_caps = info->count_caps;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The event libs handle doing this when their event loop starts,
|
||||
* if we are using the default poll() service, do it here
|
||||
*/
|
||||
|
||||
if (!LWS_LIBEV_ENABLED(context) &&
|
||||
!LWS_LIBUV_ENABLED(context) &&
|
||||
!LWS_LIBEVENT_ENABLED(context) && lws_create_event_pipes(context))
|
||||
goto bail;
|
||||
|
||||
/*
|
||||
* drop any root privs for this process
|
||||
* to listen on port < 1023 we would have needed root, but now we are
|
||||
|
@ -1365,10 +1398,6 @@ lws_context_is_deprecated(struct lws_context *context)
|
|||
return context->deprecated;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_context_destroy2(struct lws_context *context);
|
||||
|
||||
|
||||
void
|
||||
lws_vhost_destroy1(struct lws_vhost *vh)
|
||||
{
|
||||
|
@ -1540,16 +1569,10 @@ lws_vhost_destroy2(struct lws_vhost *vh)
|
|||
lws_free(vh->protocol_vh_privs);
|
||||
lws_ssl_SSL_CTX_destroy(vh);
|
||||
lws_free(vh->same_vh_protocol_list);
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (LWS_LIBUV_ENABLED(context)) {
|
||||
if (context->plugin_list)
|
||||
lws_free((void *)vh->protocols);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
|
||||
lws_free((void *)vh->protocols);
|
||||
}
|
||||
|
||||
if (context->plugin_list ||
|
||||
(context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
|
||||
lws_free((void *)vh->protocols);
|
||||
|
||||
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
|
||||
if (ar->destroy_vhost)
|
||||
|
@ -1628,6 +1651,106 @@ lws_vhost_destroy(struct lws_vhost *vh)
|
|||
vh->context->deferred_free_list = df;
|
||||
}
|
||||
|
||||
/*
|
||||
* When using an event loop, the context destruction is in three separate
|
||||
* parts. This is to cover both internal and foreign event loops cleanly.
|
||||
*
|
||||
* - lws_context_destroy() simply starts a soft close of all wsi and
|
||||
* related allocations. The event loop continues.
|
||||
*
|
||||
* As the closes complete in the event loop, reference counting is used
|
||||
* to determine when everything is closed. It then calls
|
||||
* lws_context_destroy2().
|
||||
*
|
||||
* - lws_context_destroy2() cleans up the rest of the higher-level logical
|
||||
* lws pieces like vhosts. If the loop was foreign, it then proceeds to
|
||||
* lws_context_destroy3(). If it the loop is internal, it stops the
|
||||
* internal loops and waits for lws_context_destroy() to be called again
|
||||
* outside the event loop (since we cannot destroy the loop from
|
||||
* within the loop). That will cause lws_context_destroy3() to run
|
||||
* directly.
|
||||
*
|
||||
* - lws_context_destroy3() destroys any internal event loops and then
|
||||
* destroys the context itself, setting what was info.pcontext to NULL.
|
||||
*/
|
||||
|
||||
static void
|
||||
lws_context_destroy3(struct lws_context *context)
|
||||
{
|
||||
struct lws_context **pcontext_finalize = context->pcontext_finalize;
|
||||
|
||||
lws_free(context);
|
||||
lwsl_info("%s: ctx %p freed\n", __func__, context);
|
||||
|
||||
if (pcontext_finalize)
|
||||
*pcontext_finalize = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lws_context_destroy2(struct lws_context *context)
|
||||
{
|
||||
struct lws_vhost *vh = NULL, *vh1;
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
uint32_t n;
|
||||
#endif
|
||||
|
||||
|
||||
lwsl_info("%s: ctx %p\n", __func__, context);
|
||||
|
||||
/*
|
||||
* free all the per-vhost allocations
|
||||
*/
|
||||
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
vh1 = vh->vhost_next;
|
||||
lws_vhost_destroy2(vh);
|
||||
vh = vh1;
|
||||
}
|
||||
|
||||
/* remove ourselves from the pending destruction list */
|
||||
|
||||
while (context->vhost_pending_destruction_list)
|
||||
/* removes itself from list */
|
||||
lws_vhost_destroy2(context->vhost_pending_destruction_list);
|
||||
|
||||
|
||||
lws_stats_log_dump(context);
|
||||
|
||||
lws_ssl_context_destroy(context);
|
||||
lws_plat_context_late_destroy(context);
|
||||
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
for (n = 0; n < context->pl_hash_elements; n++) {
|
||||
lws_start_foreach_llp(struct lws_peer **, peer,
|
||||
context->pl_hash_table[n]) {
|
||||
struct lws_peer *df = *peer;
|
||||
*peer = df->next;
|
||||
lws_free(df);
|
||||
continue;
|
||||
} lws_end_foreach_llp(peer, next);
|
||||
}
|
||||
lws_free(context->pl_hash_table);
|
||||
#endif
|
||||
|
||||
if (context->external_baggage_free_on_destroy)
|
||||
free(context->external_baggage_free_on_destroy);
|
||||
|
||||
lws_check_deferred_free(context, 1);
|
||||
|
||||
#if LWS_MAX_SMP > 1
|
||||
pthread_mutex_destroy(&context->lock);
|
||||
#endif
|
||||
|
||||
if (context->event_loop_ops->destroy_context2)
|
||||
if (context->event_loop_ops->destroy_context2(context)) {
|
||||
context->finalize_destroy_after_internal_loops_stopped = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
lws_context_destroy3(context);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_context_destroy(struct lws_context *context)
|
||||
{
|
||||
|
@ -1642,8 +1765,18 @@ lws_context_destroy(struct lws_context *context)
|
|||
lwsl_notice("%s: ctx %p\n", __func__, context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->finalize_destroy_after_internal_loops_stopped) {
|
||||
if (context->event_loop_ops->destroy_context2)
|
||||
context->event_loop_ops->destroy_context2(context);
|
||||
|
||||
lws_context_destroy3(context);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (context->being_destroyed1) {
|
||||
lwsl_notice("%s: ctx %p: already being destroyed\n",
|
||||
lwsl_info("%s: ctx %p: already being destroyed\n",
|
||||
__func__, context);
|
||||
return;
|
||||
}
|
||||
|
@ -1653,6 +1786,7 @@ lws_context_destroy(struct lws_context *context)
|
|||
m = context->count_threads;
|
||||
context->being_destroyed = 1;
|
||||
context->being_destroyed1 = 1;
|
||||
context->requested_kill = 1;
|
||||
|
||||
memset(&wsi, 0, sizeof(wsi));
|
||||
wsi.context = context;
|
||||
|
@ -1708,9 +1842,8 @@ lws_context_destroy(struct lws_context *context)
|
|||
for (n = 0; n < context->count_threads; n++) {
|
||||
pt = &context->pt[n];
|
||||
|
||||
lws_libev_destroyloop(context, n);
|
||||
lws_libuv_destroyloop(context, n);
|
||||
lws_libevent_destroyloop(context, 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);
|
||||
|
||||
|
@ -1721,84 +1854,14 @@ lws_context_destroy(struct lws_context *context)
|
|||
}
|
||||
lws_plat_context_early_destroy(context);
|
||||
|
||||
#if defined(LWS_WITH_LIBUV)
|
||||
if (LWS_LIBUV_ENABLED(context))
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
pt = &context->pt[n];
|
||||
if (!pt->event_loop_foreign) {
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
uv_loop_close(pt->uv.io_loop);
|
||||
#endif
|
||||
lws_free_set_NULL(pt->uv.io_loop);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (context->pt[0].fds)
|
||||
lws_free_set_NULL(context->pt[0].fds);
|
||||
|
||||
if (!LWS_LIBUV_ENABLED(context))
|
||||
lws_context_destroy2(context);
|
||||
}
|
||||
if (context->event_loop_ops->destroy_context1) {
|
||||
context->event_loop_ops->destroy_context1(context);
|
||||
|
||||
/*
|
||||
* call the second one after the event loop has been shut down cleanly
|
||||
*/
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_context_destroy2(struct lws_context *context)
|
||||
{
|
||||
struct lws_vhost *vh = NULL, *vh1;
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
uint32_t n;
|
||||
#endif
|
||||
|
||||
lwsl_info("%s: ctx %p\n", __func__, context);
|
||||
|
||||
/*
|
||||
* free all the per-vhost allocations
|
||||
*/
|
||||
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
vh1 = vh->vhost_next;
|
||||
lws_vhost_destroy2(vh);
|
||||
vh = vh1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* remove ourselves from the pending destruction list */
|
||||
|
||||
while (context->vhost_pending_destruction_list)
|
||||
/* removes itself from list */
|
||||
lws_vhost_destroy2(context->vhost_pending_destruction_list);
|
||||
|
||||
|
||||
lws_stats_log_dump(context);
|
||||
|
||||
lws_ssl_context_destroy(context);
|
||||
lws_plat_context_late_destroy(context);
|
||||
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
for (n = 0; n < context->pl_hash_elements; n++) {
|
||||
lws_start_foreach_llp(struct lws_peer **, peer,
|
||||
context->pl_hash_table[n]) {
|
||||
struct lws_peer *df = *peer;
|
||||
*peer = df->next;
|
||||
lws_free(df);
|
||||
continue;
|
||||
} lws_end_foreach_llp(peer, next);
|
||||
}
|
||||
lws_free(context->pl_hash_table);
|
||||
#endif
|
||||
|
||||
if (context->external_baggage_free_on_destroy)
|
||||
free(context->external_baggage_free_on_destroy);
|
||||
|
||||
lws_check_deferred_free(context, 1);
|
||||
|
||||
#if LWS_MAX_SMP > 1
|
||||
pthread_mutex_destroy(&context->lock);
|
||||
#endif
|
||||
|
||||
lws_free(context);
|
||||
lws_context_destroy2(context);
|
||||
}
|
||||
|
|
|
@ -61,28 +61,23 @@ lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
|
|||
LWS_VISIBLE void
|
||||
lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)
|
||||
{
|
||||
struct lws_context *context = watcher->data;
|
||||
|
||||
if (context->eventlib_signal_cb) {
|
||||
context->eventlib_signal_cb((void *)watcher, watcher->signum);
|
||||
|
||||
return;
|
||||
}
|
||||
ev_break(loop, EVBREAK_ALL);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ev_sigint_cfg(struct lws_context *context, int use_event_loop_sigint,
|
||||
lws_ev_signal_cb_t *cb)
|
||||
{
|
||||
context->use_event_loop_sigint = use_event_loop_sigint;
|
||||
if (cb)
|
||||
context->ev.sigint_cb = cb;
|
||||
else
|
||||
context->ev.sigint_cb = &lws_ev_sigint_cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
|
||||
static int
|
||||
elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi)
|
||||
{
|
||||
struct ev_signal *w_sigint = &context->pt[tsi].w_sigint.ev.watcher;
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
const char *backend_name;
|
||||
struct ev_loop *loop = (struct ev_loop *)_loop;
|
||||
int status = 0;
|
||||
int backend;
|
||||
|
||||
|
@ -93,9 +88,6 @@ lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
|
|||
|
||||
context->pt[tsi].ev.io_loop = loop;
|
||||
|
||||
if (lws_create_event_pipes(context))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Initialize the accept w_accept with all the listening sockets
|
||||
* and register a callback for read operations
|
||||
|
@ -113,9 +105,10 @@ lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
|
|||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
/* Register the signal watcher unless the user says not to */
|
||||
if (context->use_event_loop_sigint) {
|
||||
ev_signal_init(w_sigint, context->ev.sigint_cb, SIGINT);
|
||||
/* Register the signal watcher unless it's a foreign loop */
|
||||
if (!context->pt[tsi].event_loop_foreign) {
|
||||
ev_signal_init(w_sigint, lws_ev_sigint_cb, SIGINT);
|
||||
w_sigint->data = context;
|
||||
ev_signal_start(loop, w_sigint);
|
||||
}
|
||||
|
||||
|
@ -150,8 +143,8 @@ lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
|
|||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
lws_libev_destroyloop(struct lws_context *context, int tsi)
|
||||
static void
|
||||
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;
|
||||
|
@ -167,44 +160,50 @@ lws_libev_destroyloop(struct lws_context *context, int tsi)
|
|||
ev_io_stop(pt->ev.io_loop, &vh->w_accept.ev.watcher);
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
if (context->use_event_loop_sigint)
|
||||
ev_signal_stop(pt->ev.io_loop,
|
||||
&pt->w_sigint.ev.watcher);
|
||||
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);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)
|
||||
static int
|
||||
elops_init_context_ev(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(new_wsi);
|
||||
struct ev_io *r = &new_wsi->w_read.ev.watcher;
|
||||
struct ev_io *w = &new_wsi->w_write.ev.watcher;
|
||||
int n;
|
||||
|
||||
context->eventlib_signal_cb = info->signal_cb;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
context->pt[n].w_sigint.context = context;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
elops_accept_ev(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct ev_io *r = &wsi->w_read.ev.watcher;
|
||||
struct ev_io *w = &wsi->w_write.ev.watcher;
|
||||
int fd;
|
||||
|
||||
if (!LWS_LIBEV_ENABLED(context))
|
||||
return;
|
||||
|
||||
if (new_wsi->role_ops == &role_ops_raw_file)
|
||||
fd = desc.filefd;
|
||||
if (wsi->role_ops->file_handle)
|
||||
fd = wsi->desc.filefd;
|
||||
else
|
||||
fd = desc.sockfd;
|
||||
fd = wsi->desc.sockfd;
|
||||
|
||||
new_wsi->w_read.context = context;
|
||||
new_wsi->w_write.context = context;
|
||||
wsi->w_read.context = context;
|
||||
wsi->w_write.context = context;
|
||||
ev_io_init(r, lws_accept_cb, fd, EV_READ);
|
||||
ev_io_init(w, lws_accept_cb, fd, EV_WRITE);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libev_io(struct lws *wsi, int flags)
|
||||
static void
|
||||
elops_io_ev(struct lws *wsi, int flags)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
if (!LWS_LIBEV_ENABLED(context))
|
||||
return;
|
||||
|
||||
if (!pt->ev.io_loop)
|
||||
return;
|
||||
|
||||
|
@ -224,23 +223,28 @@ lws_libev_io(struct lws *wsi, int flags)
|
|||
}
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_libev_init_fd_table(struct lws_context *context)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!LWS_LIBEV_ENABLED(context))
|
||||
return 0;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
context->pt[n].w_sigint.context = context;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libev_run(const struct lws_context *context, int tsi)
|
||||
static void
|
||||
elops_run_pt_ev(struct lws_context *context, int tsi)
|
||||
{
|
||||
if (context->pt[tsi].ev.io_loop && LWS_LIBEV_ENABLED(context))
|
||||
ev_run(context->pt[tsi].ev.io_loop, 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,
|
||||
/* init_pt */ elops_init_pt_ev,
|
||||
/* wsi_logical_close */ NULL,
|
||||
/* check_client_connect_ok */ NULL,
|
||||
/* close_handle_manually */ NULL,
|
||||
/* accept */ elops_accept_ev,
|
||||
/* io */ elops_io_ev,
|
||||
/* run_pt */ elops_run_pt_ev,
|
||||
/* destroy_pt */ elops_destroy_pt_ev,
|
||||
/* destroy wsi */ NULL,
|
||||
|
||||
/* periodic_events_available */ 0,
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* This is included from private-libwebsockets.h if LWS_ROLE_WS
|
||||
* This is included from private-libwebsockets.h if LWS_WITH_LIBEV
|
||||
*/
|
||||
|
||||
#include <ev.h>
|
||||
|
@ -36,18 +36,15 @@ struct lws_signal_watcher_libev {
|
|||
};
|
||||
|
||||
struct lws_context_eventlibs_libev {
|
||||
lws_ev_signal_cb_t *sigint_cb;
|
||||
int placeholder;
|
||||
};
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
|
||||
LWS_EXTERN void
|
||||
lws_libev_io(struct lws *wsi, int flags);
|
||||
LWS_EXTERN int
|
||||
lws_libev_init_fd_table(struct lws_context *context);
|
||||
LWS_EXTERN void
|
||||
lws_libev_destroyloop(struct lws_context *context, int tsi);
|
||||
#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);
|
||||
#define LWS_LIBEV_ENABLED(context) lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV)
|
||||
LWS_EXTERN void lws_feature_status_libev(const struct lws_context_creation_info *info);
|
||||
LWS_EXTERN void
|
||||
lws_feature_status_libev(const struct lws_context_creation_info *info);
|
||||
|
|
|
@ -68,28 +68,22 @@ lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx)
|
|||
{
|
||||
struct lws_context_per_thread *pt = ctx;
|
||||
|
||||
if (pt->context->eventlib_signal_cb) {
|
||||
pt->context->eventlib_signal_cb(
|
||||
(void *)(lws_intptr_t)sock_fd, revents);
|
||||
|
||||
return;
|
||||
}
|
||||
if (!pt->event_loop_foreign)
|
||||
event_base_loopbreak(pt->event.io_loop);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_event_sigint_cfg(struct lws_context *context, int use_event_sigint,
|
||||
lws_event_signal_cb_t *cb)
|
||||
{
|
||||
context->use_event_loop_sigint = use_event_sigint;
|
||||
if (cb)
|
||||
context->event.sigint_cb = cb;
|
||||
else
|
||||
context->event.sigint_cb = &lws_event_sigint_cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_event_initloop(struct lws_context *context, struct event_base *loop,
|
||||
int tsi)
|
||||
static int
|
||||
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;
|
||||
|
||||
if (!loop)
|
||||
context->pt[tsi].event.io_loop = event_base_new();
|
||||
|
@ -98,9 +92,6 @@ int tsi)
|
|||
context->pt[tsi].event.io_loop = loop;
|
||||
}
|
||||
|
||||
if (lws_create_event_pipes(context))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Initialize all events with the listening sockets
|
||||
* and register a callback for read operations
|
||||
|
@ -118,95 +109,61 @@ int tsi)
|
|||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
/* Register the signal watcher unless the user says not to */
|
||||
if (!context->use_event_loop_sigint)
|
||||
/* Register the signal watcher unless it's a foreign loop */
|
||||
if (context->pt[tsi].event_loop_foreign)
|
||||
return 0;
|
||||
|
||||
context->pt[tsi].w_sigint.event.watcher = evsignal_new(loop, SIGINT,
|
||||
context->event.sigint_cb, &context->pt[tsi]);
|
||||
lws_event_sigint_cb, &context->pt[tsi]);
|
||||
event_add(context->pt[tsi].w_sigint.event.watcher, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_libevent_destroyloop(struct lws_context *context, int tsi)
|
||||
static int
|
||||
elops_init_context_event(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
int n;
|
||||
|
||||
if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT))
|
||||
return;
|
||||
context->eventlib_signal_cb = info->signal_cb;
|
||||
|
||||
if (!pt->event.io_loop)
|
||||
return;
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
context->pt[n].w_sigint.context = context;
|
||||
|
||||
/*
|
||||
* Free all events with the listening sockets
|
||||
*/
|
||||
while (vh) {
|
||||
if (vh->lserv_wsi) {
|
||||
event_free(vh->lserv_wsi->w_read.event.watcher);
|
||||
vh->lserv_wsi->w_read.event.watcher = NULL;
|
||||
}
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
if (context->use_event_loop_sigint)
|
||||
event_free(pt->w_sigint.event.watcher);
|
||||
if (!pt->event_loop_foreign)
|
||||
event_base_free(pt->event.io_loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libevent_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)
|
||||
static void
|
||||
elops_accept_event(struct lws *wsi)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(new_wsi);
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt;
|
||||
int fd;
|
||||
|
||||
if (!LWS_LIBEVENT_ENABLED(context))
|
||||
return;
|
||||
|
||||
new_wsi->w_read.context = context;
|
||||
new_wsi->w_write.context = context;
|
||||
wsi->w_read.context = context;
|
||||
wsi->w_write.context = context;
|
||||
|
||||
// Initialize the event
|
||||
pt = &context->pt[(int)new_wsi->tsi];
|
||||
pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
if (new_wsi->role_ops == &role_ops_raw_file)
|
||||
fd = desc.filefd;
|
||||
if (wsi->role_ops->file_handle)
|
||||
fd = wsi->desc.filefd;
|
||||
else
|
||||
fd = desc.sockfd;
|
||||
fd = wsi->desc.sockfd;
|
||||
|
||||
new_wsi->w_read.event.watcher = event_new(pt->event.io_loop, fd,
|
||||
(EV_READ | EV_PERSIST), lws_event_cb, &new_wsi->w_read);
|
||||
new_wsi->w_write.event.watcher = event_new(pt->event.io_loop, fd,
|
||||
(EV_WRITE | EV_PERSIST), lws_event_cb, &new_wsi->w_write);
|
||||
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);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libevent_destroy(struct lws *wsi)
|
||||
{
|
||||
if (!wsi)
|
||||
return;
|
||||
|
||||
if(wsi->w_read.event.watcher)
|
||||
event_free(wsi->w_read.event.watcher);
|
||||
|
||||
if(wsi->w_write.event.watcher)
|
||||
event_free(wsi->w_write.event.watcher);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libevent_io(struct lws *wsi, int flags)
|
||||
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 (!LWS_LIBEVENT_ENABLED(context))
|
||||
return;
|
||||
|
||||
if (!pt->event.io_loop || context->being_destroyed)
|
||||
return;
|
||||
|
||||
|
@ -227,25 +184,73 @@ lws_libevent_io(struct lws *wsi, int flags)
|
|||
}
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_libevent_init_fd_table(struct lws_context *context)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!LWS_LIBEVENT_ENABLED(context))
|
||||
return 0;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
context->pt[n].w_sigint.context = context;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libevent_run(const struct lws_context *context, int tsi)
|
||||
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))
|
||||
event_base_dispatch(context->pt[tsi].event.io_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
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;
|
||||
|
||||
if (!pt->event.io_loop)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Free all events with the listening sockets
|
||||
*/
|
||||
while (vh) {
|
||||
if (vh->lserv_wsi) {
|
||||
event_free(vh->lserv_wsi->w_read.event.watcher);
|
||||
vh->lserv_wsi->w_read.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
|
||||
elops_destroy_wsi_event(struct lws *wsi)
|
||||
{
|
||||
if (!wsi)
|
||||
return;
|
||||
|
||||
if(wsi->w_read.event.watcher)
|
||||
event_free(wsi->w_read.event.watcher);
|
||||
|
||||
if(wsi->w_write.event.watcher)
|
||||
event_free(wsi->w_write.event.watcher);
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
/* init_pt */ elops_init_pt_event,
|
||||
/* wsi_logical_close */ NULL,
|
||||
/* check_client_connect_ok */ NULL,
|
||||
/* close_handle_manually */ NULL,
|
||||
/* accept */ elops_accept_event,
|
||||
/* io */ elops_io_event,
|
||||
/* run_pt */ elops_run_pt_event,
|
||||
/* destroy_pt */ elops_destroy_pt_event,
|
||||
/* destroy wsi */ elops_destroy_wsi_event,
|
||||
|
||||
/* periodic_events_available */ 0,
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* This is included from private-libwebsockets.h if LWS_ROLE_WS
|
||||
* This is included from private-libwebsockets.h if LWS_WITH_LIBEVENT
|
||||
*/
|
||||
|
||||
#include <event2/event.h>
|
||||
|
@ -36,25 +36,14 @@ struct lws_signal_watcher_libevent {
|
|||
};
|
||||
|
||||
struct lws_context_eventlibs_libevent {
|
||||
#if defined(LWS_HIDE_LIBEVENT)
|
||||
void * sigint_cb;
|
||||
#else
|
||||
lws_event_signal_cb_t *sigint_cb;
|
||||
#endif
|
||||
int placeholder;
|
||||
};
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_libevent_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
|
||||
LWS_VISIBLE void
|
||||
lws_libevent_destroy(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_libevent_io(struct lws *wsi, int flags);
|
||||
LWS_EXTERN int
|
||||
lws_libevent_init_fd_table(struct lws_context *context);
|
||||
LWS_EXTERN void
|
||||
lws_libevent_destroyloop(struct lws_context *context, int tsi);
|
||||
LWS_EXTERN void
|
||||
lws_libevent_run(const struct lws_context *context, int tsi);
|
||||
#define LWS_LIBEVENT_ENABLED(context) lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT)
|
||||
LWS_EXTERN void lws_feature_status_libevent(const struct lws_context_creation_info *info);
|
||||
#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);
|
||||
|
||||
|
|
|
@ -134,24 +134,73 @@ lws_io_cb(uv_poll_t *watcher, int status, int revents)
|
|||
uv_idle_start(&pt->uv.idle, lws_uv_idle);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_uv_sigint_cb(uv_signal_t *watcher, int signum)
|
||||
/*
|
||||
* This does not actually stop the event loop. The reason is we have to pass
|
||||
* libuv handle closures through its event loop. So this tries to close all
|
||||
* wsi, and set a flag; when all the wsi closures are finalized then we
|
||||
* actually stop the libuv event loops.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_libuv_stop(struct lws_context *context)
|
||||
{
|
||||
lwsl_err("internal signal handler caught signal %d\n", signum);
|
||||
lws_libuv_stop(watcher->data);
|
||||
struct lws_context_per_thread *pt;
|
||||
int n, m;
|
||||
|
||||
lwsl_err("%s\n", __func__);
|
||||
|
||||
if (context->requested_kill) {
|
||||
lwsl_err("%s: ignoring\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
context->requested_kill = 1;
|
||||
|
||||
m = context->count_threads;
|
||||
context->being_destroyed = 1;
|
||||
|
||||
/*
|
||||
* Phase 1: start the close of every dynamic uv handle
|
||||
*/
|
||||
|
||||
while (m--) {
|
||||
pt = &context->pt[m];
|
||||
|
||||
if (pt->pipe_wsi) {
|
||||
uv_poll_stop(&pt->pipe_wsi->w_read.uv.watcher);
|
||||
lws_destroy_event_pipe(pt->pipe_wsi);
|
||||
pt->pipe_wsi = NULL;
|
||||
}
|
||||
|
||||
for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
|
||||
struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
|
||||
|
||||
if (!wsi)
|
||||
continue;
|
||||
lws_close_free_wsi(wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY, __func__
|
||||
/* no protocol close */);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
lwsl_info("%s: started closing all wsi\n", __func__);
|
||||
|
||||
/* we cannot have completed... there are at least the cancel pipes */
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
|
||||
uv_signal_cb cb)
|
||||
static void
|
||||
lws_uv_signal_handler(uv_signal_t *watcher, int signum)
|
||||
{
|
||||
context->use_event_loop_sigint = use_uv_sigint;
|
||||
if (cb)
|
||||
context->uv.sigint_cb = cb;
|
||||
else
|
||||
context->uv.sigint_cb = &lws_uv_sigint_cb;
|
||||
struct lws_context *context = watcher->data;
|
||||
|
||||
return 0;
|
||||
if (context->eventlib_signal_cb) {
|
||||
context->eventlib_signal_cb((void *)watcher, signum);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lwsl_err("internal signal handler caught signal %d\n", signum);
|
||||
lws_libuv_stop(watcher->data);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -174,127 +223,6 @@ lws_uv_timeout_cb(uv_timer_t *timer
|
|||
|
||||
static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE, SIGHUP };
|
||||
|
||||
int
|
||||
lws_uv_initvhost(struct lws_vhost* vh, struct lws* wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int n;
|
||||
|
||||
if (!LWS_LIBUV_ENABLED(vh->context))
|
||||
return 0;
|
||||
if (!wsi)
|
||||
wsi = vh->lserv_wsi;
|
||||
if (!wsi)
|
||||
return 0;
|
||||
if (wsi->w_read.context)
|
||||
return 0;
|
||||
|
||||
pt = &vh->context->pt[(int)wsi->tsi];
|
||||
if (!pt->uv.io_loop)
|
||||
return 0;
|
||||
|
||||
wsi->w_read.context = vh->context;
|
||||
n = uv_poll_init_socket(pt->uv.io_loop,
|
||||
&wsi->w_read.uv.watcher, wsi->desc.sockfd);
|
||||
if (n) {
|
||||
lwsl_err("uv_poll_init failed %d, sockfd=%p\n",
|
||||
n, (void *)(lws_intptr_t)wsi->desc.sockfd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This needs to be called after vhosts have been defined.
|
||||
*
|
||||
* If later, after server start, another vhost is added, this must be
|
||||
* called again to bind the vhost
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
int status = 0, n, ns, first = 1;
|
||||
|
||||
if (!pt->uv.io_loop) {
|
||||
if (!loop) {
|
||||
loop = lws_malloc(sizeof(*loop), "libuv loop");
|
||||
if (!loop) {
|
||||
lwsl_err("OOM\n");
|
||||
return -1;
|
||||
}
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
uv_loop_init(loop);
|
||||
#else
|
||||
lwsl_err("This libuv is too old to work...\n");
|
||||
return 1;
|
||||
#endif
|
||||
pt->event_loop_foreign = 0;
|
||||
} else {
|
||||
lwsl_notice(" Using foreign event loop...\n");
|
||||
pt->event_loop_foreign = 1;
|
||||
}
|
||||
|
||||
pt->uv.io_loop = loop;
|
||||
uv_idle_init(loop, &pt->uv.idle);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.idle, context);
|
||||
|
||||
|
||||
ns = ARRAY_SIZE(sigs);
|
||||
if (lws_check_opt(context->options,
|
||||
LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
|
||||
ns = 2;
|
||||
|
||||
if (pt->context->use_event_loop_sigint) {
|
||||
assert(ns <= (int)ARRAY_SIZE(pt->uv.signals));
|
||||
for (n = 0; n < ns; n++) {
|
||||
uv_signal_init(loop, &pt->uv.signals[n]);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.signals[n],
|
||||
context);
|
||||
pt->uv.signals[n].data = pt->context;
|
||||
uv_signal_start(&pt->uv.signals[n],
|
||||
context->uv.sigint_cb, sigs[n]);
|
||||
}
|
||||
}
|
||||
} else
|
||||
first = 0;
|
||||
|
||||
if (lws_create_event_pipes(context))
|
||||
goto bail;
|
||||
|
||||
/*
|
||||
* Initialize the accept wsi read watcher with all the listening sockets
|
||||
* and register a callback for read operations
|
||||
*
|
||||
* We have to do it here because the uv loop(s) are not
|
||||
* initialized until after context creation.
|
||||
*/
|
||||
while (vh) {
|
||||
if (lws_uv_initvhost(vh, vh->lserv_wsi) == -1)
|
||||
return -1;
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
return status;
|
||||
|
||||
uv_timer_init(pt->uv.io_loop, &pt->uv.timeout_watcher);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.timeout_watcher, context);
|
||||
uv_timer_start(&pt->uv.timeout_watcher, lws_uv_timeout_cb, 10, 1000);
|
||||
uv_timer_init(pt->uv.io_loop, &pt->uv.hrtimer);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.hrtimer, context);
|
||||
|
||||
return status;
|
||||
|
||||
bail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Closing Phase 2: Close callback for a static UV asset
|
||||
*/
|
||||
|
@ -326,17 +254,16 @@ lws_uv_close_cb_sa(uv_handle_t *handle)
|
|||
for (n = 0; n < context->count_threads; n++) {
|
||||
struct lws_context_per_thread *pt = &context->pt[n];
|
||||
|
||||
if (!pt->uv.io_loop || !LWS_LIBUV_ENABLED(context))
|
||||
continue;
|
||||
|
||||
uv_stop(pt->uv.io_loop);
|
||||
|
||||
/*
|
||||
* we can't delete non-foreign loop here, because
|
||||
* the uv_stop() hasn't got us out of the uv_run()
|
||||
* yet. So we do it in context destroy.
|
||||
*/
|
||||
if (pt->uv.io_loop && !pt->event_loop_foreign)
|
||||
uv_stop(pt->uv.io_loop);
|
||||
}
|
||||
|
||||
if (!context->pt[0].event_loop_foreign) {
|
||||
lwsl_info("%s: calling lws_context_destroy2\n", __func__);
|
||||
lws_context_destroy2(context);
|
||||
}
|
||||
|
||||
lwsl_info("%s: all done\n", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -378,136 +305,6 @@ lws_close_all_handles_in_loop(uv_loop_t *loop)
|
|||
uv_walk(loop, lws_uv_walk_cb, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
lws_libuv_destroyloop(struct lws_context *context, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
int m, /* budget = 100, */ ns;
|
||||
|
||||
lwsl_info("%s: %d\n", __func__, tsi);
|
||||
|
||||
if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
|
||||
return;
|
||||
|
||||
if (!pt->uv.io_loop)
|
||||
return;
|
||||
|
||||
if (pt->event_loop_destroy_processing_done)
|
||||
return;
|
||||
|
||||
pt->event_loop_destroy_processing_done = 1;
|
||||
|
||||
if (context->use_event_loop_sigint) {
|
||||
uv_signal_stop(&pt->w_sigint.uv.watcher);
|
||||
|
||||
ns = ARRAY_SIZE(sigs);
|
||||
if (lws_check_opt(context->options,
|
||||
LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
|
||||
ns = 2;
|
||||
|
||||
for (m = 0; m < ns; m++) {
|
||||
uv_signal_stop(&pt->uv.signals[m]);
|
||||
uv_close((uv_handle_t *)&pt->uv.signals[m],
|
||||
lws_uv_close_cb_sa);
|
||||
}
|
||||
}
|
||||
|
||||
uv_timer_stop(&pt->uv.timeout_watcher);
|
||||
uv_close((uv_handle_t *)&pt->uv.timeout_watcher, lws_uv_close_cb_sa);
|
||||
uv_timer_stop(&pt->uv.hrtimer);
|
||||
uv_close((uv_handle_t *)&pt->uv.hrtimer, lws_uv_close_cb_sa);
|
||||
|
||||
uv_idle_stop(&pt->uv.idle);
|
||||
uv_close((uv_handle_t *)&pt->uv.idle, lws_uv_close_cb_sa);
|
||||
}
|
||||
|
||||
void
|
||||
lws_libuv_accept(struct lws *wsi, lws_sock_file_fd_type desc)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
if (!LWS_LIBUV_ENABLED(context))
|
||||
return;
|
||||
|
||||
wsi->w_read.context = context;
|
||||
if (wsi->role_ops == &role_ops_raw_file || wsi->event_pipe)
|
||||
uv_poll_init(pt->uv.io_loop, &wsi->w_read.uv.watcher,
|
||||
(int)(long long)desc.filefd);
|
||||
else
|
||||
uv_poll_init_socket(pt->uv.io_loop, &wsi->w_read.uv.watcher,
|
||||
desc.sockfd);
|
||||
}
|
||||
|
||||
void
|
||||
lws_libuv_io(struct lws *wsi, int flags)
|
||||
{
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
struct lws_io_watcher *w = &wsi->w_read;
|
||||
int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE);
|
||||
|
||||
if (!LWS_LIBUV_ENABLED(context))
|
||||
return;
|
||||
|
||||
/* w->context is set after the loop is initialized */
|
||||
|
||||
if (!pt->uv.io_loop || !w->context) {
|
||||
lwsl_info("%s: no io loop yet\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
|
||||
(flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
|
||||
lwsl_err("%s: assert: flags %d", __func__, flags);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (flags & LWS_EV_START) {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
current_events |= UV_WRITABLE;
|
||||
|
||||
if (flags & LWS_EV_READ)
|
||||
current_events |= UV_READABLE;
|
||||
|
||||
uv_poll_start(&w->uv.watcher, current_events, lws_io_cb);
|
||||
} else {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
current_events &= ~UV_WRITABLE;
|
||||
|
||||
if (flags & LWS_EV_READ)
|
||||
current_events &= ~UV_READABLE;
|
||||
|
||||
if (!(current_events & (UV_READABLE | UV_WRITABLE)))
|
||||
uv_poll_stop(&w->uv.watcher);
|
||||
else
|
||||
uv_poll_start(&w->uv.watcher, current_events,
|
||||
lws_io_cb);
|
||||
}
|
||||
|
||||
w->actual_events = current_events;
|
||||
}
|
||||
|
||||
int
|
||||
lws_libuv_init_fd_table(struct lws_context *context)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!LWS_LIBUV_ENABLED(context))
|
||||
return 0;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
context->pt[n].w_sigint.context = context;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libuv_run(const struct lws_context *context, int tsi)
|
||||
{
|
||||
if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context))
|
||||
uv_run(context->pt[tsi].uv.io_loop, 0);
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_libuv_stop_without_kill(const struct lws_context *context, int tsi)
|
||||
|
@ -527,123 +324,6 @@ lws_uv_getloop(struct lws_context *context, int tsi)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_libuv_closewsi(uv_handle_t* handle)
|
||||
{
|
||||
struct lws *n = NULL, *wsi = (struct lws *)(((char *)handle) -
|
||||
(char *)(&n->w_read.uv.watcher));
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int lspd = 0, m;
|
||||
|
||||
/*
|
||||
* We get called back here for every wsi that closes
|
||||
*/
|
||||
|
||||
if (wsi->role_ops == &role_ops_listen && wsi->context->deprecated) {
|
||||
lspd = 1;
|
||||
context->deprecation_pending_listen_close_count--;
|
||||
if (!context->deprecation_pending_listen_close_count)
|
||||
lspd = 2;
|
||||
}
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
__lws_close_free_wsi_final(wsi);
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
if (lspd == 2 && context->deprecation_cb) {
|
||||
lwsl_notice("calling deprecation callback\n");
|
||||
context->deprecation_cb();
|
||||
}
|
||||
|
||||
lwsl_info("%s: sa left %d: dyn left: %d\n", __func__,
|
||||
context->count_event_loop_static_asset_handles,
|
||||
context->count_wsi_allocated);
|
||||
|
||||
/*
|
||||
* eventually, we closed all the wsi...
|
||||
*/
|
||||
|
||||
if (context->requested_kill && !context->count_wsi_allocated) {
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
|
||||
/*
|
||||
* Start Closing Phase 2: close of static handles
|
||||
*/
|
||||
|
||||
lwsl_info("%s: all lws dynamic handles down, closing static\n",
|
||||
__func__);
|
||||
|
||||
for (m = 0; m < context->count_threads; m++)
|
||||
lws_libuv_destroyloop(context, m);
|
||||
|
||||
/* protocols may have initialized libuv objects */
|
||||
|
||||
while (vh) {
|
||||
lws_vhost_destroy1(vh);
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This does not actually stop the event loop. The reason is we have to pass
|
||||
* libuv handle closures through its event loop. So this tries to close all
|
||||
* wsi, and set a flag; when all the wsi closures are finalized then we
|
||||
* actually stop the libuv event loops.
|
||||
*/
|
||||
LWS_VISIBLE void
|
||||
lws_libuv_stop(struct lws_context *context)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int n, m;
|
||||
|
||||
if (context->requested_kill)
|
||||
return;
|
||||
|
||||
context->requested_kill = 1;
|
||||
|
||||
m = context->count_threads;
|
||||
context->being_destroyed = 1;
|
||||
|
||||
/*
|
||||
* Phase 1: start the close of every dynamic uv handle
|
||||
*/
|
||||
|
||||
while (m--) {
|
||||
pt = &context->pt[m];
|
||||
|
||||
for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
|
||||
struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
|
||||
|
||||
if (!wsi)
|
||||
continue;
|
||||
lws_close_free_wsi(wsi,
|
||||
LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY, __func__
|
||||
/* no protocol close */);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
lwsl_info("%s: started closing all wsi\n", __func__);
|
||||
|
||||
/* we cannot have completed... there are at least the cancel pipes */
|
||||
}
|
||||
|
||||
void
|
||||
lws_libuv_closehandle(struct lws *wsi)
|
||||
{
|
||||
if (wsi->told_event_loop_closed) {
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
wsi->told_event_loop_closed = 1;
|
||||
|
||||
/* required to defer actual deletion until libuv has processed it */
|
||||
uv_close((uv_handle_t*)&wsi->w_read.uv.watcher, lws_libuv_closewsi);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_libuv_closewsi_m(uv_handle_t* handle)
|
||||
{
|
||||
|
@ -652,16 +332,6 @@ lws_libuv_closewsi_m(uv_handle_t* handle)
|
|||
compatible_close(sockfd);
|
||||
}
|
||||
|
||||
void
|
||||
lws_libuv_closehandle_manually(struct lws *wsi)
|
||||
{
|
||||
uv_handle_t *h = (void *)&wsi->w_read.uv.watcher;
|
||||
|
||||
h->data = (void *)(lws_intptr_t)wsi->desc.sockfd;
|
||||
/* required to defer actual deletion until libuv has processed it */
|
||||
uv_close((uv_handle_t*)&wsi->w_read.uv.watcher, lws_libuv_closewsi_m);
|
||||
}
|
||||
|
||||
int
|
||||
lws_libuv_check_watcher_active(struct lws *wsi)
|
||||
{
|
||||
|
@ -833,3 +503,441 @@ lws_plat_plugins_destroy(struct lws_context *context)
|
|||
|
||||
#endif
|
||||
|
||||
static int
|
||||
elops_init_context_uv(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
int n;
|
||||
|
||||
context->eventlib_signal_cb = info->signal_cb;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
context->pt[n].w_sigint.context = context;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_destroy_context1_uv(struct lws_context *context)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int n, m;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
int budget = 10000;
|
||||
pt = &context->pt[n];
|
||||
|
||||
/* only for internal loops... */
|
||||
|
||||
if (!pt->event_loop_foreign) {
|
||||
|
||||
while (budget-- && (m = uv_run(pt->uv.io_loop,
|
||||
UV_RUN_NOWAIT)))
|
||||
;
|
||||
if (m)
|
||||
lwsl_err("%s: tsi %d: failed to close everything\n", __func__, n);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* call destroy2 if internal loop */
|
||||
return !context->pt[0].event_loop_foreign;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_destroy_context2_uv(struct lws_context *context)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int n, internal = 0;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
pt = &context->pt[n];
|
||||
|
||||
/* only for internal loops... */
|
||||
|
||||
if (!pt->event_loop_foreign && pt->uv.io_loop) {
|
||||
internal = 1;
|
||||
if (!context->finalize_destroy_after_internal_loops_stopped)
|
||||
uv_stop(pt->uv.io_loop);
|
||||
else {
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
uv_loop_close(pt->uv.io_loop);
|
||||
#endif
|
||||
lws_free_set_NULL(pt->uv.io_loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return internal;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_wsi_logical_close_uv(struct lws *wsi)
|
||||
{
|
||||
if (wsi->parent_carries_io || !lws_sockfd_valid(wsi->desc.sockfd))
|
||||
return 0;
|
||||
|
||||
if (wsi->listener || wsi->event_pipe) {
|
||||
lwsl_debug("%s: %p: %d %d stop listener / pipe poll\n",
|
||||
__func__, wsi, wsi->listener, wsi->event_pipe);
|
||||
uv_poll_stop(&wsi->w_read.uv.watcher);
|
||||
}
|
||||
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
|
||||
/*
|
||||
* libuv has to do his own close handle processing asynchronously
|
||||
*/
|
||||
lws_libuv_closehandle(wsi);
|
||||
|
||||
return 1; /* do not complete the wsi close, uv close cb will do it */
|
||||
}
|
||||
|
||||
static int
|
||||
elops_check_client_connect_ok_uv(struct lws *wsi)
|
||||
{
|
||||
if (lws_libuv_check_watcher_active(wsi)) {
|
||||
lwsl_warn("Waiting for libuv watcher to close\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
elops_close_handle_manually_uv(struct lws *wsi)
|
||||
{
|
||||
uv_handle_t *h = (void *)&wsi->w_read.uv.watcher;
|
||||
|
||||
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
|
||||
h->data = (void *)(lws_intptr_t)wsi->desc.sockfd;
|
||||
/* required to defer actual deletion until libuv has processed it */
|
||||
uv_close((uv_handle_t*)&wsi->w_read.uv.watcher, lws_libuv_closewsi_m);
|
||||
}
|
||||
|
||||
static void
|
||||
elops_accept_uv(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
wsi->w_read.context = wsi->context;
|
||||
if (wsi->role_ops->file_handle)
|
||||
uv_poll_init(pt->uv.io_loop, &wsi->w_read.uv.watcher,
|
||||
(int)(long long)wsi->desc.filefd);
|
||||
else
|
||||
uv_poll_init_socket(pt->uv.io_loop, &wsi->w_read.uv.watcher,
|
||||
wsi->desc.sockfd);
|
||||
}
|
||||
|
||||
static void
|
||||
elops_io_uv(struct lws *wsi, int flags)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
struct lws_io_watcher *w = &wsi->w_read;
|
||||
int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE);
|
||||
|
||||
lwsl_debug("%s: %p: %d\n", __func__, wsi, flags);
|
||||
|
||||
/* w->context is set after the loop is initialized */
|
||||
|
||||
if (!pt->uv.io_loop || !w->context) {
|
||||
lwsl_info("%s: no io loop yet\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
|
||||
(flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
|
||||
lwsl_err("%s: assert: flags %d", __func__, flags);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (flags & LWS_EV_START) {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
current_events |= UV_WRITABLE;
|
||||
|
||||
if (flags & LWS_EV_READ)
|
||||
current_events |= UV_READABLE;
|
||||
|
||||
uv_poll_start(&w->uv.watcher, current_events, lws_io_cb);
|
||||
} else {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
current_events &= ~UV_WRITABLE;
|
||||
|
||||
if (flags & LWS_EV_READ)
|
||||
current_events &= ~UV_READABLE;
|
||||
|
||||
if (!(current_events & (UV_READABLE | UV_WRITABLE)))
|
||||
uv_poll_stop(&w->uv.watcher);
|
||||
else
|
||||
uv_poll_start(&w->uv.watcher, current_events,
|
||||
lws_io_cb);
|
||||
}
|
||||
|
||||
w->actual_events = current_events;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_vhost_listen_wsi_uv(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_vhost *vh = wsi->vhost;
|
||||
int n;
|
||||
|
||||
if (!wsi)
|
||||
wsi = vh->lserv_wsi;
|
||||
if (!wsi)
|
||||
return 0;
|
||||
if (wsi->w_read.context)
|
||||
return 0;
|
||||
|
||||
pt = &vh->context->pt[(int)wsi->tsi];
|
||||
if (!pt->uv.io_loop)
|
||||
return 0;
|
||||
|
||||
wsi->w_read.context = vh->context;
|
||||
n = uv_poll_init_socket(pt->uv.io_loop,
|
||||
&wsi->w_read.uv.watcher, wsi->desc.sockfd);
|
||||
if (n) {
|
||||
lwsl_err("uv_poll_init failed %d, sockfd=%p\n",
|
||||
n, (void *)(lws_intptr_t)wsi->desc.sockfd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
elops_io_uv(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
elops_run_pt_uv(struct lws_context *context, int tsi)
|
||||
{
|
||||
if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context))
|
||||
uv_run(context->pt[tsi].uv.io_loop, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
elops_destroy_pt_uv(struct lws_context *context, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
int m, ns;
|
||||
|
||||
lwsl_info("%s: %d\n", __func__, tsi);
|
||||
|
||||
if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
|
||||
return;
|
||||
|
||||
if (!pt->uv.io_loop)
|
||||
return;
|
||||
|
||||
if (pt->event_loop_destroy_processing_done)
|
||||
return;
|
||||
|
||||
pt->event_loop_destroy_processing_done = 1;
|
||||
|
||||
if (!pt->event_loop_foreign) {
|
||||
uv_signal_stop(&pt->w_sigint.uv.watcher);
|
||||
|
||||
ns = ARRAY_SIZE(sigs);
|
||||
if (lws_check_opt(context->options,
|
||||
LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
|
||||
ns = 2;
|
||||
|
||||
for (m = 0; m < ns; m++) {
|
||||
uv_signal_stop(&pt->uv.signals[m]);
|
||||
uv_close((uv_handle_t *)&pt->uv.signals[m],
|
||||
lws_uv_close_cb_sa);
|
||||
}
|
||||
} else
|
||||
lwsl_debug("%s: not closing pt signals\n", __func__);
|
||||
|
||||
uv_timer_stop(&pt->uv.timeout_watcher);
|
||||
uv_close((uv_handle_t *)&pt->uv.timeout_watcher, lws_uv_close_cb_sa);
|
||||
uv_timer_stop(&pt->uv.hrtimer);
|
||||
uv_close((uv_handle_t *)&pt->uv.hrtimer, lws_uv_close_cb_sa);
|
||||
|
||||
uv_idle_stop(&pt->uv.idle);
|
||||
uv_close((uv_handle_t *)&pt->uv.idle, lws_uv_close_cb_sa);
|
||||
}
|
||||
|
||||
/*
|
||||
* This needs to be called after vhosts have been defined.
|
||||
*
|
||||
* If later, after server start, another vhost is added, this must be
|
||||
* called again to bind the vhost
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
int status = 0, n, ns, first = 1;
|
||||
uv_loop_t *loop = (uv_loop_t *)_loop;
|
||||
|
||||
if (!pt->uv.io_loop) {
|
||||
if (!loop) {
|
||||
loop = lws_malloc(sizeof(*loop), "libuv loop");
|
||||
if (!loop) {
|
||||
lwsl_err("OOM\n");
|
||||
return -1;
|
||||
}
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
uv_loop_init(loop);
|
||||
#else
|
||||
lwsl_err("This libuv is too old to work...\n");
|
||||
return 1;
|
||||
#endif
|
||||
pt->event_loop_foreign = 0;
|
||||
} else {
|
||||
lwsl_notice(" Using foreign event loop...\n");
|
||||
pt->event_loop_foreign = 1;
|
||||
}
|
||||
|
||||
pt->uv.io_loop = loop;
|
||||
uv_idle_init(loop, &pt->uv.idle);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.idle, context);
|
||||
|
||||
|
||||
ns = ARRAY_SIZE(sigs);
|
||||
if (lws_check_opt(context->options,
|
||||
LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
|
||||
ns = 2;
|
||||
|
||||
if (!pt->event_loop_foreign) {
|
||||
assert(ns <= (int)ARRAY_SIZE(pt->uv.signals));
|
||||
for (n = 0; n < ns; n++) {
|
||||
uv_signal_init(loop, &pt->uv.signals[n]);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.signals[n],
|
||||
context);
|
||||
pt->uv.signals[n].data = pt->context;
|
||||
uv_signal_start(&pt->uv.signals[n],
|
||||
lws_uv_signal_handler, sigs[n]);
|
||||
}
|
||||
}
|
||||
} else
|
||||
first = 0;
|
||||
|
||||
/*
|
||||
* Initialize the accept wsi read watcher with all the listening sockets
|
||||
* and register a callback for read operations
|
||||
*
|
||||
* We have to do it here because the uv loop(s) are not
|
||||
* initialized until after context creation.
|
||||
*/
|
||||
while (vh) {
|
||||
if (elops_init_vhost_listen_wsi_uv(vh->lserv_wsi) == -1)
|
||||
return -1;
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
return status;
|
||||
|
||||
uv_timer_init(pt->uv.io_loop, &pt->uv.timeout_watcher);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.timeout_watcher, context);
|
||||
uv_timer_start(&pt->uv.timeout_watcher, lws_uv_timeout_cb, 10, 1000);
|
||||
|
||||
uv_timer_init(pt->uv.io_loop, &pt->uv.hrtimer);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.hrtimer, context);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_libuv_closewsi(uv_handle_t* handle)
|
||||
{
|
||||
struct lws *n = NULL, *wsi = (struct lws *)(((char *)handle) -
|
||||
(char *)(&n->w_read.uv.watcher));
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
int lspd = 0, m;
|
||||
|
||||
lwsl_info("%s: %p\n", __func__, wsi);
|
||||
|
||||
/*
|
||||
* We get called back here for every wsi that closes
|
||||
*/
|
||||
|
||||
if (wsi->role_ops == &role_ops_listen && wsi->context->deprecated) {
|
||||
lspd = 1;
|
||||
context->deprecation_pending_listen_close_count--;
|
||||
if (!context->deprecation_pending_listen_close_count)
|
||||
lspd = 2;
|
||||
}
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
__lws_close_free_wsi_final(wsi);
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
if (lspd == 2 && context->deprecation_cb) {
|
||||
lwsl_notice("calling deprecation callback\n");
|
||||
context->deprecation_cb();
|
||||
}
|
||||
|
||||
lwsl_info("%s: sa left %d: dyn left: %d (rk %d)\n", __func__,
|
||||
context->count_event_loop_static_asset_handles,
|
||||
context->count_wsi_allocated, context->requested_kill);
|
||||
|
||||
/*
|
||||
* eventually, we closed all the wsi...
|
||||
*/
|
||||
|
||||
if (context->requested_kill && !context->count_wsi_allocated) {
|
||||
struct lws_vhost *vh = context->vhost_list;
|
||||
|
||||
/*
|
||||
* Start Closing Phase 2: close of static handles
|
||||
*/
|
||||
|
||||
lwsl_info("%s: all lws dynamic handles down, closing static\n",
|
||||
__func__);
|
||||
|
||||
for (m = 0; m < context->count_threads; m++)
|
||||
elops_destroy_pt_uv(context, m);
|
||||
|
||||
/* protocols may have initialized libuv objects */
|
||||
|
||||
while (vh) {
|
||||
lws_vhost_destroy1(vh);
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
if (context->pt[0].event_loop_foreign) {
|
||||
lwsl_info("%s: calling lws_context_destroy2\n", __func__);
|
||||
lws_context_destroy2(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lws_libuv_closehandle(struct lws *wsi)
|
||||
{
|
||||
if (wsi->told_event_loop_closed) {
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: %p\n", __func__, wsi);
|
||||
|
||||
wsi->told_event_loop_closed = 1;
|
||||
|
||||
/* required to defer actual deletion until libuv has processed it */
|
||||
uv_close((uv_handle_t*)&wsi->w_read.uv.watcher, lws_libuv_closewsi);
|
||||
}
|
||||
|
||||
struct lws_event_loop_ops event_loop_ops_uv = {
|
||||
/* name */ "libuv",
|
||||
/* init_context */ elops_init_context_uv,
|
||||
/* destroy_context1 */ elops_destroy_context1_uv,
|
||||
/* destroy_context2 */ elops_destroy_context2_uv,
|
||||
/* init_vhost_listen_wsi */ elops_init_vhost_listen_wsi_uv,
|
||||
/* init_pt */ elops_init_pt_uv,
|
||||
/* wsi_logical_close */ elops_wsi_logical_close_uv,
|
||||
/* check_client_connect_ok */ elops_check_client_connect_ok_uv,
|
||||
/* close_handle_manually */ elops_close_handle_manually_uv,
|
||||
/* accept */ elops_accept_uv,
|
||||
/* io */ elops_io_uv,
|
||||
/* run_pt */ elops_run_pt_uv,
|
||||
/* destroy_pt */ elops_destroy_pt_uv,
|
||||
/* destroy wsi */ NULL,
|
||||
|
||||
/* periodic_events_available */ 0,
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* This is included from private-libwebsockets.h if LWS_ROLE_WS
|
||||
* This is included from private-libwebsockets.h if LWS_WITH_LIBUV
|
||||
*/
|
||||
|
||||
#include <uv.h>
|
||||
|
@ -49,7 +49,6 @@ struct lws_pt_eventlibs_libuv {
|
|||
};
|
||||
|
||||
struct lws_context_eventlibs_libuv {
|
||||
uv_signal_cb sigint_cb;
|
||||
uv_loop_t pu_loop;
|
||||
};
|
||||
|
||||
|
@ -61,17 +60,11 @@ 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_libuv_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
|
||||
LWS_EXTERN void
|
||||
lws_libuv_io(struct lws *wsi, int flags);
|
||||
LWS_EXTERN int
|
||||
lws_libuv_init_fd_table(struct lws_context *context);
|
||||
LWS_EXTERN void
|
||||
lws_libuv_run(const struct lws_context *context, int tsi);
|
||||
LWS_EXTERN void
|
||||
lws_libuv_destroyloop(struct lws_context *context, int tsi);
|
||||
LWS_EXTERN int
|
||||
lws_uv_initvhost(struct lws_vhost* vh, struct lws*);
|
||||
#define LWS_LIBUV_ENABLED(context) lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV)
|
||||
LWS_EXTERN void lws_feature_status_libuv(const struct lws_context_creation_info *info);
|
||||
lws_feature_status_libuv(const struct lws_context_creation_info *info);
|
||||
|
||||
|
|
43
lib/event-libs/poll/poll.c
Normal file
43
lib/event-libs/poll/poll.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* This is included from private-libwebsockets.h if LWS_ROLE_WS
|
||||
*/
|
||||
|
||||
#include <private-libwebsockets.h>
|
||||
|
||||
struct lws_event_loop_ops event_loop_ops_poll = {
|
||||
/* name */ "poll",
|
||||
/* init_context */ NULL,
|
||||
/* destroy_context1 */ NULL,
|
||||
/* destroy_context2 */ NULL,
|
||||
/* init_vhost_listen_wsi */ NULL,
|
||||
/* init_pt */ NULL,
|
||||
/* wsi_logical_close */ NULL,
|
||||
/* check_client_connect_ok */ NULL,
|
||||
/* close_handle_manually */ NULL,
|
||||
/* accept */ NULL,
|
||||
/* io */ NULL,
|
||||
/* run */ NULL,
|
||||
/* destroy_pt */ NULL,
|
||||
/* destroy wsi */ NULL,
|
||||
|
||||
/* periodic_events_available */ 1,
|
||||
};
|
23
lib/event-libs/poll/private.h
Normal file
23
lib/event-libs/poll/private.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
extern struct lws_event_loop_ops event_loop_ops_poll;
|
|
@ -152,7 +152,8 @@ __lws_free_wsi(struct lws *wsi)
|
|||
#endif
|
||||
__lws_remove_from_timeout_list(wsi);
|
||||
|
||||
lws_libevent_destroy(wsi);
|
||||
if (wsi->context->event_loop_ops->destroy_wsi)
|
||||
wsi->context->event_loop_ops->destroy_wsi(wsi);
|
||||
|
||||
wsi->context->count_wsi_allocated--;
|
||||
lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
|
||||
|
@ -796,11 +797,11 @@ just_kill_connection:
|
|||
if (!wsi->socket_is_permanently_unusable &&
|
||||
lws_sockfd_valid(wsi->desc.sockfd) &&
|
||||
lwsi_state(wsi) != LRS_SHUTDOWN &&
|
||||
!LWS_LIBUV_ENABLED(context)) {
|
||||
context->event_loop_ops->periodic_events_available) {
|
||||
__lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
|
||||
lwsi_set_state(wsi, LRS_SHUTDOWN);
|
||||
__lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,
|
||||
context->timeout_secs);
|
||||
context->timeout_secs);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -860,24 +861,9 @@ just_kill_connection:
|
|||
async_close:
|
||||
wsi->socket_is_permanently_unusable = 1;
|
||||
|
||||
#ifdef LWS_WITH_LIBUV
|
||||
if (!wsi->parent_carries_io && lws_sockfd_valid(wsi->desc.sockfd))
|
||||
if (LWS_LIBUV_ENABLED(context)) {
|
||||
if (wsi->listener) {
|
||||
lwsl_debug("%s: stop listener poll\n", __func__);
|
||||
uv_poll_stop(&wsi->w_read.uv.watcher);
|
||||
}
|
||||
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n",
|
||||
__func__, wsi);
|
||||
/*
|
||||
* libuv has to do his own close handle processing
|
||||
* asynchronously
|
||||
*/
|
||||
lws_libuv_closehandle(wsi);
|
||||
|
||||
if (wsi->context->event_loop_ops->wsi_logical_close)
|
||||
if (wsi->context->event_loop_ops->wsi_logical_close(wsi))
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
__lws_close_free_wsi_final(wsi);
|
||||
}
|
||||
|
|
|
@ -855,37 +855,6 @@ struct lws_context;
|
|||
/* needed even with extensions disabled for create context */
|
||||
struct lws_extension;
|
||||
|
||||
/*! \defgroup lwsmeta lws-meta
|
||||
*
|
||||
* ##lws-meta protocol
|
||||
*
|
||||
* The protocol wraps other muxed connections inside one tcp connection.
|
||||
*
|
||||
* Commands are assigned from 0x41 up (so they are valid unicode)
|
||||
*/
|
||||
///@{
|
||||
|
||||
enum lws_meta_commands {
|
||||
LWS_META_CMD_OPEN_SUBCHANNEL = 'A',
|
||||
/**< Client requests to open new subchannel
|
||||
*/
|
||||
LWS_META_CMD_OPEN_RESULT,
|
||||
/**< Result of client request to open new subchannel */
|
||||
LWS_META_CMD_CLOSE_NOTIFY,
|
||||
/**< Notification of subchannel closure */
|
||||
LWS_META_CMD_CLOSE_RQ,
|
||||
/**< client requests to close a subchannel */
|
||||
LWS_META_CMD_WRITE,
|
||||
/**< connection writes something to specific channel index */
|
||||
|
||||
/****** add new things just above ---^ ******/
|
||||
};
|
||||
|
||||
/* channel numbers are transported offset by 0x20 so they are valid unicode */
|
||||
|
||||
#define LWS_META_TRANSPORT_OFFSET 0x20
|
||||
|
||||
///@}
|
||||
|
||||
/*! \defgroup usercb User Callback
|
||||
*
|
||||
|
@ -2990,6 +2959,26 @@ struct lws_context_creation_info {
|
|||
* VHOST: If non-NULL, per-vhost list of advertised alpn, comma-
|
||||
* separated
|
||||
*/
|
||||
void **foreign_loops;
|
||||
/**< CONTEXT: This is ignored if the context is not being started with
|
||||
* an event loop, ie, .options has a flag like
|
||||
* LWS_SERVER_OPTION_LIBUV.
|
||||
*
|
||||
* NULL indicates lws should start its own even loop for
|
||||
* each service thread, and deal with closing the loops
|
||||
* when the context is destroyed.
|
||||
*
|
||||
* Non-NULL means it points to an array of external
|
||||
* ("foreign") event loops that are to be used in turn for
|
||||
* each service thread. In the default case of 1 service
|
||||
* thread, it can just point to one foreign event loop.
|
||||
*/
|
||||
void (*signal_cb)(void *event_lib_handle, int signum);
|
||||
/**< CONTEXT: NULL: default signal handling. Otherwise this receives
|
||||
* the signal handler callback. event_lib_handle is the
|
||||
* native event library signal handle, eg uv_signal_t *
|
||||
* for libuv.
|
||||
*/
|
||||
|
||||
/* Add new things just above here ---^
|
||||
* This is part of the ABI, don't needlessly break compatibility
|
||||
|
@ -2998,6 +2987,12 @@ struct lws_context_creation_info {
|
|||
* members added above will see 0 (default) even if the app
|
||||
* was not built against the newer headers.
|
||||
*/
|
||||
struct lws_context **pcontext;
|
||||
/**< CONTEXT: if non-NULL, at the end of context destroy processing,
|
||||
* the pointer pointed to by pcontext is written with NULL. You can
|
||||
* use this to let foreign event loops know that lws context destruction
|
||||
* is fully completed.
|
||||
*/
|
||||
|
||||
void *_unused[4]; /**< dummy */
|
||||
};
|
||||
|
@ -3039,6 +3034,7 @@ struct lws_context_creation_info {
|
|||
LWS_VISIBLE LWS_EXTERN struct lws_context *
|
||||
lws_create_context(const struct lws_context_creation_info *info);
|
||||
|
||||
|
||||
/**
|
||||
* lws_context_destroy() - Destroy the websocket context
|
||||
* \param context: Websocket context
|
||||
|
@ -3050,9 +3046,6 @@ lws_create_context(const struct lws_context_creation_info *info);
|
|||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_context_destroy(struct lws_context *context);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_context_destroy2(struct lws_context *context);
|
||||
|
||||
typedef int (*lws_reload_func)(void);
|
||||
|
||||
/**
|
||||
|
@ -4591,30 +4584,6 @@ LWS_VISIBLE LWS_EXTERN int
|
|||
lws_plat_recommended_rsa_bits(void);
|
||||
///@}
|
||||
|
||||
/*! \defgroup ev libev helpers
|
||||
*
|
||||
* ##libev helpers
|
||||
*
|
||||
* APIs specific to libev event loop itegration
|
||||
*/
|
||||
///@{
|
||||
|
||||
#if defined(LWS_WITH_LIBEV)
|
||||
typedef void (lws_ev_signal_cb_t)(EV_P_ struct ev_signal *w, int revents);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_ev_sigint_cfg(struct lws_context *context, int use_event_loop_sigint,
|
||||
lws_ev_signal_cb_t *cb);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents);
|
||||
#endif /* LWS_WITH_LIBEV */
|
||||
|
||||
///@}
|
||||
|
||||
/*! \defgroup uv libuv helpers
|
||||
*
|
||||
* ##libuv helpers
|
||||
|
@ -4623,33 +4592,8 @@ lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents);
|
|||
*/
|
||||
///@{
|
||||
#ifdef LWS_WITH_LIBUV
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
|
||||
uv_signal_cb cb);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_libuv_run(const 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_stop_without_kill(const struct lws_context *context, int tsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN uv_loop_t *
|
||||
lws_uv_getloop(struct lws_context *context, int tsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_uv_sigint_cb(uv_signal_t *watcher, int signum);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_close_all_handles_in_loop(uv_loop_t *loop);
|
||||
|
||||
/*
|
||||
* Any direct libuv allocations in protocol handlers must participate in the
|
||||
* Any direct libuv allocations in lws protocol handlers must participate in the
|
||||
* lws reference counting scheme. Two apis are provided:
|
||||
*
|
||||
* - lws_libuv_static_refcount_add(handle, context) to mark the handle with
|
||||
|
@ -4658,12 +4602,16 @@ lws_close_all_handles_in_loop(uv_loop_t *loop);
|
|||
* - lws_libuv_static_refcount_del() which should be used as the close callback
|
||||
* for your own libuv objects declared in the protocol scope.
|
||||
*
|
||||
* See the dumb increment plugin for an example of how to use them.
|
||||
*
|
||||
* Using the apis allows lws to detach itself from a libuv loop completely
|
||||
* cleanly and at the moment all of its libuv objects have completed close.
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
|
@ -4678,32 +4626,6 @@ lws_libuv_static_refcount_del(uv_handle_t *);
|
|||
#endif
|
||||
///@}
|
||||
|
||||
/*! \defgroup event libevent helpers
|
||||
*
|
||||
* ##libevent helpers
|
||||
*
|
||||
* APIs specific to libevent event loop itegration
|
||||
*/
|
||||
///@{
|
||||
|
||||
#if defined(LWS_WITH_LIBEVENT) && !defined(LWS_HIDE_LIBEVENT)
|
||||
typedef void (lws_event_signal_cb_t) (evutil_socket_t sock_fd, short revents,
|
||||
void *ctx);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_event_sigint_cfg(struct lws_context *context, int use_event_sigint,
|
||||
lws_event_signal_cb_t cb);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_event_initloop(struct lws_context *context, struct event_base *loop,
|
||||
int tsi);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_event_sigint_cb(evutil_socket_t sock_fd, short revents,
|
||||
void *ctx);
|
||||
#endif /* LWS_WITH_LIBEVENT */
|
||||
|
||||
///@}
|
||||
|
||||
/*! \defgroup timeout Connection timeouts
|
||||
|
||||
|
|
|
@ -176,9 +176,8 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
|||
if (timeout_ms < 0)
|
||||
goto faked_service;
|
||||
|
||||
lws_libev_run(context, tsi);
|
||||
lws_libuv_run(context, tsi);
|
||||
lws_libevent_run(context, tsi);
|
||||
if (context->event_loop_ops->run_pt)
|
||||
context->event_loop_ops->run_pt(context, tsi);
|
||||
|
||||
if (!context->service_tid_detected) {
|
||||
struct lws _lws;
|
||||
|
@ -738,9 +737,8 @@ lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
|||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libevent_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
if (context->event_loop_ops->io)
|
||||
context->event_loop_ops->io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
pt->fds[pt->fds_count++].revents = 0;
|
||||
}
|
||||
|
@ -751,9 +749,9 @@ lws_plat_delete_socket_from_fds(struct lws_context *context,
|
|||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
if (context->event_loop_ops->io)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
|
||||
|
||||
pt->fds_count--;
|
||||
}
|
||||
|
@ -915,10 +913,6 @@ lws_plat_init(struct lws_context *context,
|
|||
return 1;
|
||||
}
|
||||
|
||||
(void)lws_libev_init_fd_table(context);
|
||||
(void)lws_libuv_init_fd_table(context);
|
||||
(void)lws_libevent_init_fd_table(context);
|
||||
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (info->plugin_dirs)
|
||||
lws_plat_plugins_init(context, info->plugin_dirs);
|
||||
|
|
43
lib/pollfd.c
43
lib/pollfd.c
|
@ -144,25 +144,22 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
|
|||
goto bail;
|
||||
}
|
||||
|
||||
if (_and & LWS_POLLIN) {
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ);
|
||||
lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_READ);
|
||||
}
|
||||
if (_or & LWS_POLLIN) {
|
||||
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
lws_libevent_io(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
}
|
||||
if (_and & LWS_POLLOUT) {
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
|
||||
}
|
||||
if (_or & LWS_POLLOUT) {
|
||||
lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
lws_libevent_io(wsi, LWS_EV_START | LWS_EV_WRITE);
|
||||
if (context->event_loop_ops->io) {
|
||||
if (_and & LWS_POLLIN)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_STOP | LWS_EV_READ);
|
||||
|
||||
if (_or & LWS_POLLIN)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
if (_and & LWS_POLLOUT)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_STOP | LWS_EV_WRITE);
|
||||
|
||||
if (_or & LWS_POLLOUT)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_START | LWS_EV_WRITE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -319,10 +316,10 @@ __remove_wsi_socket_from_fds(struct lws *wsi)
|
|||
/* the guy who is to be deleted's slot index in pt->fds */
|
||||
m = wsi->position_in_fds_table;
|
||||
|
||||
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE |
|
||||
LWS_EV_PREPARE_DELETION);
|
||||
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE |
|
||||
LWS_EV_PREPARE_DELETION);
|
||||
if (context->event_loop_ops->io)
|
||||
context->event_loop_ops->io(wsi,
|
||||
LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE |
|
||||
LWS_EV_PREPARE_DELETION);
|
||||
|
||||
lwsl_debug("%s: wsi=%p, sock=%d, fds pos=%d, end guy pos=%d, endfd=%d\n",
|
||||
__func__, wsi, wsi->desc.sockfd, wsi->position_in_fds_table,
|
||||
|
|
|
@ -199,16 +199,6 @@
|
|||
|
||||
#include "libwebsockets.h"
|
||||
|
||||
#if defined(LWS_WITH_LIBEV)
|
||||
#include "event-libs/libev/private.h"
|
||||
#endif
|
||||
#ifdef LWS_WITH_LIBUV
|
||||
#include "event-libs/libuv/private.h"
|
||||
#endif
|
||||
#if defined(LWS_WITH_LIBEVENT) && !defined(LWS_HIDE_LIBEVENT)
|
||||
#include "event-libs/libevent/private.h"
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
#include "tls/private.h"
|
||||
#endif
|
||||
|
@ -382,6 +372,12 @@ enum lws_ssl_capable_status {
|
|||
#define lws_memory_barrier()
|
||||
#endif
|
||||
|
||||
/*
|
||||
*
|
||||
* ------ role ------
|
||||
*
|
||||
*/
|
||||
|
||||
typedef uint32_t lws_wsi_state_t;
|
||||
|
||||
/*
|
||||
|
@ -579,6 +575,8 @@ struct lws_role_ops {
|
|||
* (just client applies if no concept of client or server)
|
||||
*/
|
||||
uint16_t close_cb[2];
|
||||
|
||||
unsigned int file_handle:1; /* role operates on files not sockets */
|
||||
};
|
||||
|
||||
/* null-terminated array of pointers to roles lws built with */
|
||||
|
@ -641,6 +639,60 @@ enum {
|
|||
LWS_UPG_RET_BAIL
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* ------ event_loop ops ------
|
||||
*
|
||||
*/
|
||||
|
||||
struct lws_event_loop_ops {
|
||||
const char *name;
|
||||
/* event loop-specific context init during context creation */
|
||||
int (*init_context)(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info);
|
||||
/* called during lws_destroy_context */
|
||||
int (*destroy_context1)(struct lws_context *context);
|
||||
/* called during lws_destroy_context2 */
|
||||
int (*destroy_context2)(struct lws_context *context);
|
||||
/* init vhost listening wsi */
|
||||
int (*init_vhost_listen_wsi)(struct lws *wsi);
|
||||
/* init the event loop for a pt */
|
||||
int (*init_pt)(struct lws_context *context, void *_loop, int tsi);
|
||||
/* called at end of first phase of close_free_wsi() */
|
||||
int (*wsi_logical_close)(struct lws *wsi);
|
||||
/* return nonzero if client connect not allowed */
|
||||
int (*check_client_connect_ok)(struct lws *wsi);
|
||||
/* close handle manually */
|
||||
void (*close_handle_manually)(struct lws *wsi);
|
||||
/* event loop accept processing */
|
||||
void (*accept)(struct lws *wsi);
|
||||
/* control wsi active events */
|
||||
void (*io)(struct lws *wsi, int flags);
|
||||
/* run the event loop for a pt */
|
||||
void (*run_pt)(struct lws_context *context, int tsi);
|
||||
/* called before pt is destroyed */
|
||||
void (*destroy_pt)(struct lws_context *context, int tsi);
|
||||
/* called just before wsi is freed */
|
||||
void (*destroy_wsi)(struct lws *wsi);
|
||||
|
||||
unsigned int periodic_events_available:1;
|
||||
};
|
||||
|
||||
#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)
|
||||
#include "event-libs/libevent/private.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* enums of socks version */
|
||||
enum socks_version {
|
||||
SOCKS_VERSION_4 = 4,
|
||||
|
@ -1031,6 +1083,7 @@ struct lws_context {
|
|||
time_t time_fixup;
|
||||
const struct lws_plat_file_ops *fops;
|
||||
struct lws_plat_file_ops fops_platform;
|
||||
struct lws_context **pcontext_finalize;
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
struct http2_settings set;
|
||||
#endif
|
||||
|
@ -1067,6 +1120,7 @@ struct lws_context {
|
|||
const struct lws_protocol_vhost_options *reject_service_keywords;
|
||||
const char *alpn_default;
|
||||
lws_reload_func deprecation_cb;
|
||||
void (*eventlib_signal_cb)(void *event_lib_handle, int signum);
|
||||
|
||||
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
|
||||
cap_value_t caps[4];
|
||||
|
@ -1082,6 +1136,9 @@ struct lws_context {
|
|||
#if defined(LWS_WITH_LIBEVENT)
|
||||
struct lws_context_eventlibs_libevent event;
|
||||
#endif
|
||||
struct lws_event_loop_ops *event_loop_ops;
|
||||
|
||||
|
||||
char canonical_hostname[128];
|
||||
#ifdef LWS_LATENCY
|
||||
unsigned long worst_latency;
|
||||
|
@ -1099,10 +1156,7 @@ struct lws_context {
|
|||
#endif
|
||||
|
||||
int max_fds;
|
||||
#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || defined(LWS_WITH_LIBEVENT)
|
||||
int use_event_loop_sigint;
|
||||
int count_event_loop_static_asset_handles;
|
||||
#endif
|
||||
int started_with_parent;
|
||||
int uid, gid;
|
||||
|
||||
|
@ -1129,8 +1183,9 @@ struct lws_context {
|
|||
unsigned int requested_kill:1;
|
||||
unsigned int protocol_init_done:1;
|
||||
unsigned int ssl_gate_accepts:1;
|
||||
unsigned int doing_protocol_init;
|
||||
unsigned int done_protocol_destroy_cb;
|
||||
unsigned int doing_protocol_init:1;
|
||||
unsigned int done_protocol_destroy_cb:1;
|
||||
unsigned int finalize_destroy_after_internal_loops_stopped:1;
|
||||
/*
|
||||
* set to the Thread ID that's doing the service loop just before entry
|
||||
* to poll indicates service thread likely idling in poll()
|
||||
|
@ -1161,8 +1216,6 @@ LWS_EXTERN void
|
|||
__lws_close_free_wsi_final(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_libuv_closehandle(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_libuv_closehandle_manually(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_libuv_check_watcher_active(struct lws *wsi);
|
||||
|
||||
|
@ -1194,11 +1247,6 @@ enum {
|
|||
};
|
||||
|
||||
#if !defined(LWS_WITH_LIBEV)
|
||||
#define lws_libev_accept(_a, _b) ((void) 0)
|
||||
#define lws_libev_io(_a, _b) ((void) 0)
|
||||
#define lws_libev_init_fd_table(_a) (0)
|
||||
#define lws_libev_run(_a, _b) ((void) 0)
|
||||
#define lws_libev_destroyloop(_a, _b) ((void) 0)
|
||||
#define LWS_LIBEV_ENABLED(context) (0)
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
#define lws_feature_status_libev(_a) \
|
||||
|
@ -1209,11 +1257,6 @@ enum {
|
|||
#endif
|
||||
|
||||
#if !defined(LWS_WITH_LIBUV)
|
||||
#define lws_libuv_accept(_a, _b) ((void) 0)
|
||||
#define lws_libuv_io(_a, _b) ((void) 0)
|
||||
#define lws_libuv_init_fd_table(_a) (0)
|
||||
#define lws_libuv_run(_a, _b) ((void) 0)
|
||||
#define lws_libuv_destroyloop(_a, _b) ((void) 0)
|
||||
#define LWS_LIBUV_ENABLED(context) (0)
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
#define lws_feature_status_libuv(_a) \
|
||||
|
@ -1224,11 +1267,6 @@ enum {
|
|||
#endif
|
||||
|
||||
#if !defined(LWS_WITH_LIBEVENT)
|
||||
#define lws_libevent_accept(_a, _b) ((void) 0)
|
||||
#define lws_libevent_destroy(_a) ((void) 0)
|
||||
#define lws_libevent_io(_a, _b) ((void) 0)
|
||||
#define lws_libevent_init_fd_table(_a) (0)
|
||||
#define lws_libevent_run(_a, _b) ((void) 0)
|
||||
#define lws_libevent_destroyloop(_a, _b) ((void) 0)
|
||||
#define LWS_LIBEVENT_ENABLED(context) (0)
|
||||
#if !defined(LWS_WITH_ESP32)
|
||||
|
@ -1675,7 +1713,7 @@ LWS_EXTERN int
|
|||
lws_change_pollfd(struct lws *wsi, int _and, int _or);
|
||||
|
||||
#ifndef LWS_NO_SERVER
|
||||
int _lws_context_init_server(const struct lws_context_creation_info *info,
|
||||
int _lws_vhost_init_server(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
LWS_EXTERN struct lws_vhost *
|
||||
lws_select_vhost(struct lws_context *context, int port, const char *servername);
|
||||
|
@ -1685,7 +1723,7 @@ lws_change_pollfd(struct lws *wsi, int _and, int _or);
|
|||
lws_server_get_canonical_hostname(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info);
|
||||
#else
|
||||
#define _lws_context_init_server(_a, _b) (0)
|
||||
#define _lws_vhost_init_server(_a, _b) (0)
|
||||
#define lws_parse_ws(_a, _b, _c) (0)
|
||||
#define lws_server_get_canonical_hostname(_a, _b)
|
||||
#endif
|
||||
|
@ -2045,6 +2083,10 @@ lws_tls_server_conn_alpn(struct lws *wsi);
|
|||
|
||||
int
|
||||
lws_ws_client_rx_sm_block(struct lws *wsi, unsigned char **buf, size_t len);
|
||||
void
|
||||
lws_destroy_event_pipe(struct lws *wsi);
|
||||
void
|
||||
lws_context_destroy2(struct lws_context *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
|
|
|
@ -163,7 +163,9 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
|
|||
}
|
||||
|
||||
for (n = 0; n < 3; n++) {
|
||||
lws_libuv_accept(cgi->stdwsi[n], cgi->stdwsi[n]->desc);
|
||||
if (wsi->context->event_loop_ops->accept)
|
||||
wsi->context->event_loop_ops->accept(cgi->stdwsi[n]);
|
||||
|
||||
if (__insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
|
||||
goto bail3;
|
||||
cgi->stdwsi[n]->parent = wsi;
|
||||
|
|
|
@ -98,4 +98,5 @@ struct lws_role_ops role_ops_cgi = {
|
|||
/* destroy_role */ NULL,
|
||||
/* writeable cb clnt, srv */ { 0, 0 },
|
||||
/* close cb clnt, srv */ { 0, 0 },
|
||||
/* file_handle */ 0,
|
||||
};
|
||||
|
|
|
@ -635,4 +635,5 @@ struct lws_role_ops role_ops_h1 = {
|
|||
LWS_CALLBACK_HTTP_WRITEABLE },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP,
|
||||
LWS_CALLBACK_CLOSED_HTTP },
|
||||
/* file_handle */ 0,
|
||||
};
|
||||
|
|
|
@ -1052,4 +1052,5 @@ struct lws_role_ops role_ops_h2 = {
|
|||
LWS_CALLBACK_HTTP_WRITEABLE },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP,
|
||||
LWS_CALLBACK_CLOSED_HTTP },
|
||||
/* file_handle */ 0,
|
||||
};
|
||||
|
|
|
@ -338,14 +338,11 @@ create_new_conn:
|
|||
|
||||
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
|
||||
|
||||
#if defined(LWS_WITH_LIBUV)
|
||||
if (LWS_LIBUV_ENABLED(wsi->context))
|
||||
if (lws_libuv_check_watcher_active(wsi)) {
|
||||
lwsl_warn("Waiting for libuv watcher to close\n");
|
||||
cce = "waiting for libuv watcher to close";
|
||||
goto oom4;
|
||||
}
|
||||
#endif
|
||||
if (wsi->context->event_loop_ops->check_client_connect_ok &&
|
||||
wsi->context->event_loop_ops->check_client_connect_ok(wsi)) {
|
||||
cce = "waiting for event loop watcher to close";
|
||||
goto oom4;
|
||||
}
|
||||
|
||||
#ifdef LWS_WITH_IPV6
|
||||
if (wsi->ipv6)
|
||||
|
@ -369,9 +366,8 @@ create_new_conn:
|
|||
|
||||
lwsi_set_state(wsi, LRS_WAITING_CONNECT);
|
||||
|
||||
lws_libev_accept(wsi, wsi->desc);
|
||||
lws_libuv_accept(wsi, wsi->desc);
|
||||
lws_libevent_accept(wsi, wsi->desc);
|
||||
if (wsi->context->event_loop_ops->accept)
|
||||
wsi->context->event_loop_ops->accept(wsi);
|
||||
|
||||
if (__insert_wsi_socket_into_fds(wsi->context, wsi)) {
|
||||
compatible_close(wsi->desc.sockfd);
|
||||
|
@ -650,21 +646,10 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
|
|||
lws_ssl_close(wsi);
|
||||
#endif
|
||||
|
||||
#ifdef LWS_WITH_LIBUV
|
||||
if (LWS_LIBUV_ENABLED(wsi->context)) {
|
||||
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
|
||||
/*
|
||||
* libuv has to do his own close handle processing asynchronously
|
||||
* but once it starts we can do everything else synchronously,
|
||||
* including trash wsi->desc.sockfd since it took a copy.
|
||||
*
|
||||
* When it completes it will call compatible_close()
|
||||
*/
|
||||
lws_libuv_closehandle_manually(wsi);
|
||||
} else
|
||||
#else
|
||||
compatible_close(wsi->desc.sockfd);
|
||||
#endif
|
||||
if (wsi->context->event_loop_ops->close_handle_manually)
|
||||
wsi->context->event_loop_ops->close_handle_manually(wsi);
|
||||
else
|
||||
compatible_close(wsi->desc.sockfd);
|
||||
|
||||
__remove_wsi_socket_from_fds(wsi);
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ const char * const method_names[] = {
|
|||
*/
|
||||
|
||||
int
|
||||
_lws_context_init_server(const struct lws_context_creation_info *info,
|
||||
_lws_vhost_init_server(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost)
|
||||
{
|
||||
int n, opt = 1, limit = 1;
|
||||
|
@ -240,10 +240,8 @@ done_list:
|
|||
wsi->vhost = vhost;
|
||||
wsi->listener = 1;
|
||||
|
||||
#ifdef LWS_WITH_LIBUV
|
||||
if (LWS_LIBUV_ENABLED(vhost->context))
|
||||
lws_uv_initvhost(vhost, wsi);
|
||||
#endif
|
||||
if (wsi->context->event_loop_ops->init_vhost_listen_wsi)
|
||||
wsi->context->event_loop_ops->init_vhost_listen_wsi(wsi);
|
||||
|
||||
if (__insert_wsi_socket_into_fds(vhost->context, wsi)) {
|
||||
lwsl_notice("inserting wsi socket into fds failed\n");
|
||||
|
@ -1353,7 +1351,8 @@ deal_body:
|
|||
if (m < 0)
|
||||
return -1;
|
||||
|
||||
lws_buflist_aware_consume(wsi, &ebuf, m, 1);
|
||||
if (lws_buflist_aware_consume(wsi, &ebuf, m, 1))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1988,9 +1987,8 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
|
||||
lwsl_debug("new wsi wsistate 0x%x\n", new_wsi->wsistate);
|
||||
|
||||
lws_libev_accept(new_wsi, new_wsi->desc);
|
||||
lws_libuv_accept(new_wsi, new_wsi->desc);
|
||||
lws_libevent_accept(new_wsi, new_wsi->desc);
|
||||
if (context->event_loop_ops->accept)
|
||||
context->event_loop_ops->accept(new_wsi);
|
||||
|
||||
if (!ssl) {
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
|
|
@ -172,4 +172,5 @@ struct lws_role_ops role_ops_listen = {
|
|||
/* destroy_role */ NULL,
|
||||
/* writeable cb clnt, srv */ { 0, 0 },
|
||||
/* close cb clnt, srv */ { 0, 0 },
|
||||
/* file_handle */ 0,
|
||||
};
|
||||
|
|
|
@ -77,4 +77,5 @@ struct lws_role_ops role_ops_pipe = {
|
|||
/* destroy_role */ NULL,
|
||||
/* writeable cb clnt, srv */ { 0, 0 },
|
||||
/* close cb clnt, srv */ { 0, 0 },
|
||||
/* file_handle */ 1,
|
||||
};
|
||||
|
|
|
@ -186,6 +186,7 @@ struct lws_role_ops role_ops_raw_skt = {
|
|||
/* destroy_role */ NULL,
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE, 0 },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE, 0 },
|
||||
/* file_handle */ 0,
|
||||
};
|
||||
|
||||
|
||||
|
@ -213,4 +214,5 @@ struct lws_role_ops role_ops_raw_file = {
|
|||
/* destroy_role */ NULL,
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE_FILE, 0 },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE_FILE, 0 },
|
||||
/* file_handle */ 1,
|
||||
};
|
||||
|
|
|
@ -750,7 +750,7 @@ lws_service_periodic_checks(struct lws_context *context,
|
|||
context->no_listener_vhost_list) {
|
||||
struct lws_vhost *v = *pv;
|
||||
lwsl_debug("deferred iface: checking if on vh %s\n", (*pv)->name);
|
||||
if (_lws_context_init_server(NULL, *pv) == 0) {
|
||||
if (_lws_vhost_init_server(NULL, *pv) == 0) {
|
||||
/* became happy */
|
||||
lwsl_notice("vh %s: became connected\n", v->name);
|
||||
*pv = v->no_listener_vhost_list;
|
||||
|
@ -899,12 +899,24 @@ lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd)
|
|||
LWS_VISIBLE int
|
||||
lws_service(struct lws_context *context, int timeout_ms)
|
||||
{
|
||||
if (context->event_loop_ops->run_pt) {
|
||||
/* we are configured for an event loop */
|
||||
context->event_loop_ops->run_pt(context, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
return lws_plat_service(context, timeout_ms);
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
||||
{
|
||||
if (context->event_loop_ops->run_pt) {
|
||||
/* we are configured for an event loop */
|
||||
context->event_loop_ops->run_pt(context, tsi);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return _lws_plat_service_tsi(context, timeout_ms, tsi);
|
||||
}
|
||||
|
||||
|
|
56
lwsws/main.c
56
lwsws/main.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* libwebsockets web server application
|
||||
*
|
||||
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
|
@ -36,6 +36,7 @@
|
|||
#else
|
||||
#include <io.h>
|
||||
#include "gettimeofday.h"
|
||||
#include <uv.h>
|
||||
|
||||
int fork(void)
|
||||
{
|
||||
|
@ -52,7 +53,7 @@ static struct lws_context *context;
|
|||
static char config_dir[128];
|
||||
static int opts = 0, do_reload = 1;
|
||||
static uv_loop_t loop;
|
||||
static uv_signal_t signal_outer;
|
||||
static uv_signal_t signal_outer[2];
|
||||
static int pids[32];
|
||||
void lwsl_emit_stderr(int level, const char *line);
|
||||
|
||||
|
@ -101,7 +102,9 @@ void signal_cb(uv_signal_t *watcher, int signum)
|
|||
break;
|
||||
}
|
||||
lwsl_err("Signal %d caught\n", watcher->signum);
|
||||
lws_libuv_stop(context);
|
||||
uv_signal_stop(watcher);
|
||||
uv_signal_stop(&signal_outer[1]);
|
||||
lws_context_destroy(context);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -110,6 +113,7 @@ context_creation(void)
|
|||
int cs_len = LWSWS_CONFIG_STRING_SIZE - 1;
|
||||
struct lws_context_creation_info info;
|
||||
char *cs, *config_strings;
|
||||
void *foreign_loops[1];
|
||||
|
||||
cs = config_strings = malloc(LWSWS_CONFIG_STRING_SIZE);
|
||||
if (!config_strings) {
|
||||
|
@ -120,7 +124,6 @@ context_creation(void)
|
|||
memset(&info, 0, sizeof(info));
|
||||
|
||||
info.external_baggage_free_on_destroy = config_strings;
|
||||
info.max_http_header_pool = 1024;
|
||||
info.pt_serv_buf_size = 8192;
|
||||
info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 |
|
||||
LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
|
||||
|
@ -135,15 +138,16 @@ context_creation(void)
|
|||
if (lwsws_get_config_globals(&info, config_dir, &cs, &cs_len))
|
||||
goto init_failed;
|
||||
|
||||
foreign_loops[0] = &loop;
|
||||
info.foreign_loops = foreign_loops;
|
||||
info.pcontext = &context;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (context == NULL) {
|
||||
lwsl_err("libwebsocket init failed\n");
|
||||
goto init_failed;
|
||||
}
|
||||
|
||||
lws_uv_sigint_cfg(context, 1, signal_cb);
|
||||
lws_uv_initloop(context, &loop, 0);
|
||||
|
||||
/*
|
||||
* then create the vhosts... protocols are entirely coming from
|
||||
* plugins, so we leave it NULL
|
||||
|
@ -151,8 +155,7 @@ context_creation(void)
|
|||
|
||||
info.extensions = exts;
|
||||
|
||||
if (lwsws_get_config_vhosts(context, &info, config_dir,
|
||||
&cs, &cs_len))
|
||||
if (lwsws_get_config_vhosts(context, &info, config_dir, &cs, &cs_len))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
@ -190,6 +193,8 @@ reload_handler(int signum)
|
|||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGKILL:
|
||||
fprintf(stderr, "master process waiting 2s...\n");
|
||||
sleep(2); /* give children a chance to deal with the signal */
|
||||
fprintf(stderr, "killing service processes\n");
|
||||
for (m = 0; m < (int)ARRAY_SIZE(pids); m++)
|
||||
if (pids[m])
|
||||
|
@ -203,7 +208,7 @@ reload_handler(int signum)
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n = 0, debug_level = 7;
|
||||
int n = 0, budget = 100, debug_level = 7;
|
||||
#ifndef _WIN32
|
||||
int m;
|
||||
int status, syslog_options = LOG_PID | LOG_PERROR;
|
||||
|
@ -283,7 +288,7 @@ int main(int argc, char **argv)
|
|||
lws_set_log_level(debug_level, lwsl_emit_syslog);
|
||||
|
||||
lwsl_notice("lwsws libwebsockets web server - license CC0 + LGPL2.1\n");
|
||||
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
|
||||
lwsl_notice("(C) Copyright 2010-2018 Andy Green <andy@warmcat.com>\n");
|
||||
|
||||
#if (UV_VERSION_MAJOR > 0) // Travis...
|
||||
uv_loop_init(&loop);
|
||||
|
@ -291,30 +296,31 @@ int main(int argc, char **argv)
|
|||
fprintf(stderr, "Your libuv is too old!\n");
|
||||
return 0;
|
||||
#endif
|
||||
uv_signal_init(&loop, &signal_outer);
|
||||
uv_signal_start(&signal_outer, signal_cb, SIGINT);
|
||||
uv_signal_start(&signal_outer, signal_cb, SIGHUP);
|
||||
uv_signal_init(&loop, &signal_outer[0]);
|
||||
uv_signal_start(&signal_outer[0], signal_cb, SIGINT);
|
||||
uv_signal_init(&loop, &signal_outer[1]);
|
||||
uv_signal_start(&signal_outer[1], signal_cb, SIGHUP);
|
||||
|
||||
if (context_creation()) {
|
||||
lwsl_err("Context creation failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lws_libuv_run(context, 0);
|
||||
lws_service(context, 0);
|
||||
|
||||
lwsl_err("%s: closing\n", __func__);
|
||||
|
||||
for (n = 0; n < 2; n++) {
|
||||
uv_signal_stop(&signal_outer[n]);
|
||||
uv_close((uv_handle_t *)&signal_outer[n], NULL);
|
||||
}
|
||||
|
||||
uv_signal_stop(&signal_outer);
|
||||
lws_context_destroy(context);
|
||||
|
||||
#if (UV_VERSION_MAJOR > 0) // Travis...
|
||||
lws_close_all_handles_in_loop(&loop);
|
||||
n = 0;
|
||||
while (n++ < 4096 && uv_loop_close(&loop))
|
||||
uv_run(&loop, UV_RUN_NOWAIT);
|
||||
#endif
|
||||
while ((n = uv_loop_close(&loop)) && --budget)
|
||||
uv_run(&loop, UV_RUN_ONCE);
|
||||
|
||||
lws_context_destroy2(context);
|
||||
|
||||
fprintf(stderr, "lwsws exited cleanly\n");
|
||||
fprintf(stderr, "lwsws exited cleanly: %d\n", n);
|
||||
|
||||
#ifndef _WIN32
|
||||
closelog();
|
||||
|
|
|
@ -3,7 +3,19 @@
|
|||
This demonstrates having lws take part in a libuv loop owned by
|
||||
something else, with its own objects running in the loop.
|
||||
|
||||
Lws can join the loop, and clean up perfectly after itself.
|
||||
Lws can join the loop, and clean up perfectly after itself without
|
||||
leaving anything behind or making trouble in the larger loop, which
|
||||
does not need to stop during lws creation or destruction.
|
||||
|
||||
First the foreign loop is created with a 1s timer, and runs alone for 5s.
|
||||
|
||||
Then the lws context is created inside the timer callback and runs for 10s...
|
||||
during this period you can visit http://localhost:7681 for normal lws
|
||||
service using the foreign loop.
|
||||
|
||||
After the 10s are up, the lws context is destroyed inside the foreign loop
|
||||
timer. The foreign loop runs alone again for a further 5s and then
|
||||
exits itself.
|
||||
|
||||
## build
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,52 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
fBrpEY1IATtPq1taBZZogRqI3rOkkPk=
|
||||
-----END PRIVATE KEY-----
|
|
@ -20,6 +20,17 @@
|
|||
#include <signal.h>
|
||||
|
||||
static struct lws_context *context;
|
||||
static uv_loop_t loop;
|
||||
static int lifetime = 5, reported;
|
||||
struct lws_context_creation_info info;
|
||||
|
||||
enum {
|
||||
TEST_STATE_CREATE_LWS_CONTEXT,
|
||||
TEST_STATE_DESTROY_LWS_CONTEXT,
|
||||
TEST_STATE_EXIT
|
||||
};
|
||||
|
||||
static int sequence = TEST_STATE_CREATE_LWS_CONTEXT;
|
||||
|
||||
static const struct lws_http_mount mount = {
|
||||
/* .mount_next */ NULL, /* linked-list "next" */
|
||||
|
@ -54,32 +65,66 @@ void signal_cb(uv_signal_t *watcher, int signum)
|
|||
abort();
|
||||
break;
|
||||
}
|
||||
lws_libuv_stop(context);
|
||||
|
||||
if (context)
|
||||
lws_context_destroy(context);
|
||||
}
|
||||
|
||||
/* this logs once a second to show that the foreign loop assets are working */
|
||||
|
||||
static void timer_cb(uv_timer_t *t)
|
||||
static void
|
||||
timer_cb(uv_timer_t *t)
|
||||
{
|
||||
void *foreign_loops[1];
|
||||
|
||||
foreign_loops[0] = &loop;
|
||||
info.foreign_loops = foreign_loops;
|
||||
|
||||
lwsl_user("Foreign 1Hz timer\n");
|
||||
|
||||
if (sequence == TEST_STATE_EXIT && !context && !reported) {
|
||||
/*
|
||||
* at this point the lws_context_destroy() we did earlier
|
||||
* has completed and the entire context is wholly destroyed
|
||||
*/
|
||||
lwsl_user("lws_destroy_context() completed, continuing for 5s\n");
|
||||
reported = 1;
|
||||
}
|
||||
|
||||
if (--lifetime)
|
||||
return;
|
||||
|
||||
switch (sequence++) {
|
||||
case TEST_STATE_CREATE_LWS_CONTEXT:
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return;
|
||||
}
|
||||
lwsl_user("LWS Context created and active for 10s\n");
|
||||
lifetime = 11;
|
||||
break;
|
||||
case TEST_STATE_DESTROY_LWS_CONTEXT:
|
||||
/* cleanup the lws part */
|
||||
lwsl_user("Destroying lws context and continuing loop for 5s\n");
|
||||
lws_context_destroy(context);
|
||||
lifetime = 6;
|
||||
break;
|
||||
|
||||
case TEST_STATE_EXIT:
|
||||
lwsl_user("Deciding to exit foreign loop too\n");
|
||||
uv_stop(&loop);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void lws_uv_close_cb(uv_handle_t *handle)
|
||||
{
|
||||
}
|
||||
|
||||
static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
|
||||
{
|
||||
lwsl_info("%s: closing foreign loop asset: %p (type %d)\n",
|
||||
__func__, handle, handle->type);
|
||||
uv_close(handle, lws_uv_close_cb);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
struct lws_context_creation_info info;
|
||||
uv_timer_t timer_outer;
|
||||
uv_loop_t loop;
|
||||
uv_signal_t sighandler;
|
||||
const char *p;
|
||||
int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
|
||||
/* for LLL_ verbosity above NOTICE to be built into lws,
|
||||
|
@ -96,61 +141,58 @@ int main(int argc, const char **argv)
|
|||
lwsl_user("LWS minimal http server libuv + foreign loop |"
|
||||
" visit http://localhost:7681\n");
|
||||
|
||||
/*
|
||||
* We prepare the info here, but don't use it until later in the
|
||||
* timer callback, to demonstrate the independence of the foreign loop
|
||||
* and lws.
|
||||
*/
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.port = 7681;
|
||||
info.mounts = &mount;
|
||||
info.error_document_404 = "/404.html";
|
||||
info.options = LWS_SERVER_OPTION_LIBUV;
|
||||
info.pcontext = &context;
|
||||
if (lws_cmdline_option(argc, argv, "-s")) {
|
||||
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||
info.ssl_cert_filepath = "localhost-100y.cert";
|
||||
info.ssl_private_key_filepath = "localhost-100y.key";
|
||||
}
|
||||
info.pcontext = &context;
|
||||
|
||||
lwsl_user(" This app creates a uv loop with a timer + signalhandler, and\n");
|
||||
lwsl_user(" performs a test in three phases:\n");
|
||||
lwsl_user("\n");
|
||||
lwsl_user(" 1) 5s: Runs the loop with just the timer\n");
|
||||
lwsl_user(" 2) 10s: create an lws context serving on localhost:7681\n");
|
||||
lwsl_user(" using the same uv loop. Destroy it after 10s.\n");
|
||||
lwsl_user(" 3) 5s: Run the loop again with just the timer\n");
|
||||
lwsl_user("\n");
|
||||
lwsl_user(" Finally close only the timer and signalhandler and\n");
|
||||
lwsl_user(" exit the loop cleanly\n");
|
||||
|
||||
/* we create and start our "foreign loop" */
|
||||
|
||||
uv_loop_init(&loop);
|
||||
uv_signal_init(&loop, &sighandler);
|
||||
uv_signal_start(&sighandler, signal_cb, SIGINT);
|
||||
|
||||
uv_timer_init(&loop, &timer_outer);
|
||||
uv_timer_start(&timer_outer, timer_cb, 0, 1000);
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
lws_uv_sigint_cfg(context, 1, signal_cb);
|
||||
|
||||
if (lws_uv_initloop(context, &loop, 0)) {
|
||||
lwsl_err("lws_uv_initloop failed\n");
|
||||
|
||||
goto bail;
|
||||
}
|
||||
|
||||
lws_libuv_run(context, 0);
|
||||
|
||||
bail:
|
||||
lwsl_user("%s: starting exit cleanup...\n", __func__);
|
||||
|
||||
/* cleanup the lws part */
|
||||
|
||||
lws_context_destroy(context);
|
||||
lws_context_destroy2(context);
|
||||
|
||||
/* cleanup the foreign loop part */
|
||||
|
||||
lwsl_user("%s: lws context destroyed: cleaning the foreign loop\n",
|
||||
__func__);
|
||||
|
||||
/*
|
||||
* Instead of walking to close all the foreign assets, it's also
|
||||
* fine to close them individually instead as below
|
||||
*/
|
||||
// uv_timer_stop(&timer_outer);
|
||||
// uv_close((uv_handle_t*)&timer_outer, NULL);
|
||||
|
||||
/* close every foreign loop asset unconditionally */
|
||||
uv_walk(&loop, lws_uv_walk_cb, NULL);
|
||||
|
||||
/* let it run until everything completed close */
|
||||
uv_run(&loop, UV_RUN_DEFAULT);
|
||||
|
||||
/* nothing left in the foreign loop, destroy it */
|
||||
/* in the case we hit ^C while lws still exists */
|
||||
lws_context_destroy(context);
|
||||
|
||||
/* cleanup the foreign loop assets */
|
||||
|
||||
uv_timer_stop(&timer_outer);
|
||||
uv_close((uv_handle_t*)&timer_outer, NULL);
|
||||
uv_signal_stop(&sighandler);
|
||||
uv_close((uv_handle_t *)&sighandler, NULL);
|
||||
|
||||
uv_run(&loop, UV_RUN_DEFAULT);
|
||||
uv_loop_close(&loop);
|
||||
|
||||
lwsl_user("%s: exiting...\n", __func__);
|
||||
|
|
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8)
|
|||
include(CheckCSourceCompiles)
|
||||
|
||||
set(SAMP lws-minimal-http-server-libuv)
|
||||
set(SRCS minimal-http-server.c)
|
||||
set(SRCS minimal-http-server-libuv.c)
|
||||
|
||||
# If we are being built as part of lws, confirm current build config supports
|
||||
# reqconfig, else skip building ourselves.
|
||||
|
@ -76,4 +76,4 @@ if (requirements)
|
|||
else()
|
||||
target_link_libraries(${SAMP} websockets)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* This demonstrates the most minimal http server you can make with lws.
|
||||
* This demonstrates the most minimal http server you can make with lws using
|
||||
* the libuv event loop.
|
||||
*
|
||||
* To keep it simple, it serves stuff from the subdirectory
|
||||
* "./mount-origin" of the directory it was started in.
|
||||
|
@ -39,8 +40,10 @@ static const struct lws_http_mount mount = {
|
|||
/* .basic_auth_login_file */ NULL,
|
||||
};
|
||||
|
||||
void signal_cb(uv_signal_t *watcher, int signum)
|
||||
void signal_cb(void *handle, int signum)
|
||||
{
|
||||
uv_signal_t *watcher = (uv_signal_t *)handle;
|
||||
|
||||
lwsl_notice("Signal %d caught, exiting...\n", watcher->signum);
|
||||
|
||||
switch (watcher->signum) {
|
||||
|
@ -52,7 +55,7 @@ void signal_cb(uv_signal_t *watcher, int signum)
|
|||
abort();
|
||||
break;
|
||||
}
|
||||
lws_libuv_stop(context);
|
||||
lws_context_destroy(context);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
|
@ -83,6 +86,7 @@ int main(int argc, const char **argv)
|
|||
info.ssl_private_key_filepath = "localhost-100y.key";
|
||||
}
|
||||
info.options |= LWS_SERVER_OPTION_LIBUV;
|
||||
info.signal_cb = signal_cb;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
|
@ -90,19 +94,9 @@ int main(int argc, const char **argv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
lws_uv_sigint_cfg(context, 1, signal_cb);
|
||||
lws_service(context, 0);
|
||||
|
||||
if (lws_uv_initloop(context, NULL, 0)) {
|
||||
lwsl_err("lws_uv_initloop failed\n");
|
||||
|
||||
goto bail;
|
||||
}
|
||||
|
||||
lws_libuv_run(context, 0);
|
||||
|
||||
bail:
|
||||
lws_context_destroy(context);
|
||||
lws_context_destroy2(context);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -52,10 +52,10 @@ struct per_session_data__server_status {
|
|||
};
|
||||
|
||||
struct per_vhost_data__lws_server_status {
|
||||
uv_timer_t timeout_watcher;
|
||||
struct lws_context *context;
|
||||
int hide_vhosts;
|
||||
int tow_flag;
|
||||
int period_us;
|
||||
struct lws_ss_dumps d;
|
||||
struct lws_ss_filepath *fp;
|
||||
};
|
||||
|
@ -63,15 +63,8 @@ struct per_vhost_data__lws_server_status {
|
|||
static const struct lws_protocols protocols[1];
|
||||
|
||||
static void
|
||||
uv_timeout_cb_server_status(uv_timer_t *w
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
update(struct per_vhost_data__lws_server_status *v)
|
||||
{
|
||||
struct per_vhost_data__lws_server_status *v = lws_container_of(w,
|
||||
struct per_vhost_data__lws_server_status,
|
||||
timeout_watcher);
|
||||
struct lws_ss_filepath *fp;
|
||||
char *p = v->d.buf + LWS_PRE, contents[256], pure[256];
|
||||
int n, l, first = 1, fd;
|
||||
|
@ -135,12 +128,13 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
|
||||
lws_get_protocol(wsi));
|
||||
struct lws_ss_filepath *fp, *fp1, **fp_old;
|
||||
int m, period = 1000;
|
||||
int m;
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
|
||||
lws_set_timer_usecs(wsi, v->period_us);
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
|
@ -161,7 +155,9 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
if (!strcmp(pvo->name, "hide-vhosts"))
|
||||
v->hide_vhosts = atoi(pvo->value);
|
||||
if (!strcmp(pvo->name, "update-ms"))
|
||||
period = atoi(pvo->value);
|
||||
v->period_us = atoi(pvo->value) * 1000;
|
||||
else
|
||||
v->period_us = 5 * 1000 * 1000;
|
||||
if (!strcmp(pvo->name, "filepath")) {
|
||||
fp = malloc(sizeof(*fp));
|
||||
fp->next = NULL;
|
||||
|
@ -174,17 +170,12 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
pvo = pvo->next;
|
||||
}
|
||||
v->context = lws_get_context(wsi);
|
||||
uv_timer_init(lws_uv_getloop(v->context, 0),
|
||||
&v->timeout_watcher);
|
||||
uv_timer_start(&v->timeout_watcher,
|
||||
uv_timeout_cb_server_status, 2000, period);
|
||||
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
|
||||
if (!v)
|
||||
break;
|
||||
uv_timer_stop(&v->timeout_watcher);
|
||||
uv_close((uv_handle_t *)&v->timeout_watcher, NULL);
|
||||
fp = v->fp;
|
||||
while (fp) {
|
||||
fp1= fp->next;
|
||||
|
@ -200,6 +191,12 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
return -1;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_TIMER:
|
||||
lws_set_timer_usecs(wsi, v->period_us);
|
||||
update(v);
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -198,6 +198,7 @@ int main(int argc, char **argv)
|
|||
struct lws_context_creation_info info;
|
||||
char interface_name[128] = "";
|
||||
const char *iface = NULL;
|
||||
void *foreign_loops[1];
|
||||
char cert_path[1024];
|
||||
char key_path[1024];
|
||||
int use_ssl = 0;
|
||||
|
@ -319,6 +320,9 @@ int main(int argc, char **argv)
|
|||
info.uid = -1;
|
||||
info.options = opts | LWS_SERVER_OPTION_LIBEV;
|
||||
|
||||
foreign_loops[0] = &loop;
|
||||
info.foreign_loops = foreign_loops;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (context == NULL) {
|
||||
lwsl_err("libwebsocket init failed\n");
|
||||
|
@ -335,8 +339,7 @@ int main(int argc, char **argv)
|
|||
/* override the active fops */
|
||||
lws_get_fops(context)->open = test_server_fops_open;
|
||||
|
||||
lws_ev_initloop(context, loop, 0);
|
||||
ev_run(loop, 0);
|
||||
lws_service(context, 0);
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
|
|
|
@ -192,6 +192,7 @@ int main(int argc, char **argv)
|
|||
struct event_base *event_base_loop = event_base_new();
|
||||
struct lws_context_creation_info info;
|
||||
char interface_name[128] = "";
|
||||
void *foreign_loops[1];
|
||||
const char *iface = NULL;
|
||||
char cert_path[1024];
|
||||
char key_path[1024];
|
||||
|
@ -273,7 +274,8 @@ int main(int argc, char **argv)
|
|||
#endif
|
||||
|
||||
for (n = 0; n < (int)ARRAY_SIZE(sigs); n++) {
|
||||
signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_base_loop);
|
||||
signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb,
|
||||
event_base_loop);
|
||||
|
||||
evsignal_add(signals[n], NULL);
|
||||
}
|
||||
|
@ -315,9 +317,11 @@ int main(int argc, char **argv)
|
|||
}
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
info.max_http_header_pool = 1;
|
||||
info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
|
||||
|
||||
foreign_loops[0] = event_base_loop;
|
||||
info.foreign_loops = foreign_loops;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (context == NULL) {
|
||||
lwsl_err("libwebsocket init failed\n");
|
||||
|
@ -334,13 +338,11 @@ int main(int argc, char **argv)
|
|||
/* override the active fops */
|
||||
lws_get_fops(context)->open = test_server_fops_open;
|
||||
|
||||
// Don't use the default Signal Event Watcher & Handler
|
||||
lws_event_sigint_cfg(context, 0, NULL);
|
||||
// Initialize the LWS with libevent loop
|
||||
lws_event_initloop(context, event_base_loop, 0);
|
||||
|
||||
event_base_dispatch(event_base_loop);
|
||||
|
||||
for (n = 0; n < (int)ARRAY_SIZE(sigs); n++)
|
||||
event_free(signals[n]);
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
lwsl_notice("libwebsockets-test-server exited cleanly\n");
|
||||
|
|
|
@ -82,8 +82,10 @@ static const struct lws_extension exts[] = {
|
|||
{ NULL, NULL, NULL /* terminator */ }
|
||||
};
|
||||
|
||||
void signal_cb(uv_signal_t *watcher, int signum)
|
||||
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:
|
||||
|
@ -94,7 +96,7 @@ void signal_cb(uv_signal_t *watcher, int signum)
|
|||
abort();
|
||||
break;
|
||||
}
|
||||
lws_libuv_stop(context);
|
||||
lws_context_destroy(context);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -228,6 +230,11 @@ static void timer_close_cb(uv_handle_t *h)
|
|||
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);
|
||||
|
@ -255,6 +262,7 @@ int main(int argc, char **argv)
|
|||
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;
|
||||
|
@ -351,6 +359,7 @@ int main(int argc, char **argv)
|
|||
info.protocols = protocols;
|
||||
info.extensions = exts;
|
||||
info.mounts = &mount;
|
||||
info.pcontext = &context;
|
||||
|
||||
info.ssl_cert_filepath = NULL;
|
||||
info.ssl_private_key_filepath = NULL;
|
||||
|
@ -375,7 +384,6 @@ int main(int argc, char **argv)
|
|||
}
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
info.max_http_header_pool = 16;
|
||||
info.timeout_secs = 5;
|
||||
info.options = opts | LWS_SERVER_OPTION_LIBUV;
|
||||
|
||||
|
@ -403,7 +411,11 @@ int main(int argc, char **argv)
|
|||
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);
|
||||
|
@ -412,25 +424,6 @@ int main(int argc, char **argv)
|
|||
return -1;
|
||||
}
|
||||
|
||||
lws_uv_sigint_cfg(context, 1, signal_cb);
|
||||
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
if (foreign_libuv_loop) {
|
||||
/* we have our own uv loop outside of lws */
|
||||
lws_uv_initloop(context, &loop, 0);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/*
|
||||
* lws will create his own libuv loop in the context
|
||||
*/
|
||||
if (lws_uv_initloop(context, NULL, 0)) {
|
||||
lwsl_err("lws_uv_initloop failed\n");
|
||||
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
if (foreign_libuv_loop) {
|
||||
/*
|
||||
|
@ -462,7 +455,6 @@ int main(int argc, char **argv)
|
|||
|
||||
/* detach lws */
|
||||
lws_context_destroy(context);
|
||||
lws_context_destroy2(context);
|
||||
|
||||
lwsl_notice("Please wait while the outer libuv test continues for 10s\n");
|
||||
|
||||
|
@ -478,10 +470,13 @@ int main(int argc, char **argv)
|
|||
* outside of lws */
|
||||
|
||||
uv_timer_stop(&timer_outer);
|
||||
uv_timer_stop(&timer_test_cancel);
|
||||
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--)
|
||||
|
@ -490,17 +485,21 @@ int main(int argc, char **argv)
|
|||
/* PHASE 2: close the UV loop itself */
|
||||
|
||||
e = uv_loop_close(&loop);
|
||||
lwsl_notice("uv loop close rc %s\n",
|
||||
e ? uv_strerror(e) : "ok");
|
||||
if (e) {
|
||||
lwsl_notice("uv loop close rc %s\n", e ? uv_strerror(e) : "ok");
|
||||
|
||||
uv_walk(&loop, walk_cb, NULL);
|
||||
}
|
||||
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
lws_libuv_run(context, 0);
|
||||
lws_service(context, 0);
|
||||
|
||||
bail:
|
||||
/*
|
||||
* we can't destroy the internal loops while they are running
|
||||
*/
|
||||
lws_context_destroy(context);
|
||||
lws_context_destroy2(context);
|
||||
}
|
||||
|
||||
lwsl_notice("libwebsockets-test-server exited cleanly\n");
|
||||
|
|
|
@ -265,8 +265,10 @@ static const struct lws_protocol_vhost_options pvo = {
|
|||
""
|
||||
};
|
||||
|
||||
static void signal_cb(uv_signal_t *watcher, int signum)
|
||||
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:
|
||||
|
@ -277,7 +279,7 @@ static void signal_cb(uv_signal_t *watcher, int signum)
|
|||
abort();
|
||||
break;
|
||||
}
|
||||
lws_libuv_stop(context);
|
||||
lws_context_destroy(context);
|
||||
}
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -318,6 +320,7 @@ int main(int argc, char **argv)
|
|||
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;
|
||||
|
@ -507,6 +510,10 @@ int main(int argc, char **argv)
|
|||
* 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
|
||||
|
@ -534,19 +541,10 @@ int main(int argc, char **argv)
|
|||
info.port++;
|
||||
#endif
|
||||
|
||||
/* libuv event loop */
|
||||
lws_uv_sigint_cfg(context, 1, signal_cb);
|
||||
if (lws_uv_initloop(context, &loop, 0)) {
|
||||
lwsl_err("lws_uv_initloop failed\n");
|
||||
goto bail;
|
||||
}
|
||||
lws_service(context, 0);
|
||||
|
||||
lws_libuv_run(context, 0);
|
||||
|
||||
bail:
|
||||
/* when we decided to exit the event loop */
|
||||
lws_context_destroy(context);
|
||||
lws_context_destroy2(context);
|
||||
|
||||
|
||||
#if defined(TEST_DYNAMIC_VHOST)
|
||||
|
|
Loading…
Add table
Reference in a new issue