1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

vhost: allow adding vhosts after server init

This should allow adding vhosts "late", ie, after the server is up and
running with its initial vhost(s).  The necessary housekeeping is folded
into lws_create_vhost() itself so it should be transparent.

Notice though that at the point the server starts to do service after it
starts initially, if it was requested that the UID / GID change, that
is performed at that point and is not reversible.

So vhosts added "late" find themselves running under the unprivileged
UID / GID from the very start, whereas vhosts added "early" initially
run under the UID / GID the process started with.  If protocols the
vhost uses want to, eg, open privileged files at init and then use
them unprivileged, that will fail if the vhost is added late because
the initial privs are already gone.

AG: also deal with lws_protocol_init() on late vhost init (does the
callbacks for per vh protocol creation), add comments
This commit is contained in:
Bablooos 2016-11-30 07:05:13 +08:00 committed by Andy Green
parent fded366ea0
commit 6e436dca39
4 changed files with 108 additions and 45 deletions

View file

@ -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:

View file

@ -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;
}

View file

@ -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

View file

@ -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;