diff --git a/lib/context.c b/lib/context.c index 17615fb5..88e7fe45 100644 --- a/lib/context.c +++ b/lib/context.c @@ -122,6 +122,10 @@ lws_vhost_protocol_options(struct lws_vhost *vh, const char *name) return NULL; } +/* + * inform every vhost that hasn't already done it, that + * his protocols are initializing + */ int lws_protocol_init(struct lws_context *context) { @@ -138,6 +142,10 @@ lws_protocol_init(struct lws_context *context) while (vh) { wsi.vhost = vh; + /* only do the protocol init once for a given vhost */ + if (vh->created_vhost_protocols) + goto next; + /* initialize supported protocols on this vhost */ for (n = 0; n < vh->count_protocols; n++) { @@ -185,11 +193,15 @@ lws_protocol_init(struct lws_context *context) return 1; } + vh->created_vhost_protocols = 1; +next: vh = vh->vhost_next; } + if (!context->protocol_init_done) + lws_finalize_startup(context); + context->protocol_init_done = 1; - lws_finalize_startup(context); return 0; } @@ -520,6 +532,11 @@ lws_create_vhost(struct lws_context *context, vh1 = &(*vh1)->vhost_next; }; + /* for the case we are adding a vhost much later, after server init */ + + if (context->protocol_init_done) + lws_protocol_init(context); + return vh; bail: diff --git a/lib/libuv.c b/lib/libuv.c index 742ca87a..4e80936b 100644 --- a/lib/libuv.c +++ b/lib/libuv.c @@ -143,47 +143,91 @@ lws_uv_timeout_cb(uv_timer_t *timer static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE }; +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->io_loop_uv) + return 0; + + wsi->w_read.context = vh->context; + n = uv_poll_init_socket(pt->io_loop_uv, + &wsi->w_read.uv_watcher, wsi->sock); + if (n) { + lwsl_err("uv_poll_init failed %d, sockfd=%p\n", + n, (void *)(long)wsi->sock); + + 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; + int status = 0, n, ns, first = 1; - if (!loop) { - loop = lws_malloc(sizeof(*loop)); + if (!pt->io_loop_uv) { if (!loop) { - lwsl_err("OOM\n"); - return -1; + loop = lws_malloc(sizeof(*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->ev_loop_foreign = 0; + } else { + lwsl_notice(" Using foreign event loop...\n"); + pt->ev_loop_foreign = 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->ev_loop_foreign = 0; - } else { - lwsl_notice(" Using foreign event loop...\n"); - pt->ev_loop_foreign = 1; - } - pt->io_loop_uv = loop; - uv_idle_init(loop, &pt->uv_idle); + pt->io_loop_uv = loop; + uv_idle_init(loop, &pt->uv_idle); - ns = ARRAY_SIZE(sigs); - if (lws_check_opt(context->options, LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN)) - ns = 2; + ns = ARRAY_SIZE(sigs); + if (lws_check_opt(context->options, + LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN)) + ns = 2; - if (pt->context->use_ev_sigint) { - assert(ns <= ARRAY_SIZE(pt->signals)); - for (n = 0; n < ns; n++) { - uv_signal_init(loop, &pt->signals[n]); - pt->signals[n].data = pt->context; - uv_signal_start(&pt->signals[n], - context->lws_uv_sigint_cb, sigs[n]); + if (pt->context->use_ev_sigint) { + assert(ns <= ARRAY_SIZE(pt->signals)); + for (n = 0; n < ns; n++) { + uv_signal_init(loop, &pt->signals[n]); + pt->signals[n].data = pt->context; + uv_signal_start(&pt->signals[n], + context->lws_uv_sigint_cb, sigs[n]); + } } - } + } else + first = 0; /* * Initialize the accept wsi read watcher with all the listening sockets @@ -193,24 +237,16 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi) * initialized until after context creation. */ while (vh) { - if (vh->lserv_wsi) { - vh->lserv_wsi->w_read.context = context; - n = uv_poll_init_socket(pt->io_loop_uv, - &vh->lserv_wsi->w_read.uv_watcher, - vh->lserv_wsi->sock); - if (n) { - lwsl_err("uv_poll_init failed %d, sockfd=%p\n", - n, (void *)(long)vh->lserv_wsi->sock); - - return -1; - } - lws_libuv_io(vh->lserv_wsi, LWS_EV_START | LWS_EV_READ); - } + if (lws_uv_initvhost(vh, vh->lserv_wsi) == -1) + return -1; vh = vh->vhost_next; } - uv_timer_init(pt->io_loop_uv, &pt->uv_timeout_watcher); - uv_timer_start(&pt->uv_timeout_watcher, lws_uv_timeout_cb, 10, 1000); + if (first) { + uv_timer_init(pt->io_loop_uv, &pt->uv_timeout_watcher); + uv_timer_start(&pt->uv_timeout_watcher, lws_uv_timeout_cb, + 10, 1000); + } return status; } diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 6162d55e..6a3ad8cb 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -800,6 +800,8 @@ struct lws_vhost { unsigned int user_supplied_ssl_ctx:1; #endif + unsigned int created_vhost_protocols:1; + unsigned char default_protocol_index; }; @@ -965,6 +967,8 @@ 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(struct lws_context_creation_info *info); #else diff --git a/lib/server.c b/lib/server.c index f7e6fb42..d4a9d16e 100644 --- a/lib/server.c +++ b/lib/server.c @@ -153,6 +153,12 @@ lws_context_init_server(struct lws_context_creation_info *info, wsi->listener = 1; vhost->context->pt[m].wsi_listening = wsi; + +#ifdef LWS_USE_LIBUV + if (LWS_LIBUV_ENABLED(vhost->context)) + lws_uv_initvhost(vhost, wsi); +#endif + if (insert_wsi_socket_into_fds(vhost->context, wsi)) goto bail;