{
#ifdef LWS_WITH_CGI
struct lws_cgi_args *args;
- char buf[128];
+#endif
+#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
+ char buf[512];
int n;
#endif
+
switch (reason) {
case LWS_CALLBACK_HTTP:
#ifndef LWS_NO_SERVER
#endif
return -1;
break;
+#if !defined(LWS_NO_SERVER)
+ case LWS_CALLBACK_HTTP_FILE_COMPLETION:
+ if (lws_http_transaction_completed(wsi))
+ return -1;
+ break;
+#endif
case LWS_CALLBACK_HTTP_WRITEABLE:
#ifdef LWS_WITH_CGI
if (lws_cgi_write_split_stdout_headers(wsi) < 0)
return -1;
- wsi->reason_bf &= ~1;
+ if (wsi->reason_bf & 8)
+ wsi->reason_bf &= ~8;
+ else
+ wsi->reason_bf &= ~1;
break;
}
#endif
+#if defined(LWS_WITH_HTTP_PROXY)
+ if (wsi->reason_bf & 2) {
+ char *px = buf + LWS_PRE;
+ int lenx = sizeof(buf) - LWS_PRE;
+ /*
+ * our sink is writeable and our source has something
+ * to read. So read a lump of source material of
+ * suitable size to send or what's available, whichever
+ * is the smaller.
+ */
+
+ wsi->reason_bf &= ~2;
+ if (!lws_get_child(wsi))
+ break;
+ if (lws_http_client_read(lws_get_child(wsi), &px, &lenx) < 0)
+ return -1;
+ break;
+ }
+#endif
break;
+#if defined(LWS_WITH_HTTP_PROXY)
+ case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
+ //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p\n", wsi);
+ assert(lws_get_parent(wsi));
+ if (!lws_get_parent(wsi))
+ break;
+ lws_get_parent(wsi)->reason_bf |= 2;
+ lws_callback_on_writable(lws_get_parent(wsi));
+ break;
+
+ case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
+ //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", (int)len);
+ assert(lws_get_parent(wsi));
+ n = lws_write(lws_get_parent(wsi), (unsigned char *)in,
+ len, LWS_WRITE_HTTP);
+ if (n < 0)
+ return -1;
+ break;
+
+ case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
+ unsigned char *p, *end;
+ char ctype[64], ctlen = 0;
+
+ //lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n");
+
+ p = (unsigned char *)buf + LWS_PRE;
+ end = p + sizeof(buf) - LWS_PRE;
+
+ if (lws_add_http_header_status(lws_get_parent(wsi), HTTP_STATUS_OK, &p, end))
+ return 1;
+ if (lws_add_http_header_by_token(lws_get_parent(wsi),
+ WSI_TOKEN_HTTP_SERVER,
+ (unsigned char *)"libwebsockets",
+ 13, &p, end))
+ return 1;
+
+ ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype), WSI_TOKEN_HTTP_CONTENT_TYPE);
+ if (ctlen > 0) {
+ if (lws_add_http_header_by_token(lws_get_parent(wsi),
+ WSI_TOKEN_HTTP_CONTENT_TYPE,
+ (unsigned char *)ctype, ctlen, &p, end))
+ return 1;
+ }
+#if 0
+ if (lws_add_http_header_content_length(lws_get_parent(wsi),
+ file_len, &p, end))
+ return 1;
+#endif
+ if (lws_finalize_http_header(lws_get_parent(wsi), &p, end))
+ return 1;
+
+ *p = '\0';
+// lwsl_info("%s\n", buf + LWS_PRE);
+
+ n = lws_write(lws_get_parent(wsi), (unsigned char *)buf + LWS_PRE,
+ p - ((unsigned char *)buf + LWS_PRE),
+ LWS_WRITE_HTTP_HEADERS);
+ if (n < 0)
+ return -1;
+
+ break; }
+
+#endif
+
#ifdef LWS_WITH_CGI
/* CGI IO events (POLLIN/OUT) appear here, our default policy is:
*
"sent %d only %d went", n, args->len);
return n;
#endif
+
+ case LWS_CALLBACK_SSL_INFO:
+ {
+ struct lws_ssl_info *si = in;
+
+ (void)si;
+ lwsl_notice("LWS_CALLBACK_SSL_INFO: where: 0x%x, ret: 0x%x\n",
+ si->where, si->ret);
+ }
+ break;
+
default:
break;
}
lws_callback_http_dummy, /* callback */
0, /* per_session_data_size */
0, /* max frame size / rx buffer */
- 0, NULL
+ 0, NULL, 0
},
/*
* the other protocols are provided by lws plugins
*/
- { NULL, NULL, 0, 0, 0, NULL} /* terminator */
+ { NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */
};
#ifdef LWS_PLAT_OPTEE
vh->name = info->vhost_name;
vh->iface = info->iface;
+#if !defined(LWS_WITH_ESP8266) && !defined(LWS_WITH_ESP32) && !defined(OPTEE_TA) && !defined(WIN32)
+ vh->bind_iface = info->bind_iface;
+#endif
+
for (vh->count_protocols = 0;
info->protocols[vh->count_protocols].callback;
vh->count_protocols++)
vh->options = info->options;
vh->pvo = info->pvo;
vh->headers = info->headers;
+ vh->ssl_info_event_mask = info->ssl_info_event_mask;
if (info->keepalive_timeout)
vh->keepalive_timeout = info->keepalive_timeout;
else
vh->keepalive_timeout = 5;
+ if (info->timeout_secs_ah_idle)
+ vh->timeout_secs_ah_idle = info->timeout_secs_ah_idle;
+ else
+ vh->timeout_secs_ah_idle = 10;
+
/*
* give the vhost a unified list of protocols including the
* ones that came from plugins
* for a protocol get it enabled.
*/
- if (info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
+ if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
f = 0;
(void)f;
#ifdef LWS_WITH_PLUGINS
#ifdef LWS_WITH_PLUGINS
(context->plugin_list) ||
#endif
- info->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
+ context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
vh->protocols = lwsp;
else {
vh->protocols = info->protocols;
- free(lwsp);
+ lws_free(lwsp);
}
vh->same_vh_protocol_list = (struct lws **)
mounts = info->mounts;
while (mounts) {
+ (void)mount_protocols[0];
lwsl_notice(" mounting %s%s to %s\n",
mount_protocols[mounts->origin_protocol],
mounts->origin, mounts->mountpoint);
for (n = 0; n < vh->count_protocols; n++)
if (!strcmp(pvo->value, vh->protocols[n].name)) {
((struct lws_protocol_vhost_options *)pvo)->value =
- (const char *)(long)n;
+ (const char *)(lws_intptr_t)n;
break;
}
if (n == vh->count_protocols)
#if !defined(LWS_WITH_ESP8266)
vh->http_proxy_port = 0;
vh->http_proxy_address[0] = '\0';
+#if defined(LWS_WITH_SOCKS5)
+ vh->socks_proxy_port = 0;
+ vh->socks_proxy_address[0] = '\0';
+#endif
/* either use proxy from info, or try get it from env var */
+ /* http proxy */
if (info->http_proxy_address) {
/* override for backwards compatibility */
if (info->http_proxy_port)
lws_set_proxy(vh, p);
#endif
}
+#if defined(LWS_WITH_SOCKS5)
+ /* socks proxy */
+ if (info->socks_proxy_address) {
+ /* override for backwards compatibility */
+ if (info->socks_proxy_port)
+ vh->socks_proxy_port = info->socks_proxy_port;
+ lws_set_socks(vh, info->socks_proxy_address);
+ } else {
+#ifdef LWS_HAVE_GETENV
+ p = getenv("socks_proxy");
+ if (p)
+ lws_set_socks(vh, p);
+#endif
+ }
+#endif
#endif
+
vh->ka_time = info->ka_time;
vh->ka_interval = info->ka_interval;
vh->ka_probes = info->ka_probes;
lwsl_info(" LWS_MAX_SMP : %u\n", LWS_MAX_SMP);
lwsl_info(" SPEC_LATEST_SUPPORTED : %u\n", SPEC_LATEST_SUPPORTED);
lwsl_info(" sizeof (*info) : %ld\n", (long)sizeof(*info));
+#if defined(LWS_WITH_STATS)
+ lwsl_notice(" LWS_WITH_STATS : on\n");
+#endif
#if LWS_POSIX
lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
#endif
/* default to just the platform fops implementation */
- context->fops_platform.open = _lws_plat_file_open;
- context->fops_platform.close = _lws_plat_file_close;
- context->fops_platform.seek_cur = _lws_plat_file_seek_cur;
- context->fops_platform.read = _lws_plat_file_read;
- context->fops_platform.write = _lws_plat_file_write;
+ context->fops_platform.LWS_FOP_OPEN = _lws_plat_file_open;
+ context->fops_platform.LWS_FOP_CLOSE = _lws_plat_file_close;
+ context->fops_platform.LWS_FOP_SEEK_CUR = _lws_plat_file_seek_cur;
+ context->fops_platform.LWS_FOP_READ = _lws_plat_file_read;
+ context->fops_platform.LWS_FOP_WRITE = _lws_plat_file_write;
context->fops_platform.fi[0].sig = NULL;
/*
context->time_up = time(NULL);
+ context->simultaneous_ssl_restriction = info->simultaneous_ssl_restriction;
+
#ifndef LWS_NO_DAEMONIZE
if (pid_daemon) {
context->started_with_parent = pid_daemon;
context->use_ev_sigint = 1;
context->lws_uv_sigint_cb = &lws_uv_sigint_cb;
#endif
+#ifdef LWS_USE_LIBEVENT
+ /* (Issue #264) In order to *avoid breaking backwards compatibility*, we
+ * enable libev mediated SIGINT handling with a default handler of
+ * lws_sigint_cb. The handler can be overridden or disabled
+ * by invoking lws_sigint_cfg after creating the context, but
+ * before invoking lws_initloop:
+ */
+ context->use_ev_sigint = 1;
+ context->lws_event_sigint_cb = &lws_event_sigint_cb;
+#endif /* LWS_USE_LIBEVENT */
lwsl_info(" mem: context: %5lu bytes (%ld ctx + (%ld thr x %d))\n",
(long)sizeof(struct lws_context) +
context->server_string = info->server_string;
context->server_string_len = (short)
strlen(context->server_string);
- } else {
- context->server_string = "libwebsockets";
- context->server_string_len = 13;
}
#if LWS_MAX_SMP > 1
context->uid = info->uid;
context->gid = info->gid;
+#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
+ memcpy(context->caps, info->caps, sizeof(context->caps));
+ context->count_caps = info->count_caps;
+#endif
+
/*
* drop any root privs for this process
* to listen on port < 1023 we would have needed root, but now we are
LWS_VISIBLE void
lws_context_destroy2(struct lws_context *context);
+
+static void
+lws_vhost_destroy1(struct lws_vhost *vh)
+{
+ const struct lws_protocols *protocol = NULL;
+ struct lws_context_per_thread *pt;
+ int n, m = vh->context->count_threads;
+ struct lws_context *context = vh->context;
+ struct lws wsi;
+
+ lwsl_notice("%s\n", __func__);
+
+ if (vh->being_destroyed)
+ return;
+
+ vh->being_destroyed = 1;
+
+ /*
+ * 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
+ * so it will remain open. If not, leave it attached to the closing
+ * vhost and it will get closed.
+ */
+
+ if (vh->lserv_wsi)
+ 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)))) {
+ /*
+ * this can only be a listen wsi, which is
+ * restricted... it has no protocol or other
+ * bindings or states. So we can simply
+ * swap it to a vhost that has the same
+ * iface + port, but is not closing.
+ */
+ assert(v->lserv_wsi == NULL);
+ v->lserv_wsi = vh->lserv_wsi;
+ vh->lserv_wsi = NULL;
+ v->lserv_wsi->vhost = v;
+
+ lwsl_notice("%s: listen skt from %s to %s\n",
+ __func__, vh->name, v->name);
+ break;
+ }
+ } lws_end_foreach_ll(v, vhost_next);
+
+ /*
+ * Forcibly close every wsi assoicated with this vhost. That will
+ * include the listen socket if it is still associated with the closing
+ * vhost.
+ */
+
+ 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;
+ if (wsi->vhost != vh)
+ continue;
+
+ lws_close_free_wsi(wsi,
+ LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
+ /* no protocol close */);
+ n--;
+ }
+ }
+
+ /*
+ * let the protocols destroy the per-vhost protocol objects
+ */
+
+ memset(&wsi, 0, sizeof(wsi));
+ wsi.context = vh->context;
+ wsi.vhost = vh;
+ protocol = vh->protocols;
+ if (protocol) {
+ n = 0;
+ while (n < vh->count_protocols) {
+ wsi.protocol = protocol;
+ protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
+ NULL, NULL, 0);
+ protocol++;
+ n++;
+ }
+ }
+
+ /*
+ * remove vhost from context list of vhosts
+ */
+
+ lws_start_foreach_llp(struct lws_vhost **, pv, context->vhost_list) {
+ if (*pv == vh) {
+ *pv = vh->vhost_next;
+ break;
+ }
+ } lws_end_foreach_llp(pv, vhost_next);
+
+ /* add ourselves to the pending destruction list */
+
+ vh->vhost_next = vh->context->vhost_pending_destruction_list;
+ vh->context->vhost_pending_destruction_list = vh;
+}
+
+static void
+lws_vhost_destroy2(struct lws_vhost *vh)
+{
+ const struct lws_protocols *protocol = NULL;
+ struct lws_context *context = vh->context;
+ struct lws_deferred_free *df;
+ int n;
+
+ lwsl_notice("%s: %p\n", __func__, vh);
+
+ /* if we are still on deferred free list, remove ourselves */
+
+ lws_start_foreach_llp(struct lws_deferred_free **, pdf, context->deferred_free_list) {
+ if ((*pdf)->payload == vh) {
+ df = *pdf;
+ *pdf = df->next;
+ lws_free(df);
+ break;
+ }
+ } lws_end_foreach_llp(pdf, next);
+
+ /* remove ourselves from the pending destruction list */
+
+ lws_start_foreach_llp(struct lws_vhost **, pv, context->vhost_pending_destruction_list) {
+ if ((*pv) == vh) {
+ *pv = (*pv)->vhost_next;
+ break;
+ }
+ } lws_end_foreach_llp(pv, vhost_next);
+
+ /*
+ * Free all the allocations associated with the vhost
+ */
+
+ protocol = vh->protocols;
+ if (protocol) {
+ n = 0;
+ while (n < vh->count_protocols) {
+ if (vh->protocol_vh_privs &&
+ vh->protocol_vh_privs[n]) {
+ lws_free(vh->protocol_vh_privs[n]);
+ vh->protocol_vh_privs[n] = NULL;
+ }
+ protocol++;
+ n++;
+ }
+ }
+ if (vh->protocol_vh_privs)
+ 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);
+ }
+
+#ifdef LWS_WITH_PLUGINS
+#ifndef LWS_NO_EXTENSIONS
+ if (context->plugin_extension_count)
+ lws_free((void *)vh->extensions);
+#endif
+#endif
+#ifdef LWS_WITH_ACCESS_LOG
+ if (vh->log_fd != (int)LWS_INVALID_FILE)
+ close(vh->log_fd);
+#endif
+
+ /*
+ * although async event callbacks may still come for wsi handles with
+ * pending close in the case of asycn event library like libuv,
+ * they do not refer to the vhost. So it's safe to free.
+ */
+
+ lwsl_notice(" %s: Freeing vhost %p\n", __func__, vh);
+
+ memset(vh, 0, sizeof(*vh));
+ free(vh);
+}
+
+int
+lws_check_deferred_free(struct lws_context *context, int force)
+{
+ struct lws_deferred_free *df;
+ time_t now = lws_now_secs();
+
+ lws_start_foreach_llp(struct lws_deferred_free **, pdf, context->deferred_free_list) {
+ if (now > (*pdf)->deadline || force) {
+ df = *pdf;
+ *pdf = df->next;
+ /* finalize vh destruction */
+ lwsl_notice("doing deferred vh %p destroy\n", df->payload);
+ lws_vhost_destroy2(df->payload);
+ lws_free(df);
+ continue; /* after deletion we already point to next */
+ }
+ } lws_end_foreach_llp(pdf, next);
+
+ return 0;
+}
+
+LWS_VISIBLE void
+lws_vhost_destroy(struct lws_vhost *vh)
+{
+ struct lws_deferred_free *df = malloc(sizeof(*df));
+
+ if (!df)
+ return;
+
+ lws_vhost_destroy1(vh);
+
+ /* part 2 is deferred to allow all the handle closes to complete */
+
+ df->next = vh->context->deferred_free_list;
+ df->deadline = lws_now_secs() + 5;
+ df->payload = vh;
+ vh->context->deferred_free_list = df;
+}
+
LWS_VISIBLE void
lws_context_destroy(struct lws_context *context)
{
- const struct lws_protocols *protocol = NULL;
struct lws_context_per_thread *pt;
struct lws_vhost *vh = NULL;
struct lws wsi;
if (context->protocol_init_done)
vh = context->vhost_list;
while (vh) {
- wsi.vhost = vh;
- protocol = vh->protocols;
- if (protocol) {
- n = 0;
- while (n < vh->count_protocols) {
- wsi.protocol = protocol;
- protocol->callback(&wsi, LWS_CALLBACK_PROTOCOL_DESTROY,
- NULL, NULL, 0);
- protocol++;
- n++;
- }
- }
-
+ lws_vhost_destroy1(vh);
vh = vh->vhost_next;
}
lws_libev_destroyloop(context, n);
lws_libuv_destroyloop(context, n);
+ lws_libevent_destroyloop(context, n);
lws_free_set_NULL(context->pt[n].serv_buf);
if (pt->ah_pool)
LWS_VISIBLE void
lws_context_destroy2(struct lws_context *context)
{
- const struct lws_protocols *protocol = NULL;
struct lws_vhost *vh = NULL, *vh1;
- int n;
lwsl_notice("%s: ctx %p\n", __func__, context);
vh = context->vhost_list;
while (vh) {
- protocol = vh->protocols;
- if (protocol) {
- n = 0;
- while (n < vh->count_protocols) {
- if (vh->protocol_vh_privs &&
- vh->protocol_vh_privs[n]) {
- // lwsl_notice(" %s: freeing per-vhost protocol data %p\n", __func__, vh->protocol_vh_privs[n]);
- lws_free(vh->protocol_vh_privs[n]);
- vh->protocol_vh_privs[n] = NULL;
- }
- protocol++;
- n++;
- }
- }
- if (vh->protocol_vh_privs)
- lws_free(vh->protocol_vh_privs);
- lws_ssl_SSL_CTX_destroy(vh);
- lws_free(vh->same_vh_protocol_list);
-#ifdef LWS_WITH_PLUGINS
- if (context->plugin_list)
- lws_free((void *)vh->protocols);
-#else
- if (vh->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
- lws_free((void *)vh->protocols);
-#endif
-#ifdef LWS_WITH_PLUGINS
-#ifndef LWS_NO_EXTENSIONS
- if (context->plugin_extension_count)
- lws_free((void *)vh->extensions);
-#endif
-#endif
-#ifdef LWS_WITH_ACCESS_LOG
- if (vh->log_fd != (int)LWS_INVALID_FILE)
- close(vh->log_fd);
-#endif
-
vh1 = vh->vhost_next;
- lws_free(vh);
+ 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 (context->external_baggage_free_on_destroy)
free(context->external_baggage_free_on_destroy);
+ lws_check_deferred_free(context, 1);
lws_free(context);
}