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:
parent
fded366ea0
commit
6e436dca39
4 changed files with 108 additions and 45 deletions
|
@ -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:
|
||||
|
|
124
lib/libuv.c
124
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue