diff --git a/include/libwebsockets/lws-dll2.h b/include/libwebsockets/lws-dll2.h index 478aa4344..14f0fcd47 100644 --- a/include/libwebsockets/lws-dll2.h +++ b/include/libwebsockets/lws-dll2.h @@ -228,9 +228,11 @@ lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner); LWS_VISIBLE LWS_EXTERN void lws_dll2_remove(struct lws_dll2 *d); +typedef int (*lws_dll2_foreach_cb_t)(struct lws_dll2 *d, void *user); + LWS_VISIBLE LWS_EXTERN int lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user, - int (*cb)(struct lws_dll2 *d, void *user)); + lws_dll2_foreach_cb_t cb); LWS_VISIBLE LWS_EXTERN void lws_dll2_clear(struct lws_dll2 *d); diff --git a/include/libwebsockets/lws-eventlib-exports.h b/include/libwebsockets/lws-eventlib-exports.h index 1a1bc5103..972d339ac 100644 --- a/include/libwebsockets/lws-eventlib-exports.h +++ b/include/libwebsockets/lws-eventlib-exports.h @@ -96,6 +96,10 @@ LWS_VISIBLE LWS_EXTERN void lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *caller); +LWS_VISIBLE LWS_EXTERN int +lws_vhost_foreach_listen_wsi(struct lws_context *cx, void *arg, + lws_dll2_foreach_cb_t cb); + struct lws_context_per_thread; LWS_VISIBLE LWS_EXTERN void lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt); diff --git a/lib/core-net/close.c b/lib/core-net/close.c index 45c88c9ee..494c967f8 100644 --- a/lib/core-net/close.c +++ b/lib/core-net/close.c @@ -136,8 +136,10 @@ __lws_reset_wsi(struct lws *wsi) lws_buflist_destroy_all_segments(&wsi->http.buflist_post_body); #endif - if (wsi->a.vhost && wsi->a.vhost->lserv_wsi == wsi) - wsi->a.vhost->lserv_wsi = NULL; +#if defined(LWS_WITH_SERVER) + lws_dll2_remove(&wsi->listen_list); +#endif + #if defined(LWS_WITH_CLIENT) if (wsi->a.vhost) lws_dll2_remove(&wsi->dll_cli_active_conns); diff --git a/lib/core-net/pollfd.c b/lib/core-net/pollfd.c index 80f445f7a..b98d16a7e 100644 --- a/lib/core-net/pollfd.c +++ b/lib/core-net/pollfd.c @@ -230,14 +230,15 @@ lws_accept_modulation(struct lws_context *context, struct lws_pollargs pa1; while (vh) { - if (vh->lserv_wsi) { - if (allow) - _lws_change_pollfd(vh->lserv_wsi, - 0, LWS_POLLIN, &pa1); - else - _lws_change_pollfd(vh->lserv_wsi, - LWS_POLLIN, 0, &pa1); - } + lws_start_foreach_dll(struct lws_dll2 *, d, + lws_dll2_get_head(&vh->listen_wsi)) { + struct lws *wsi = lws_container_of(d, struct lws, + listen_list); + + _lws_change_pollfd(wsi, allow ? 0 : LWS_POLLIN, + allow ? LWS_POLLIN : 0, &pa1); + } lws_end_foreach_dll(d); + vh = vh->vhost_next; } } diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index 38073baeb..06c69f312 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -480,7 +480,8 @@ struct lws_vhost { lws_ss_handle_t *ss_handle; /* ss handle for the server obj */ #endif - struct lws *lserv_wsi; + lws_dll2_owner_t listen_wsi; + const char *name; const char *iface; const char *listen_accept_role; @@ -682,6 +683,9 @@ struct lws { struct lws_dll2 dll_cli_active_conns; struct lws_dll2 dll2_cli_txn_queue; struct lws_dll2_owner dll2_cli_txn_queue_owner; +#if defined(LWS_WITH_SERVER) + struct lws_dll2 listen_list; +#endif /**< caliper is reused for tcp, tls and txn conn phases */ @@ -1532,6 +1536,9 @@ lws_sul_nonmonotonic_adjust(struct lws_context *ctx, int64_t step_us); void __lws_vhost_destroy_pt_wsi_dieback_start(struct lws_vhost *vh); +int +lws_vhost_compare_listen(struct lws_vhost *v1, struct lws_vhost *v2); + void lws_netdev_instance_remove_destroy(struct lws_netdev_instance *ni); diff --git a/lib/core-net/vhost.c b/lib/core-net/vhost.c index 7654faaf9..a5a1dfcee 100644 --- a/lib/core-net/vhost.c +++ b/lib/core-net/vhost.c @@ -1211,6 +1211,35 @@ __lws_vhost_destroy_pt_wsi_dieback_start(struct lws_vhost *vh) #endif } +#if defined(LWS_WITH_NETWORK) +int +lws_vhost_compare_listen(struct lws_vhost *v1, struct lws_vhost *v2) +{ + return ((!v1->iface && !v2->iface) || + (v1->iface && v2->iface && !strcmp(v1->iface, v2->iface))) && + v1->listen_port == v2->listen_port; +} + +int +lws_vhost_foreach_listen_wsi(struct lws_context *cx, void *arg, + lws_dll2_foreach_cb_t cb) +{ + struct lws_vhost *v = cx->vhost_list; + int n; + + while (v) { + + n = lws_dll2_foreach_safe(&v->listen_wsi, arg, cb); + if (n) + return n; + + v = v->vhost_next; + } + + return 0; +} + +#endif /* * Mark the vhost as being destroyed, so things trying to use it abort. @@ -1244,8 +1273,8 @@ lws_vhost_destroy1(struct lws_vhost *vh) /* * PHASE 1: take down or reassign any listen wsi * - * Are there other vhosts that are piggybacking on our listen socket? - * If so we need to hand the listen socket off to one of the others + * Are there other vhosts that are piggybacking on our listen sockets? + * If so we need to hand each listen socket off to one of the others * so it will remain open. * * If not, close the listen socket now. @@ -1254,15 +1283,21 @@ lws_vhost_destroy1(struct lws_vhost *vh) * immediately performed. */ - if (vh->lserv_wsi) { + lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, + lws_dll2_get_head(&vh->listen_wsi)) { + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + + /* + * For each of our listen sockets, check every other vhost to + * see if another vhost should be given our listen socket. + * + * ipv4 and ipv6 sockets will both match and be migrated. + */ + lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) { - if (v != vh && - !v->being_destroyed && - v->listen_port == vh->listen_port && - ((!v->iface && !vh->iface) || - (v->iface && vh->iface && - !strcmp(v->iface, vh->iface)))) { + if (v != vh && !v->being_destroyed && + lws_vhost_compare_listen(v, vh)) { /* * this can only be a listen wsi, which is * restricted... it has no protocol or other @@ -1275,31 +1310,32 @@ lws_vhost_destroy1(struct lws_vhost *vh) __func__, lws_vh_tag(vh), lws_vh_tag(v)); - assert(v->lserv_wsi == NULL); - v->lserv_wsi = vh->lserv_wsi; - - if (v->lserv_wsi) { - /* req cx + vh lock */ - __lws_vhost_unbind_wsi(vh->lserv_wsi); - lws_vhost_bind_wsi(v, v->lserv_wsi); - vh->lserv_wsi = NULL; - } + lws_dll2_remove(&wsi->listen_list); + lws_dll2_add_tail(&wsi->listen_list, + &v->listen_wsi); + /* req cx + vh lock */ + __lws_vhost_unbind_wsi(wsi); + lws_vhost_bind_wsi(v, wsi); break; } } lws_end_foreach_ll(v, vhost_next); - if (vh->lserv_wsi) { - /* - * we didn't pass it off to another vhost on the same - * listen port... let's close it next time around the - * event loop without waiting for the logical destroy - * of the vhost itself - */ - lws_set_timeout(vh->lserv_wsi, 1, LWS_TO_KILL_ASYNC); - vh->lserv_wsi = NULL; - } - } + } lws_end_foreach_dll_safe(d, d1); + + /* + * If any listen wsi left we couldn't pass to other vhosts, close them + */ + + lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, + lws_dll2_get_head(&vh->listen_wsi)) { + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + + lws_dll2_remove(&wsi->listen_list); + lws_wsi_close(wsi, LWS_TO_KILL_ASYNC); + + } lws_end_foreach_dll_safe(d, d1); + #endif #if defined(LWS_WITH_TLS_JIT_TRUST) lws_sul_cancel(&vh->sul_unref); @@ -1578,44 +1614,40 @@ lws_get_vhost_listen_port(struct lws_vhost *vhost) #if defined(LWS_WITH_SERVER) void -lws_context_deprecate(struct lws_context *context, lws_reload_func cb) +lws_context_deprecate(struct lws_context *cx, lws_reload_func cb) { - struct lws_vhost *vh = context->vhost_list, *vh1; + struct lws_vhost *vh = cx->vhost_list; /* - * "deprecation" means disable the context from accepting any new + * "deprecation" means disable the cx from accepting any new * connections and free up listen sockets to be used by a replacement - * context. + * cx. * - * Otherwise the deprecated context remains operational, until its + * Otherwise the deprecated cx remains operational, until its * number of connected sockets falls to zero, when it is deleted. + * + * So, for each vhost, close his listen sockets */ - /* for each vhost, close his listen socket */ - while (vh) { - struct lws *wsi = vh->lserv_wsi; - if (wsi) { + lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, + lws_dll2_get_head(&vh->listen_wsi)) { + struct lws *wsi = lws_container_of(d, struct lws, + listen_list); + wsi->socket_is_permanently_unusable = 1; - lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "ctx deprecate"); - wsi->a.context->deprecation_pending_listen_close_count++; - /* - * other vhosts can share the listen port, they - * point to the same wsi. So zap those too. - */ - vh1 = context->vhost_list; - while (vh1) { - if (vh1->lserv_wsi == wsi) - vh1->lserv_wsi = NULL; - vh1 = vh1->vhost_next; - } - } + lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, + __func__); + cx->deprecation_pending_listen_close_count++; + + } lws_end_foreach_dll_safe(d, d1); + vh = vh->vhost_next; } - context->deprecated = 1; - context->deprecation_cb = cb; + cx->deprecated = 1; + cx->deprecation_cb = cb; } #endif diff --git a/lib/event-libs/glib/glib.c b/lib/event-libs/glib/glib.c index 8ff3703a8..5e3c4f234 100644 --- a/lib/event-libs/glib/glib.c +++ b/lib/event-libs/glib/glib.c @@ -293,12 +293,21 @@ elops_accept_glib(struct lws *wsi) return 0; } +static int +elops_listen_init_glib(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + + elops_accept_glib(wsi); + + return 0; +} + static int elops_init_pt_glib(struct lws_context *context, void *_loop, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_pt_eventlibs_glib *ptpr = pt_to_priv_glib(pt); - struct lws_vhost *vh = context->vhost_list; GMainLoop *loop = (GMainLoop *)_loop; if (!loop) @@ -314,17 +323,7 @@ elops_init_pt_glib(struct lws_context *context, void *_loop, int tsi) ptpr->loop = loop; - /* - * Initialize all events with the listening sockets - * and register a callback for read operations - */ - - while (vh) { - if (vh->lserv_wsi) - elops_accept_glib(vh->lserv_wsi); - - vh = vh->vhost_next; - } + lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_glib); lws_glib_set_idle(pt); @@ -420,25 +419,26 @@ elops_destroy_wsi_glib(struct lws *wsi) wsi_to_subclass(wsi) = NULL; } +static int +elops_listen_destroy_glib(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + + elops_destroy_wsi_glib(wsi); + + return 0; +} + static void elops_destroy_pt_glib(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_pt_eventlibs_glib *ptpr = pt_to_priv_glib(pt); - struct lws_vhost *vh = context->vhost_list; if (!pt_to_loop(pt)) return; - /* - * Free all events with the listening sockets - */ - while (vh) { - if (vh->lserv_wsi) - elops_destroy_wsi_glib(vh->lserv_wsi); - - vh = vh->vhost_next; - } + lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_glib); lws_gs_destroy(ptpr->idle); lws_gs_destroy(ptpr->hrtimer); diff --git a/lib/event-libs/libev/libev.c b/lib/event-libs/libev/libev.c index a8583b8f5..acd4d4b80 100644 --- a/lib/event-libs/libev/libev.c +++ b/lib/event-libs/libev/libev.c @@ -133,6 +133,27 @@ lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents) ev_break(loop, EVBREAK_ALL); } +static int +elops_listen_init_ev(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + struct lws_context *context = (struct lws_context *)user; + struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; + struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt); + struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi); + struct lws_vhost *vh = wsi->a.vhost; + + w->w_read.context = context; + w->w_write.context = context; + vh_to_priv_ev(vh)->w_accept.context = context; + + ev_io_init(&vh_to_priv_ev(vh)->w_accept.watcher, + lws_accept_cb, wsi->desc.sockfd, EV_READ); + ev_io_start(ptpr->io_loop, &vh_to_priv_ev(vh)->w_accept.watcher); + + return 0; +} + static int elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) { @@ -140,7 +161,6 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt); struct ev_signal *w_sigint = &ptpr->w_sigint.watcher; struct ev_loop *loop = (struct ev_loop *)_loop; - struct lws_vhost *vh = context->vhost_list; const char *backend_name; unsigned int backend; int status = 0; @@ -162,26 +182,7 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) ptpr->io_loop = loop; - /* - * Initialize the accept w_accept with all the listening sockets - * and register a callback for read operations - */ - while (vh) { - if (vh->lserv_wsi) { - struct lws_wsi_eventlibs_libev *w = - wsi_to_priv_ev(vh->lserv_wsi); - - w->w_read.context = context; - w->w_write.context = context; - vh_to_priv_ev(vh)->w_accept.context = context; - - ev_io_init(&vh_to_priv_ev(vh)->w_accept.watcher, - lws_accept_cb, - vh->lserv_wsi->desc.sockfd, EV_READ); - ev_io_start(loop, &vh_to_priv_ev(vh)->w_accept.watcher); - } - vh = vh->vhost_next; - } + lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_ev); /* Register the signal watcher unless it's a foreign loop */ if (!context->pt[tsi].event_loop_foreign) { @@ -236,19 +237,27 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) return status; } +static int +elops_listen_destroy_ev(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + struct lws_context *context = (struct lws_context *)user; + struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; + struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt); + struct lws_vhost *vh = wsi->a.vhost; + + ev_io_stop(ptpr->io_loop, &vh_to_priv_ev(vh)->w_accept.watcher); + + return 0; +} + static void elops_destroy_pt_ev(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt); - struct lws_vhost *vh = context->vhost_list; - while (vh) { - if (vh->lserv_wsi) - ev_io_stop(ptpr->io_loop, - &vh_to_priv_ev(vh)->w_accept.watcher); - vh = vh->vhost_next; - } + lws_vhost_foreach_listen_wsi(context, context, elops_listen_destroy_ev); /* static assets */ diff --git a/lib/event-libs/libevent/libevent.c b/lib/event-libs/libevent/libevent.c index e9240a094..a4fe99dca 100644 --- a/lib/event-libs/libevent/libevent.c +++ b/lib/event-libs/libevent/libevent.c @@ -175,6 +175,25 @@ lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx) event_base_loopbreak(pt_to_priv_event(pt)->io_loop); } +static int +elops_listen_init_event(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + struct lws_context *context = (struct lws_context *)user; + struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; + struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt); + struct lws_io_watcher_libevent *w_read = + &(wsi_to_priv_event(wsi)->w_read); + + w_read->context = context; + w_read->watcher = event_new(ptpr->io_loop, wsi->desc.sockfd, + (EV_READ | EV_PERSIST), lws_event_cb, w_read); + event_add(w_read->watcher, NULL); + w_read->set = 1; + + return 0; +} + static int elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) { @@ -198,26 +217,7 @@ elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) ptpr->io_loop = loop; - /* - * Initialize all events with the listening sockets - * and register a callback for read operations - */ - - while (vh) { - if (vh->lserv_wsi) { - struct lws_io_watcher_libevent *w_read = - &(wsi_to_priv_event(vh->lserv_wsi)->w_read); - - w_read->context = context; - w_read->watcher = event_new( - loop, vh->lserv_wsi->desc.sockfd, - (EV_READ | EV_PERSIST), lws_event_cb, - w_read); - event_add(w_read->watcher, NULL); - w_read->set = 1; - } - vh = vh->vhost_next; - } + lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_event); /* static event loop objects */ @@ -334,6 +334,23 @@ elops_run_pt_event(struct lws_context *context, int tsi) pt_to_priv_event(&context->pt[tsi])->io_loop); } +static int +elops_listen_destroy_event(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + struct lws_context *context = (struct lws_context *)user; + struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; + struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt); + struct lws_wsi_eventlibs_libevent *w = wsi_to_priv_event(wsi); + + event_free(w->w_read.watcher); + w->w_read.watcher = NULL; + event_free(w->w_write.watcher); + w->w_write.watcher = NULL; + + return 0; +} + static void elops_destroy_pt_event(struct lws_context *context, int tsi) { @@ -346,21 +363,7 @@ elops_destroy_pt_event(struct lws_context *context, int tsi) if (!ptpr->io_loop) return; - /* - * Free all events with the listening sockets - */ - while (vh) { - if (vh->lserv_wsi) { - struct lws_wsi_eventlibs_libevent *w = - wsi_to_priv_event(vh->lserv_wsi); - - event_free(w->w_read.watcher); - w->w_read.watcher = NULL; - event_free(w->w_write.watcher); - w->w_write.watcher = NULL; - } - vh = vh->vhost_next; - } + lws_vhost_foreach_listen_wsi(context, context, elops_listen_destroy_event); event_free(ptpr->hrtimer); event_free(ptpr->idle_timer); diff --git a/lib/event-libs/libuv/libuv.c b/lib/event-libs/libuv/libuv.c index 7a5bc56b9..e6e4f3960 100644 --- a/lib/event-libs/libuv/libuv.c +++ b/lib/event-libs/libuv/libuv.c @@ -677,6 +677,17 @@ elops_destroy_pt_uv(struct lws_context *context, int tsi) uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->idle, lws_uv_close_cb_sa); } +static int +elops_listen_init_uv(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + + if (elops_init_vhost_listen_wsi_uv(wsi) == -1) + return -1; + + return 0; +} + /* * This needs to be called after vhosts have been defined. * @@ -689,7 +700,6 @@ elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt); - struct lws_vhost *vh = context->vhost_list; int status = 0, n, ns, first = 1; uv_loop_t *loop = (uv_loop_t *)_loop; @@ -745,11 +755,7 @@ elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi) * 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; - } + lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_uv); if (!first) return status; diff --git a/lib/event-libs/sdevent/sdevent.c b/lib/event-libs/sdevent/sdevent.c index a89395863..feae8db51 100644 --- a/lib/event-libs/sdevent/sdevent.c +++ b/lib/event-libs/sdevent/sdevent.c @@ -231,18 +231,28 @@ init_vhost_listen_wsi_sd(struct lws *wsi) return 0; } +static int +elops_listen_init_sdevent(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + + if (init_vhost_listen_wsi_sd(wsi) == -1) + return -1; + + return 0; +} + static int init_pt_sd(struct lws_context *context, void *_loop, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt); struct sd_event *loop = (struct sd_event *)_loop; - struct lws_vhost *vh; - int first = 1; // we are the first that create and initialize the loop + int first = 1; /* first to create and initialize the loop */ ptpriv->pt = pt; - // make sure we have an event loop + /* make sure we have an event loop */ if (!ptpriv->io_loop) { if (!loop) { if (sd_event_default(&loop) < 0) { @@ -257,7 +267,6 @@ init_pt_sd(struct lws_context *context, void *_loop, int tsi) } ptpriv->io_loop = loop; - } else /* * If the loop was initialized before, we do not need to @@ -265,12 +274,7 @@ init_pt_sd(struct lws_context *context, void *_loop, int tsi) */ first = 0; - // initialize accept/read for vhosts - // Note: default vhost usually not included here - for (vh = context->vhost_list; vh; vh = vh->vhost_next) - /* call lws_event_loop_ops->init_vhost_listen_wsi */ - if (init_vhost_listen_wsi_sd(vh->lserv_wsi) == -1) - return -1; + lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_sdevent); if (first) { @@ -361,16 +365,23 @@ run_pt_sd(struct lws_context *context, int tsi) sd_event_run(ptpriv->io_loop, (uint64_t) -1); } +static int +elops_listen_destroy_sdevent(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + + wsi_logical_close_sd(wsi); + + return 0; +} + static void destroy_pt_sd(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt); - struct lws_vhost *vh; - for (vh = context->vhost_list; vh; vh = vh->vhost_next) - if (vh->lserv_wsi) - wsi_logical_close_sd(vh->lserv_wsi); + lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_sdevent); if (ptpriv->sultimer) { sd_event_source_set_enabled(ptpriv->sultimer, @@ -390,7 +401,6 @@ destroy_pt_sd(struct lws_context *context, int tsi) sd_event_unref(ptpriv->io_loop); ptpriv->io_loop = NULL; } - } const struct lws_event_loop_ops event_loop_ops_sdevent = { diff --git a/lib/event-libs/uloop/uloop.c b/lib/event-libs/uloop/uloop.c index 00ed5373d..37e29398e 100644 --- a/lib/event-libs/uloop/uloop.c +++ b/lib/event-libs/uloop/uloop.c @@ -132,33 +132,30 @@ lws_uloop_cb(struct uloop_fd *ufd, unsigned int revents) uloop_timeout_set(&pt_to_priv_uloop(pt)->idle_timer, 1); } +static int +elops_listen_init_uloop(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi); + + wu->wsi = wsi; + wu->fd.fd = wsi->desc.sockfd; + wu->fd.cb = lws_uloop_cb; + uloop_fd_add(&wu->fd, ULOOP_READ); + wu->actual_events = ULOOP_READ; + + return 0; +} + static int elops_init_pt_uloop(struct lws_context *context, void *v, int tsi) { - struct lws_vhost *vh = context->vhost_list; struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_pt_eventlibs_uloop *ptpr = pt_to_priv_uloop(pt); ptpr->pt = pt; - /* - * Initialize all events with the listening sockets - * and register a callback for read operations - */ - - while (vh) { - if (vh->lserv_wsi) { - struct lws_wsi_eventlibs_uloop *wu = - wsi_to_priv_uloop(vh->lserv_wsi); - wu->wsi = vh->lserv_wsi; - wu->fd.fd = vh->lserv_wsi->desc.sockfd; - wu->fd.cb = lws_uloop_cb; - uloop_fd_add(&wu->fd, ULOOP_READ); - wu->actual_events = ULOOP_READ; - } - - vh = vh->vhost_next; - } + lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_uloop); /* static event loop objects */ @@ -217,20 +214,24 @@ elops_run_pt_uloop(struct lws_context *context, int tsi) uloop_run(); } +static int +elops_listen_destroy_uloop(struct lws_dll2 *d, void *user) +{ + struct lws *wsi = lws_container_of(d, struct lws, listen_list); + struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi); + + uloop_fd_delete(&wu->fd); + + return 0; +} + static void elops_destroy_pt_uloop(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; struct lws_pt_eventlibs_uloop *ptpr = pt_to_priv_uloop(pt); - struct lws_vhost *vh; - vh = context->vhost_list; - while (vh) { - if (vh->lserv_wsi) - uloop_fd_delete(&wsi_to_priv_uloop(vh->lserv_wsi)->fd); - - vh = vh->vhost_next; - } + lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_uloop); uloop_timeout_cancel(&ptpr->hrtimer); uloop_timeout_cancel(&ptpr->idle_timer); diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 265187ee3..9ddb108c1 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -80,18 +80,15 @@ _lws_vhost_init_server(const struct lws_context_creation_info *info, vhost->listen_port == CONTEXT_PORT_NO_LISTEN_SERVER) return 0; + + vh = vhost->context->vhost_list; while (vh) { - if (vh->listen_port == vhost->listen_port) { - if (((!vhost->iface && !vh->iface) || - (vhost->iface && vh->iface && - !strcmp(vhost->iface, vh->iface))) && - vh->lserv_wsi - ) { - lwsl_notice(" using listen skt from vhost %s\n", - vh->name); - return 0; - } + if (vh->listen_wsi.count && + lws_vhost_compare_listen(vhost, vh)) { + lwsl_notice(" using listen skt from vhost %s\n", + vh->name); + return 0; } vh = vh->vhost_next; } @@ -346,7 +343,7 @@ done_list: goto bail; } - vhost->lserv_wsi = wsi; + lws_dll2_add_tail(&wsi->listen_list, &vhost->listen_wsi); lws_pt_unlock(pt); #if defined(WIN32) && defined(TCP_FASTOPEN) @@ -375,7 +372,7 @@ done_list: n = listen(wsi->desc.sockfd, LWS_SOMAXCONN); if (n < 0) { lwsl_err("listen failed with error %d\n", LWS_ERRNO); - vhost->lserv_wsi = NULL; + lws_dll2_remove(&wsi->listen_list); __remove_wsi_socket_from_fds(wsi); goto bail; } diff --git a/lib/tls/tls-network.c b/lib/tls/tls-network.c index c90faa78e..644ed7e9d 100644 --- a/lib/tls/tls-network.c +++ b/lib/tls/tls-network.c @@ -205,10 +205,17 @@ lws_gate_accepts(struct lws_context *context, int on) lwsl_notice("%s: on = %d\n", __func__, on); while (v) { - if (v->tls.use_ssl && v->lserv_wsi && - lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on, - (LWS_POLLIN) * on)) - lwsl_notice("Unable to set accept POLLIN %d\n", on); + lws_start_foreach_dll(struct lws_dll2 *, d, + lws_dll2_get_head(&v->listen_wsi)) { + struct lws *wsi = lws_container_of(d, struct lws, + listen_list); + + if (v->tls.use_ssl && + lws_change_pollfd(wsi, on ? 0 : LWS_POLLIN, + on ? LWS_POLLIN : 0)) + lwsl_notice("%s: Unable to set POLLIN %d\n", + __func__, on); + } lws_end_foreach_dll(d); v = v->vhost_next; }