summaryrefslogtreecommitdiff
path: root/thirdparty/libwebsockets/lib/core
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/libwebsockets/lib/core')
-rw-r--r--thirdparty/libwebsockets/lib/core/adopt.c414
-rw-r--r--thirdparty/libwebsockets/lib/core/alloc.c92
-rw-r--r--thirdparty/libwebsockets/lib/core/connect.c287
-rw-r--r--thirdparty/libwebsockets/lib/core/context.c1865
-rw-r--r--thirdparty/libwebsockets/lib/core/dummy-callback.c611
-rw-r--r--thirdparty/libwebsockets/lib/core/libwebsockets.c3986
-rw-r--r--thirdparty/libwebsockets/lib/core/output.c323
-rw-r--r--thirdparty/libwebsockets/lib/core/pollfd.c566
-rw-r--r--thirdparty/libwebsockets/lib/core/private.h1573
-rw-r--r--thirdparty/libwebsockets/lib/core/service.c1114
10 files changed, 0 insertions, 10831 deletions
diff --git a/thirdparty/libwebsockets/lib/core/adopt.c b/thirdparty/libwebsockets/lib/core/adopt.c
deleted file mode 100644
index 49ac5af161..0000000000
--- a/thirdparty/libwebsockets/lib/core/adopt.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-
-#include "core/private.h"
-
-
-static int
-lws_get_idlest_tsi(struct lws_context *context)
-{
- unsigned int lowest = ~0;
- int n = 0, hit = -1;
-
- for (; n < context->count_threads; n++) {
- if ((unsigned int)context->pt[n].fds_count !=
- context->fd_limit_per_thread - 1 &&
- (unsigned int)context->pt[n].fds_count < lowest) {
- lowest = context->pt[n].fds_count;
- hit = n;
- }
- }
-
- return hit;
-}
-
-struct lws *
-lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi)
-{
- struct lws *new_wsi;
- int n = fixed_tsi;
-
- if (n < 0)
- n = lws_get_idlest_tsi(vhost->context);
-
- if (n < 0) {
- lwsl_err("no space for new conn\n");
- return NULL;
- }
-
- new_wsi = lws_zalloc(sizeof(struct lws), "new server wsi");
- if (new_wsi == NULL) {
- lwsl_err("Out of memory for new connection\n");
- return NULL;
- }
-
- new_wsi->tsi = n;
- lwsl_debug("new wsi %p joining vhost %s, tsi %d\n", new_wsi,
- vhost->name, new_wsi->tsi);
-
- lws_vhost_bind_wsi(vhost, new_wsi);
- new_wsi->context = vhost->context;
- new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
- new_wsi->rxflow_change_to = LWS_RXFLOW_ALLOW;
-
- /* initialize the instance struct */
-
- lwsi_set_state(new_wsi, LRS_UNCONNECTED);
- new_wsi->hdr_parsing_completed = 0;
-
-#ifdef LWS_WITH_TLS
- new_wsi->tls.use_ssl = LWS_SSL_ENABLED(vhost);
-#endif
-
- /*
- * these can only be set once the protocol is known
- * we set an un-established connection's protocol pointer
- * to the start of the supported list, so it can look
- * for matching ones during the handshake
- */
- new_wsi->protocol = vhost->protocols;
- new_wsi->user_space = NULL;
- new_wsi->desc.sockfd = LWS_SOCK_INVALID;
- new_wsi->position_in_fds_table = LWS_NO_FDS_POS;
-
- vhost->context->count_wsi_allocated++;
-
- /*
- * outermost create notification for wsi
- * no user_space because no protocol selection
- */
- vhost->protocols[0].callback(new_wsi, LWS_CALLBACK_WSI_CREATE, NULL,
- NULL, 0);
-
- return new_wsi;
-}
-
-
-/* if not a socket, it's a raw, non-ssl file descriptor */
-
-LWS_VISIBLE struct lws *
-lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
- lws_sock_file_fd_type fd, const char *vh_prot_name,
- struct lws *parent)
-{
- struct lws_context *context = vh->context;
- struct lws *new_wsi;
- struct lws_context_per_thread *pt;
- int n;
-
-#if defined(LWS_WITH_PEER_LIMITS)
- struct lws_peer *peer = NULL;
-
- if (type & LWS_ADOPT_SOCKET) {
- peer = lws_get_or_create_peer(vh, fd.sockfd);
-
- if (peer && context->ip_limit_wsi &&
- peer->count_wsi >= context->ip_limit_wsi) {
- lwsl_notice("Peer reached wsi limit %d\n",
- context->ip_limit_wsi);
- lws_stats_atomic_bump(context, &context->pt[0],
- LWSSTATS_C_PEER_LIMIT_WSI_DENIED,
- 1);
- return NULL;
- }
- }
-#endif
-
- n = -1;
- if (parent)
- n = parent->tsi;
- new_wsi = lws_create_new_server_wsi(vh, n);
- if (!new_wsi) {
- if (type & LWS_ADOPT_SOCKET)
- compatible_close(fd.sockfd);
- return NULL;
- }
-#if defined(LWS_WITH_PEER_LIMITS)
- if (peer)
- lws_peer_add_wsi(context, peer, new_wsi);
-#endif
- pt = &context->pt[(int)new_wsi->tsi];
- lws_stats_atomic_bump(context, pt, LWSSTATS_C_CONNECTIONS, 1);
-
- if (parent) {
- new_wsi->parent = parent;
- new_wsi->sibling_list = parent->child_list;
- parent->child_list = new_wsi;
- }
-
- new_wsi->desc = fd;
-
- if (vh_prot_name) {
- new_wsi->protocol = lws_vhost_name_to_protocol(new_wsi->vhost,
- vh_prot_name);
- if (!new_wsi->protocol) {
- lwsl_err("Protocol %s not enabled on vhost %s\n",
- vh_prot_name, new_wsi->vhost->name);
- goto bail;
- }
- if (lws_ensure_user_space(new_wsi)) {
- lwsl_notice("OOM trying to get user_space\n");
- goto bail;
- }
- }
-
- if (!LWS_SSL_ENABLED(new_wsi->vhost) || !(type & LWS_ADOPT_SOCKET))
- type &= ~LWS_ADOPT_ALLOW_SSL;
-
- if (lws_role_call_adoption_bind(new_wsi, type, vh_prot_name)) {
- lwsl_err("Unable to find a role that can adopt descriptor\n");
- goto bail;
- }
-
- /*
- * A new connection was accepted. Give the user a chance to
- * set properties of the newly created wsi. There's no protocol
- * selected yet so we issue this to the vhosts's default protocol,
- * itself by default protocols[0]
- */
- n = LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED;
- if (!(type & LWS_ADOPT_HTTP)) {
- if (!(type & LWS_ADOPT_SOCKET))
- n = LWS_CALLBACK_RAW_ADOPT_FILE;
- else
- n = LWS_CALLBACK_RAW_ADOPT;
- }
-
- lwsl_debug("new wsi wsistate 0x%x\n", new_wsi->wsistate);
-
- if (context->event_loop_ops->accept)
- if (context->event_loop_ops->accept(new_wsi))
- goto fail;
-
- if (!(type & LWS_ADOPT_ALLOW_SSL)) {
- lws_pt_lock(pt, __func__);
- if (__insert_wsi_socket_into_fds(context, new_wsi)) {
- lws_pt_unlock(pt);
- lwsl_err("%s: fail inserting socket\n", __func__);
- goto fail;
- }
- lws_pt_unlock(pt);
- } else
- if (lws_server_socket_service_ssl(new_wsi, fd.sockfd)) {
- lwsl_info("%s: fail ssl negotiation\n", __func__);
- goto fail;
- }
-
- /*
- * by deferring callback to this point, after insertion to fds,
- * lws_callback_on_writable() can work from the callback
- */
- if ((new_wsi->protocol->callback)(new_wsi, n, new_wsi->user_space,
- NULL, 0))
- goto fail;
-
- /* role may need to do something after all adoption completed */
-
- lws_role_call_adoption_bind(new_wsi, type | _LWS_ADOPT_FINISH,
- vh_prot_name);
-
- lws_cancel_service_pt(new_wsi);
-
- return new_wsi;
-
-fail:
- if (type & LWS_ADOPT_SOCKET)
- lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS,
- "adopt skt fail");
-
- return NULL;
-
-bail:
- lwsl_notice("%s: exiting on bail\n", __func__);
- if (parent)
- parent->child_list = new_wsi->sibling_list;
- if (new_wsi->user_space)
- lws_free(new_wsi->user_space);
-
- vh->context->count_wsi_allocated--;
-
- lws_vhost_unbind_wsi(new_wsi);
- lws_free(new_wsi);
-
- compatible_close(fd.sockfd);
-
- return NULL;
-}
-
-LWS_VISIBLE struct lws *
-lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd)
-{
- lws_sock_file_fd_type fd;
-
- fd.sockfd = accept_fd;
- return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET |
- LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL);
-}
-
-LWS_VISIBLE struct lws *
-lws_adopt_socket(struct lws_context *context, lws_sockfd_type accept_fd)
-{
- return lws_adopt_socket_vhost(context->vhost_list, accept_fd);
-}
-
-/* Common read-buffer adoption for lws_adopt_*_readbuf */
-static struct lws*
-adopt_socket_readbuf(struct lws *wsi, const char *readbuf, size_t len)
-{
- struct lws_context_per_thread *pt;
- struct lws_pollfd *pfd;
- int n;
-
- if (!wsi)
- return NULL;
-
- if (!readbuf || len == 0)
- return wsi;
-
- if (wsi->position_in_fds_table == LWS_NO_FDS_POS)
- return wsi;
-
- pt = &wsi->context->pt[(int)wsi->tsi];
-
- n = lws_buflist_append_segment(&wsi->buflist, (const uint8_t *)readbuf,
- len);
- if (n < 0)
- goto bail;
- if (n)
- lws_dll_lws_add_front(&wsi->dll_buflist, &pt->dll_head_buflist);
-
- /*
- * we can't process the initial read data until we can attach an ah.
- *
- * if one is available, get it and place the data in his ah rxbuf...
- * wsi with ah that have pending rxbuf get auto-POLLIN service.
- *
- * no autoservice because we didn't get a chance to attach the
- * readbuf data to wsi or ah yet, and we will do it next if we get
- * the ah.
- */
- if (wsi->http.ah || !lws_header_table_attach(wsi, 0)) {
-
- lwsl_notice("%s: calling service on readbuf ah\n", __func__);
-
- /*
- * unlike a normal connect, we have the headers already
- * (or the first part of them anyway).
- * libuv won't come back and service us without a network
- * event, so we need to do the header service right here.
- */
- pfd = &pt->fds[wsi->position_in_fds_table];
- pfd->revents |= LWS_POLLIN;
- lwsl_err("%s: calling service\n", __func__);
- if (lws_service_fd_tsi(wsi->context, pfd, wsi->tsi))
- /* service closed us */
- return NULL;
-
- return wsi;
- }
- lwsl_err("%s: deferring handling ah\n", __func__);
-
- return wsi;
-
-bail:
- lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
- "adopt skt readbuf fail");
-
- return NULL;
-}
-
-LWS_EXTERN struct lws *
-lws_create_adopt_udp(struct lws_vhost *vhost, int port, int flags,
- const char *protocol_name, struct lws *parent_wsi)
-{
- lws_sock_file_fd_type sock;
- struct addrinfo h, *r, *rp;
- struct lws *wsi = NULL;
- char buf[16];
- int n;
-
- memset(&h, 0, sizeof(h));
- h.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
- h.ai_socktype = SOCK_DGRAM;
- h.ai_protocol = IPPROTO_UDP;
- h.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
-
- lws_snprintf(buf, sizeof(buf), "%u", port);
- n = getaddrinfo(NULL, buf, &h, &r);
- if (n) {
- lwsl_info("%s: getaddrinfo error: %s\n", __func__,
- gai_strerror(n));
- goto bail;
- }
-
- for (rp = r; rp; rp = rp->ai_next) {
- sock.sockfd = socket(rp->ai_family, rp->ai_socktype,
- rp->ai_protocol);
- if (sock.sockfd != LWS_SOCK_INVALID)
- break;
- }
- if (!rp) {
- lwsl_err("%s: unable to create INET socket\n", __func__);
- goto bail1;
- }
-
- if ((flags & LWS_CAUDP_BIND) && bind(sock.sockfd, rp->ai_addr,
-#if defined(_WIN32)
- (int)rp->ai_addrlen
-#else
- rp->ai_addrlen
-#endif
- ) == -1) {
- lwsl_err("%s: bind failed\n", __func__);
- goto bail2;
- }
-
- wsi = lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_RAW_SOCKET_UDP, sock,
- protocol_name, parent_wsi);
- if (!wsi)
- lwsl_err("%s: udp adoption failed\n", __func__);
-
-bail2:
- if (!wsi)
- compatible_close((int)sock.sockfd);
-bail1:
- freeaddrinfo(r);
-
-bail:
- return wsi;
-}
-
-LWS_VISIBLE struct lws *
-lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd,
- const char *readbuf, size_t len)
-{
- return adopt_socket_readbuf(lws_adopt_socket(context, accept_fd),
- readbuf, len);
-}
-
-LWS_VISIBLE struct lws *
-lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
- lws_sockfd_type accept_fd,
- const char *readbuf, size_t len)
-{
- return adopt_socket_readbuf(lws_adopt_socket_vhost(vhost, accept_fd),
- readbuf, len);
-}
diff --git a/thirdparty/libwebsockets/lib/core/alloc.c b/thirdparty/libwebsockets/lib/core/alloc.c
deleted file mode 100644
index f169fc3767..0000000000
--- a/thirdparty/libwebsockets/lib/core/alloc.c
+++ /dev/null
@@ -1,92 +0,0 @@
-#include "core/private.h"
-
-#if defined(LWS_PLAT_OPTEE)
-
-#define TEE_USER_MEM_HINT_NO_FILL_ZERO 0x80000000
-
-void *__attribute__((weak))
- TEE_Malloc(uint32_t size, uint32_t hint)
-{
- return NULL;
-}
-void *__attribute__((weak))
- TEE_Realloc(void *buffer, uint32_t newSize)
-{
- return NULL;
-}
-void __attribute__((weak))
- TEE_Free(void *buffer)
-{
-}
-
-void *lws_realloc(void *ptr, size_t size, const char *reason)
-{
- return TEE_Realloc(ptr, size);
-}
-
-void *lws_malloc(size_t size, const char *reason)
-{
- return TEE_Malloc(size, TEE_USER_MEM_HINT_NO_FILL_ZERO);
-}
-
-void lws_free(void *p)
-{
- TEE_Free(p);
-}
-
-void *lws_zalloc(size_t size, const char *reason)
-{
- void *ptr = TEE_Malloc(size, TEE_USER_MEM_HINT_NO_FILL_ZERO);
- if (ptr)
- memset(ptr, 0, size);
- return ptr;
-}
-
-void lws_set_allocator(void *(*cb)(void *ptr, size_t size, const char *reason))
-{
- (void)cb;
-}
-#else
-
-static void *_realloc(void *ptr, size_t size, const char *reason)
-{
- if (size) {
-#if defined(LWS_WITH_ESP32)
- lwsl_notice("%s: size %lu: %s (free heap %d)\n", __func__,
- (unsigned long)size, reason, (unsigned int)esp_get_free_heap_size() - (int)size);
-#else
- lwsl_debug("%s: size %lu: %s\n", __func__,
- (unsigned long)size, reason);
-#endif
-#if defined(LWS_PLAT_OPTEE)
- return (void *)TEE_Realloc(ptr, size);
-#else
- return (void *)realloc(ptr, size);
-#endif
- }
- if (ptr)
- free(ptr);
-
- return NULL;
-}
-
-void *(*_lws_realloc)(void *ptr, size_t size, const char *reason) = _realloc;
-
-void *lws_realloc(void *ptr, size_t size, const char *reason)
-{
- return _lws_realloc(ptr, size, reason);
-}
-
-void *lws_zalloc(size_t size, const char *reason)
-{
- void *ptr = _lws_realloc(NULL, size, reason);
- if (ptr)
- memset(ptr, 0, size);
- return ptr;
-}
-
-void lws_set_allocator(void *(*cb)(void *ptr, size_t size, const char *reason))
-{
- _lws_realloc = cb;
-}
-#endif
diff --git a/thirdparty/libwebsockets/lib/core/connect.c b/thirdparty/libwebsockets/lib/core/connect.c
deleted file mode 100644
index daffc193c8..0000000000
--- a/thirdparty/libwebsockets/lib/core/connect.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-
-#include "core/private.h"
-
-void
-lws_client_stash_destroy(struct lws *wsi)
-{
- if (!wsi || !wsi->stash)
- return;
-
- lws_free_set_NULL(wsi->stash->address);
- lws_free_set_NULL(wsi->stash->path);
- lws_free_set_NULL(wsi->stash->host);
- lws_free_set_NULL(wsi->stash->origin);
- lws_free_set_NULL(wsi->stash->protocol);
- lws_free_set_NULL(wsi->stash->method);
- lws_free_set_NULL(wsi->stash->iface);
- lws_free_set_NULL(wsi->stash->alpn);
-
- lws_free_set_NULL(wsi->stash);
-}
-
-LWS_VISIBLE struct lws *
-lws_client_connect_via_info(const struct lws_client_connect_info *i)
-{
- struct lws *wsi, *safe = NULL;
- const struct lws_protocols *p;
- const char *local = i->protocol;
-#if LWS_MAX_SMP > 1
- int n, tid;
-#endif
-
- if (i->context->requested_kill)
- return NULL;
-
- if (!i->context->protocol_init_done)
- lws_protocol_init(i->context);
- /*
- * If we have .local_protocol_name, use it to select the local protocol
- * handler to bind to. Otherwise use .protocol if http[s].
- */
- if (i->local_protocol_name)
- local = i->local_protocol_name;
-
- /* PHASE 1: create a bare wsi */
-
- wsi = lws_zalloc(sizeof(struct lws), "client wsi");
- if (wsi == NULL)
- goto bail;
-
- wsi->context = i->context;
- wsi->desc.sockfd = LWS_SOCK_INVALID;
-
- wsi->vhost = NULL;
- if (!i->vhost)
- lws_vhost_bind_wsi(i->context->vhost_list, wsi);
- else
- lws_vhost_bind_wsi(i->vhost, wsi);
-
- if (!wsi->vhost) {
- lwsl_err("%s: No vhost in the context\n", __func__);
-
- goto bail;
- }
-
- /*
- * PHASE 2: if SMP, bind the client to whatever tsi the current thread
- * represents
- */
-
-#if LWS_MAX_SMP > 1
- tid = wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_GET_THREAD_ID,
- NULL, NULL, 0);
-
- lws_context_lock(i->context, "client find tsi");
-
- for (n = 0; n < i->context->count_threads; n++)
- if (i->context->pt[n].service_tid == tid) {
- lwsl_info("%s: client binds to caller tsi %d\n",
- __func__, n);
- wsi->tsi = n;
- break;
- }
-
- /*
- * this binding is sort of provisional, since when we try to insert
- * into the pt fds, there may be no space and it will fail
- */
-
- lws_context_unlock(i->context);
-#endif
-
- /*
- * PHASE 3: Choose an initial role for the wsi and do role-specific init
- *
- * Note the initial role may not reflect the final role, eg,
- * we may want ws, but first we have to go through h1 to get that
- */
-
- lws_role_call_client_bind(wsi, i);
-
- /*
- * PHASE 4: fill up the wsi with stuff from the connect_info as far as
- * it can go. It's uncertain because not only is our connection
- * going to complete asynchronously, we might have bound to h1 and not
- * even be able to get ahold of an ah immediately.
- */
-
- wsi->user_space = NULL;
- wsi->pending_timeout = NO_PENDING_TIMEOUT;
- wsi->position_in_fds_table = LWS_NO_FDS_POS;
- wsi->c_port = i->port;
-
- wsi->protocol = &wsi->vhost->protocols[0];
- wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE);
-
- /*
- * PHASE 5: handle external user_space now, generic alloc is done in
- * role finalization
- */
-
- if (!wsi->user_space && i->userdata) {
- wsi->user_space_externally_allocated = 1;
- wsi->user_space = i->userdata;
- }
-
- if (local) {
- lwsl_info("%s: protocol binding to %s\n", __func__, local);
- p = lws_vhost_name_to_protocol(wsi->vhost, local);
- if (p)
- lws_bind_protocol(wsi, p, __func__);
- }
-
- /*
- * PHASE 5: handle external user_space now, generic alloc is done in
- * role finalization
- */
-
- if (!wsi->user_space && i->userdata) {
- wsi->user_space_externally_allocated = 1;
- wsi->user_space = i->userdata;
- }
-
-#if defined(LWS_WITH_TLS)
- wsi->tls.use_ssl = i->ssl_connection;
-#else
- if (i->ssl_connection & LCCSCF_USE_SSL) {
- lwsl_err("%s: lws not configured for tls\n", __func__);
- goto bail;
- }
-#endif
-
- /*
- * PHASE 6: stash the things from connect_info that we can't process
- * right now, eg, if http binding, without an ah. If h1 and no ah, we
- * will go on the ah waiting list and process those things later (after
- * the connect_info and maybe the things pointed to have gone out of
- * scope)
- *
- * However these things are stashed in a generic way at this point,
- * with no relationship to http or ah
- */
-
- wsi->stash = lws_zalloc(sizeof(*wsi->stash), "client stash");
- if (!wsi->stash) {
- lwsl_err("%s: OOM\n", __func__);
- goto bail1;
- }
-
- wsi->stash->address = lws_strdup(i->address);
- wsi->stash->path = lws_strdup(i->path);
- wsi->stash->host = lws_strdup(i->host);
-
- if (!wsi->stash->address || !wsi->stash->path || !wsi->stash->host)
- goto bail1;
-
- if (i->origin) {
- wsi->stash->origin = lws_strdup(i->origin);
- if (!wsi->stash->origin)
- goto bail1;
- }
- if (i->protocol) {
- wsi->stash->protocol = lws_strdup(i->protocol);
- if (!wsi->stash->protocol)
- goto bail1;
- }
- if (i->method) {
- wsi->stash->method = lws_strdup(i->method);
- if (!wsi->stash->method)
- goto bail1;
- }
- if (i->iface) {
- wsi->stash->iface = lws_strdup(i->iface);
- if (!wsi->stash->iface)
- goto bail1;
- }
- if (i->alpn) {
- wsi->stash->alpn = lws_strdup(i->alpn);
- if (!wsi->stash->alpn)
- goto bail1;
- }
-
- /*
- * at this point user callbacks like
- * LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER will be interested to
- * know the parent... eg for proxying we can grab extra headers from
- * the parent's incoming ah and add them to the child client handshake
- */
-
- if (i->parent_wsi) {
- lwsl_info("%s: created child %p of parent %p\n", __func__,
- wsi, i->parent_wsi);
- wsi->parent = i->parent_wsi;
- safe = wsi->sibling_list = i->parent_wsi->child_list;
- i->parent_wsi->child_list = wsi;
- }
-
- /*
- * PHASE 7: Do any role-specific finalization processing. We can still
- * see important info things via wsi->stash
- */
-
- if (wsi->role_ops->client_bind) {
- int n = wsi->role_ops->client_bind(wsi, NULL);
-
- if (n && i->parent_wsi) {
- /* unpick from parent */
-
- i->parent_wsi->child_list = safe;
- }
-
- if (n < 0)
- /* we didn't survive, wsi is freed */
- goto bail2;
-
- if (n)
- /* something else failed, wsi needs freeing */
- goto bail;
- }
-
- /* let the caller's optional wsi storage have the wsi we created */
-
- if (i->pwsi)
- *i->pwsi = wsi;
-
-
-#if defined(LWS_WITH_HUBBUB)
- if (i->uri_replace_to)
- wsi->http.rw = lws_rewrite_create(wsi, html_parser_cb,
- i->uri_replace_from,
- i->uri_replace_to);
-#endif
-
- return wsi;
-
-bail1:
- lws_client_stash_destroy(wsi);
-
-bail:
- lws_free(wsi);
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-bail2:
-#endif
- if (i->pwsi)
- *i->pwsi = NULL;
-
- return NULL;
-}
diff --git a/thirdparty/libwebsockets/lib/core/context.c b/thirdparty/libwebsockets/lib/core/context.c
deleted file mode 100644
index 94b2d86339..0000000000
--- a/thirdparty/libwebsockets/lib/core/context.c
+++ /dev/null
@@ -1,1865 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-
-#include "core/private.h"
-
-#ifndef LWS_BUILD_HASH
-#define LWS_BUILD_HASH "unknown-build-hash"
-#endif
-
-const struct lws_role_ops *available_roles[] = {
-#if defined(LWS_ROLE_H2)
- &role_ops_h2,
-#endif
-#if defined(LWS_ROLE_H1)
- &role_ops_h1,
-#endif
-#if defined(LWS_ROLE_WS)
- &role_ops_ws,
-#endif
-#if defined(LWS_ROLE_DBUS)
- &role_ops_dbus,
-#endif
- NULL
-};
-
-const struct lws_event_loop_ops *available_event_libs[] = {
-#if defined(LWS_WITH_POLL)
- &event_loop_ops_poll,
-#endif
-#if defined(LWS_WITH_LIBUV)
- &event_loop_ops_uv,
-#endif
-#if defined(LWS_WITH_LIBEVENT)
- &event_loop_ops_event,
-#endif
-#if defined(LWS_WITH_LIBEV)
- &event_loop_ops_ev,
-#endif
- NULL
-};
-
-static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
-
-/**
- * lws_get_library_version: get version and git hash library built from
- *
- * returns a const char * to a string like "1.1 178d78c"
- * representing the library version followed by the git head hash it
- * was built from
- */
-LWS_VISIBLE const char *
-lws_get_library_version(void)
-{
- return library_version;
-}
-
-int
-lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn)
-{
-#if defined(LWS_WITH_TLS)
- if (!alpn)
- return 0;
-
- lwsl_info("%s: '%s'\n", __func__, alpn);
-
- LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
- if (ar->alpn && !strcmp(ar->alpn, alpn) && ar->alpn_negotiated)
- return ar->alpn_negotiated(wsi, alpn);
- LWS_FOR_EVERY_AVAILABLE_ROLE_END;
-#endif
- return 0;
-}
-
-#if !defined(LWS_WITHOUT_SERVER)
-int
-lws_role_call_adoption_bind(struct lws *wsi, int type, const char *prot)
-{
- LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
- if (ar->adoption_bind)
- if (ar->adoption_bind(wsi, type, prot))
- return 0;
- LWS_FOR_EVERY_AVAILABLE_ROLE_END;
-
- /* fall back to raw socket role if, eg, h1 not configured */
-
- if (role_ops_raw_skt.adoption_bind &&
- role_ops_raw_skt.adoption_bind(wsi, type, prot))
- return 0;
-
- /* fall back to raw file role if, eg, h1 not configured */
-
- if (role_ops_raw_file.adoption_bind &&
- role_ops_raw_file.adoption_bind(wsi, type, prot))
- return 0;
-
- return 1;
-}
-#endif
-
-#if !defined(LWS_WITHOUT_CLIENT)
-int
-lws_role_call_client_bind(struct lws *wsi,
- const struct lws_client_connect_info *i)
-{
- LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
- if (ar->client_bind) {
- int m = ar->client_bind(wsi, i);
- if (m < 0)
- return m;
- if (m)
- return 0;
- }
- LWS_FOR_EVERY_AVAILABLE_ROLE_END;
-
- /* fall back to raw socket role if, eg, h1 not configured */
-
- if (role_ops_raw_skt.client_bind &&
- role_ops_raw_skt.client_bind(wsi, i))
- return 0;
-
- return 1;
-}
-#endif
-
-static const char * const mount_protocols[] = {
- "http://",
- "https://",
- "file://",
- "cgi://",
- ">http://",
- ">https://",
- "callback://"
-};
-
-LWS_VISIBLE void *
-lws_protocol_vh_priv_zalloc(struct lws_vhost *vhost,
- const struct lws_protocols *prot, int size)
-{
- int n = 0;
-
- /* allocate the vh priv array only on demand */
- if (!vhost->protocol_vh_privs) {
- vhost->protocol_vh_privs = (void **)lws_zalloc(
- vhost->count_protocols * sizeof(void *),
- "protocol_vh_privs");
- if (!vhost->protocol_vh_privs)
- return NULL;
- }
-
- while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
- n++;
-
- if (n == vhost->count_protocols) {
- n = 0;
- while (n < vhost->count_protocols &&
- strcmp(vhost->protocols[n].name, prot->name))
- n++;
-
- if (n == vhost->count_protocols)
- return NULL;
- }
-
- vhost->protocol_vh_privs[n] = lws_zalloc(size, "vh priv");
- return vhost->protocol_vh_privs[n];
-}
-
-LWS_VISIBLE void *
-lws_protocol_vh_priv_get(struct lws_vhost *vhost,
- const struct lws_protocols *prot)
-{
- int n = 0;
-
- if (!vhost || !vhost->protocol_vh_privs || !prot)
- return NULL;
-
- while (n < vhost->count_protocols && &vhost->protocols[n] != prot)
- n++;
-
- if (n == vhost->count_protocols) {
- n = 0;
- while (n < vhost->count_protocols &&
- strcmp(vhost->protocols[n].name, prot->name))
- n++;
-
- if (n == vhost->count_protocols) {
- lwsl_err("%s: unknown protocol %p\n", __func__, prot);
- return NULL;
- }
- }
-
- return vhost->protocol_vh_privs[n];
-}
-
-static const struct lws_protocol_vhost_options *
-lws_vhost_protocol_options(struct lws_vhost *vh, const char *name)
-{
- const struct lws_protocol_vhost_options *pvo = vh->pvo;
-
- if (!name)
- return NULL;
-
- while (pvo) {
- if (!strcmp(pvo->name, name))
- return pvo;
- pvo = pvo->next;
- }
-
- return NULL;
-}
-
-/*
- * inform every vhost that hasn't already done it, that
- * his protocols are initializing
- */
-LWS_VISIBLE int
-lws_protocol_init(struct lws_context *context)
-{
- struct lws_vhost *vh = context->vhost_list;
- const struct lws_protocol_vhost_options *pvo, *pvo1;
- struct lws wsi;
- int n, any = 0;
-
- if (context->doing_protocol_init)
- return 0;
-
- context->doing_protocol_init = 1;
-
- memset(&wsi, 0, sizeof(wsi));
- wsi.context = context;
-
- lwsl_info("%s\n", __func__);
-
- while (vh) {
- wsi.vhost = vh;
-
- /* only do the protocol init once for a given vhost */
- if (vh->created_vhost_protocols ||
- (vh->options & LWS_SERVER_OPTION_SKIP_PROTOCOL_INIT))
- goto next;
-
- /* initialize supported protocols on this vhost */
-
- for (n = 0; n < vh->count_protocols; n++) {
- wsi.protocol = &vh->protocols[n];
- if (!vh->protocols[n].name)
- continue;
- pvo = lws_vhost_protocol_options(vh,
- vh->protocols[n].name);
- if (pvo) {
- /*
- * linked list of options specific to
- * vh + protocol
- */
- pvo1 = pvo;
- pvo = pvo1->options;
-
- while (pvo) {
- lwsl_debug(
- " vhost \"%s\", "
- "protocol \"%s\", "
- "option \"%s\"\n",
- vh->name,
- vh->protocols[n].name,
- pvo->name);
-
- if (!strcmp(pvo->name, "default")) {
- lwsl_info("Setting default "
- "protocol for vh %s to %s\n",
- vh->name,
- vh->protocols[n].name);
- vh->default_protocol_index = n;
- }
- if (!strcmp(pvo->name, "raw")) {
- lwsl_info("Setting raw "
- "protocol for vh %s to %s\n",
- vh->name,
- vh->protocols[n].name);
- vh->raw_protocol_index = n;
- }
- pvo = pvo->next;
- }
-
- pvo = pvo1->options;
- }
-
-#if defined(LWS_WITH_TLS)
- any |= !!vh->tls.ssl_ctx;
-#endif
-
- /*
- * inform all the protocols that they are doing their
- * one-time initialization if they want to.
- *
- * NOTE the wsi is all zeros except for the context, vh
- * + protocol ptrs so lws_get_context(wsi) etc can work
- */
- if (vh->protocols[n].callback(&wsi,
- LWS_CALLBACK_PROTOCOL_INIT, NULL,
- (void *)pvo, 0)) {
- lws_free(vh->protocol_vh_privs[n]);
- vh->protocol_vh_privs[n] = NULL;
- lwsl_err("%s: protocol %s failed init\n",
- __func__, vh->protocols[n].name);
-
- return 1;
- }
- }
-
- vh->created_vhost_protocols = 1;
-next:
- vh = vh->vhost_next;
- }
-
- context->doing_protocol_init = 0;
-
- if (!context->protocol_init_done)
- lws_finalize_startup(context);
-
- context->protocol_init_done = 1;
-
- if (any)
- lws_tls_check_all_cert_lifetimes(context);
-
- return 0;
-}
-
-
-/* list of supported protocols and callbacks */
-
-static const struct lws_protocols protocols_dummy[] = {
- /* first protocol must always be HTTP handler */
-
- {
- "http-only", /* name */
- lws_callback_http_dummy, /* callback */
- 0, /* per_session_data_size */
- 0, /* rx_buffer_size */
- 0, /* id */
- NULL, /* user */
- 0 /* tx_packet_size */
- },
- /*
- * the other protocols are provided by lws plugins
- */
- { NULL, NULL, 0, 0, 0, NULL, 0} /* terminator */
-};
-
-#ifdef LWS_PLAT_OPTEE
-#undef LWS_HAVE_GETENV
-#endif
-
-LWS_VISIBLE struct lws_vhost *
-lws_create_vhost(struct lws_context *context,
- const struct lws_context_creation_info *info)
-{
- struct lws_vhost *vh = lws_zalloc(sizeof(*vh), "create vhost"),
- **vh1 = &context->vhost_list;
- const struct lws_http_mount *mounts;
- const struct lws_protocols *pcols = info->protocols;
- const struct lws_protocol_vhost_options *pvo;
-#ifdef LWS_WITH_PLUGINS
- struct lws_plugin *plugin = context->plugin_list;
-#endif
- struct lws_protocols *lwsp;
- int m, f = !info->pvo;
- char buf[20];
-#if !defined(LWS_WITHOUT_CLIENT) && defined(LWS_HAVE_GETENV)
- char *p;
-#endif
- int n;
-
- if (!vh)
- return NULL;
-
-#if LWS_MAX_SMP > 1
- pthread_mutex_init(&vh->lock, NULL);
-#endif
-
- if (!pcols)
- pcols = &protocols_dummy[0];
-
- vh->context = context;
- if (!info->vhost_name)
- vh->name = "default";
- else
- vh->name = info->vhost_name;
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- vh->http.error_document_404 = info->error_document_404;
-#endif
-
- if (info->options & LWS_SERVER_OPTION_ONLY_RAW)
- lwsl_info("%s set to only support RAW\n", vh->name);
-
- vh->iface = info->iface;
-#if !defined(LWS_WITH_ESP32) && \
- !defined(OPTEE_TA) && !defined(WIN32)
- vh->bind_iface = info->bind_iface;
-#endif
-
- for (vh->count_protocols = 0;
- pcols[vh->count_protocols].callback;
- vh->count_protocols++)
- ;
-
- vh->options = info->options;
- vh->pvo = info->pvo;
- vh->headers = info->headers;
- vh->user = info->user;
- vh->finalize = info->finalize;
- vh->finalize_arg = info->finalize_arg;
-
- LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
- if (ar->init_vhost)
- if (ar->init_vhost(vh, info))
- return NULL;
- LWS_FOR_EVERY_AVAILABLE_ROLE_END;
-
-
- 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;
-
-#if defined(LWS_WITH_TLS)
-
- vh->tls.alpn = info->alpn;
- vh->tls.ssl_info_event_mask = info->ssl_info_event_mask;
-
- if (info->ecdh_curve)
- lws_strncpy(vh->tls.ecdh_curve, info->ecdh_curve,
- sizeof(vh->tls.ecdh_curve));
-
- /* carefully allocate and take a copy of cert + key paths if present */
- n = 0;
- if (info->ssl_cert_filepath)
- n += (int)strlen(info->ssl_cert_filepath) + 1;
- if (info->ssl_private_key_filepath)
- n += (int)strlen(info->ssl_private_key_filepath) + 1;
-
- if (n) {
- vh->tls.key_path = vh->tls.alloc_cert_path =
- lws_malloc(n, "vh paths");
- if (info->ssl_cert_filepath) {
- n = (int)strlen(info->ssl_cert_filepath) + 1;
- memcpy(vh->tls.alloc_cert_path,
- info->ssl_cert_filepath, n);
- vh->tls.key_path += n;
- }
- if (info->ssl_private_key_filepath)
- memcpy(vh->tls.key_path, info->ssl_private_key_filepath,
- strlen(info->ssl_private_key_filepath) + 1);
- }
-#endif
-
- /*
- * give the vhost a unified list of protocols including the
- * ones that came from plugins
- */
- lwsp = lws_zalloc(sizeof(struct lws_protocols) * (vh->count_protocols +
- context->plugin_protocol_count + 1),
- "vhost-specific plugin table");
- if (!lwsp) {
- lwsl_err("OOM\n");
- return NULL;
- }
-
- m = vh->count_protocols;
- memcpy(lwsp, pcols, sizeof(struct lws_protocols) * m);
-
- /* for compatibility, all protocols enabled on vhost if only
- * the default vhost exists. Otherwise only vhosts who ask
- * for a protocol get it enabled.
- */
-
- if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
- f = 0;
- (void)f;
-#ifdef LWS_WITH_PLUGINS
- if (plugin) {
-
- while (plugin) {
- for (n = 0; n < plugin->caps.count_protocols; n++) {
- /*
- * for compatibility's sake, no pvo implies
- * allow all protocols
- */
- if (f || lws_vhost_protocol_options(vh,
- plugin->caps.protocols[n].name)) {
- memcpy(&lwsp[m],
- &plugin->caps.protocols[n],
- sizeof(struct lws_protocols));
- m++;
- vh->count_protocols++;
- }
- }
- plugin = plugin->list;
- }
- }
-#endif
-
- if (
-#ifdef LWS_WITH_PLUGINS
- (context->plugin_list) ||
-#endif
- context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
- vh->protocols = lwsp;
- else {
- vh->protocols = pcols;
- lws_free(lwsp);
- }
-
- vh->same_vh_protocol_heads = (struct lws_dll_lws *)
- lws_zalloc(sizeof(struct lws_dll_lws) *
- vh->count_protocols, "same vh list");
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- vh->http.mount_list = info->mounts;
-#endif
-
-#ifdef LWS_WITH_UNIX_SOCK
- if (LWS_UNIX_SOCK_ENABLED(vh)) {
- lwsl_notice("Creating Vhost '%s' path \"%s\", %d protocols\n",
- vh->name, vh->iface, vh->count_protocols);
- } else
-#endif
- {
- switch(info->port) {
- case CONTEXT_PORT_NO_LISTEN:
- strcpy(buf, "(serving disabled)");
- break;
- case CONTEXT_PORT_NO_LISTEN_SERVER:
- strcpy(buf, "(no listener)");
- break;
- default:
- lws_snprintf(buf, sizeof(buf), "port %u", info->port);
- break;
- }
- lwsl_notice("Creating Vhost '%s' %s, %d protocols, IPv6 %s\n",
- vh->name, buf, vh->count_protocols,
- LWS_IPV6_ENABLED(vh) ? "on" : "off");
- }
- mounts = info->mounts;
- while (mounts) {
- (void)mount_protocols[0];
- lwsl_info(" mounting %s%s to %s\n",
- mount_protocols[mounts->origin_protocol],
- mounts->origin, mounts->mountpoint);
-
- /* convert interpreter protocol names to pointers */
- pvo = mounts->interpret;
- while (pvo) {
- for (n = 0; n < vh->count_protocols; n++) {
- if (strcmp(pvo->value, vh->protocols[n].name))
- continue;
- ((struct lws_protocol_vhost_options *)pvo)->
- value = (const char *)(lws_intptr_t)n;
- break;
- }
- if (n == vh->count_protocols)
- lwsl_err("ignoring unknown interp pr %s\n",
- pvo->value);
- pvo = pvo->next;
- }
-
- mounts = mounts->mount_next;
- }
-
- vh->listen_port = info->port;
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- vh->http.http_proxy_port = 0;
- vh->http.http_proxy_address[0] = '\0';
-#endif
-#if defined(LWS_WITH_SOCKS5)
- vh->socks_proxy_port = 0;
- vh->socks_proxy_address[0] = '\0';
-#endif
-
-#if !defined(LWS_WITHOUT_CLIENT)
- /* either use proxy from info, or try get it from env var */
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- /* http proxy */
- if (info->http_proxy_address) {
- /* override for backwards compatibility */
- if (info->http_proxy_port)
- vh->http.http_proxy_port = info->http_proxy_port;
- lws_set_proxy(vh, info->http_proxy_address);
- } else
-#endif
- {
-#ifdef LWS_HAVE_GETENV
- p = getenv("http_proxy");
- if (p)
- lws_set_proxy(vh, p);
-#endif
- }
-#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
-
- vh->ka_time = info->ka_time;
- vh->ka_interval = info->ka_interval;
- vh->ka_probes = info->ka_probes;
-
- if (vh->options & LWS_SERVER_OPTION_STS)
- lwsl_notice(" STS enabled\n");
-
-#ifdef LWS_WITH_ACCESS_LOG
- if (info->log_filepath) {
- vh->log_fd = lws_open(info->log_filepath,
- O_CREAT | O_APPEND | O_RDWR, 0600);
- if (vh->log_fd == (int)LWS_INVALID_FILE) {
- lwsl_err("unable to open log filepath %s\n",
- info->log_filepath);
- goto bail;
- }
-#ifndef WIN32
- if (context->uid != -1)
- if (chown(info->log_filepath, context->uid,
- context->gid) == -1)
- lwsl_err("unable to chown log file %s\n",
- info->log_filepath);
-#endif
- } else
- vh->log_fd = (int)LWS_INVALID_FILE;
-#endif
- if (lws_context_init_server_ssl(info, vh)) {
- lwsl_err("%s: lws_context_init_server_ssl failed\n", __func__);
- goto bail1;
- }
- if (lws_context_init_client_ssl(info, vh)) {
- lwsl_err("%s: lws_context_init_client_ssl failed\n", __func__);
- goto bail1;
- }
- lws_context_lock(context, "create_vhost");
- n = _lws_vhost_init_server(info, vh);
- lws_context_unlock(context);
- if (n < 0) {
- lwsl_err("init server failed\n");
- goto bail1;
- }
-
- while (1) {
- if (!(*vh1)) {
- *vh1 = vh;
- break;
- }
- vh1 = &(*vh1)->vhost_next;
- };
-
- /* for the case we are adding a vhost much later, after server init */
-
- if (context->protocol_init_done)
- if (lws_protocol_init(context)) {
- lwsl_err("%s: lws_protocol_init failed\n", __func__);
- goto bail1;
- }
-
- return vh;
-
-bail1:
- lws_vhost_destroy(vh);
-
- return NULL;
-
-#ifdef LWS_WITH_ACCESS_LOG
-bail:
- lws_free(vh);
-#endif
-
- return NULL;
-}
-
-LWS_VISIBLE int
-lws_init_vhost_client_ssl(const struct lws_context_creation_info *info,
- struct lws_vhost *vhost)
-{
- struct lws_context_creation_info i;
-
- memcpy(&i, info, sizeof(i));
- i.port = CONTEXT_PORT_NO_LISTEN;
-
- return lws_context_init_client_ssl(&i, vhost);
-}
-
-LWS_VISIBLE void
-lws_cancel_service_pt(struct lws *wsi)
-{
- lws_plat_pipe_signal(wsi);
-}
-
-LWS_VISIBLE void
-lws_cancel_service(struct lws_context *context)
-{
- struct lws_context_per_thread *pt = &context->pt[0];
- short m = context->count_threads;
-
- if (context->being_destroyed1)
- return;
-
- lwsl_info("%s\n", __func__);
-
- while (m--) {
- if (pt->pipe_wsi)
- lws_plat_pipe_signal(pt->pipe_wsi);
- pt++;
- }
-}
-
-int
-lws_create_event_pipes(struct lws_context *context)
-{
- struct lws *wsi;
- int n;
-
- /*
- * Create the pt event pipes... these are unique in that they are
- * not bound to a vhost or protocol (both are NULL)
- */
-
- for (n = 0; n < context->count_threads; n++) {
- if (context->pt[n].pipe_wsi)
- continue;
-
- wsi = lws_zalloc(sizeof(*wsi), "event pipe wsi");
- if (!wsi) {
- lwsl_err("%s: Out of mem\n", __func__);
- return 1;
- }
- wsi->context = context;
- lws_role_transition(wsi, 0, LRS_UNCONNECTED, &role_ops_pipe);
- wsi->protocol = NULL;
- wsi->tsi = n;
- wsi->vhost = NULL;
- wsi->event_pipe = 1;
- wsi->desc.sockfd = LWS_SOCK_INVALID;
- context->pt[n].pipe_wsi = wsi;
- context->count_wsi_allocated++;
-
- if (lws_plat_pipe_create(wsi))
- /*
- * platform code returns 0 if it actually created pipes
- * and initialized pt->dummy_pipe_fds[]. If it used
- * some other mechanism outside of signaling in the
- * normal event loop, we skip treating the pipe as
- * related to dummy_pipe_fds[], adding it to the fds,
- * etc.
- */
- continue;
-
- wsi->desc.sockfd = context->pt[n].dummy_pipe_fds[0];
- lwsl_debug("event pipe fd %d\n", wsi->desc.sockfd);
-
- if (context->event_loop_ops->accept)
- if (context->event_loop_ops->accept(wsi))
- return 1;
-
- if (__insert_wsi_socket_into_fds(context, wsi))
- return 1;
- }
-
- return 0;
-}
-
-void
-lws_destroy_event_pipe(struct lws *wsi)
-{
- lwsl_info("%s\n", __func__);
- __remove_wsi_socket_from_fds(wsi);
-
- if (wsi->context->event_loop_ops->wsi_logical_close) {
- wsi->context->event_loop_ops->wsi_logical_close(wsi);
- lws_plat_pipe_close(wsi);
- wsi->context->count_wsi_allocated--;
- return;
- }
-
- if (wsi->context->event_loop_ops->destroy_wsi)
- wsi->context->event_loop_ops->destroy_wsi(wsi);
- lws_plat_pipe_close(wsi);
- wsi->context->count_wsi_allocated--;
- lws_free(wsi);
-}
-
-LWS_VISIBLE struct lws_context *
-lws_create_context(const struct lws_context_creation_info *info)
-{
- struct lws_context *context = NULL;
- struct lws_plat_file_ops *prev;
-#ifndef LWS_NO_DAEMONIZE
- int pid_daemon = get_daemonize_pid();
-#endif
- int n;
-#if defined(__ANDROID__)
- struct rlimit rt;
-#endif
-
- lwsl_info("Initial logging level %d\n", log_level);
- lwsl_info("Libwebsockets version: %s\n", library_version);
-
-#ifdef LWS_WITH_IPV6
- if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_IPV6))
- lwsl_info("IPV6 compiled in and enabled\n");
- else
- lwsl_info("IPV6 compiled in but disabled\n");
-#else
- lwsl_info("IPV6 not compiled in\n");
-#endif
-
- lwsl_info(" LWS_DEF_HEADER_LEN : %u\n", LWS_DEF_HEADER_LEN);
- lwsl_info(" LWS_MAX_PROTOCOLS : %u\n", LWS_MAX_PROTOCOLS);
- lwsl_info(" LWS_MAX_SMP : %u\n", LWS_MAX_SMP);
- lwsl_info(" sizeof (*info) : %ld\n", (long)sizeof(*info));
-#if defined(LWS_WITH_STATS)
- lwsl_info(" LWS_WITH_STATS : on\n");
-#endif
- lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
-#if defined(LWS_WITH_HTTP2)
- lwsl_info(" HTTP2 support : available\n");
-#else
- lwsl_info(" HTTP2 support : not configured\n");
-#endif
- if (lws_plat_context_early_init())
- return NULL;
-
- context = lws_zalloc(sizeof(struct lws_context), "context");
- if (!context) {
- lwsl_err("No memory for websocket context\n");
- return NULL;
- }
-
-#if defined(LWS_WITH_TLS)
-#if defined(LWS_WITH_MBEDTLS)
- context->tls_ops = &tls_ops_mbedtls;
-#else
- context->tls_ops = &tls_ops_openssl;
-#endif
-#endif
-
- if (info->pt_serv_buf_size)
- context->pt_serv_buf_size = info->pt_serv_buf_size;
- else
- context->pt_serv_buf_size = 4096;
-
-#if defined(LWS_ROLE_H2)
- role_ops_h2.init_context(context, info);
-#endif
-
-#if LWS_MAX_SMP > 1
- lws_mutex_refcount_init(&context->mr);
-#endif
-
-#if defined(LWS_WITH_ESP32)
- context->last_free_heap = esp_get_free_heap_size();
-#endif
-
- /* default to just the platform fops implementation */
-
- 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;
-
- /*
- * arrange a linear linked-list of fops starting from context->fops
- *
- * platform fops
- * [ -> fops_zip (copied into context so .next settable) ]
- * [ -> info->fops ]
- */
-
- context->fops = &context->fops_platform;
- prev = (struct lws_plat_file_ops *)context->fops;
-
-#if defined(LWS_WITH_ZIP_FOPS)
- /* make a soft copy so we can set .next */
- context->fops_zip = fops_zip;
- prev->next = &context->fops_zip;
- prev = (struct lws_plat_file_ops *)prev->next;
-#endif
-
- /* if user provided fops, tack them on the end of the list */
- if (info->fops)
- prev->next = info->fops;
-
- context->reject_service_keywords = info->reject_service_keywords;
- if (info->external_baggage_free_on_destroy)
- context->external_baggage_free_on_destroy =
- info->external_baggage_free_on_destroy;
-
- context->time_up = time(NULL);
- context->pcontext_finalize = info->pcontext;
-
- context->simultaneous_ssl_restriction =
- info->simultaneous_ssl_restriction;
-
-#ifndef LWS_NO_DAEMONIZE
- if (pid_daemon) {
- context->started_with_parent = pid_daemon;
- lwsl_info(" Started with daemon pid %d\n", pid_daemon);
- }
-#endif
-#if defined(__ANDROID__)
- n = getrlimit ( RLIMIT_NOFILE,&rt);
- if (-1 == n) {
- lwsl_err("Get RLIMIT_NOFILE failed!\n");
- return NULL;
- }
- context->max_fds = rt.rlim_cur;
-#else
- context->max_fds = getdtablesize();
-#endif
-
- if (info->count_threads)
- context->count_threads = info->count_threads;
- else
- context->count_threads = 1;
-
- if (context->count_threads > LWS_MAX_SMP)
- context->count_threads = LWS_MAX_SMP;
-
- context->token_limits = info->token_limits;
-
- context->options = info->options;
-
- /*
- * set the context event loops ops struct
- *
- * after this, all event_loop actions use the generic ops
- */
-
-#if defined(LWS_WITH_POLL)
- context->event_loop_ops = &event_loop_ops_poll;
-#endif
-
- if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
-#if defined(LWS_WITH_LIBUV)
- context->event_loop_ops = &event_loop_ops_uv;
-#else
- goto fail_event_libs;
-#endif
-
- if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV))
-#if defined(LWS_WITH_LIBEV)
- context->event_loop_ops = &event_loop_ops_ev;
-#else
- goto fail_event_libs;
-#endif
-
- if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT))
-#if defined(LWS_WITH_LIBEVENT)
- context->event_loop_ops = &event_loop_ops_event;
-#else
- goto fail_event_libs;
-#endif
-
- if (!context->event_loop_ops)
- goto fail_event_libs;
-
- lwsl_info("Using event loop: %s\n", context->event_loop_ops->name);
-
-#if defined(LWS_WITH_TLS)
- time(&context->tls.last_cert_check_s);
- if (info->alpn)
- context->tls.alpn_default = info->alpn;
- else {
- char *p = context->tls.alpn_discovered, first = 1;
-
- LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar) {
- if (ar->alpn) {
- if (!first)
- *p++ = ',';
- p += lws_snprintf(p,
- context->tls.alpn_discovered +
- sizeof(context->tls.alpn_discovered) -
- 2 - p, "%s", ar->alpn);
- first = 0;
- }
- } LWS_FOR_EVERY_AVAILABLE_ROLE_END;
-
- context->tls.alpn_default = context->tls.alpn_discovered;
- }
-
- lwsl_info("Default ALPN advertisment: %s\n", context->tls.alpn_default);
-#endif
-
- if (info->timeout_secs)
- context->timeout_secs = info->timeout_secs;
- else
- context->timeout_secs = AWAITING_TIMEOUT;
-
- context->ws_ping_pong_interval = info->ws_ping_pong_interval;
-
- lwsl_info(" default timeout (secs): %u\n", context->timeout_secs);
-
- if (info->max_http_header_data)
- context->max_http_header_data = info->max_http_header_data;
- else
- if (info->max_http_header_data2)
- context->max_http_header_data =
- info->max_http_header_data2;
- else
- context->max_http_header_data = LWS_DEF_HEADER_LEN;
-
- if (info->max_http_header_pool)
- context->max_http_header_pool = info->max_http_header_pool;
- else
- if (info->max_http_header_pool2)
- context->max_http_header_pool =
- info->max_http_header_pool2;
- else
- context->max_http_header_pool = context->max_fds;
-
- if (info->fd_limit_per_thread)
- context->fd_limit_per_thread = info->fd_limit_per_thread;
- else
- context->fd_limit_per_thread = context->max_fds /
- context->count_threads;
-
- /*
- * Allocate the per-thread storage for scratchpad buffers,
- * and header data pool
- */
- for (n = 0; n < context->count_threads; n++) {
- context->pt[n].serv_buf = lws_malloc(context->pt_serv_buf_size,
- "pt_serv_buf");
- if (!context->pt[n].serv_buf) {
- lwsl_err("OOM\n");
- return NULL;
- }
-
- context->pt[n].context = context;
- context->pt[n].tid = n;
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- context->pt[n].http.ah_list = NULL;
- context->pt[n].http.ah_pool_length = 0;
-#endif
- lws_pt_mutex_init(&context->pt[n]);
- }
-
- lwsl_info(" Threads: %d each %d fds\n", context->count_threads,
- context->fd_limit_per_thread);
-
- if (!info->ka_interval && info->ka_time > 0) {
- lwsl_err("info->ka_interval can't be 0 if ka_time used\n");
- return NULL;
- }
-
-#if defined(LWS_WITH_PEER_LIMITS)
- /* scale the peer hash table according to the max fds for the process,
- * so that the max list depth averages 16. Eg, 1024 fd -> 64,
- * 102400 fd -> 6400
- */
-
- context->pl_hash_elements =
- (context->count_threads * context->fd_limit_per_thread) / 16;
- context->pl_hash_table = lws_zalloc(sizeof(struct lws_peer *) *
- context->pl_hash_elements, "peer limits hash table");
-
- context->ip_limit_ah = info->ip_limit_ah;
- context->ip_limit_wsi = info->ip_limit_wsi;
-#endif
-
- lwsl_info(" mem: context: %5lu B (%ld ctx + (%ld thr x %d))\n",
- (long)sizeof(struct lws_context) +
- (context->count_threads * context->pt_serv_buf_size),
- (long)sizeof(struct lws_context),
- (long)context->count_threads,
- context->pt_serv_buf_size);
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- lwsl_info(" mem: http hdr rsvd: %5lu B (%u thr x (%u + %lu) x %u))\n",
- (long)(context->max_http_header_data +
- sizeof(struct allocated_headers)) *
- context->max_http_header_pool * context->count_threads,
- context->count_threads,
- context->max_http_header_data,
- (long)sizeof(struct allocated_headers),
- context->max_http_header_pool);
-#endif
- n = sizeof(struct lws_pollfd) * context->count_threads *
- context->fd_limit_per_thread;
- context->pt[0].fds = lws_zalloc(n, "fds table");
- if (context->pt[0].fds == NULL) {
- lwsl_err("OOM allocating %d fds\n", context->max_fds);
- goto bail;
- }
- lwsl_info(" mem: pollfd map: %5u\n", n);
-
- if (info->server_string) {
- context->server_string = info->server_string;
- context->server_string_len = (short)
- strlen(context->server_string);
- }
-
-#if LWS_MAX_SMP > 1
- /* each thread serves his own chunk of fds */
- for (n = 1; n < (int)info->count_threads; n++)
- context->pt[n].fds = context->pt[n - 1].fds +
- context->fd_limit_per_thread;
-#endif
-
- if (lws_plat_init(context, info))
- goto bail;
-
- if (context->event_loop_ops->init_context)
- if (context->event_loop_ops->init_context(context, info))
- goto bail;
-
-
- if (context->event_loop_ops->init_pt)
- for (n = 0; n < context->count_threads; n++) {
- void *lp = NULL;
-
- if (info->foreign_loops)
- lp = info->foreign_loops[n];
-
- if (context->event_loop_ops->init_pt(context, lp, n))
- goto bail;
- }
-
- if (lws_create_event_pipes(context))
- goto bail;
-
- lws_context_init_ssl_library(info);
-
- context->user_space = info->user;
-
- /*
- * if he's not saying he'll make his own vhosts later then act
- * compatibly and make a default vhost using the data in the info
- */
- if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
- if (!lws_create_vhost(context, info)) {
- lwsl_err("Failed to create default vhost\n");
- for (n = 0; n < context->count_threads; n++)
- lws_free_set_NULL(context->pt[n].serv_buf);
-#if defined(LWS_WITH_PEER_LIMITS)
- lws_free_set_NULL(context->pl_hash_table);
-#endif
- lws_free_set_NULL(context->pt[0].fds);
- lws_plat_context_late_destroy(context);
- lws_free_set_NULL(context);
- return NULL;
- }
-
- lws_context_init_extensions(info, context);
-
- lwsl_info(" mem: per-conn: %5lu bytes + protocol rx buf\n",
- (unsigned long)sizeof(struct lws));
-
- strcpy(context->canonical_hostname, "unknown");
- lws_server_get_canonical_hostname(context, info);
-
- 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
- * listening, we don't want the power for anything else
- */
- if (!lws_check_opt(info->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
- lws_plat_drop_app_privileges(info);
-
- /* expedite post-context init (eg, protocols) */
- lws_cancel_service(context);
-
-#if defined(LWS_WITH_SELFTESTS)
- lws_jws_selftest();
-#endif
-
- return context;
-
-bail:
- lws_context_destroy(context);
-
- return NULL;
-
-fail_event_libs:
- lwsl_err("Requested event library support not configured, available:\n");
- {
- const struct lws_event_loop_ops **elops = available_event_libs;
-
- while (*elops) {
- lwsl_err(" - %s\n", (*elops)->name);
- elops++;
- }
- }
- lws_free(context);
-
- return NULL;
-}
-
-LWS_VISIBLE LWS_EXTERN void
-lws_context_deprecate(struct lws_context *context, lws_reload_func cb)
-{
- struct lws_vhost *vh = context->vhost_list, *vh1;
-
- /*
- * "deprecation" means disable the context from accepting any new
- * connections and free up listen sockets to be used by a replacement
- * context.
- *
- * Otherwise the deprecated context remains operational, until its
- * number of connected sockets falls to zero, when it is deleted.
- */
-
- /* for each vhost, close his listen socket */
-
- while (vh) {
- struct lws *wsi = vh->lserv_wsi;
-
- if (wsi) {
- wsi->socket_is_permanently_unusable = 1;
- lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "ctx deprecate");
- wsi->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;
- }
- }
- vh = vh->vhost_next;
- }
-
- context->deprecated = 1;
- context->deprecation_cb = cb;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_context_is_deprecated(struct lws_context *context)
-{
- return context->deprecated;
-}
-
-void
-lws_vhost_destroy1(struct lws_vhost *vh)
-{
- struct lws_context *context = vh->context;
-
- lwsl_info("%s\n", __func__);
-
- lws_context_lock(context, "vhost destroy 1"); /* ---------- context { */
-
- if (vh->being_destroyed)
- goto out;
-
- lws_vhost_lock(vh); /* -------------- vh { */
-
- vh->being_destroyed = 1;
-
- /*
- * 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
- * so it will remain open.
- *
- * If not, leave it attached to the closing vhost, the vh being marked
- * being_destroyed will defeat any service and it will get closed in
- * later phases.
- */
-
- 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;
-
- lwsl_notice("%s: listen skt from %s to %s\n",
- __func__, vh->name, v->name);
-
- if (v->lserv_wsi) {
- lws_vhost_unbind_wsi(vh->lserv_wsi);
- lws_vhost_bind_wsi(v, v->lserv_wsi);
- }
-
- break;
- }
- } lws_end_foreach_ll(v, vhost_next);
-
- lws_vhost_unlock(vh); /* } vh -------------- */
-
- /*
- * lws_check_deferred_free() will notice there is a vhost that is
- * marked for destruction during the next 1s, for all tsi.
- *
- * It will start closing all wsi on this vhost. When the last wsi
- * is closed, it will trigger lws_vhost_destroy2()
- */
-
-out:
- lws_context_unlock(context); /* --------------------------- context { */
-}
-
-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;
- struct lws wsi;
- int n;
-
- /*
- * destroy any pending timed events
- */
-
- while (vh->timed_vh_protocol_list)
- __lws_timed_callback_remove(vh, vh->timed_vh_protocol_list);
-
- /*
- * let the protocols destroy the per-vhost protocol objects
- */
-
- memset(&wsi, 0, sizeof(wsi));
- wsi.context = vh->context;
- wsi.vhost = vh; /* not a real bound wsi */
- protocol = vh->protocols;
- if (protocol && vh->created_vhost_protocols) {
- 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;
-
- lwsl_info("%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_heads);
-
- if (context->plugin_list ||
- (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
- lws_free((void *)vh->protocols);
-
- LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
- if (ar->destroy_vhost)
- ar->destroy_vhost(vh);
- LWS_FOR_EVERY_AVAILABLE_ROLE_END;
-
-#ifdef LWS_WITH_ACCESS_LOG
- if (vh->log_fd != (int)LWS_INVALID_FILE)
- close(vh->log_fd);
-#endif
-
-#if defined (LWS_WITH_TLS)
- lws_free_set_NULL(vh->tls.alloc_cert_path);
-#endif
-
-#if LWS_MAX_SMP > 1
- pthread_mutex_destroy(&vh->lock);
-#endif
-
-#if defined(LWS_WITH_UNIX_SOCK)
- if (LWS_UNIX_SOCK_ENABLED(vh)) {
- n = unlink(vh->iface);
- if (n)
- lwsl_info("Closing unix socket %s: errno %d\n",
- vh->iface, errno);
- }
-#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.
- */
-
- if (vh->finalize)
- vh->finalize(vh, vh->finalize_arg);
-
- lwsl_info(" %s: Freeing vhost %p\n", __func__, vh);
-
- memset(vh, 0, sizeof(*vh));
- lws_free(vh);
-}
-
-/*
- * each service thread calls this once a second or so
- */
-
-int
-lws_check_deferred_free(struct lws_context *context, int tsi, int force)
-{
- struct lws_context_per_thread *pt;
- int n;
-
- /*
- * If we see a vhost is being destroyed, forcibly close every wsi on
- * this tsi associated with this vhost. That will include the listen
- * socket if it is still associated with the closing vhost.
- *
- * For SMP, we do this once per tsi per destroyed vhost. The reference
- * counting on the vhost as the bound wsi close will notice that there
- * are no bound wsi left, that vhost destruction can complete,
- * and perform it. It doesn't matter which service thread does that
- * because there is nothing left using the vhost to conflict.
- */
-
- lws_context_lock(context, "check deferred free"); /* ------ context { */
-
- lws_start_foreach_ll_safe(struct lws_vhost *, v, context->vhost_list, vhost_next) {
- if (v->being_destroyed
-#if LWS_MAX_SMP > 1
- && !v->close_flow_vs_tsi[tsi]
-#endif
- ) {
-
- pt = &context->pt[tsi];
-
- lws_pt_lock(pt, "vhost removal"); /* -------------- pt { */
-
-#if LWS_MAX_SMP > 1
- v->close_flow_vs_tsi[tsi] = 1;
-#endif
-
- for (n = 0; (unsigned int)n < pt->fds_count; n++) {
- struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
- if (!wsi)
- continue;
- if (wsi->vhost != v)
- continue;
-
- __lws_close_free_wsi(wsi,
- LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
- "vh destroy"
- /* no protocol close */);
- n--;
- }
-
- lws_pt_unlock(pt); /* } pt -------------- */
- }
- } lws_end_foreach_ll_safe(v);
-
-
- lws_context_unlock(context); /* } context ------------------- */
-
- return 0;
-}
-
-LWS_VISIBLE void
-lws_vhost_destroy(struct lws_vhost *vh)
-{
- struct lws_deferred_free *df = lws_malloc(sizeof(*df), "deferred free");
- struct lws_context *context = vh->context;
-
- if (!df)
- return;
-
- lws_context_lock(context, __func__); /* ------ context { */
-
- lws_vhost_destroy1(vh);
-
- if (!vh->count_bound_wsi) {
- /*
- * After listen handoff, there are already no wsi bound to this
- * vhost by any pt: nothing can be servicing any wsi belonging
- * to it any more.
- *
- * Finalize the vh destruction immediately
- */
- __lws_vhost_destroy2(vh);
- lws_free(df);
-
- goto out;
- }
-
- /* part 2 is deferred to allow all the handle closes to complete */
-
- df->next = vh->context->deferred_free_list;
- df->deadline = lws_now_secs();
- df->payload = vh;
- vh->context->deferred_free_list = df;
-
-out:
- lws_context_unlock(context); /* } context ------------------- */
-}
-
-/*
- * When using an event loop, the context destruction is in three separate
- * parts. This is to cover both internal and foreign event loops cleanly.
- *
- * - lws_context_destroy() simply starts a soft close of all wsi and
- * related allocations. The event loop continues.
- *
- * As the closes complete in the event loop, reference counting is used
- * to determine when everything is closed. It then calls
- * lws_context_destroy2().
- *
- * - lws_context_destroy2() cleans up the rest of the higher-level logical
- * lws pieces like vhosts. If the loop was foreign, it then proceeds to
- * lws_context_destroy3(). If it the loop is internal, it stops the
- * internal loops and waits for lws_context_destroy() to be called again
- * outside the event loop (since we cannot destroy the loop from
- * within the loop). That will cause lws_context_destroy3() to run
- * directly.
- *
- * - lws_context_destroy3() destroys any internal event loops and then
- * destroys the context itself, setting what was info.pcontext to NULL.
- */
-
-/*
- * destroy the actual context itself
- */
-
-static void
-lws_context_destroy3(struct lws_context *context)
-{
- struct lws_context **pcontext_finalize = context->pcontext_finalize;
- int n;
-
- for (n = 0; n < context->count_threads; n++) {
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- struct lws_context_per_thread *pt = &context->pt[n];
-#endif
-
- if (context->event_loop_ops->destroy_pt)
- context->event_loop_ops->destroy_pt(context, n);
-
- lws_free_set_NULL(context->pt[n].serv_buf);
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- while (pt->http.ah_list)
- _lws_destroy_ah(pt, pt->http.ah_list);
-#endif
- }
-
- if (context->pt[0].fds)
- lws_free_set_NULL(context->pt[0].fds);
-
- lws_free(context);
- lwsl_info("%s: ctx %p freed\n", __func__, context);
-
- if (pcontext_finalize)
- *pcontext_finalize = NULL;
-}
-
-/*
- * really start destroying things
- */
-
-void
-lws_context_destroy2(struct lws_context *context)
-{
- struct lws_vhost *vh = NULL, *vh1;
-#if defined(LWS_WITH_PEER_LIMITS)
- uint32_t nu;
-#endif
-
- lwsl_info("%s: ctx %p\n", __func__, context);
-
- lws_context_lock(context, "context destroy 2"); /* ------ context { */
-
- context->being_destroyed2 = 1;
-
- /*
- * free all the per-vhost allocations
- */
-
- vh = context->vhost_list;
- while (vh) {
- vh1 = vh->vhost_next;
- __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 defined(LWS_WITH_PEER_LIMITS)
- for (nu = 0; nu < context->pl_hash_elements; nu++) {
- lws_start_foreach_llp(struct lws_peer **, peer,
- context->pl_hash_table[nu]) {
- struct lws_peer *df = *peer;
- *peer = df->next;
- lws_free(df);
- continue;
- } lws_end_foreach_llp(peer, next);
- }
- lws_free(context->pl_hash_table);
-#endif
-
- if (context->external_baggage_free_on_destroy)
- free(context->external_baggage_free_on_destroy);
-
- lws_check_deferred_free(context, 0, 1);
-
-#if LWS_MAX_SMP > 1
- lws_mutex_refcount_destroy(&context->mr);
-#endif
-
- if (context->event_loop_ops->destroy_context2)
- if (context->event_loop_ops->destroy_context2(context)) {
- lws_context_unlock(context); /* } context ----------- */
- context->finalize_destroy_after_internal_loops_stopped = 1;
- return;
- }
-
- if (!context->pt[0].event_loop_foreign) {
- int n;
- for (n = 0; n < context->count_threads; n++)
- if (context->pt[n].inside_service) {
- lws_context_unlock(context); /* } context --- */
- return;
- }
- }
-
- lws_context_unlock(context); /* } context ------------------- */
-
- lws_context_destroy3(context);
-}
-
-/*
- * Begin the context takedown
- */
-
-LWS_VISIBLE void
-lws_context_destroy(struct lws_context *context)
-{
- volatile struct lws_foreign_thread_pollfd *ftp, *next;
- volatile struct lws_context_per_thread *vpt;
- struct lws_vhost *vh = NULL;
- struct lws wsi;
- int n, m;
-
- if (!context)
- return;
-
- if (context->finalize_destroy_after_internal_loops_stopped) {
- if (context->event_loop_ops->destroy_context2)
- context->event_loop_ops->destroy_context2(context);
-
- lws_context_destroy3(context);
-
- return;
- }
-
- if (context->being_destroyed1) {
- if (!context->being_destroyed2) {
- lws_context_destroy2(context);
-
- return;
- }
- lwsl_info("%s: ctx %p: already being destroyed\n",
- __func__, context);
-
- lws_context_destroy3(context);
- return;
- }
-
- lwsl_info("%s: ctx %p\n", __func__, context);
-
- m = context->count_threads;
- context->being_destroyed = 1;
- context->being_destroyed1 = 1;
- context->requested_kill = 1;
-
- memset(&wsi, 0, sizeof(wsi));
- wsi.context = context;
-
-#ifdef LWS_LATENCY
- if (context->worst_latency_info[0])
- lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
-#endif
-
- while (m--) {
- struct lws_context_per_thread *pt = &context->pt[m];
- vpt = (volatile struct lws_context_per_thread *)pt;
-
- ftp = vpt->foreign_pfd_list;
- while (ftp) {
- next = ftp->next;
- lws_free((void *)ftp);
- ftp = next;
- }
- vpt->foreign_pfd_list = NULL;
-
- 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->event_pipe)
- lws_destroy_event_pipe(wsi);
- else
- lws_close_free_wsi(wsi,
- LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY,
- "ctx destroy"
- /* no protocol close */);
- n--;
- }
- lws_pt_mutex_destroy(pt);
- }
-
- /*
- * inform all the protocols that they are done and will have no more
- * callbacks.
- *
- * We can't free things until after the event loop shuts down.
- */
- if (context->protocol_init_done)
- vh = context->vhost_list;
- while (vh) {
- struct lws_vhost *vhn = vh->vhost_next;
- lws_vhost_destroy1(vh);
- vh = vhn;
- }
-
- lws_plat_context_early_destroy(context);
-
- /*
- * We face two different needs depending if foreign loop or not.
- *
- * 1) If foreign loop, we really want to advance the destroy_context()
- * past here, and block only for libuv-style async close completion.
- *
- * 2a) If poll, and we exited by ourselves and are calling a final
- * destroy_context() outside of any service already, we want to
- * advance all the way in one step.
- *
- * 2b) If poll, and we are reacting to a SIGINT, service thread(s) may
- * be in poll wait or servicing. We can't advance the
- * destroy_context() to the point it's freeing things; we have to
- * leave that for the final destroy_context() after the service
- * thread(s) are finished calling for service.
- */
-
- if (context->event_loop_ops->destroy_context1) {
- context->event_loop_ops->destroy_context1(context);
-
- return;
- }
-
- lws_context_destroy2(context);
-}
diff --git a/thirdparty/libwebsockets/lib/core/dummy-callback.c b/thirdparty/libwebsockets/lib/core/dummy-callback.c
deleted file mode 100644
index 8fd18be9c5..0000000000
--- a/thirdparty/libwebsockets/lib/core/dummy-callback.c
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-
-#include "core/private.h"
-
-#if defined(LWS_WITH_HTTP_PROXY)
-static int
-proxy_header(struct lws *wsi, struct lws *par, unsigned char *temp,
- int temp_len, int index, unsigned char **p, unsigned char *end)
-{
- int n = lws_hdr_total_length(par, index);
-
- if (n < 1) {
- lwsl_debug("%s: no index %d:\n", __func__, index);
- return 0;
- }
-
- if (lws_hdr_copy(par, (char *)temp, temp_len, index) < 0)
- return -1;
-
- lwsl_debug("%s: index %d: %s\n", __func__, index, (char *)temp);
-
- if (lws_add_http_header_by_token(wsi, index, temp, n, p, end))
- return -1;
-
- return 0;
-}
-
-static int
-stream_close(struct lws *wsi)
-{
- char buf[LWS_PRE + 6], *out = buf + LWS_PRE;
-
- if (wsi->http.did_stream_close)
- return 0;
-
- wsi->http.did_stream_close = 1;
-
- if (wsi->http2_substream) {
- if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
- LWS_WRITE_HTTP_FINAL) < 0) {
- lwsl_info("%s: COMPL_CLIENT_HTTP: h2 fin wr failed\n",
- __func__);
-
- return -1;
- }
- } else {
- *out++ = '0';
- *out++ = '\x0d';
- *out++ = '\x0a';
- *out++ = '\x0d';
- *out++ = '\x0a';
-
- if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 5,
- LWS_WRITE_HTTP_FINAL) < 0) {
- lwsl_err("%s: COMPL_CLIENT_HTTP: "
- "h2 final write failed\n", __func__);
-
- return -1;
- }
- }
-
- return 0;
-}
-
-#endif
-
-LWS_VISIBLE int
-lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
- void *user, void *in, size_t len)
-{
- struct lws_ssl_info *si;
-#ifdef LWS_WITH_CGI
- struct lws_cgi_args *args;
-#endif
-#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
- char buf[8192];
- int n;
-#endif
-#if defined(LWS_WITH_HTTP_PROXY)
- unsigned char **p, *end;
- struct lws *parent;
-#endif
-
- switch (reason) {
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- case LWS_CALLBACK_HTTP:
-#ifndef LWS_NO_SERVER
- if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
- return -1;
-
- if (lws_http_transaction_completed(wsi))
-#endif
- return -1;
- break;
-#if !defined(LWS_NO_SERVER)
- case LWS_CALLBACK_HTTP_BODY_COMPLETION:
- 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 (wsi->reason_bf & (LWS_CB_REASON_AUX_BF__CGI_HEADERS |
- LWS_CB_REASON_AUX_BF__CGI)) {
- n = lws_cgi_write_split_stdout_headers(wsi);
- if (n < 0) {
- lwsl_debug("AUX_BF__CGI forcing close\n");
- return -1;
- }
- if (!n)
- lws_rx_flow_control(
- wsi->http.cgi->stdwsi[LWS_STDOUT], 1);
-
- if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
- wsi->reason_bf &=
- ~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
- else
- wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI;
-
- if (wsi->http.cgi && wsi->http.cgi->cgi_transaction_over)
- return -1;
- break;
- }
-
- if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END) {
- if (!wsi->http2_substream) {
- memcpy(buf + LWS_PRE, "0\x0d\x0a\x0d\x0a", 5);
- lwsl_debug("writing chunk term and exiting\n");
- n = lws_write(wsi, (unsigned char *)buf +
- LWS_PRE, 5, LWS_WRITE_HTTP);
- } else
- n = lws_write(wsi, (unsigned char *)buf +
- LWS_PRE, 0,
- LWS_WRITE_HTTP_FINAL);
-
- /* always close after sending it */
- return -1;
- }
-#endif
-#if defined(LWS_WITH_HTTP_PROXY)
-
- if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_HEADERS) {
-
- wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
-
- lwsl_debug("%s: %p: issuing proxy headers\n",
- __func__, wsi);
- n = lws_write(wsi, wsi->http.pending_return_headers +
- LWS_PRE,
- wsi->http.pending_return_headers_len,
- LWS_WRITE_HTTP_HEADERS);
-
- lws_free_set_NULL(wsi->http.pending_return_headers);
-
- if (n < 0) {
- lwsl_err("%s: EST_CLIENT_HTTP: write failed\n",
- __func__);
- return -1;
- }
- lws_callback_on_writable(wsi);
- break;
- }
-
- if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
- char *px = buf + LWS_PRE;
- int lenx = sizeof(buf) - LWS_PRE - 32;
-
- /*
- * 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 &= ~LWS_CB_REASON_AUX_BF__PROXY;
- if (!lws_get_child(wsi))
- break;
-
- /* this causes LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ */
- if (lws_http_client_read(lws_get_child(wsi), &px,
- &lenx) < 0) {
- lwsl_info("%s: LWS_CB_REASON_AUX_BF__PROXY: "
- "client closed\n", __func__);
-
- stream_close(wsi);
-
- return -1;
- }
- break;
- }
-
- if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_TRANS_END) {
- lwsl_info("%s: LWS_CB_REASON_AUX_BF__PROXY_TRANS_END\n",
- __func__);
-
- wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
-
- if (stream_close(wsi))
- return -1;
-
- if (lws_http_transaction_completed(wsi))
- return -1;
- }
-#endif
- break;
-
-#if defined(LWS_WITH_HTTP_PROXY)
- case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
- assert(lws_get_parent(wsi));
- if (!lws_get_parent(wsi))
- break;
- lws_get_parent(wsi)->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
- lws_callback_on_writable(lws_get_parent(wsi));
- break;
-
- case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: {
- char *out = buf + LWS_PRE;
-
- assert(lws_get_parent(wsi));
-
- if (wsi->http.proxy_parent_chunked) {
-
- if (len > sizeof(buf) - LWS_PRE - 16) {
- lwsl_err("oversize buf %d %d\n", (int)len,
- (int)sizeof(buf) - LWS_PRE - 16);
- return -1;
- }
-
- /*
- * this only needs dealing with on http/1.1 to allow
- * pipelining
- */
- n = lws_snprintf(out, 14, "%X\x0d\x0a", (int)len);
- out += n;
- memcpy(out, in, len);
- out += len;
- *out++ = '\x0d';
- *out++ = '\x0a';
-
- n = lws_write(lws_get_parent(wsi),
- (unsigned char *)buf + LWS_PRE,
- len + n + 2, LWS_WRITE_HTTP);
- } else
- n = lws_write(lws_get_parent(wsi), (unsigned char *)in,
- len, LWS_WRITE_HTTP);
- if (n < 0)
- return -1;
- break; }
-
-
- /* this handles the proxy case... */
- case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
- unsigned char *start, *p, *end;
-
- /*
- * We want to proxy these headers, but we are being called
- * at the point the onward client was established, which is
- * unrelated to the state or writability of our proxy
- * connection.
- *
- * Therefore produce the headers using the onward client ah
- * while we have it, and stick them on the output buflist to be
- * written on the proxy connection as soon as convenient.
- */
-
- parent = lws_get_parent(wsi);
-
- if (!parent)
- return 0;
-
- start = p = (unsigned char *)buf + LWS_PRE;
- end = p + sizeof(buf) - LWS_PRE - 256;
-
- if (lws_add_http_header_status(lws_get_parent(wsi),
- lws_http_client_http_response(wsi), &p, end))
- return 1;
-
- /*
- * copy these headers from the client connection to the parent
- */
-
- proxy_header(parent, wsi, end, 256,
- WSI_TOKEN_HTTP_CONTENT_LENGTH, &p, end);
- proxy_header(parent, wsi, end, 256,
- WSI_TOKEN_HTTP_CONTENT_TYPE, &p, end);
- proxy_header(parent, wsi, end, 256,
- WSI_TOKEN_HTTP_ETAG, &p, end);
- proxy_header(parent, wsi, end, 256,
- WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, &p, end);
- proxy_header(parent, wsi, end, 256,
- WSI_TOKEN_HTTP_CONTENT_ENCODING, &p, end);
- proxy_header(parent, wsi, end, 256,
- WSI_TOKEN_HTTP_CACHE_CONTROL, &p, end);
-
- if (!parent->http2_substream)
- if (lws_add_http_header_by_token(parent,
- WSI_TOKEN_CONNECTION, (unsigned char *)"close",
- 5, &p, end))
- return -1;
-
- /*
- * We proxy using h1 only atm, and strip any chunking so it
- * can go back out on h2 just fine.
- *
- * However if we are actually going out on h1, we need to add
- * our own chunking since we still don't know the size.
- */
-
- if (!parent->http2_substream &&
- !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
- lwsl_debug("downstream parent chunked\n");
- if (lws_add_http_header_by_token(parent,
- WSI_TOKEN_HTTP_TRANSFER_ENCODING,
- (unsigned char *)"chunked", 7, &p, end))
- return -1;
-
- wsi->http.proxy_parent_chunked = 1;
- }
-
- if (lws_finalize_http_header(parent, &p, end))
- return 1;
-
- parent->http.pending_return_headers_len =
- lws_ptr_diff(p, start);
- parent->http.pending_return_headers =
- lws_malloc(parent->http.pending_return_headers_len +
- LWS_PRE, "return proxy headers");
- if (!parent->http.pending_return_headers)
- return -1;
-
- memcpy(parent->http.pending_return_headers + LWS_PRE, start,
- parent->http.pending_return_headers_len);
-
- parent->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
-
- lwsl_debug("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: "
- "prepared headers\n", __func__);
- lws_callback_on_writable(parent);
-
- break; }
-
- case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
- lwsl_info("%s: COMPLETED_CLIENT_HTTP: %p (parent %p)\n",
- __func__, wsi, lws_get_parent(wsi));
- if (!lws_get_parent(wsi))
- break;
- lws_get_parent(wsi)->reason_bf |=
- LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
- lws_callback_on_writable(lws_get_parent(wsi));
- break;
-
- case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
- if (!lws_get_parent(wsi))
- break;
- lwsl_err("%s: LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", __func__);
- lws_set_timeout(lws_get_parent(wsi), LWS_TO_KILL_ASYNC,
- PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE);
- break;
-
- case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
- parent = lws_get_parent(wsi);
-
- if (!parent)
- break;
-
- p = (unsigned char **)in;
- end = (*p) + len;
-
- /*
- * copy these headers from the parent request to the client
- * connection's request
- */
-
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HOST, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_ETAG, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_ACCEPT_ENCODING, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_CACHE_CONTROL, p, end);
-
- buf[0] = '\0';
- lws_get_peer_simple(parent, buf, sizeof(buf));
- if (lws_add_http_header_by_token(wsi, WSI_TOKEN_X_FORWARDED_FOR,
- (unsigned char *)buf, (int)strlen(buf), p, end))
- return -1;
-
- break;
-
-#endif
-
-#ifdef LWS_WITH_CGI
- /* CGI IO events (POLLIN/OUT) appear here, our default policy is:
- *
- * - POST data goes on subprocess stdin
- * - subprocess stdout goes on http via writeable callback
- * - subprocess stderr goes to the logs
- */
- case LWS_CALLBACK_CGI:
- args = (struct lws_cgi_args *)in;
- switch (args->ch) { /* which of stdin/out/err ? */
- case LWS_STDIN:
- /* TBD stdin rx flow control */
- break;
- case LWS_STDOUT:
- /* quench POLLIN on STDOUT until MASTER got writeable */
- lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
- wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
- /* when writing to MASTER would not block */
- lws_callback_on_writable(wsi);
- break;
- case LWS_STDERR:
- n = lws_get_socket_fd(args->stdwsi[LWS_STDERR]);
- if (n < 0)
- break;
- n = read(n, buf, sizeof(buf) - 2);
- if (n > 0) {
- if (buf[n - 1] != '\n')
- buf[n++] = '\n';
- buf[n] = '\0';
- lwsl_notice("CGI-stderr: %s\n", buf);
- }
- break;
- }
- break;
-
- case LWS_CALLBACK_CGI_TERMINATED:
- lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: %d %" PRIu64 "\n",
- wsi->http.cgi->explicitly_chunked,
- (uint64_t)wsi->http.cgi->content_length);
- if (!wsi->http.cgi->explicitly_chunked &&
- !wsi->http.cgi->content_length) {
- /* send terminating chunk */
- lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: ending\n");
- wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
- lws_callback_on_writable(wsi);
- lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);
- break;
- }
- return -1;
-
- case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
- args = (struct lws_cgi_args *)in;
- args->data[args->len] = '\0';
- if (!args->stdwsi[LWS_STDIN])
- return -1;
- n = lws_get_socket_fd(args->stdwsi[LWS_STDIN]);
- if (n < 0)
- return -1;
-
-#if defined(LWS_WITH_ZLIB)
- if (wsi->http.cgi->gzip_inflate) {
- /* gzip handling */
-
- if (!wsi->http.cgi->gzip_init) {
- lwsl_info("inflating gzip\n");
-
- memset(&wsi->http.cgi->inflate, 0,
- sizeof(wsi->http.cgi->inflate));
-
- if (inflateInit2(&wsi->http.cgi->inflate,
- 16 + 15) != Z_OK) {
- lwsl_err("%s: iniflateInit failed\n",
- __func__);
- return -1;
- }
-
- wsi->http.cgi->gzip_init = 1;
- }
-
- wsi->http.cgi->inflate.next_in = args->data;
- wsi->http.cgi->inflate.avail_in = args->len;
-
- do {
-
- wsi->http.cgi->inflate.next_out =
- wsi->http.cgi->inflate_buf;
- wsi->http.cgi->inflate.avail_out =
- sizeof(wsi->http.cgi->inflate_buf);
-
- n = inflate(&wsi->http.cgi->inflate,
- Z_SYNC_FLUSH);
-
- switch (n) {
- case Z_NEED_DICT:
- case Z_STREAM_ERROR:
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- inflateEnd(&wsi->http.cgi->inflate);
- wsi->http.cgi->gzip_init = 0;
- lwsl_err("zlib error inflate %d\n", n);
- return -1;
- }
-
- if (wsi->http.cgi->inflate.avail_out !=
- sizeof(wsi->http.cgi->inflate_buf)) {
- int written;
-
- written = write(args->stdwsi[LWS_STDIN]->desc.filefd,
- wsi->http.cgi->inflate_buf,
- sizeof(wsi->http.cgi->inflate_buf) -
- wsi->http.cgi->inflate.avail_out);
-
- if (written != (int)(
- sizeof(wsi->http.cgi->inflate_buf) -
- wsi->http.cgi->inflate.avail_out)) {
- lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
- "sent %d only %d went", n, args->len);
- }
-
- if (n == Z_STREAM_END) {
- lwsl_err("gzip inflate end\n");
- inflateEnd(&wsi->http.cgi->inflate);
- wsi->http.cgi->gzip_init = 0;
- break;
- }
-
- } else
- break;
-
- if (wsi->http.cgi->inflate.avail_out)
- break;
-
- } while (1);
-
- return args->len;
- }
-#endif /* WITH_ZLIB */
-
- n = write(n, args->data, args->len);
-// lwsl_hexdump_notice(args->data, args->len);
- if (n < args->len)
- lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
- "sent %d only %d went", n, args->len);
-
- if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] &&
- args->stdwsi[LWS_STDIN]->desc.filefd > 0) {
- wsi->http.cgi->post_in_expected -= n;
- if (!wsi->http.cgi->post_in_expected) {
- struct lws *siwsi = args->stdwsi[LWS_STDIN];
-
- lwsl_debug("%s: expected POST in end: "
- "closing stdin wsi %p, fd %d\n",
- __func__, siwsi, siwsi->desc.sockfd);
-
- __remove_wsi_socket_from_fds(siwsi);
- lwsi_set_state(siwsi, LRS_DEAD_SOCKET);
- siwsi->socket_is_permanently_unusable = 1;
- lws_remove_child_from_any_parent(siwsi);
- if (wsi->context->event_loop_ops->
- close_handle_manually) {
- wsi->context->event_loop_ops->
- close_handle_manually(siwsi);
- siwsi->told_event_loop_closed = 1;
- } else {
- compatible_close(siwsi->desc.sockfd);
- __lws_free_wsi(siwsi);
- }
- wsi->http.cgi->pipe_fds[LWS_STDIN][1] = -1;
-
- args->stdwsi[LWS_STDIN] = NULL;
- }
- }
-
- return n;
-#endif /* WITH_CGI */
-#endif /* ROLE_ H1 / H2 */
- case LWS_CALLBACK_SSL_INFO:
- si = in;
-
- (void)si;
- lwsl_notice("LWS_CALLBACK_SSL_INFO: where: 0x%x, ret: 0x%x\n",
- si->where, si->ret);
- break;
-
-#if LWS_MAX_SMP > 1
- case LWS_CALLBACK_GET_THREAD_ID:
- return (int)(unsigned long long)pthread_self();
-#endif
-
- default:
- break;
- }
-
- return 0;
-}
diff --git a/thirdparty/libwebsockets/lib/core/libwebsockets.c b/thirdparty/libwebsockets/lib/core/libwebsockets.c
deleted file mode 100644
index 972422114a..0000000000
--- a/thirdparty/libwebsockets/lib/core/libwebsockets.c
+++ /dev/null
@@ -1,3986 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-
-#include "core/private.h"
-
-#ifdef LWS_HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef LWS_WITH_IPV6
-#if defined(WIN32) || defined(_WIN32)
-#include <wincrypt.h>
-#include <iphlpapi.h>
-#else
-#include <net/if.h>
-#endif
-#endif
-
-int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE;
-static void (*lwsl_emit)(int level, const char *line)
-#ifndef LWS_PLAT_OPTEE
- = lwsl_emit_stderr
-#endif
- ;
-#ifndef LWS_PLAT_OPTEE
-static const char * const log_level_names[] = {
- "ERR",
- "WARN",
- "NOTICE",
- "INFO",
- "DEBUG",
- "PARSER",
- "HEADER",
- "EXTENSION",
- "CLIENT",
- "LATENCY",
- "USER",
- "THREAD",
- "?",
- "?"
-};
-#endif
-
-#if defined (_DEBUG)
-void lwsi_set_role(struct lws *wsi, lws_wsi_state_t role)
-{
- wsi->wsistate = (wsi->wsistate & (~LWSI_ROLE_MASK)) | role;
-
- lwsl_debug("lwsi_set_role(%p, 0x%x)\n", wsi, wsi->wsistate);
-}
-
-void lwsi_set_state(struct lws *wsi, lws_wsi_state_t lrs)
-{
- wsi->wsistate = (wsi->wsistate & (~LRS_MASK)) | lrs;
-
- lwsl_debug("lwsi_set_state(%p, 0x%x)\n", wsi, wsi->wsistate);
-}
-#endif
-
-signed char char_to_hex(const char c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
-
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
-
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
-
- return -1;
-}
-
-int lws_open(const char *__file, int __oflag, ...)
-{
- va_list ap;
- int n;
-
- va_start(ap, __oflag);
- if (((__oflag & O_CREAT) == O_CREAT)
-#if defined(O_TMPFILE)
- || ((__oflag & O_TMPFILE) == O_TMPFILE)
-#endif
- )
- /* last arg is really a mode_t. But windows... */
- n = open(__file, __oflag, va_arg(ap, uint32_t));
- else
- n = open(__file, __oflag);
- va_end(ap);
-
- if (n != -1 && lws_plat_apply_FD_CLOEXEC(n)) {
- close(n);
-
- return -1;
- }
-
- return n;
-}
-
-void
-lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi)
-{
- if (wsi->vhost == vh)
- return;
- lws_context_lock(vh->context, __func__); /* ---------- context { */
- wsi->vhost = vh;
- vh->count_bound_wsi++;
- lws_context_unlock(vh->context); /* } context ---------- */
- lwsl_info("%s: vh %s: count_bound_wsi %d\n",
- __func__, vh->name, vh->count_bound_wsi);
- assert(wsi->vhost->count_bound_wsi > 0);
-}
-
-void
-lws_vhost_unbind_wsi(struct lws *wsi)
-{
- if (!wsi->vhost)
- return;
-
- lws_context_lock(wsi->context, __func__); /* ---------- context { */
-
- assert(wsi->vhost->count_bound_wsi > 0);
- wsi->vhost->count_bound_wsi--;
- lwsl_info("%s: vh %s: count_bound_wsi %d\n", __func__,
- wsi->vhost->name, wsi->vhost->count_bound_wsi);
-
- if (!wsi->vhost->count_bound_wsi &&
- wsi->vhost->being_destroyed) {
- /*
- * We have closed all wsi that were bound to this vhost
- * by any pt: nothing can be servicing any wsi belonging
- * to it any more.
- *
- * Finalize the vh destruction
- */
- __lws_vhost_destroy2(wsi->vhost);
- }
- wsi->vhost = NULL;
-
- lws_context_unlock(wsi->context); /* } context ---------- */
-}
-
-void
-__lws_free_wsi(struct lws *wsi)
-{
- if (!wsi)
- return;
-
- /*
- * Protocol user data may be allocated either internally by lws
- * or by specified the user. We should only free what we allocated.
- */
- if (wsi->protocol && wsi->protocol->per_session_data_size &&
- wsi->user_space && !wsi->user_space_externally_allocated)
- lws_free(wsi->user_space);
-
- lws_buflist_destroy_all_segments(&wsi->buflist);
- lws_buflist_destroy_all_segments(&wsi->buflist_out);
- lws_free_set_NULL(wsi->udp);
-
- if (wsi->vhost && wsi->vhost->lserv_wsi == wsi)
- wsi->vhost->lserv_wsi = NULL;
-#if !defined(LWS_NO_CLIENT)
- lws_dll_lws_remove(&wsi->dll_active_client_conns);
-#endif
- wsi->context->count_wsi_allocated--;
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- __lws_header_table_detach(wsi, 0);
-#endif
- __lws_same_vh_protocol_remove(wsi);
-#if !defined(LWS_NO_CLIENT)
- lws_client_stash_destroy(wsi);
- lws_free_set_NULL(wsi->client_hostname_copy);
-#endif
-
- if (wsi->role_ops->destroy_role)
- wsi->role_ops->destroy_role(wsi);
-
-#if defined(LWS_WITH_PEER_LIMITS)
- lws_peer_track_wsi_close(wsi->context, wsi->peer);
- wsi->peer = NULL;
-#endif
-
- /* since we will destroy the wsi, make absolutely sure now */
-
-#if defined(LWS_WITH_OPENSSL)
- __lws_ssl_remove_wsi_from_buffered_list(wsi);
-#endif
- __lws_remove_from_timeout_list(wsi);
-
- if (wsi->context->event_loop_ops->destroy_wsi)
- wsi->context->event_loop_ops->destroy_wsi(wsi);
-
- lws_vhost_unbind_wsi(wsi);
-
- lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
- wsi->context->count_wsi_allocated);
-
- lws_free(wsi);
-}
-
-void
-lws_dll_add_front(struct lws_dll *d, struct lws_dll *phead)
-{
- if (d->prev)
- return;
-
- /* our next guy is current first guy */
- d->next = phead->next;
- /* if there is a next guy, set his prev ptr to our next ptr */
- if (d->next)
- d->next->prev = d;
- /* our prev ptr is first ptr */
- d->prev = phead;
- /* set the first guy to be us */
- phead->next = d;
-}
-
-/* situation is:
- *
- * HEAD: struct lws_dll * = &entry1
- *
- * Entry 1: struct lws_dll .pprev = &HEAD , .next = Entry 2
- * Entry 2: struct lws_dll .pprev = &entry1 , .next = &entry2
- * Entry 3: struct lws_dll .pprev = &entry2 , .next = NULL
- *
- * Delete Entry1:
- *
- * - HEAD = &entry2
- * - Entry2: .pprev = &HEAD, .next = &entry3
- * - Entry3: .pprev = &entry2, .next = NULL
- *
- * Delete Entry2:
- *
- * - HEAD = &entry1
- * - Entry1: .pprev = &HEAD, .next = &entry3
- * - Entry3: .pprev = &entry1, .next = NULL
- *
- * Delete Entry3:
- *
- * - HEAD = &entry1
- * - Entry1: .pprev = &HEAD, .next = &entry2
- * - Entry2: .pprev = &entry1, .next = NULL
- *
- */
-
-void
-lws_dll_remove(struct lws_dll *d)
-{
- if (!d->prev) /* ie, not part of the list */
- return;
-
- /*
- * remove us
- *
- * USp <-> us <-> USn --> USp <-> USn
- */
-
- /* if we have a next guy, set his prev to our prev */
- if (d->next)
- d->next->prev = d->prev;
-
- /* set our prev guy to our next guy instead of us */
- if (d->prev)
- d->prev->next = d->next;
-
- /* we're out of the list, we should not point anywhere any more */
- d->prev = NULL;
- d->next = NULL;
-}
-
-void
-__lws_remove_from_timeout_list(struct lws *wsi)
-{
- lws_dll_lws_remove(&wsi->dll_timeout);
-}
-
-void
-lws_remove_from_timeout_list(struct lws *wsi)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-
- lws_pt_lock(pt, __func__);
- __lws_remove_from_timeout_list(wsi);
- lws_pt_unlock(pt);
-}
-
-void
-lws_dll_dump(struct lws_dll_lws *head, const char *title)
-{
- int n = 0;
-
- (void)n;
- lwsl_notice("%s: %s (head.next %p)\n", __func__, title, head->next);
-
- lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1, head->next) {
- struct lws *wsi = lws_container_of(d, struct lws, dll_hrtimer);
-
- (void)wsi;
-
- lwsl_notice(" %d: wsi %p: %llu\n", n++, wsi,
- (unsigned long long)wsi->pending_timer);
- } lws_end_foreach_dll_safe(d, d1);
-}
-
-void
-__lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
- struct lws_dll_lws *dd = &pt->dll_head_hrtimer;
- struct timeval now;
- struct lws *wsi1;
- int bef = 0;
-
- lws_dll_lws_remove(&wsi->dll_hrtimer);
-
- if (usecs == LWS_SET_TIMER_USEC_CANCEL)
- return;
-
- gettimeofday(&now, NULL);
- wsi->pending_timer = ((now.tv_sec * 1000000ll) + now.tv_usec) + usecs;
-
- /*
- * we sort the hrtimer list with the earliest timeout first
- */
-
- lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
- pt->dll_head_hrtimer.next) {
- dd = d;
- wsi1 = lws_container_of(d, struct lws, dll_hrtimer);
-
- if (wsi1->pending_timer >= wsi->pending_timer) {
- /* d, dprev's next, is >= our time */
- bef = 1;
- break;
- }
- } lws_end_foreach_dll_safe(d, d1);
-
- if (bef) {
- /*
- * we go before dd
- * DDp <-> DD <-> DDn --> DDp <-> us <-> DD <-> DDn
- */
- /* we point forward to dd */
- wsi->dll_hrtimer.next = dd;
- /* we point back to what dd used to point back to */
- wsi->dll_hrtimer.prev = dd->prev;
- /* DDp points forward to us now */
- dd->prev->next = &wsi->dll_hrtimer;
- /* DD points back to us now */
- dd->prev = &wsi->dll_hrtimer;
- } else {
- /*
- * we go after dd
- * DDp <-> DD <-> DDn --> DDp <-> DD <-> us <-> DDn
- */
- /* we point forward to what dd used to point forward to */
- wsi->dll_hrtimer.next = dd->next;
- /* we point back to dd */
- wsi->dll_hrtimer.prev = dd;
- /* DDn points back to us */
- if (dd->next)
- dd->next->prev = &wsi->dll_hrtimer;
- /* DD points forward to us */
- dd->next = &wsi->dll_hrtimer;
- }
-
-// lws_dll_dump(&pt->dll_head_hrtimer, "after set_timer_usec");
-}
-
-LWS_VISIBLE lws_usec_t
-lws_now_usecs(void)
-{
- struct timeval now;
-
- gettimeofday(&now, NULL);
- return (now.tv_sec * 1000000ll) + now.tv_usec;
-}
-
-LWS_VISIBLE void
-lws_set_timer_usecs(struct lws *wsi, lws_usec_t usecs)
-{
- __lws_set_timer_usecs(wsi, usecs);
-}
-
-lws_usec_t
-__lws_hrtimer_service(struct lws_context_per_thread *pt)
-{
- struct timeval now;
- struct lws *wsi;
- lws_usec_t t;
-
- gettimeofday(&now, NULL);
- t = (now.tv_sec * 1000000ll) + now.tv_usec;
-
- lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
- pt->dll_head_hrtimer.next) {
- wsi = lws_container_of(d, struct lws, dll_hrtimer);
-
- /*
- * if we met one in the future, we are done, because the list
- * is sorted by time in the future.
- */
- if (wsi->pending_timer > t)
- break;
-
- lws_set_timer_usecs(wsi, LWS_SET_TIMER_USEC_CANCEL);
-
- /* it's time for the timer to be serviced */
-
- if (wsi->protocol &&
- wsi->protocol->callback(wsi, LWS_CALLBACK_TIMER,
- wsi->user_space, NULL, 0))
- __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
- "timer cb errored");
- } lws_end_foreach_dll_safe(d, d1);
-
- /* return an estimate how many us until next timer hit */
-
- if (!pt->dll_head_hrtimer.next)
- return LWS_HRTIMER_NOWAIT;
-
- wsi = lws_container_of(pt->dll_head_hrtimer.next, struct lws,
- dll_hrtimer);
-
- gettimeofday(&now, NULL);
- t = (now.tv_sec * 1000000ll) + now.tv_usec;
-
- if (wsi->pending_timer < t)
- return 0;
-
- return wsi->pending_timer - t;
-}
-
-void
-__lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
- time_t now;
-
- time(&now);
-
- lwsl_debug("%s: %p: %d secs (reason %d)\n", __func__, wsi, secs, reason);
- wsi->pending_timeout_limit = secs;
- wsi->pending_timeout_set = now;
- wsi->pending_timeout = reason;
-
- if (!reason)
- lws_dll_lws_remove(&wsi->dll_timeout);
- else
- lws_dll_lws_add_front(&wsi->dll_timeout, &pt->dll_head_timeout);
-}
-
-LWS_VISIBLE void
-lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-
- if (secs == LWS_TO_KILL_SYNC) {
- lws_remove_from_timeout_list(wsi);
- lwsl_debug("synchronously killing %p\n", wsi);
- lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
- "to sync kill");
- return;
- }
-
- if (secs == LWS_TO_KILL_ASYNC)
- secs = 0;
-
- lws_pt_lock(pt, __func__);
- __lws_set_timeout(wsi, reason, secs);
- lws_pt_unlock(pt);
-}
-
-/* requires context + vh lock */
-
-int
-__lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p)
-{
- lws_start_foreach_llp(struct lws_timed_vh_protocol **, pt,
- vh->timed_vh_protocol_list) {
- if (*pt == p) {
- *pt = p->next;
- lws_free(p);
-
- return 0;
- }
- } lws_end_foreach_llp(pt, next);
-
- return 1;
-}
-
-int
-lws_pthread_self_to_tsi(struct lws_context *context)
-{
-#if LWS_MAX_SMP > 1
- pthread_t ps = pthread_self();
- struct lws_context_per_thread *pt = &context->pt[0];
- int n;
-
- for (n = 0; n < context->count_threads; n++) {
- if (pthread_equal(ps, pt->self))
- return n;
- pt++;
- }
-
- return -1;
-#else
- return 0;
-#endif
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_timed_callback_vh_protocol(struct lws_vhost *vh,
- const struct lws_protocols *prot, int reason,
- int secs)
-{
- struct lws_timed_vh_protocol *p = (struct lws_timed_vh_protocol *)
- lws_malloc(sizeof(*p), "timed_vh");
-
- if (!p)
- return 1;
-
- p->tsi_req = lws_pthread_self_to_tsi(vh->context);
- if (p->tsi_req < 0) /* not called from a service thread --> tsi 0 */
- p->tsi_req = 0;
-
- lws_context_lock(vh->context, __func__); /* context ----------------- */
-
- p->protocol = prot;
- p->reason = reason;
- p->time = lws_now_secs() + secs;
-
- lws_vhost_lock(vh); /* vhost ---------------------------------------- */
- p->next = vh->timed_vh_protocol_list;
- vh->timed_vh_protocol_list = p;
- lws_vhost_unlock(vh); /* -------------------------------------- vhost */
-
- lws_context_unlock(vh->context); /* ------------------------- context */
-
- return 0;
-}
-
-void
-lws_remove_child_from_any_parent(struct lws *wsi)
-{
- struct lws **pwsi;
- int seen = 0;
-
- if (!wsi->parent)
- return;
-
- /* detach ourselves from parent's child list */
- pwsi = &wsi->parent->child_list;
- while (*pwsi) {
- if (*pwsi == wsi) {
- lwsl_info("%s: detach %p from parent %p\n", __func__,
- wsi, wsi->parent);
-
- if (wsi->parent->protocol)
- wsi->parent->protocol->callback(wsi,
- LWS_CALLBACK_CHILD_CLOSING,
- wsi->parent->user_space, wsi, 0);
-
- *pwsi = wsi->sibling_list;
- seen = 1;
- break;
- }
- pwsi = &(*pwsi)->sibling_list;
- }
- if (!seen)
- lwsl_err("%s: failed to detach from parent\n", __func__);
-
- wsi->parent = NULL;
-}
-
-int
-lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
- const char *reason)
-{
-// if (wsi->protocol == p)
-// return 0;
- const struct lws_protocols *vp = wsi->vhost->protocols, *vpo;
-
- if (wsi->protocol && wsi->protocol_bind_balance) {
- wsi->protocol->callback(wsi,
- wsi->role_ops->protocol_unbind_cb[!!lwsi_role_server(wsi)],
- wsi->user_space, (void *)reason, 0);
- wsi->protocol_bind_balance = 0;
- }
- if (!wsi->user_space_externally_allocated)
- lws_free_set_NULL(wsi->user_space);
-
- lws_same_vh_protocol_remove(wsi);
-
- wsi->protocol = p;
- if (!p)
- return 0;
-
- if (lws_ensure_user_space(wsi))
- return 1;
-
- if (p > vp && p < &vp[wsi->vhost->count_protocols])
- lws_same_vh_protocol_insert(wsi, (int)(p - vp));
- else {
- int n = wsi->vhost->count_protocols;
- int hit = 0;
-
- vpo = vp;
-
- while (n--) {
- if (p->name && vp->name && !strcmp(p->name, vp->name)) {
- hit = 1;
- lws_same_vh_protocol_insert(wsi, (int)(vp - vpo));
- break;
- }
- vp++;
- }
- if (!hit)
- lwsl_err("%s: %p is not in vhost '%s' protocols list\n",
- __func__, p, wsi->vhost->name);
- }
-
- if (wsi->protocol->callback(wsi, wsi->role_ops->protocol_bind_cb[
- !!lwsi_role_server(wsi)],
- wsi->user_space, NULL, 0))
- return 1;
-
- wsi->protocol_bind_balance = 1;
-
- return 0;
-}
-
-void
-__lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
- const char *caller)
-{
- struct lws_context_per_thread *pt;
- struct lws *wsi1, *wsi2;
- struct lws_context *context;
- int n;
-
- lwsl_info("%s: %p: caller: %s\n", __func__, wsi, caller);
-
- if (!wsi)
- return;
-
- lws_access_log(wsi);
-
- context = wsi->context;
- pt = &context->pt[(int)wsi->tsi];
- lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_CLOSE, 1);
-
-#if !defined(LWS_NO_CLIENT)
-
- lws_free_set_NULL(wsi->client_hostname_copy);
- /* we are no longer an active client connection that can piggyback */
- lws_dll_lws_remove(&wsi->dll_active_client_conns);
-
- /*
- * if we have wsi in our transaction queue, if we are closing we
- * must go through and close all those first
- */
- if (wsi->vhost) {
- if ((int)reason != -1)
- lws_vhost_lock(wsi->vhost);
- lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
- wsi->dll_client_transaction_queue_head.next) {
- struct lws *w = lws_container_of(d, struct lws,
- dll_client_transaction_queue);
-
- __lws_close_free_wsi(w, -1, "trans q leader closing");
- } lws_end_foreach_dll_safe(d, d1);
-
- /*
- * !!! If we are closing, but we have pending pipelined
- * transaction results we already sent headers for, that's going
- * to destroy sync for HTTP/1 and leave H2 stream with no live
- * swsi.
- *
- * However this is normal if we are being closed because the
- * transaction queue leader is closing.
- */
- lws_dll_lws_remove(&wsi->dll_client_transaction_queue);
- if ((int)reason !=-1)
- lws_vhost_unlock(wsi->vhost);
- }
-#endif
-
- /* if we have children, close them first */
- if (wsi->child_list) {
- wsi2 = wsi->child_list;
- while (wsi2) {
- wsi1 = wsi2->sibling_list;
- wsi2->parent = NULL;
- /* stop it doing shutdown processing */
- wsi2->socket_is_permanently_unusable = 1;
- __lws_close_free_wsi(wsi2, reason,
- "general child recurse");
- wsi2 = wsi1;
- }
- wsi->child_list = NULL;
- }
-
- if (wsi->role_ops == &role_ops_raw_file) {
- lws_remove_child_from_any_parent(wsi);
- __remove_wsi_socket_from_fds(wsi);
- wsi->protocol->callback(wsi, wsi->role_ops->close_cb[0],
- wsi->user_space, NULL, 0);
- goto async_close;
- }
-
- wsi->wsistate_pre_close = wsi->wsistate;
-
-#ifdef LWS_WITH_CGI
- if (wsi->role_ops == &role_ops_cgi) {
- /* we are not a network connection, but a handler for CGI io */
- if (wsi->parent && wsi->parent->http.cgi) {
-
- if (wsi->cgi_channel == LWS_STDOUT)
- lws_cgi_remove_and_kill(wsi->parent);
-
- /* end the binding between us and master */
- wsi->parent->http.cgi->stdwsi[(int)wsi->cgi_channel] =
- NULL;
- }
- wsi->socket_is_permanently_unusable = 1;
-
- goto just_kill_connection;
- }
-
- if (wsi->http.cgi)
- lws_cgi_remove_and_kill(wsi);
-#endif
-
-#if !defined(LWS_NO_CLIENT)
- lws_client_stash_destroy(wsi);
-#endif
-
- if (wsi->role_ops == &role_ops_raw_skt) {
- wsi->socket_is_permanently_unusable = 1;
- goto just_kill_connection;
- }
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- if (lwsi_role_http(wsi) && lwsi_role_server(wsi) &&
- wsi->http.fop_fd != NULL)
- lws_vfs_file_close(&wsi->http.fop_fd);
-#endif
-
- if (lwsi_state(wsi) == LRS_DEAD_SOCKET)
- return;
-
- if (wsi->socket_is_permanently_unusable ||
- reason == LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY ||
- lwsi_state(wsi) == LRS_SHUTDOWN)
- goto just_kill_connection;
-
- switch (lwsi_state_PRE_CLOSE(wsi)) {
- case LRS_DEAD_SOCKET:
- return;
-
- /* we tried the polite way... */
- case LRS_WAITING_TO_SEND_CLOSE:
- case LRS_AWAITING_CLOSE_ACK:
- case LRS_RETURNED_CLOSE:
- goto just_kill_connection;
-
- case LRS_FLUSHING_BEFORE_CLOSE:
- if (lws_has_buffered_out(wsi)
-#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
- || wsi->http.comp_ctx.buflist_comp ||
- wsi->http.comp_ctx.may_have_more
-#endif
- ) {
- lws_callback_on_writable(wsi);
- return;
- }
- lwsl_info("%p: end LRS_FLUSHING_BEFORE_CLOSE\n", wsi);
- goto just_kill_connection;
- default:
- if (lws_has_buffered_out(wsi)
-#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
- || wsi->http.comp_ctx.buflist_comp ||
- wsi->http.comp_ctx.may_have_more
-#endif
- ) {
- lwsl_info("%p: LRS_FLUSHING_BEFORE_CLOSE\n", wsi);
- lwsi_set_state(wsi, LRS_FLUSHING_BEFORE_CLOSE);
- __lws_set_timeout(wsi,
- PENDING_FLUSH_STORED_SEND_BEFORE_CLOSE, 5);
- return;
- }
- break;
- }
-
- if (lwsi_state(wsi) == LRS_WAITING_CONNECT ||
- lwsi_state(wsi) == LRS_H1C_ISSUE_HANDSHAKE)
- goto just_kill_connection;
-
- if (!wsi->told_user_closed && wsi->user_space && wsi->protocol &&
- wsi->protocol_bind_balance) {
- wsi->protocol->callback(wsi,
- wsi->role_ops->protocol_unbind_cb[
- !!lwsi_role_server(wsi)],
- wsi->user_space, (void *)__func__, 0);
- wsi->protocol_bind_balance = 0;
- }
-
- /*
- * signal we are closing, lws_write will
- * add any necessary version-specific stuff. If the write fails,
- * no worries we are closing anyway. If we didn't initiate this
- * close, then our state has been changed to
- * LRS_RETURNED_CLOSE and we will skip this.
- *
- * Likewise if it's a second call to close this connection after we
- * sent the close indication to the peer already, we are in state
- * LRS_AWAITING_CLOSE_ACK and will skip doing this a second time.
- */
-
- if (wsi->role_ops->close_via_role_protocol &&
- wsi->role_ops->close_via_role_protocol(wsi, reason))
- return;
-
-just_kill_connection:
-
- if (wsi->role_ops->close_kill_connection)
- wsi->role_ops->close_kill_connection(wsi, reason);
-
- lws_remove_child_from_any_parent(wsi);
- n = 0;
-
- if (!wsi->told_user_closed && wsi->user_space &&
- wsi->protocol_bind_balance) {
- lwsl_debug("%s: %p: DROP_PROTOCOL %s\n", __func__, wsi,
- wsi->protocol->name);
- wsi->protocol->callback(wsi,
- wsi->role_ops->protocol_unbind_cb[
- !!lwsi_role_server(wsi)],
- wsi->user_space, (void *)__func__, 0);
- wsi->protocol_bind_balance = 0;
- }
-
- if ((lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY ||
- lwsi_state(wsi) == LRS_WAITING_CONNECT) && !wsi->already_did_cce)
- wsi->protocol->callback(wsi,
- LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
- wsi->user_space, NULL, 0);
-
- /*
- * Testing with ab shows that we have to stage the socket close when
- * the system is under stress... shutdown any further TX, change the
- * state to one that won't emit anything more, and wait with a timeout
- * for the POLLIN to show a zero-size rx before coming back and doing
- * the actual close.
- */
- if (wsi->role_ops != &role_ops_raw_skt && !lwsi_role_client(wsi) &&
- lwsi_state(wsi) != LRS_SHUTDOWN &&
- lwsi_state(wsi) != LRS_UNCONNECTED &&
- reason != LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY &&
- !wsi->socket_is_permanently_unusable) {
-
-#if defined(LWS_WITH_TLS)
- if (lws_is_ssl(wsi) && wsi->tls.ssl) {
- n = 0;
- switch (__lws_tls_shutdown(wsi)) {
- case LWS_SSL_CAPABLE_DONE:
- case LWS_SSL_CAPABLE_ERROR:
- case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
- case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
- case LWS_SSL_CAPABLE_MORE_SERVICE:
- break;
- }
- } else
-#endif
- {
- lwsl_info("%s: shutdown conn: %p (sk %d, state 0x%x)\n",
- __func__, wsi, (int)(long)wsi->desc.sockfd,
- lwsi_state(wsi));
- if (!wsi->socket_is_permanently_unusable &&
- lws_socket_is_valid(wsi->desc.sockfd)) {
- wsi->socket_is_permanently_unusable = 1;
- n = shutdown(wsi->desc.sockfd, SHUT_WR);
- }
- }
- if (n)
- lwsl_debug("closing: shutdown (state 0x%x) ret %d\n",
- lwsi_state(wsi), LWS_ERRNO);
-
- /*
- * This causes problems on WINCE / ESP32 with disconnection
- * when the events are half closing connection
- */
-#if !defined(_WIN32_WCE) && !defined(LWS_WITH_ESP32)
- /* libuv: no event available to guarantee completion */
- if (!wsi->socket_is_permanently_unusable &&
- lws_socket_is_valid(wsi->desc.sockfd) &&
- lwsi_state(wsi) != LRS_SHUTDOWN &&
- context->event_loop_ops->periodic_events_available) {
- __lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
- lwsi_set_state(wsi, LRS_SHUTDOWN);
- __lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,
- context->timeout_secs);
-
- return;
- }
-#endif
- }
-
- lwsl_debug("%s: real just_kill_connection: %p (sockfd %d)\n", __func__,
- wsi, wsi->desc.sockfd);
-
-#ifdef LWS_WITH_HUBBUB
- if (wsi->http.rw) {
- lws_rewrite_destroy(wsi->http.rw);
- wsi->http.rw = NULL;
- }
-#endif
-
- if (wsi->http.pending_return_headers)
- lws_free_set_NULL(wsi->http.pending_return_headers);
-
- /*
- * we won't be servicing or receiving anything further from this guy
- * delete socket from the internal poll list if still present
- */
- __lws_ssl_remove_wsi_from_buffered_list(wsi);
- __lws_remove_from_timeout_list(wsi);
- lws_dll_lws_remove(&wsi->dll_hrtimer);
-
- /* don't repeat event loop stuff */
- if (wsi->told_event_loop_closed)
- return;
-
- /* checking return redundant since we anyway close */
- if (wsi->desc.sockfd != LWS_SOCK_INVALID)
- __remove_wsi_socket_from_fds(wsi);
- else
- __lws_same_vh_protocol_remove(wsi);
-
- lwsi_set_state(wsi, LRS_DEAD_SOCKET);
- lws_buflist_destroy_all_segments(&wsi->buflist);
- lws_dll_lws_remove(&wsi->dll_buflist);
-
- if (wsi->role_ops->close_role)
- wsi->role_ops->close_role(pt, wsi);
-
- /* tell the user it's all over for this guy */
-
- if ((lwsi_state_est_PRE_CLOSE(wsi) ||
- lwsi_state_PRE_CLOSE(wsi) == LRS_WAITING_SERVER_REPLY) &&
- !wsi->told_user_closed &&
- wsi->role_ops->close_cb[lwsi_role_server(wsi)]) {
- const struct lws_protocols *pro = wsi->protocol;
-
- if (!wsi->protocol)
- pro = &wsi->vhost->protocols[0];
-
- if (!wsi->upgraded_to_http2 || !lwsi_role_client(wsi))
- /*
- * The network wsi for a client h2 connection shouldn't
- * call back for its role: the child stream connections
- * own the role. Otherwise h2 will call back closed
- * one too many times as the children do it and then
- * the closing network stream.
- */
- pro->callback(wsi,
- wsi->role_ops->close_cb[lwsi_role_server(wsi)],
- wsi->user_space, NULL, 0);
- wsi->told_user_closed = 1;
- }
-
-async_close:
- wsi->socket_is_permanently_unusable = 1;
-
- if (wsi->context->event_loop_ops->wsi_logical_close)
- if (wsi->context->event_loop_ops->wsi_logical_close(wsi))
- return;
-
- __lws_close_free_wsi_final(wsi);
-}
-
-void
-__lws_close_free_wsi_final(struct lws *wsi)
-{
- int n;
-
- if (!wsi->shadow &&
- lws_socket_is_valid(wsi->desc.sockfd) && !lws_ssl_close(wsi)) {
- lwsl_debug("%s: wsi %p: fd %d\n", __func__, wsi, wsi->desc.sockfd);
- n = compatible_close(wsi->desc.sockfd);
- if (n)
- lwsl_debug("closing: close ret %d\n", LWS_ERRNO);
-
- wsi->desc.sockfd = LWS_SOCK_INVALID;
- }
-
- /* outermost destroy notification for wsi (user_space still intact) */
- if (wsi->vhost)
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY,
- wsi->user_space, NULL, 0);
-
-#ifdef LWS_WITH_CGI
- if (wsi->http.cgi) {
-
- for (n = 0; n < 3; n++) {
- if (wsi->http.cgi->pipe_fds[n][!!(n == 0)] == 0)
- lwsl_err("ZERO FD IN CGI CLOSE");
-
- if (wsi->http.cgi->pipe_fds[n][!!(n == 0)] >= 0)
- close(wsi->http.cgi->pipe_fds[n][!!(n == 0)]);
- }
-
- lws_free(wsi->http.cgi);
- }
-#endif
-
- __lws_free_wsi(wsi);
-}
-
-
-void
-lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, const char *caller)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-
- lws_pt_lock(pt, __func__);
- __lws_close_free_wsi(wsi, reason, caller);
- lws_pt_unlock(pt);
-}
-
-/* lws_buflist */
-
-int
-lws_buflist_append_segment(struct lws_buflist **head, const uint8_t *buf,
- size_t len)
-{
- struct lws_buflist *nbuf;
- int first = !*head;
- void *p = *head;
- int sanity = 1024;
-
- assert(buf);
- assert(len);
-
- /* append at the tail */
- while (*head) {
- if (!--sanity || head == &((*head)->next)) {
- lwsl_err("%s: corrupt list points to self\n", __func__);
- return -1;
- }
- head = &((*head)->next);
- }
-
- lwsl_info("%s: len %u first %d %p\n", __func__, (uint32_t)len, first, p);
-
- nbuf = (struct lws_buflist *)lws_malloc(sizeof(**head) + len, __func__);
- if (!nbuf) {
- lwsl_err("%s: OOM\n", __func__);
- return -1;
- }
-
- nbuf->len = len;
- nbuf->pos = 0;
- nbuf->next = NULL;
-
- p = (void *)nbuf->buf;
- memcpy(p, buf, len);
-
- *head = nbuf;
-
- return first; /* returns 1 if first segment just created */
-}
-
-static int
-lws_buflist_destroy_segment(struct lws_buflist **head)
-{
- struct lws_buflist *old = *head;
-
- assert(*head);
- *head = (*head)->next;
- old->next = NULL;
- lws_free(old);
-
- return !*head; /* returns 1 if last segment just destroyed */
-}
-
-void
-lws_buflist_destroy_all_segments(struct lws_buflist **head)
-{
- struct lws_buflist *p = *head, *p1;
-
- while (p) {
- p1 = p->next;
- p->next = NULL;
- lws_free(p);
- p = p1;
- }
-
- *head = NULL;
-}
-
-size_t
-lws_buflist_next_segment_len(struct lws_buflist **head, uint8_t **buf)
-{
- if (!*head) {
- if (buf)
- *buf = NULL;
-
- return 0;
- }
-
- if (!(*head)->len && (*head)->next)
- lws_buflist_destroy_segment(head);
-
- if (!*head) {
- if (buf)
- *buf = NULL;
-
- return 0;
- }
-
- assert((*head)->pos < (*head)->len);
-
- if (buf)
- *buf = (*head)->buf + (*head)->pos;
-
- return (*head)->len - (*head)->pos;
-}
-
-int
-lws_buflist_use_segment(struct lws_buflist **head, size_t len)
-{
- assert(*head);
- assert(len);
- assert((*head)->pos + len <= (*head)->len);
-
- (*head)->pos += len;
- if ((*head)->pos == (*head)->len)
- lws_buflist_destroy_segment(head);
-
- if (!*head)
- return 0;
-
- return (int)((*head)->len - (*head)->pos);
-}
-
-void
-lws_buflist_describe(struct lws_buflist **head, void *id)
-{
- struct lws_buflist *old;
- int n = 0;
-
- if (*head == NULL)
- lwsl_notice("%p: buflist empty\n", id);
-
- while (*head) {
- lwsl_notice("%p: %d: %llu / %llu (%llu left)\n", id, n,
- (unsigned long long)(*head)->pos,
- (unsigned long long)(*head)->len,
- (unsigned long long)(*head)->len - (*head)->pos);
- old = *head;
- head = &((*head)->next);
- if (*head == old) {
- lwsl_err("%s: next points to self\n", __func__);
- break;
- }
- n++;
- }
-}
-
-/* ... */
-
-LWS_VISIBLE LWS_EXTERN const char *
-lws_get_urlarg_by_name(struct lws *wsi, const char *name, char *buf, int len)
-{
- int n = 0, sl = (int)strlen(name);
-
- while (lws_hdr_copy_fragment(wsi, buf, len,
- WSI_TOKEN_HTTP_URI_ARGS, n) >= 0) {
-
- if (!strncmp(buf, name, sl))
- return buf + sl;
-
- n++;
- }
-
- return NULL;
-}
-
-#if !defined(LWS_WITH_ESP32)
-LWS_VISIBLE int
-interface_to_sa(struct lws_vhost *vh, const char *ifname,
- struct sockaddr_in *addr, size_t addrlen)
-{
- int ipv6 = 0;
-#ifdef LWS_WITH_IPV6
- ipv6 = LWS_IPV6_ENABLED(vh);
-#endif
- (void)vh;
-
- return lws_interface_to_sa(ipv6, ifname, addr, addrlen);
-}
-#endif
-
-#ifndef LWS_PLAT_OPTEE
-static int
-lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
- int name_len, char *rip, int rip_len)
-{
- struct addrinfo ai, *res;
- struct sockaddr_in addr4;
-
- rip[0] = '\0';
- name[0] = '\0';
- addr4.sin_family = AF_UNSPEC;
-
-#ifdef LWS_WITH_IPV6
- if (LWS_IPV6_ENABLED(vh)) {
- if (!lws_plat_inet_ntop(AF_INET6,
- &((struct sockaddr_in6 *)ads)->sin6_addr,
- rip, rip_len)) {
- lwsl_err("inet_ntop: %s", strerror(LWS_ERRNO));
- return -1;
- }
-
- // Strip off the IPv4 to IPv6 header if one exists
- if (strncmp(rip, "::ffff:", 7) == 0)
- memmove(rip, rip + 7, strlen(rip) - 6);
-
- getnameinfo((struct sockaddr *)ads, sizeof(struct sockaddr_in6),
- name, name_len, NULL, 0, 0);
-
- return 0;
- } else
-#endif
- {
- struct addrinfo *result;
-
- memset(&ai, 0, sizeof ai);
- ai.ai_family = PF_UNSPEC;
- ai.ai_socktype = SOCK_STREAM;
-#if !defined(LWS_WITH_ESP32)
- if (getnameinfo((struct sockaddr *)ads,
- sizeof(struct sockaddr_in),
- name, name_len, NULL, 0, 0))
- return -1;
-#endif
-
- if (getaddrinfo(name, NULL, &ai, &result))
- return -1;
-
- res = result;
- while (addr4.sin_family == AF_UNSPEC && res) {
- switch (res->ai_family) {
- case AF_INET:
- addr4.sin_addr =
- ((struct sockaddr_in *)res->ai_addr)->sin_addr;
- addr4.sin_family = AF_INET;
- break;
- }
-
- res = res->ai_next;
- }
- freeaddrinfo(result);
- }
-
- if (addr4.sin_family == AF_UNSPEC)
- return -1;
-
- if (lws_plat_inet_ntop(AF_INET, &addr4.sin_addr, rip, rip_len) == NULL)
- return -1;
-
- return 0;
-}
-
-
-LWS_VISIBLE const char *
-lws_get_peer_simple(struct lws *wsi, char *name, int namelen)
-{
- socklen_t len, olen;
-#ifdef LWS_WITH_IPV6
- struct sockaddr_in6 sin6;
-#endif
- struct sockaddr_in sin4;
- int af = AF_INET;
- void *p, *q;
-
- wsi = lws_get_network_wsi(wsi);
-
-#ifdef LWS_WITH_IPV6
- if (LWS_IPV6_ENABLED(wsi->vhost)) {
- len = sizeof(sin6);
- p = &sin6;
- af = AF_INET6;
- q = &sin6.sin6_addr;
- } else
-#endif
- {
- len = sizeof(sin4);
- p = &sin4;
- q = &sin4.sin_addr;
- }
-
- olen = len;
- if (getpeername(wsi->desc.sockfd, p, &len) < 0 || len > olen) {
- lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
- return NULL;
- }
-
- return lws_plat_inet_ntop(af, q, name, namelen);
-}
-#endif
-
-LWS_VISIBLE void
-lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
- int name_len, char *rip, int rip_len)
-{
-#ifndef LWS_PLAT_OPTEE
- socklen_t len;
-#ifdef LWS_WITH_IPV6
- struct sockaddr_in6 sin6;
-#endif
- struct sockaddr_in sin4;
- struct lws_context *context = wsi->context;
- int ret = -1;
- void *p;
-
- rip[0] = '\0';
- name[0] = '\0';
-
- lws_latency_pre(context, wsi);
-
-#ifdef LWS_WITH_IPV6
- if (LWS_IPV6_ENABLED(wsi->vhost)) {
- len = sizeof(sin6);
- p = &sin6;
- } else
-#endif
- {
- len = sizeof(sin4);
- p = &sin4;
- }
-
- if (getpeername(fd, p, &len) < 0) {
- lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
- goto bail;
- }
-
- ret = lws_get_addresses(wsi->vhost, p, name, name_len, rip, rip_len);
-
-bail:
- lws_latency(context, wsi, "lws_get_peer_addresses", ret, 1);
-#endif
- (void)wsi;
- (void)fd;
- (void)name;
- (void)name_len;
- (void)rip;
- (void)rip_len;
-
-}
-
-LWS_EXTERN void *
-lws_vhost_user(struct lws_vhost *vhost)
-{
- return vhost->user;
-}
-
-LWS_EXTERN void *
-lws_context_user(struct lws_context *context)
-{
- return context->user_space;
-}
-
-LWS_VISIBLE struct lws_vhost *
-lws_vhost_get(struct lws *wsi)
-{
- return wsi->vhost;
-}
-
-LWS_VISIBLE struct lws_vhost *
-lws_get_vhost(struct lws *wsi)
-{
- return wsi->vhost;
-}
-
-LWS_VISIBLE const struct lws_protocols *
-lws_protocol_get(struct lws *wsi)
-{
- return wsi->protocol;
-}
-
-LWS_VISIBLE const struct lws_udp *
-lws_get_udp(const struct lws *wsi)
-{
- return wsi->udp;
-}
-
-LWS_VISIBLE struct lws *
-lws_get_network_wsi(struct lws *wsi)
-{
- if (!wsi)
- return NULL;
-
-#if defined(LWS_WITH_HTTP2)
- if (!wsi->http2_substream
-#if !defined(LWS_NO_CLIENT)
- && !wsi->client_h2_substream
-#endif
- )
- return wsi;
-
- while (wsi->h2.parent_wsi)
- wsi = wsi->h2.parent_wsi;
-#endif
-
- return wsi;
-}
-
-LWS_VISIBLE LWS_EXTERN const struct lws_protocols *
-lws_vhost_name_to_protocol(struct lws_vhost *vh, const char *name)
-{
- int n;
-
- for (n = 0; n < vh->count_protocols; n++)
- if (!strcmp(name, vh->protocols[n].name))
- return &vh->protocols[n];
-
- return NULL;
-}
-
-LWS_VISIBLE int
-lws_callback_all_protocol(struct lws_context *context,
- const struct lws_protocols *protocol, int reason)
-{
- struct lws_context_per_thread *pt = &context->pt[0];
- unsigned int n, m = context->count_threads;
- struct lws *wsi;
-
- while (m--) {
- for (n = 0; n < pt->fds_count; n++) {
- wsi = wsi_from_fd(context, pt->fds[n].fd);
- if (!wsi)
- continue;
- if (wsi->protocol == protocol)
- protocol->callback(wsi, reason, wsi->user_space,
- NULL, 0);
- }
- pt++;
- }
-
- return 0;
-}
-
-LWS_VISIBLE int
-lws_callback_all_protocol_vhost_args(struct lws_vhost *vh,
- const struct lws_protocols *protocol, int reason,
- void *argp, size_t len)
-{
- struct lws_context *context = vh->context;
- struct lws_context_per_thread *pt = &context->pt[0];
- unsigned int n, m = context->count_threads;
- struct lws *wsi;
-
- while (m--) {
- for (n = 0; n < pt->fds_count; n++) {
- wsi = wsi_from_fd(context, pt->fds[n].fd);
- if (!wsi)
- continue;
- if (wsi->vhost == vh && (wsi->protocol == protocol ||
- !protocol))
- wsi->protocol->callback(wsi, reason,
- wsi->user_space, argp, len);
- }
- pt++;
- }
-
- return 0;
-}
-
-LWS_VISIBLE int
-lws_callback_all_protocol_vhost(struct lws_vhost *vh,
- const struct lws_protocols *protocol, int reason)
-{
- return lws_callback_all_protocol_vhost_args(vh, protocol, reason, NULL, 0);
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_callback_vhost_protocols(struct lws *wsi, int reason, void *in, int len)
-{
- int n;
-
- for (n = 0; n < wsi->vhost->count_protocols; n++)
- if (wsi->vhost->protocols[n].callback(wsi, reason, NULL, in, len))
- return 1;
-
- return 0;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_callback_vhost_protocols_vhost(struct lws_vhost *vh, int reason, void *in,
- size_t len)
-{
- int n;
- struct lws *wsi = lws_zalloc(sizeof(*wsi), "fake wsi");
-
- wsi->context = vh->context;
- lws_vhost_bind_wsi(vh, wsi);
-
- for (n = 0; n < wsi->vhost->count_protocols; n++) {
- wsi->protocol = &vh->protocols[n];
- if (wsi->protocol->callback(wsi, reason, NULL, in, len)) {
- lws_free(wsi);
- return 1;
- }
- }
-
- lws_free(wsi);
-
- return 0;
-}
-
-LWS_VISIBLE LWS_EXTERN void
-lws_set_fops(struct lws_context *context, const struct lws_plat_file_ops *fops)
-{
- context->fops = fops;
-}
-
-LWS_VISIBLE LWS_EXTERN lws_filepos_t
-lws_vfs_tell(lws_fop_fd_t fop_fd)
-{
- return fop_fd->pos;
-}
-
-LWS_VISIBLE LWS_EXTERN lws_filepos_t
-lws_vfs_get_length(lws_fop_fd_t fop_fd)
-{
- return fop_fd->len;
-}
-
-LWS_VISIBLE LWS_EXTERN uint32_t
-lws_vfs_get_mod_time(lws_fop_fd_t fop_fd)
-{
- return fop_fd->mod_time;
-}
-
-LWS_VISIBLE lws_fileofs_t
-lws_vfs_file_seek_set(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
-{
- lws_fileofs_t ofs;
-
- ofs = fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd, offset - fop_fd->pos);
-
- return ofs;
-}
-
-
-LWS_VISIBLE lws_fileofs_t
-lws_vfs_file_seek_end(lws_fop_fd_t fop_fd, lws_fileofs_t offset)
-{
- return fop_fd->fops->LWS_FOP_SEEK_CUR(fop_fd, fop_fd->len +
- fop_fd->pos + offset);
-}
-
-
-const struct lws_plat_file_ops *
-lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
- const char **vpath)
-{
- const struct lws_plat_file_ops *pf;
- const char *p = vfs_path;
- int n;
-
- *vpath = NULL;
-
- /* no non-platform fops, just use that */
-
- if (!fops->next)
- return fops;
-
- /*
- * scan the vfs path looking for indications we are to be
- * handled by a specific fops
- */
-
- while (p && *p) {
- if (*p != '/') {
- p++;
- continue;
- }
- /* the first one is always platform fops, so skip */
- pf = fops->next;
- while (pf) {
- n = 0;
- while (n < (int)LWS_ARRAY_SIZE(pf->fi) && pf->fi[n].sig) {
- if (p >= vfs_path + pf->fi[n].len)
- if (!strncmp(p - (pf->fi[n].len - 1),
- pf->fi[n].sig,
- pf->fi[n].len - 1)) {
- *vpath = p + 1;
- return pf;
- }
-
- n++;
- }
- pf = pf->next;
- }
- p++;
- }
-
- return fops;
-}
-
-LWS_VISIBLE LWS_EXTERN lws_fop_fd_t LWS_WARN_UNUSED_RESULT
-lws_vfs_file_open(const struct lws_plat_file_ops *fops, const char *vfs_path,
- lws_fop_flags_t *flags)
-{
- const char *vpath = "";
- const struct lws_plat_file_ops *selected;
-
- selected = lws_vfs_select_fops(fops, vfs_path, &vpath);
-
- return selected->LWS_FOP_OPEN(fops, vfs_path, vpath, flags);
-}
-
-
-/**
- * lws_now_secs() - seconds since 1970-1-1
- *
- */
-LWS_VISIBLE LWS_EXTERN unsigned long
-lws_now_secs(void)
-{
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
-
- return tv.tv_sec;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_compare_time_t(struct lws_context *context, time_t t1, time_t t2)
-{
- if (t1 < context->time_discontiguity)
- t1 += context->time_fixup;
-
- if (t2 < context->time_discontiguity)
- t2 += context->time_fixup;
-
- return (int)(t1 - t2);
-}
-
-LWS_VISIBLE lws_sockfd_type
-lws_get_socket_fd(struct lws *wsi)
-{
- if (!wsi)
- return -1;
- return wsi->desc.sockfd;
-}
-
-#ifdef LWS_LATENCY
-void
-lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
- int ret, int completed)
-{
- unsigned long long u;
- char buf[256];
-
- u = lws_time_in_microseconds();
-
- if (!action) {
- wsi->latency_start = u;
- if (!wsi->action_start)
- wsi->action_start = u;
- return;
- }
- if (completed) {
- if (wsi->action_start == wsi->latency_start)
- sprintf(buf,
- "Completion first try lat %lluus: %p: ret %d: %s\n",
- u - wsi->latency_start,
- (void *)wsi, ret, action);
- else
- sprintf(buf,
- "Completion %lluus: lat %lluus: %p: ret %d: %s\n",
- u - wsi->action_start,
- u - wsi->latency_start,
- (void *)wsi, ret, action);
- wsi->action_start = 0;
- } else
- sprintf(buf, "lat %lluus: %p: ret %d: %s\n",
- u - wsi->latency_start, (void *)wsi, ret, action);
-
- if (u - wsi->latency_start > context->worst_latency) {
- context->worst_latency = u - wsi->latency_start;
- strcpy(context->worst_latency_info, buf);
- }
- lwsl_latency("%s", buf);
-}
-#endif
-
-LWS_VISIBLE int
-lws_rx_flow_control(struct lws *wsi, int _enable)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
- int en = _enable;
-
- // h2 ignores rx flow control atm
- if (lwsi_role_h2(wsi) || wsi->http2_substream ||
- lwsi_role_h2_ENCAPSULATION(wsi))
- return 0; // !!!
-
- lwsl_info("%s: %p 0x%x\n", __func__, wsi, _enable);
-
- if (!(_enable & LWS_RXFLOW_REASON_APPLIES)) {
- /*
- * convert user bool style to bitmap style... in user simple
- * bool style _enable = 0 = flow control it, = 1 = allow rx
- */
- en = LWS_RXFLOW_REASON_APPLIES | LWS_RXFLOW_REASON_USER_BOOL;
- if (_enable & 1)
- en |= LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT;
- }
-
- lws_pt_lock(pt, __func__);
-
- /* any bit set in rxflow_bitmap DISABLEs rxflow control */
- if (en & LWS_RXFLOW_REASON_APPLIES_ENABLE_BIT)
- wsi->rxflow_bitmap &= ~(en & 0xff);
- else
- wsi->rxflow_bitmap |= en & 0xff;
-
- if ((LWS_RXFLOW_PENDING_CHANGE | (!wsi->rxflow_bitmap)) ==
- wsi->rxflow_change_to)
- goto skip;
-
- wsi->rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE |
- (!wsi->rxflow_bitmap);
-
- lwsl_info("%s: %p: bitmap 0x%x: en 0x%x, ch 0x%x\n", __func__, wsi,
- wsi->rxflow_bitmap, en, wsi->rxflow_change_to);
-
- if (_enable & LWS_RXFLOW_REASON_FLAG_PROCESS_NOW ||
- !wsi->rxflow_will_be_applied) {
- en = __lws_rx_flow_control(wsi);
- lws_pt_unlock(pt);
-
- return en;
- }
-
-skip:
- lws_pt_unlock(pt);
-
- return 0;
-}
-
-LWS_VISIBLE void
-lws_rx_flow_allow_all_protocol(const struct lws_context *context,
- const struct lws_protocols *protocol)
-{
- const struct lws_context_per_thread *pt = &context->pt[0];
- struct lws *wsi;
- unsigned int n, m = context->count_threads;
-
- while (m--) {
- for (n = 0; n < pt->fds_count; n++) {
- wsi = wsi_from_fd(context, pt->fds[n].fd);
- if (!wsi)
- continue;
- if (wsi->protocol == protocol)
- lws_rx_flow_control(wsi, LWS_RXFLOW_ALLOW);
- }
- pt++;
- }
-}
-
-int
-lws_broadcast(struct lws_context *context, int reason, void *in, size_t len)
-{
- struct lws_vhost *v = context->vhost_list;
- struct lws wsi;
- int n, ret = 0;
-
- memset(&wsi, 0, sizeof(wsi));
- wsi.context = context;
-
- while (v) {
- const struct lws_protocols *p = v->protocols;
- wsi.vhost = v; /* not a real bound wsi */
-
- for (n = 0; n < v->count_protocols; n++) {
- wsi.protocol = p;
- if (p->callback &&
- p->callback(&wsi, reason, NULL, in, len))
- ret |= 1;
- p++;
- }
- v = v->vhost_next;
- }
-
- return ret;
-}
-
-LWS_VISIBLE extern const char *
-lws_canonical_hostname(struct lws_context *context)
-{
- return (const char *)context->canonical_hostname;
-}
-
-LWS_VISIBLE LWS_EXTERN const char *
-lws_get_vhost_name(struct lws_vhost *vhost)
-{
- return vhost->name;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_get_vhost_port(struct lws_vhost *vhost)
-{
- return vhost->listen_port;
-}
-
-LWS_VISIBLE LWS_EXTERN void *
-lws_get_vhost_user(struct lws_vhost *vhost)
-{
- return vhost->user;
-}
-
-LWS_VISIBLE LWS_EXTERN const char *
-lws_get_vhost_iface(struct lws_vhost *vhost)
-{
- return vhost->iface;
-}
-
-int user_callback_handle_rxflow(lws_callback_function callback_function,
- struct lws *wsi,
- enum lws_callback_reasons reason, void *user,
- void *in, size_t len)
-{
- int n;
-
- wsi->rxflow_will_be_applied = 1;
- n = callback_function(wsi, reason, user, in, len);
- wsi->rxflow_will_be_applied = 0;
- if (!n)
- n = __lws_rx_flow_control(wsi);
-
- return n;
-}
-
-#if !defined(LWS_WITHOUT_CLIENT)
-LWS_VISIBLE int
-lws_set_proxy(struct lws_vhost *vhost, const char *proxy)
-{
- char *p;
- char authstring[96];
-
- if (!proxy)
- return -1;
-
- /* we have to deal with a possible redundant leading http:// */
- if (!strncmp(proxy, "http://", 7))
- proxy += 7;
-
- p = strrchr(proxy, '@');
- if (p) { /* auth is around */
-
- if ((unsigned int)(p - proxy) > sizeof(authstring) - 1)
- goto auth_too_long;
-
- lws_strncpy(authstring, proxy, p - proxy + 1);
- // null termination not needed on input
- if (lws_b64_encode_string(authstring, lws_ptr_diff(p, proxy),
- vhost->proxy_basic_auth_token,
- sizeof vhost->proxy_basic_auth_token) < 0)
- goto auth_too_long;
-
- lwsl_info(" Proxy auth in use\n");
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- proxy = p + 1;
-#endif
- } else
- vhost->proxy_basic_auth_token[0] = '\0';
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- lws_strncpy(vhost->http.http_proxy_address, proxy,
- sizeof(vhost->http.http_proxy_address));
-
- p = strchr(vhost->http.http_proxy_address, ':');
- if (!p && !vhost->http.http_proxy_port) {
- lwsl_err("http_proxy needs to be ads:port\n");
-
- return -1;
- } else {
- if (p) {
- *p = '\0';
- vhost->http.http_proxy_port = atoi(p + 1);
- }
- }
-
- lwsl_info(" Proxy %s:%u\n", vhost->http.http_proxy_address,
- vhost->http.http_proxy_port);
-#endif
- return 0;
-
-auth_too_long:
- lwsl_err("proxy auth too long\n");
-
- return -1;
-}
-#endif
-
-#if defined(LWS_WITH_SOCKS5)
-LWS_VISIBLE int
-lws_set_socks(struct lws_vhost *vhost, const char *socks)
-{
- char *p_at, *p_colon;
- char user[96];
- char password[96];
-
- if (!socks)
- return -1;
-
- vhost->socks_user[0] = '\0';
- vhost->socks_password[0] = '\0';
-
- p_at = strrchr(socks, '@');
- if (p_at) { /* auth is around */
- if ((unsigned int)(p_at - socks) > (sizeof(user)
- + sizeof(password) - 2)) {
- lwsl_err("Socks auth too long\n");
- goto bail;
- }
-
- p_colon = strchr(socks, ':');
- if (p_colon) {
- if ((unsigned int)(p_colon - socks) > (sizeof(user)
- - 1) ) {
- lwsl_err("Socks user too long\n");
- goto bail;
- }
- if ((unsigned int)(p_at - p_colon) > (sizeof(password)
- - 1) ) {
- lwsl_err("Socks password too long\n");
- goto bail;
- }
-
- lws_strncpy(vhost->socks_user, socks, p_colon - socks + 1);
- lws_strncpy(vhost->socks_password, p_colon + 1,
- p_at - (p_colon + 1) + 1);
- }
-
- lwsl_info(" Socks auth, user: %s, password: %s\n",
- vhost->socks_user, vhost->socks_password );
-
- socks = p_at + 1;
- }
-
- lws_strncpy(vhost->socks_proxy_address, socks,
- sizeof(vhost->socks_proxy_address));
-
- p_colon = strchr(vhost->socks_proxy_address, ':');
- if (!p_colon && !vhost->socks_proxy_port) {
- lwsl_err("socks_proxy needs to be address:port\n");
- return -1;
- } else {
- if (p_colon) {
- *p_colon = '\0';
- vhost->socks_proxy_port = atoi(p_colon + 1);
- }
- }
-
- lwsl_info(" Socks %s:%u\n", vhost->socks_proxy_address,
- vhost->socks_proxy_port);
-
- return 0;
-
-bail:
- return -1;
-}
-#endif
-
-LWS_VISIBLE const struct lws_protocols *
-lws_get_protocol(struct lws *wsi)
-{
- return wsi->protocol;
-}
-
-
-int
-lws_ensure_user_space(struct lws *wsi)
-{
- if (!wsi->protocol)
- return 0;
-
- /* allocate the per-connection user memory (if any) */
-
- if (wsi->protocol->per_session_data_size && !wsi->user_space) {
- wsi->user_space = lws_zalloc(
- wsi->protocol->per_session_data_size, "user space");
- if (wsi->user_space == NULL) {
- lwsl_err("%s: OOM\n", __func__);
- return 1;
- }
- } else
- lwsl_debug("%s: %p protocol pss %lu, user_space=%p\n", __func__,
- wsi, (long)wsi->protocol->per_session_data_size,
- wsi->user_space);
- return 0;
-}
-
-LWS_VISIBLE void *
-lws_adjust_protocol_psds(struct lws *wsi, size_t new_size)
-{
- ((struct lws_protocols *)lws_get_protocol(wsi))->per_session_data_size =
- new_size;
-
- if (lws_ensure_user_space(wsi))
- return NULL;
-
- return wsi->user_space;
-}
-
-LWS_VISIBLE int
-lwsl_timestamp(int level, char *p, int len)
-{
-#ifndef LWS_PLAT_OPTEE
-#ifndef _WIN32_WCE
- time_t o_now = time(NULL);
-#endif
- unsigned long long now;
- struct tm *ptm = NULL;
-#ifndef WIN32
- struct tm tm;
-#endif
- int n;
-
-#ifndef _WIN32_WCE
-#ifdef WIN32
- ptm = localtime(&o_now);
-#else
- if (localtime_r(&o_now, &tm))
- ptm = &tm;
-#endif
-#endif
- p[0] = '\0';
- for (n = 0; n < LLL_COUNT; n++) {
- if (level != (1 << n))
- continue;
- now = lws_time_in_microseconds() / 100;
- if (ptm)
- n = lws_snprintf(p, len,
- "[%04d/%02d/%02d %02d:%02d:%02d:%04d] %s: ",
- ptm->tm_year + 1900,
- ptm->tm_mon + 1,
- ptm->tm_mday,
- ptm->tm_hour,
- ptm->tm_min,
- ptm->tm_sec,
- (int)(now % 10000), log_level_names[n]);
- else
- n = lws_snprintf(p, len, "[%llu:%04d] %s: ",
- (unsigned long long) now / 10000,
- (int)(now % 10000), log_level_names[n]);
- return n;
- }
-#else
- p[0] = '\0';
-#endif
-
- return 0;
-}
-
-#ifndef LWS_PLAT_OPTEE
-static const char * const colours[] = {
- "[31;1m", /* LLL_ERR */
- "[36;1m", /* LLL_WARN */
- "[35;1m", /* LLL_NOTICE */
- "[32;1m", /* LLL_INFO */
- "[34;1m", /* LLL_DEBUG */
- "[33;1m", /* LLL_PARSER */
- "[33m", /* LLL_HEADER */
- "[33m", /* LLL_EXT */
- "[33m", /* LLL_CLIENT */
- "[33;1m", /* LLL_LATENCY */
- "[30;1m", /* LLL_USER */
- "[31m", /* LLL_THREAD */
-};
-
-static char tty;
-
-LWS_VISIBLE void
-lwsl_emit_stderr(int level, const char *line)
-{
- char buf[50];
- int n, m = LWS_ARRAY_SIZE(colours) - 1;
-
- if (!tty)
- tty = isatty(2) | 2;
- lwsl_timestamp(level, buf, sizeof(buf));
-
- if (tty == 3) {
- n = 1 << (LWS_ARRAY_SIZE(colours) - 1);
- while (n) {
- if (level & n)
- break;
- m--;
- n >>= 1;
- }
- fprintf(stderr, "%c%s%s%s%c[0m", 27, colours[m], buf, line, 27);
- } else
- fprintf(stderr, "%s%s", buf, line);
-}
-
-LWS_VISIBLE void
-lwsl_emit_stderr_notimestamp(int level, const char *line)
-{
- int n, m = LWS_ARRAY_SIZE(colours) - 1;
-
- if (!tty)
- tty = isatty(2) | 2;
-
- if (tty == 3) {
- n = 1 << (LWS_ARRAY_SIZE(colours) - 1);
- while (n) {
- if (level & n)
- break;
- m--;
- n >>= 1;
- }
- fprintf(stderr, "%c%s%s%c[0m", 27, colours[m], line, 27);
- } else
- fprintf(stderr, "%s", line);
-}
-
-#endif
-
-LWS_VISIBLE void _lws_logv(int filter, const char *format, va_list vl)
-{
- char buf[256];
- int n;
-
- if (!(log_level & filter))
- return;
-
- n = vsnprintf(buf, sizeof(buf) - 1, format, vl);
- (void)n;
- /* vnsprintf returns what it would have written, even if truncated */
- if (n > (int)sizeof(buf) - 1) {
- n = sizeof(buf) - 5;
- buf[n++] = '.';
- buf[n++] = '.';
- buf[n++] = '.';
- buf[n++] = '\n';
- buf[n] = '\0';
- }
- if (n > 0)
- buf[n] = '\0';
-
- lwsl_emit(filter, buf);
-}
-
-LWS_VISIBLE void _lws_log(int filter, const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- _lws_logv(filter, format, ap);
- va_end(ap);
-}
-
-LWS_VISIBLE void lws_set_log_level(int level,
- void (*func)(int level, const char *line))
-{
- log_level = level;
- if (func)
- lwsl_emit = func;
-}
-
-LWS_VISIBLE int lwsl_visible(int level)
-{
- return log_level & level;
-}
-
-LWS_VISIBLE void
-lwsl_hexdump_level(int hexdump_level, const void *vbuf, size_t len)
-{
- unsigned char *buf = (unsigned char *)vbuf;
- unsigned int n;
-
- if (!lwsl_visible(hexdump_level))
- return;
-
- if (!len)
- return;
-
- if (!vbuf)
- return;
-
- _lws_log(hexdump_level, "\n");
-
- for (n = 0; n < len;) {
- unsigned int start = n, m;
- char line[80], *p = line;
-
- p += sprintf(p, "%04X: ", start);
-
- for (m = 0; m < 16 && n < len; m++)
- p += sprintf(p, "%02X ", buf[n++]);
- while (m++ < 16)
- p += sprintf(p, " ");
-
- p += sprintf(p, " ");
-
- for (m = 0; m < 16 && (start + m) < len; m++) {
- if (buf[start + m] >= ' ' && buf[start + m] < 127)
- *p++ = buf[start + m];
- else
- *p++ = '.';
- }
- while (m++ < 16)
- *p++ = ' ';
-
- *p++ = '\n';
- *p = '\0';
- _lws_log(hexdump_level, "%s", line);
- (void)line;
- }
-
- _lws_log(hexdump_level, "\n");
-}
-
-LWS_VISIBLE void
-lwsl_hexdump(const void *vbuf, size_t len)
-{
-#if defined(_DEBUG)
- lwsl_hexdump_level(LLL_DEBUG, vbuf, len);
-#endif
-}
-
-LWS_VISIBLE int
-lws_is_ssl(struct lws *wsi)
-{
-#if defined(LWS_WITH_TLS)
- return wsi->tls.use_ssl & LCCSCF_USE_SSL;
-#else
- (void)wsi;
- return 0;
-#endif
-}
-
-#if defined(LWS_WITH_TLS) && !defined(LWS_WITH_MBEDTLS)
-LWS_VISIBLE lws_tls_conn*
-lws_get_ssl(struct lws *wsi)
-{
- return wsi->tls.ssl;
-}
-#endif
-
-LWS_VISIBLE int
-lws_partial_buffered(struct lws *wsi)
-{
- return lws_has_buffered_out(wsi);
-}
-
-LWS_VISIBLE lws_fileofs_t
-lws_get_peer_write_allowance(struct lws *wsi)
-{
- if (!wsi->role_ops->tx_credit)
- return -1;
- return wsi->role_ops->tx_credit(wsi);
-}
-
-LWS_VISIBLE void
-lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state,
- struct lws_role_ops *ops)
-{
-#if defined(_DEBUG)
- const char *name = "(unset)";
-#endif
- wsi->wsistate = role | state;
- if (ops)
- wsi->role_ops = ops;
-#if defined(_DEBUG)
- if (wsi->role_ops)
- name = wsi->role_ops->name;
- lwsl_debug("%s: %p: wsistate 0x%x, ops %s\n", __func__, wsi,
- wsi->wsistate, name);
-#endif
-}
-
-LWS_VISIBLE struct lws_plat_file_ops *
-lws_get_fops(struct lws_context *context)
-{
- return (struct lws_plat_file_ops *)context->fops;
-}
-
-LWS_VISIBLE LWS_EXTERN struct lws_context *
-lws_get_context(const struct lws *wsi)
-{
- return wsi->context;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_get_count_threads(struct lws_context *context)
-{
- return context->count_threads;
-}
-
-LWS_VISIBLE LWS_EXTERN void *
-lws_wsi_user(struct lws *wsi)
-{
- return wsi->user_space;
-}
-
-LWS_VISIBLE LWS_EXTERN void
-lws_set_wsi_user(struct lws *wsi, void *data)
-{
- if (wsi->user_space_externally_allocated)
- wsi->user_space = data;
- else
- lwsl_err("%s: Cannot set internally-allocated user_space\n",
- __func__);
-}
-
-LWS_VISIBLE LWS_EXTERN struct lws *
-lws_get_parent(const struct lws *wsi)
-{
- return wsi->parent;
-}
-
-LWS_VISIBLE LWS_EXTERN struct lws *
-lws_get_child(const struct lws *wsi)
-{
- return wsi->child_list;
-}
-
-LWS_VISIBLE LWS_EXTERN void *
-lws_get_opaque_parent_data(const struct lws *wsi)
-{
- return wsi->opaque_parent_data;
-}
-
-LWS_VISIBLE LWS_EXTERN void
-lws_set_opaque_parent_data(struct lws *wsi, void *data)
-{
- wsi->opaque_parent_data = data;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_get_child_pending_on_writable(const struct lws *wsi)
-{
- return wsi->parent_pending_cb_on_writable;
-}
-
-LWS_VISIBLE LWS_EXTERN void
-lws_clear_child_pending_on_writable(struct lws *wsi)
-{
- wsi->parent_pending_cb_on_writable = 0;
-}
-
-
-LWS_EXTERN int
-__lws_rx_flow_control(struct lws *wsi)
-{
- struct lws *wsic = wsi->child_list;
-
- // h2 ignores rx flow control atm
- if (lwsi_role_h2(wsi) || wsi->http2_substream ||
- lwsi_role_h2_ENCAPSULATION(wsi))
- return 0; // !!!
-
- /* if he has children, do those if they were changed */
- while (wsic) {
- if (wsic->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE)
- __lws_rx_flow_control(wsic);
-
- wsic = wsic->sibling_list;
- }
-
- /* there is no pending change */
- if (!(wsi->rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE))
- return 0;
-
- /* stuff is still buffered, not ready to really accept new input */
- if (lws_buflist_next_segment_len(&wsi->buflist, NULL)) {
- /* get ourselves called back to deal with stashed buffer */
- lws_callback_on_writable(wsi);
- return 0;
- }
-
- /* now the pending is cleared, we can change rxflow state */
-
- wsi->rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE;
-
- lwsl_info("rxflow: wsi %p change_to %d\n", wsi,
- wsi->rxflow_change_to & LWS_RXFLOW_ALLOW);
-
- /* adjust the pollfd for this wsi */
-
- if (wsi->rxflow_change_to & LWS_RXFLOW_ALLOW) {
- if (__lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
- lwsl_info("%s: fail\n", __func__);
- return -1;
- }
- } else
- if (__lws_change_pollfd(wsi, LWS_POLLIN, 0))
- return -1;
-
- return 0;
-}
-
-static const unsigned char e0f4[] = {
- 0xa0 | ((2 - 1) << 2) | 1, /* e0 */
- 0x80 | ((4 - 1) << 2) | 1, /* e1 */
- 0x80 | ((4 - 1) << 2) | 1, /* e2 */
- 0x80 | ((4 - 1) << 2) | 1, /* e3 */
- 0x80 | ((4 - 1) << 2) | 1, /* e4 */
- 0x80 | ((4 - 1) << 2) | 1, /* e5 */
- 0x80 | ((4 - 1) << 2) | 1, /* e6 */
- 0x80 | ((4 - 1) << 2) | 1, /* e7 */
- 0x80 | ((4 - 1) << 2) | 1, /* e8 */
- 0x80 | ((4 - 1) << 2) | 1, /* e9 */
- 0x80 | ((4 - 1) << 2) | 1, /* ea */
- 0x80 | ((4 - 1) << 2) | 1, /* eb */
- 0x80 | ((4 - 1) << 2) | 1, /* ec */
- 0x80 | ((2 - 1) << 2) | 1, /* ed */
- 0x80 | ((4 - 1) << 2) | 1, /* ee */
- 0x80 | ((4 - 1) << 2) | 1, /* ef */
- 0x90 | ((3 - 1) << 2) | 2, /* f0 */
- 0x80 | ((4 - 1) << 2) | 2, /* f1 */
- 0x80 | ((4 - 1) << 2) | 2, /* f2 */
- 0x80 | ((4 - 1) << 2) | 2, /* f3 */
- 0x80 | ((1 - 1) << 2) | 2, /* f4 */
-
- 0, /* s0 */
- 0x80 | ((4 - 1) << 2) | 0, /* s2 */
- 0x80 | ((4 - 1) << 2) | 1, /* s3 */
-};
-
-LWS_EXTERN int
-lws_check_byte_utf8(unsigned char state, unsigned char c)
-{
- unsigned char s = state;
-
- if (!s) {
- if (c >= 0x80) {
- if (c < 0xc2 || c > 0xf4)
- return -1;
- if (c < 0xe0)
- return 0x80 | ((4 - 1) << 2);
- else
- return e0f4[c - 0xe0];
- }
-
- return s;
- }
- if (c < (s & 0xf0) || c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
- return -1;
-
- return e0f4[21 + (s & 3)];
-}
-
-LWS_EXTERN int
-lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len)
-{
- unsigned char s = *state;
-
- while (len--) {
- unsigned char c = *buf++;
-
- if (!s) {
- if (c >= 0x80) {
- if (c < 0xc2 || c > 0xf4)
- return 1;
- if (c < 0xe0)
- s = 0x80 | ((4 - 1) << 2);
- else
- s = e0f4[c - 0xe0];
- }
- } else {
- if (c < (s & 0xf0) ||
- c >= (s & 0xf0) + 0x10 + ((s << 2) & 0x30))
- return 1;
- s = e0f4[21 + (s & 3)];
- }
- }
-
- *state = s;
-
- return 0;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_parse_uri(char *p, const char **prot, const char **ads, int *port,
- const char **path)
-{
- const char *end;
- char unix_skt = 0;
-
- /* cut up the location into address, port and path */
- *prot = p;
- while (*p && (*p != ':' || p[1] != '/' || p[2] != '/'))
- p++;
- if (!*p) {
- end = p;
- p = (char *)*prot;
- *prot = end;
- } else {
- *p = '\0';
- p += 3;
- }
- if (*p == '+') /* unix skt */
- unix_skt = 1;
-
- *ads = p;
- if (!strcmp(*prot, "http") || !strcmp(*prot, "ws"))
- *port = 80;
- else if (!strcmp(*prot, "https") || !strcmp(*prot, "wss"))
- *port = 443;
-
- if (*p == '[') {
- ++(*ads);
- while (*p && *p != ']')
- p++;
- if (*p)
- *p++ = '\0';
- } else
- while (*p && *p != ':' && (unix_skt || *p != '/'))
- p++;
-
- if (*p == ':') {
- *p++ = '\0';
- *port = atoi(p);
- while (*p && *p != '/')
- p++;
- }
- *path = "/";
- if (*p) {
- *p++ = '\0';
- if (*p)
- *path = p;
- }
-
- return 0;
-}
-
-char *
-lws_strdup(const char *s)
-{
- char *d = lws_malloc(strlen(s) + 1, "strdup");
-
- if (d)
- strcpy(d, s);
-
- return d;
-}
-
-#if defined(LWS_WITHOUT_EXTENSIONS)
-
-/* we need to provide dummy callbacks for internal exts
- * so user code runs when faced with a lib compiled with
- * extensions disabled.
- */
-
-LWS_VISIBLE int
-lws_extension_callback_pm_deflate(struct lws_context *context,
- const struct lws_extension *ext,
- struct lws *wsi,
- enum lws_extension_callback_reasons reason,
- void *user, void *in, size_t len)
-{
- (void)context;
- (void)ext;
- (void)wsi;
- (void)reason;
- (void)user;
- (void)in;
- (void)len;
-
- return 0;
-}
-
-LWS_EXTERN int
-lws_set_extension_option(struct lws *wsi, const char *ext_name,
- const char *opt_name, const char *opt_val)
-{
- return -1;
-}
-#endif
-
-/* note: this returns a random port, or one of these <= 0 return codes:
- *
- * LWS_ITOSA_USABLE: the interface is usable, returned if so and sockfd invalid
- * LWS_ITOSA_NOT_EXIST: the requested iface does not even exist
- * LWS_ITOSA_NOT_USABLE: the requested iface exists but is not usable (eg, no IP)
- * LWS_ITOSA_BUSY: the port at the requested iface + port is already in use
- */
-
-LWS_EXTERN int
-lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
- const char *iface)
-{
-#ifdef LWS_WITH_UNIX_SOCK
- struct sockaddr_un serv_unix;
-#endif
-#ifdef LWS_WITH_IPV6
- struct sockaddr_in6 serv_addr6;
-#endif
- struct sockaddr_in serv_addr4;
-#ifndef LWS_PLAT_OPTEE
- socklen_t len = sizeof(struct sockaddr_storage);
-#endif
- int n;
-#if !defined(LWS_WITH_ESP32)
- int m;
-#endif
- struct sockaddr_storage sin;
- struct sockaddr *v;
-
- memset(&sin, 0, sizeof(sin));
-
-#if defined(LWS_WITH_UNIX_SOCK)
- if (LWS_UNIX_SOCK_ENABLED(vhost)) {
- v = (struct sockaddr *)&serv_unix;
- n = sizeof(struct sockaddr_un);
- bzero((char *) &serv_unix, sizeof(serv_unix));
- serv_unix.sun_family = AF_UNIX;
- if (!iface)
- return LWS_ITOSA_NOT_EXIST;
- if (sizeof(serv_unix.sun_path) <= strlen(iface)) {
- lwsl_err("\"%s\" too long for UNIX domain socket\n",
- iface);
- return LWS_ITOSA_NOT_EXIST;
- }
- strcpy(serv_unix.sun_path, iface);
- if (serv_unix.sun_path[0] == '@')
- serv_unix.sun_path[0] = '\0';
- else
- unlink(serv_unix.sun_path);
-
- } else
-#endif
-#if defined(LWS_WITH_IPV6) && !defined(LWS_WITH_ESP32)
- if (LWS_IPV6_ENABLED(vhost)) {
- v = (struct sockaddr *)&serv_addr6;
- n = sizeof(struct sockaddr_in6);
- bzero((char *) &serv_addr6, sizeof(serv_addr6));
- if (iface) {
- m = interface_to_sa(vhost, iface,
- (struct sockaddr_in *)v, n);
- if (m == LWS_ITOSA_NOT_USABLE) {
- lwsl_info("%s: netif %s: Not usable\n",
- __func__, iface);
- return m;
- }
- if (m == LWS_ITOSA_NOT_EXIST) {
- lwsl_info("%s: netif %s: Does not exist\n",
- __func__, iface);
- return m;
- }
- serv_addr6.sin6_scope_id = lws_get_addr_scope(iface);
- }
-
- serv_addr6.sin6_family = AF_INET6;
- serv_addr6.sin6_port = htons(port);
- } else
-#endif
- {
- v = (struct sockaddr *)&serv_addr4;
- n = sizeof(serv_addr4);
- bzero((char *) &serv_addr4, sizeof(serv_addr4));
- serv_addr4.sin_addr.s_addr = INADDR_ANY;
- serv_addr4.sin_family = AF_INET;
-
-#if !defined(LWS_WITH_ESP32)
- if (iface) {
- m = interface_to_sa(vhost, iface,
- (struct sockaddr_in *)v, n);
- if (m == LWS_ITOSA_NOT_USABLE) {
- lwsl_info("%s: netif %s: Not usable\n",
- __func__, iface);
- return m;
- }
- if (m == LWS_ITOSA_NOT_EXIST) {
- lwsl_info("%s: netif %s: Does not exist\n",
- __func__, iface);
- return m;
- }
- }
-#endif
- serv_addr4.sin_port = htons(port);
- } /* ipv4 */
-
- /* just checking for the interface extant */
- if (sockfd == LWS_SOCK_INVALID)
- return LWS_ITOSA_USABLE;
-
- n = bind(sockfd, v, n);
-#ifdef LWS_WITH_UNIX_SOCK
- if (n < 0 && LWS_UNIX_SOCK_ENABLED(vhost)) {
- lwsl_err("ERROR on binding fd %d to \"%s\" (%d %d)\n",
- sockfd, iface, n, LWS_ERRNO);
- return LWS_ITOSA_NOT_EXIST;
- } else
-#endif
- if (n < 0) {
- lwsl_err("ERROR on binding fd %d to port %d (%d %d)\n",
- sockfd, port, n, LWS_ERRNO);
-
- /* if something already listening, tell caller to fail permanently */
-
- if (LWS_ERRNO == LWS_EADDRINUSE)
- return LWS_ITOSA_BUSY;
-
- /* otherwise ask caller to retry later */
-
- return LWS_ITOSA_NOT_EXIST;
- }
-
-#if defined(LWS_WITH_UNIX_SOCK)
- if (LWS_UNIX_SOCK_ENABLED(vhost) && vhost->context->uid)
- if (chown(serv_unix.sun_path, vhost->context->uid,
- vhost->context->gid))
- lwsl_notice("%s: chown for unix skt %s failed\n",
- __func__, serv_unix.sun_path);
-#endif
-
-#ifndef LWS_PLAT_OPTEE
- if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1)
- lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
- else
-#endif
-#if defined(LWS_WITH_IPV6)
- port = (sin.ss_family == AF_INET6) ?
- ntohs(((struct sockaddr_in6 *) &sin)->sin6_port) :
- ntohs(((struct sockaddr_in *) &sin)->sin_port);
-#else
- {
- struct sockaddr_in sain;
- memcpy(&sain, &sin, sizeof(sain));
- port = ntohs(sain.sin_port);
- }
-#endif
-
- return port;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_get_vhost_listen_port(struct lws_vhost *vhost)
-{
- return vhost->listen_port;
-}
-
-#if defined(LWS_WITH_IPV6)
-LWS_EXTERN unsigned long
-lws_get_addr_scope(const char *ipaddr)
-{
- unsigned long scope = 0;
-
-#ifndef WIN32
- struct ifaddrs *addrs, *addr;
- char ip[NI_MAXHOST];
- unsigned int i;
-
- getifaddrs(&addrs);
- for (addr = addrs; addr; addr = addr->ifa_next) {
- if (!addr->ifa_addr ||
- addr->ifa_addr->sa_family != AF_INET6)
- continue;
-
- getnameinfo(addr->ifa_addr,
- sizeof(struct sockaddr_in6),
- ip, sizeof(ip),
- NULL, 0, NI_NUMERICHOST);
-
- i = 0;
- while (ip[i])
- if (ip[i++] == '%') {
- ip[i - 1] = '\0';
- break;
- }
-
- if (!strcmp(ip, ipaddr)) {
- scope = if_nametoindex(addr->ifa_name);
- break;
- }
- }
- freeifaddrs(addrs);
-#else
- PIP_ADAPTER_ADDRESSES adapter, addrs = NULL;
- PIP_ADAPTER_UNICAST_ADDRESS addr;
- ULONG size = 0;
- DWORD ret;
- struct sockaddr_in6 *sockaddr;
- char ip[NI_MAXHOST];
- unsigned int i;
- int found = 0;
-
- for (i = 0; i < 5; i++)
- {
- ret = GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX,
- NULL, addrs, &size);
- if ((ret == NO_ERROR) || (ret == ERROR_NO_DATA)) {
- break;
- } else if (ret == ERROR_BUFFER_OVERFLOW)
- {
- if (addrs)
- free(addrs);
- addrs = (IP_ADAPTER_ADDRESSES *)malloc(size);
- } else
- {
- if (addrs)
- {
- free(addrs);
- addrs = NULL;
- }
- lwsl_err("Failed to get IPv6 address table (%d)", ret);
- break;
- }
- }
-
- if ((ret == NO_ERROR) && (addrs)) {
- adapter = addrs;
- while (adapter && !found) {
- addr = adapter->FirstUnicastAddress;
- while (addr && !found) {
- if (addr->Address.lpSockaddr->sa_family ==
- AF_INET6) {
- sockaddr = (struct sockaddr_in6 *)
- (addr->Address.lpSockaddr);
-
- lws_plat_inet_ntop(sockaddr->sin6_family,
- &sockaddr->sin6_addr,
- ip, sizeof(ip));
-
- if (!strcmp(ip, ipaddr)) {
- scope = sockaddr->sin6_scope_id;
- found = 1;
- break;
- }
- }
- addr = addr->Next;
- }
- adapter = adapter->Next;
- }
- }
- if (addrs)
- free(addrs);
-#endif
-
- return scope;
-}
-#endif
-
-static const char *hex = "0123456789ABCDEF";
-
-LWS_VISIBLE LWS_EXTERN const char *
-lws_sql_purify(char *escaped, const char *string, int len)
-{
- const char *p = string;
- char *q = escaped;
-
- while (*p && len-- > 2) {
- if (*p == '\'') {
- *q++ = '\'';
- *q++ = '\'';
- len --;
- p++;
- } else
- *q++ = *p++;
- }
- *q = '\0';
-
- return escaped;
-}
-
-LWS_VISIBLE LWS_EXTERN const char *
-lws_json_purify(char *escaped, const char *string, int len)
-{
- const char *p = string;
- char *q = escaped;
-
- if (!p) {
- escaped[0] = '\0';
- return escaped;
- }
-
- while (*p && len-- > 6) {
- if (*p == '\t') {
- p++;
- *q++ = '\\';
- *q++ = 't';
- continue;
- }
-
- if (*p == '\n') {
- p++;
- *q++ = '\\';
- *q++ = 'n';
- continue;
- }
-
- if (*p == '\r') {
- p++;
- *q++ = '\\';
- *q++ = 'r';
- continue;
- }
-
- if (*p == '\"' || *p == '\\' || *p < 0x20) {
- *q++ = '\\';
- *q++ = 'u';
- *q++ = '0';
- *q++ = '0';
- *q++ = hex[((*p) >> 4) & 15];
- *q++ = hex[(*p) & 15];
- len -= 5;
- p++;
- } else
- *q++ = *p++;
- }
- *q = '\0';
-
- return escaped;
-}
-
-LWS_VISIBLE LWS_EXTERN void
-lws_filename_purify_inplace(char *filename)
-{
- while (*filename) {
-
- if (*filename == '.' && filename[1] == '.') {
- *filename = '_';
- filename[1] = '_';
- }
-
- if (*filename == ':' ||
- *filename == '/' ||
- *filename == '\\' ||
- *filename == '$' ||
- *filename == '%')
- *filename = '_';
-
- filename++;
- }
-}
-
-LWS_VISIBLE LWS_EXTERN const char *
-lws_urlencode(char *escaped, const char *string, int len)
-{
- const char *p = string;
- char *q = escaped;
-
- while (*p && len-- > 3) {
- if (*p == ' ') {
- *q++ = '+';
- p++;
- continue;
- }
- if ((*p >= '0' && *p <= '9') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= 'a' && *p <= 'z')) {
- *q++ = *p++;
- continue;
- }
- *q++ = '%';
- *q++ = hex[(*p >> 4) & 0xf];
- *q++ = hex[*p & 0xf];
-
- len -= 2;
- p++;
- }
- *q = '\0';
-
- return escaped;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_urldecode(char *string, const char *escaped, int len)
-{
- int state = 0, n;
- char sum = 0;
-
- while (*escaped && len) {
- switch (state) {
- case 0:
- if (*escaped == '%') {
- state++;
- escaped++;
- continue;
- }
- if (*escaped == '+') {
- escaped++;
- *string++ = ' ';
- len--;
- continue;
- }
- *string++ = *escaped++;
- len--;
- break;
- case 1:
- n = char_to_hex(*escaped);
- if (n < 0)
- return -1;
- escaped++;
- sum = n << 4;
- state++;
- break;
-
- case 2:
- n = char_to_hex(*escaped);
- if (n < 0)
- return -1;
- escaped++;
- *string++ = sum | n;
- len--;
- state = 0;
- break;
- }
-
- }
- *string = '\0';
-
- return 0;
-}
-
-LWS_VISIBLE LWS_EXTERN int
-lws_finalize_startup(struct lws_context *context)
-{
- struct lws_context_creation_info info;
-
- info.uid = context->uid;
- info.gid = context->gid;
-
-#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
- memcpy(info.caps, context->caps, sizeof(info.caps));
- info.count_caps = context->count_caps;
-#endif
-
- if (lws_check_opt(context->options, LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
- lws_plat_drop_app_privileges(&info);
-
- return 0;
-}
-
-LWS_VISIBLE LWS_EXTERN void
-lws_get_effective_uid_gid(struct lws_context *context, int *uid, int *gid)
-{
- *uid = context->uid;
- *gid = context->gid;
-}
-
-int
-lws_snprintf(char *str, size_t size, const char *format, ...)
-{
- va_list ap;
- int n;
-
- if (!size)
- return 0;
-
- va_start(ap, format);
- n = vsnprintf(str, size, format, ap);
- va_end(ap);
-
- if (n >= (int)size)
- return (int)size;
-
- return n;
-}
-
-char *
-lws_strncpy(char *dest, const char *src, size_t size)
-{
- strncpy(dest, src, size - 1);
- dest[size - 1] = '\0';
-
- return dest;
-}
-
-
-typedef enum {
- LWS_TOKZS_LEADING_WHITESPACE,
- LWS_TOKZS_QUOTED_STRING,
- LWS_TOKZS_TOKEN,
- LWS_TOKZS_TOKEN_POST_TERMINAL
-} lws_tokenize_state;
-
-int
-lws_tokenize(struct lws_tokenize *ts)
-{
- const char *rfc7230_delims = "(),/:;<=>?@[\\]{}";
- lws_tokenize_state state = LWS_TOKZS_LEADING_WHITESPACE;
- char c, flo = 0, d_minus = '-', d_dot = '.', s_minus = '\0',
- s_dot = '\0';
- signed char num = -1;
- int utf8 = 0;
-
- /* for speed, compute the effect of the flags outside the loop */
-
- if (ts->flags & LWS_TOKENIZE_F_MINUS_NONTERM) {
- d_minus = '\0';
- s_minus = '-';
- }
- if (ts->flags & LWS_TOKENIZE_F_DOT_NONTERM) {
- d_dot = '\0';
- s_dot = '.';
- }
-
- ts->token = NULL;
- ts->token_len = 0;
-
- while (ts->len) {
- c = *ts->start++;
- ts->len--;
-
- utf8 = lws_check_byte_utf8((unsigned char)utf8, c);
- if (utf8 < 0)
- return LWS_TOKZE_ERR_BROKEN_UTF8;
-
- if (!c)
- break;
-
- /* whitespace */
-
- if (c == ' ' || c == '\t' || c == '\n' || c == '\r' ||
- c == '\f') {
- switch (state) {
- case LWS_TOKZS_LEADING_WHITESPACE:
- case LWS_TOKZS_TOKEN_POST_TERMINAL:
- continue;
- case LWS_TOKZS_QUOTED_STRING:
- ts->token_len++;
- continue;
- case LWS_TOKZS_TOKEN:
- /* we want to scan forward to look for = */
-
- state = LWS_TOKZS_TOKEN_POST_TERMINAL;
- continue;
- }
- }
-
- /* quoted string */
-
- if (c == '\"') {
- if (state == LWS_TOKZS_QUOTED_STRING)
- return LWS_TOKZE_QUOTED_STRING;
-
- /* starting a quoted string */
-
- if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
- if (ts->delim == LWSTZ_DT_NEED_DELIM)
- return LWS_TOKZE_ERR_COMMA_LIST;
- ts->delim = LWSTZ_DT_NEED_DELIM;
- }
-
- state = LWS_TOKZS_QUOTED_STRING;
- ts->token = ts->start;
- ts->token_len = 0;
-
- continue;
- }
-
- /* token= aggregation */
-
- if (c == '=' && (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
- state == LWS_TOKZS_TOKEN)) {
- if (num == 1)
- return LWS_TOKZE_ERR_NUM_ON_LHS;
- /* swallow the = */
- return LWS_TOKZE_TOKEN_NAME_EQUALS;
- }
-
- /* optional token: aggregation */
-
- if ((ts->flags & LWS_TOKENIZE_F_AGG_COLON) && c == ':' &&
- (state == LWS_TOKZS_TOKEN_POST_TERMINAL ||
- state == LWS_TOKZS_TOKEN))
- /* swallow the : */
- return LWS_TOKZE_TOKEN_NAME_COLON;
-
- /* aggregate . in a number as a float */
-
- if (c == '.' && !(ts->flags & LWS_TOKENIZE_F_NO_FLOATS) &&
- state == LWS_TOKZS_TOKEN && num == 1) {
- if (flo)
- return LWS_TOKZE_ERR_MALFORMED_FLOAT;
- flo = 1;
- ts->token_len++;
- continue;
- }
-
- /*
- * Delimiter... by default anything that:
- *
- * - isn't matched earlier, or
- * - is [A-Z, a-z, 0-9, _], and
- * - is not a partial utf8 char
- *
- * is a "delimiter", it marks the end of a token and is itself
- * reported as a single LWS_TOKZE_DELIMITER each time.
- *
- * However with LWS_TOKENIZE_F_RFC7230_DELIMS flag, tokens may
- * contain any noncontrol character that isn't defined in
- * rfc7230_delims, and only characters listed there are treated
- * as delimiters.
- */
-
- if (!utf8 &&
- ((ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS &&
- strchr(rfc7230_delims, c) && c > 32) ||
- ((!(ts->flags & LWS_TOKENIZE_F_RFC7230_DELIMS) &&
- (c < '0' || c > '9') && (c < 'A' || c > 'Z') &&
- (c < 'a' || c > 'z') && c != '_') &&
- c != s_minus && c != s_dot) ||
- c == d_minus || c == d_dot
- )) {
- switch (state) {
- case LWS_TOKZS_LEADING_WHITESPACE:
- if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
- if (c != ',' ||
- ts->delim != LWSTZ_DT_NEED_DELIM)
- return LWS_TOKZE_ERR_COMMA_LIST;
- ts->delim = LWSTZ_DT_NEED_NEXT_CONTENT;
- }
-
- ts->token = ts->start - 1;
- ts->token_len = 1;
- return LWS_TOKZE_DELIMITER;
-
- case LWS_TOKZS_QUOTED_STRING:
- ts->token_len++;
- continue;
-
- case LWS_TOKZS_TOKEN_POST_TERMINAL:
- case LWS_TOKZS_TOKEN:
- /* report the delimiter next time */
- ts->start--;
- ts->len++;
- goto token_or_numeric;
- }
- }
-
- /* anything that's not whitespace or delimiter is payload */
-
- switch (state) {
- case LWS_TOKZS_LEADING_WHITESPACE:
-
- if (ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
- if (ts->delim == LWSTZ_DT_NEED_DELIM)
- return LWS_TOKZE_ERR_COMMA_LIST;
- ts->delim = LWSTZ_DT_NEED_DELIM;
- }
-
- state = LWS_TOKZS_TOKEN;
- ts->token = ts->start - 1;
- ts->token_len = 1;
- if (c < '0' || c > '9')
- num = 0;
- else
- if (num < 0)
- num = 1;
- continue;
- case LWS_TOKZS_QUOTED_STRING:
- case LWS_TOKZS_TOKEN:
- if (c < '0' || c > '9')
- num = 0;
- else
- if (num < 0)
- num = 1;
- ts->token_len++;
- continue;
- case LWS_TOKZS_TOKEN_POST_TERMINAL:
- /* report the new token next time */
- ts->start--;
- ts->len++;
- goto token_or_numeric;
- }
- }
-
- /* we ran out of content */
-
- if (utf8) /* ended partway through a multibyte char */
- return LWS_TOKZE_ERR_BROKEN_UTF8;
-
- if (state == LWS_TOKZS_QUOTED_STRING)
- return LWS_TOKZE_ERR_UNTERM_STRING;
-
- if (state != LWS_TOKZS_TOKEN_POST_TERMINAL &&
- state != LWS_TOKZS_TOKEN) {
- if ((ts->flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) &&
- ts->delim == LWSTZ_DT_NEED_NEXT_CONTENT)
- return LWS_TOKZE_ERR_COMMA_LIST;
-
- return LWS_TOKZE_ENDED;
- }
-
- /* report the pending token */
-
-token_or_numeric:
-
- if (num != 1)
- return LWS_TOKZE_TOKEN;
- if (flo)
- return LWS_TOKZE_FLOAT;
-
- return LWS_TOKZE_INTEGER;
-}
-
-
-LWS_VISIBLE LWS_EXTERN int
-lws_tokenize_cstr(struct lws_tokenize *ts, char *str, int max)
-{
- if (ts->token_len + 1 >= max)
- return 1;
-
- memcpy(str, ts->token, ts->token_len);
- str[ts->token_len] = '\0';
-
- return 0;
-}
-
-LWS_VISIBLE LWS_EXTERN void
-lws_tokenize_init(struct lws_tokenize *ts, const char *start, int flags)
-{
- ts->start = start;
- ts->len = 0x7fffffff;
- ts->flags = flags;
- ts->delim = LWSTZ_DT_NEED_FIRST_CONTENT;
-}
-
-#if LWS_MAX_SMP > 1
-
-void
-lws_mutex_refcount_init(struct lws_mutex_refcount *mr)
-{
- pthread_mutex_init(&mr->lock, NULL);
- mr->last_lock_reason = NULL;
- mr->lock_depth = 0;
- mr->metadata = 0;
- mr->lock_owner = 0;
-}
-
-void
-lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr)
-{
- pthread_mutex_destroy(&mr->lock);
-}
-
-void
-lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason)
-{
- /* if true, this sequence is atomic because our thread has the lock
- *
- * - if true, only guy who can race to make it untrue is our thread,
- * and we are here.
- *
- * - if false, only guy who could race to make it true is our thread,
- * and we are here
- *
- * - it can be false and change to a different tid that is also false
- */
- if (mr->lock_owner == pthread_self()) {
- /* atomic because we only change it if we own the lock */
- mr->lock_depth++;
- return;
- }
-
- pthread_mutex_lock(&mr->lock);
- /* atomic because only we can have the lock */
- mr->last_lock_reason = reason;
- mr->lock_owner = pthread_self();
- mr->lock_depth = 1;
- //lwsl_notice("tid %d: lock %s\n", mr->tid, reason);
-}
-
-void
-lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr)
-{
- if (--mr->lock_depth)
- /* atomic because only thread that has the lock can unlock */
- return;
-
- mr->last_lock_reason = "free";
- mr->lock_owner = 0;
- //lwsl_notice("tid %d: unlock %s\n", mr->tid, mr->last_lock_reason);
- pthread_mutex_unlock(&mr->lock);
-}
-
-#endif /* SMP */
-
-LWS_VISIBLE LWS_EXTERN int
-lws_is_cgi(struct lws *wsi) {
-#ifdef LWS_WITH_CGI
- return !!wsi->http.cgi;
-#else
- return 0;
-#endif
-}
-
-const struct lws_protocol_vhost_options *
-lws_pvo_search(const struct lws_protocol_vhost_options *pvo, const char *name)
-{
- while (pvo) {
- if (!strcmp(pvo->name, name))
- break;
-
- pvo = pvo->next;
- }
-
- return pvo;
-}
-
-int
-lws_pvo_get_str(void *in, const char *name, const char **result)
-{
- const struct lws_protocol_vhost_options *pv =
- lws_pvo_search((const struct lws_protocol_vhost_options *)in,
- name);
-
- if (!pv)
- return 1;
-
- *result = (const char *)pv->value;
-
- return 0;
-}
-
-void
-lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs)
-{
- const struct lws_vhost *vh = ctx->vhost_list;
-
- while (vh) {
-
- cs->rx += vh->conn_stats.rx;
- cs->tx += vh->conn_stats.tx;
- cs->h1_conn += vh->conn_stats.h1_conn;
- cs->h1_trans += vh->conn_stats.h1_trans;
- cs->h2_trans += vh->conn_stats.h2_trans;
- cs->ws_upg += vh->conn_stats.ws_upg;
- cs->h2_upg += vh->conn_stats.h2_upg;
- cs->h2_alpn += vh->conn_stats.h2_alpn;
- cs->h2_subs += vh->conn_stats.h2_subs;
- cs->rejected += vh->conn_stats.rejected;
-
- vh = vh->vhost_next;
- }
-}
-
-const char *
-lws_cmdline_option(int argc, const char **argv, const char *val)
-{
- int n = (int)strlen(val), c = argc;
-
- while (--c > 0) {
-
- if (!strncmp(argv[c], val, n)) {
- if (!*(argv[c] + n) && c < argc - 1) {
- /* coverity treats unchecked argv as "tainted" */
- if (!argv[c + 1] || strlen(argv[c + 1]) > 1024)
- return NULL;
- return argv[c + 1];
- }
-
- return argv[c] + n;
- }
- }
-
- return NULL;
-}
-
-#ifdef LWS_WITH_SERVER_STATUS
-
-LWS_EXTERN int
-lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len)
-{
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- static const char * const prots[] = {
- "http://",
- "https://",
- "file://",
- "cgi://",
- ">http://",
- ">https://",
- "callback://"
- };
-#endif
- char *orig = buf, *end = buf + len - 1, first = 1;
- int n = 0;
-
- if (len < 100)
- return 0;
-
- buf += lws_snprintf(buf, end - buf,
- "{\n \"name\":\"%s\",\n"
- " \"port\":\"%d\",\n"
- " \"use_ssl\":\"%d\",\n"
- " \"sts\":\"%d\",\n"
- " \"rx\":\"%llu\",\n"
- " \"tx\":\"%llu\",\n"
- " \"h1_conn\":\"%lu\",\n"
- " \"h1_trans\":\"%lu\",\n"
- " \"h2_trans\":\"%lu\",\n"
- " \"ws_upg\":\"%lu\",\n"
- " \"rejected\":\"%lu\",\n"
- " \"h2_upg\":\"%lu\",\n"
- " \"h2_alpn\":\"%lu\",\n"
- " \"h2_subs\":\"%lu\""
- ,
- vh->name, vh->listen_port,
-#if defined(LWS_WITH_TLS)
- vh->tls.use_ssl & LCCSCF_USE_SSL,
-#else
- 0,
-#endif
- !!(vh->options & LWS_SERVER_OPTION_STS),
- vh->conn_stats.rx, vh->conn_stats.tx,
- vh->conn_stats.h1_conn,
- vh->conn_stats.h1_trans,
- vh->conn_stats.h2_trans,
- vh->conn_stats.ws_upg,
- vh->conn_stats.rejected,
- vh->conn_stats.h2_upg,
- vh->conn_stats.h2_alpn,
- vh->conn_stats.h2_subs
- );
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- if (vh->http.mount_list) {
- const struct lws_http_mount *m = vh->http.mount_list;
-
- buf += lws_snprintf(buf, end - buf, ",\n \"mounts\":[");
- while (m) {
- if (!first)
- buf += lws_snprintf(buf, end - buf, ",");
- buf += lws_snprintf(buf, end - buf,
- "\n {\n \"mountpoint\":\"%s\",\n"
- " \"origin\":\"%s%s\",\n"
- " \"cache_max_age\":\"%d\",\n"
- " \"cache_reuse\":\"%d\",\n"
- " \"cache_revalidate\":\"%d\",\n"
- " \"cache_intermediaries\":\"%d\"\n"
- ,
- m->mountpoint,
- prots[m->origin_protocol],
- m->origin,
- m->cache_max_age,
- m->cache_reusable,
- m->cache_revalidate,
- m->cache_intermediaries);
- if (m->def)
- buf += lws_snprintf(buf, end - buf,
- ",\n \"default\":\"%s\"",
- m->def);
- buf += lws_snprintf(buf, end - buf, "\n }");
- first = 0;
- m = m->mount_next;
- }
- buf += lws_snprintf(buf, end - buf, "\n ]");
- }
-#endif
- if (vh->protocols) {
- n = 0;
- first = 1;
-
- buf += lws_snprintf(buf, end - buf, ",\n \"ws-protocols\":[");
- while (n < vh->count_protocols) {
- if (!first)
- buf += lws_snprintf(buf, end - buf, ",");
- buf += lws_snprintf(buf, end - buf,
- "\n {\n \"%s\":{\n"
- " \"status\":\"ok\"\n }\n }"
- ,
- vh->protocols[n].name);
- first = 0;
- n++;
- }
- buf += lws_snprintf(buf, end - buf, "\n ]");
- }
-
- buf += lws_snprintf(buf, end - buf, "\n}");
-
- return buf - orig;
-}
-
-
-LWS_EXTERN LWS_VISIBLE int
-lws_json_dump_context(const struct lws_context *context, char *buf, int len,
- int hide_vhosts)
-{
- char *orig = buf, *end = buf + len - 1, first = 1;
- const struct lws_vhost *vh = context->vhost_list;
- const struct lws_context_per_thread *pt;
- time_t t = time(NULL);
- int n, listening = 0, cgi_count = 0;
- struct lws_conn_stats cs;
- double d = 0;
-#ifdef LWS_WITH_CGI
- struct lws_cgi * const *pcgi;
-#endif
-
-#ifdef LWS_WITH_LIBUV
- uv_uptime(&d);
-#endif
-
- buf += lws_snprintf(buf, end - buf, "{ "
- "\"version\":\"%s\",\n"
- "\"uptime\":\"%ld\",\n",
- lws_get_library_version(),
- (long)d);
-
-#ifdef LWS_HAVE_GETLOADAVG
- {
- double d[3];
- int m;
-
- m = getloadavg(d, 3);
- for (n = 0; n < m; n++) {
- buf += lws_snprintf(buf, end - buf,
- "\"l%d\":\"%.2f\",\n",
- n + 1, d[n]);
- }
- }
-#endif
-
- buf += lws_snprintf(buf, end - buf, "\"contexts\":[\n");
-
- buf += lws_snprintf(buf, end - buf, "{ "
- "\"context_uptime\":\"%ld\",\n"
- "\"cgi_spawned\":\"%d\",\n"
- "\"pt_fd_max\":\"%d\",\n"
- "\"ah_pool_max\":\"%d\",\n"
- "\"deprecated\":\"%d\",\n"
- "\"wsi_alive\":\"%d\",\n",
- (unsigned long)(t - context->time_up),
- context->count_cgi_spawned,
- context->fd_limit_per_thread,
- context->max_http_header_pool,
- context->deprecated,
- context->count_wsi_allocated);
-
- buf += lws_snprintf(buf, end - buf, "\"pt\":[\n ");
- for (n = 0; n < context->count_threads; n++) {
- pt = &context->pt[n];
- if (n)
- buf += lws_snprintf(buf, end - buf, ",");
- buf += lws_snprintf(buf, end - buf,
- "\n {\n"
- " \"fds_count\":\"%d\",\n"
- " \"ah_pool_inuse\":\"%d\",\n"
- " \"ah_wait_list\":\"%d\"\n"
- " }",
- pt->fds_count,
- pt->http.ah_count_in_use,
- pt->http.ah_wait_list_length);
- }
-
- buf += lws_snprintf(buf, end - buf, "]");
-
- buf += lws_snprintf(buf, end - buf, ", \"vhosts\":[\n ");
-
- first = 1;
- vh = context->vhost_list;
- listening = 0;
- cs = context->conn_stats;
- lws_sum_stats(context, &cs);
- while (vh) {
-
- if (!hide_vhosts) {
- if (!first)
- if(buf != end)
- *buf++ = ',';
- buf += lws_json_dump_vhost(vh, buf, end - buf);
- first = 0;
- }
- if (vh->lserv_wsi)
- listening++;
- vh = vh->vhost_next;
- }
-
- buf += lws_snprintf(buf, end - buf,
- "],\n\"listen_wsi\":\"%d\",\n"
- " \"rx\":\"%llu\",\n"
- " \"tx\":\"%llu\",\n"
- " \"h1_conn\":\"%lu\",\n"
- " \"h1_trans\":\"%lu\",\n"
- " \"h2_trans\":\"%lu\",\n"
- " \"ws_upg\":\"%lu\",\n"
- " \"rejected\":\"%lu\",\n"
- " \"h2_alpn\":\"%lu\",\n"
- " \"h2_subs\":\"%lu\",\n"
- " \"h2_upg\":\"%lu\"",
- listening, cs.rx, cs.tx,
- cs.h1_conn,
- cs.h1_trans,
- cs.h2_trans,
- cs.ws_upg,
- cs.rejected,
- cs.h2_alpn,
- cs.h2_subs,
- cs.h2_upg);
-
-#ifdef LWS_WITH_CGI
- for (n = 0; n < context->count_threads; n++) {
- pt = &context->pt[n];
- pcgi = &pt->http.cgi_list;
-
- while (*pcgi) {
- pcgi = &(*pcgi)->cgi_list;
-
- cgi_count++;
- }
- }
-#endif
- buf += lws_snprintf(buf, end - buf, ",\n \"cgi_alive\":\"%d\"\n ",
- cgi_count);
-
- buf += lws_snprintf(buf, end - buf, "}");
-
-
- buf += lws_snprintf(buf, end - buf, "]}\n ");
-
- return buf - orig;
-}
-
-#endif
-
-#if defined(LWS_WITH_STATS)
-
-LWS_VISIBLE LWS_EXTERN uint64_t
-lws_stats_get(struct lws_context *context, int index)
-{
- if (index >= LWSSTATS_SIZE)
- return 0;
-
- return context->lws_stats[index];
-}
-
-LWS_VISIBLE LWS_EXTERN void
-lws_stats_log_dump(struct lws_context *context)
-{
- struct lws_vhost *v = context->vhost_list;
- int n;
-#if defined(LWS_WITH_PEER_LIMITS)
- int m;
-#endif
-
- if (!context->updated)
- return;
-
- context->updated = 0;
-
- lwsl_notice("\n");
- lwsl_notice("LWS internal statistics dump ----->\n");
- lwsl_notice("LWSSTATS_C_CONNECTIONS: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_CONNECTIONS));
- lwsl_notice("LWSSTATS_C_API_CLOSE: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_API_CLOSE));
- lwsl_notice("LWSSTATS_C_API_READ: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_API_READ));
- lwsl_notice("LWSSTATS_C_API_LWS_WRITE: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_API_LWS_WRITE));
- lwsl_notice("LWSSTATS_C_API_WRITE: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_API_WRITE));
- lwsl_notice("LWSSTATS_C_WRITE_PARTIALS: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_WRITE_PARTIALS));
- lwsl_notice("LWSSTATS_C_WRITEABLE_CB_REQ: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_WRITEABLE_CB_REQ));
- lwsl_notice("LWSSTATS_C_WRITEABLE_CB_EFF_REQ: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_WRITEABLE_CB_EFF_REQ));
- lwsl_notice("LWSSTATS_C_WRITEABLE_CB: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_WRITEABLE_CB));
- lwsl_notice("LWSSTATS_C_SSL_CONNECTIONS_ACCEPT_SPIN: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_SSL_CONNECTIONS_ACCEPT_SPIN));
- lwsl_notice("LWSSTATS_C_SSL_CONNECTIONS_FAILED: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_SSL_CONNECTIONS_FAILED));
- lwsl_notice("LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED));
- lwsl_notice("LWSSTATS_C_SSL_CONNS_HAD_RX: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_SSL_CONNS_HAD_RX));
- lwsl_notice("LWSSTATS_C_PEER_LIMIT_AH_DENIED: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_PEER_LIMIT_AH_DENIED));
- lwsl_notice("LWSSTATS_C_PEER_LIMIT_WSI_DENIED: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_PEER_LIMIT_WSI_DENIED));
-
- lwsl_notice("LWSSTATS_C_TIMEOUTS: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_TIMEOUTS));
- lwsl_notice("LWSSTATS_C_SERVICE_ENTRY: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_C_SERVICE_ENTRY));
- lwsl_notice("LWSSTATS_B_READ: %8llu\n",
- (unsigned long long)lws_stats_get(context, LWSSTATS_B_READ));
- lwsl_notice("LWSSTATS_B_WRITE: %8llu\n",
- (unsigned long long)lws_stats_get(context, LWSSTATS_B_WRITE));
- lwsl_notice("LWSSTATS_B_PARTIALS_ACCEPTED_PARTS: %8llu\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_B_PARTIALS_ACCEPTED_PARTS));
- lwsl_notice("LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY: %8llums\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY) / 1000);
- if (lws_stats_get(context, LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED))
- lwsl_notice(" Avg accept delay: %8llums\n",
- (unsigned long long)(lws_stats_get(context,
- LWSSTATS_MS_SSL_CONNECTIONS_ACCEPTED_DELAY) /
- lws_stats_get(context,
- LWSSTATS_C_SSL_CONNECTIONS_ACCEPTED)) / 1000);
- lwsl_notice("LWSSTATS_MS_SSL_RX_DELAY: %8llums\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_MS_SSL_RX_DELAY) / 1000);
- if (lws_stats_get(context, LWSSTATS_C_SSL_CONNS_HAD_RX))
- lwsl_notice(" Avg accept-rx delay: %8llums\n",
- (unsigned long long)(lws_stats_get(context,
- LWSSTATS_MS_SSL_RX_DELAY) /
- lws_stats_get(context,
- LWSSTATS_C_SSL_CONNS_HAD_RX)) / 1000);
-
- lwsl_notice("LWSSTATS_MS_WRITABLE_DELAY: %8lluus\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_MS_WRITABLE_DELAY));
- lwsl_notice("LWSSTATS_MS_WORST_WRITABLE_DELAY: %8lluus\n",
- (unsigned long long)lws_stats_get(context,
- LWSSTATS_MS_WORST_WRITABLE_DELAY));
- if (lws_stats_get(context, LWSSTATS_C_WRITEABLE_CB))
- lwsl_notice(" Avg writable delay: %8lluus\n",
- (unsigned long long)(lws_stats_get(context,
- LWSSTATS_MS_WRITABLE_DELAY) /
- lws_stats_get(context, LWSSTATS_C_WRITEABLE_CB)));
- lwsl_notice("Simultaneous SSL restriction: %8d/%d\n",
- context->simultaneous_ssl,
- context->simultaneous_ssl_restriction);
-
- lwsl_notice("Live wsi: %8d\n",
- context->count_wsi_allocated);
-
- context->updated = 1;
-
- while (v) {
- if (v->lserv_wsi &&
- v->lserv_wsi->position_in_fds_table != LWS_NO_FDS_POS) {
-
- struct lws_context_per_thread *pt =
- &context->pt[(int)v->lserv_wsi->tsi];
- struct lws_pollfd *pfd;
-
- pfd = &pt->fds[v->lserv_wsi->position_in_fds_table];
-
- lwsl_notice(" Listen port %d actual POLLIN: %d\n",
- v->listen_port,
- (int)pfd->events & LWS_POLLIN);
- }
-
- v = v->vhost_next;
- }
-
- for (n = 0; n < context->count_threads; n++) {
- struct lws_context_per_thread *pt = &context->pt[n];
- struct lws *wl;
- int m = 0;
-
- lwsl_notice("PT %d\n", n + 1);
-
- lws_pt_lock(pt, __func__);
-
- lwsl_notice(" AH in use / max: %d / %d\n",
- pt->http.ah_count_in_use,
- context->max_http_header_pool);
-
- wl = pt->http.ah_wait_list;
- while (wl) {
- m++;
- wl = wl->http.ah_wait_list;
- }
-
- lwsl_notice(" AH wait list count / actual: %d / %d\n",
- pt->http.ah_wait_list_length, m);
-
- lws_pt_unlock(pt);
- }
-
-#if defined(LWS_WITH_PEER_LIMITS)
- m = 0;
- for (n = 0; n < (int)context->pl_hash_elements; n++) {
- lws_start_foreach_llp(struct lws_peer **, peer,
- context->pl_hash_table[n]) {
- m++;
- } lws_end_foreach_llp(peer, next);
- }
-
- lwsl_notice(" Peers: total active %d\n", m);
- if (m > 10) {
- m = 10;
- lwsl_notice(" (showing 10 peers only)\n");
- }
-
- if (m) {
- for (n = 0; n < (int)context->pl_hash_elements; n++) {
- char buf[72];
-
- lws_start_foreach_llp(struct lws_peer **, peer,
- context->pl_hash_table[n]) {
- struct lws_peer *df = *peer;
-
- if (!lws_plat_inet_ntop(df->af, df->addr, buf,
- sizeof(buf) - 1))
- strcpy(buf, "unknown");
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- lwsl_notice(" peer %s: count wsi: %d, count ah: %d\n",
- buf, df->count_wsi,
- df->http.count_ah);
-#else
- lwsl_notice(" peer %s: count wsi: %d\n",
- buf, df->count_wsi);
-#endif
-
- if (!--m)
- break;
- } lws_end_foreach_llp(peer, next);
- }
- }
-#endif
-
- lwsl_notice("\n");
-}
-
-void
-lws_stats_atomic_bump(struct lws_context * context,
- struct lws_context_per_thread *pt, int index, uint64_t bump)
-{
- lws_pt_stats_lock(pt);
- context->lws_stats[index] += bump;
- if (index != LWSSTATS_C_SERVICE_ENTRY)
- context->updated = 1;
- lws_pt_stats_unlock(pt);
-}
-
-void
-lws_stats_atomic_max(struct lws_context * context,
- struct lws_context_per_thread *pt, int index, uint64_t val)
-{
- lws_pt_stats_lock(pt);
- if (val > context->lws_stats[index]) {
- context->lws_stats[index] = val;
- context->updated = 1;
- }
- lws_pt_stats_unlock(pt);
-}
-
-#endif
-
diff --git a/thirdparty/libwebsockets/lib/core/output.c b/thirdparty/libwebsockets/lib/core/output.c
deleted file mode 100644
index 49d289db40..0000000000
--- a/thirdparty/libwebsockets/lib/core/output.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-
-#include "core/private.h"
-
-/*
- * notice this returns number of bytes consumed, or -1
- */
-int lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len)
-{
- struct lws_context *context = lws_get_context(wsi);
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
- size_t real_len = len;
- unsigned int n, m;
-
- // lwsl_notice("%s: len %d\n", __func__, (int)len);
- // lwsl_hexdump_level(LLL_NOTICE, buf, len);
-
- /*
- * Detect if we got called twice without going through the
- * event loop to handle pending. Since that guarantees extending any
- * existing buflist_out it's inefficient.
- */
- if (0 && buf && wsi->could_have_pending) {
- lwsl_hexdump_level(LLL_INFO, buf, len);
- lwsl_info("** %p: vh: %s, prot: %s, role %s: "
- "Inefficient back-to-back write of %lu detected...\n",
- wsi, wsi->vhost->name, wsi->protocol->name,
- wsi->role_ops->name,
- (unsigned long)len);
- }
-
- lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_WRITE, 1);
-
- /* just ignore sends after we cleared the truncation buffer */
- if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE &&
- !lws_has_buffered_out(wsi)
-#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
- && !wsi->http.comp_ctx.may_have_more
-#endif
- )
- return (int)len;
-
- if (buf && lws_has_buffered_out(wsi)) {
- lwsl_info("** %p: vh: %s, prot: %s, incr buflist_out by %lu\n",
- wsi, wsi->vhost->name, wsi->protocol->name,
- (unsigned long)len);
-
- /*
- * already buflist ahead of this, add it on the tail of the
- * buflist, then ignore it for now and act like we're flushing
- * the buflist...
- */
-
- lws_buflist_append_segment(&wsi->buflist_out, buf, len);
-
- buf = NULL;
- len = 0;
- }
-
- if (wsi->buflist_out) {
- /* we have to drain the earliest buflist_out stuff first */
-
- len = lws_buflist_next_segment_len(&wsi->buflist_out, &buf);
- real_len = len;
-
- lwsl_debug("%s: draining %d\n", __func__, (int)len);
- }
-
- if (!len || !buf)
- return 0;
-
- if (!wsi->http2_substream && !lws_socket_is_valid(wsi->desc.sockfd))
- lwsl_warn("** error invalid sock but expected to send\n");
-
- /* limit sending */
- if (wsi->protocol->tx_packet_size)
- n = (int)wsi->protocol->tx_packet_size;
- else {
- n = (int)wsi->protocol->rx_buffer_size;
- if (!n)
- n = context->pt_serv_buf_size;
- }
- n += LWS_PRE + 4;
- if (n > len)
- n = (int)len;
-
- /* nope, send it on the socket directly */
- lws_latency_pre(context, wsi);
- m = lws_ssl_capable_write(wsi, buf, n);
- lws_latency(context, wsi, "send lws_issue_raw", n, n == m);
-
- lwsl_info("%s: ssl_capable_write (%d) says %d\n", __func__, n, m);
-
- /* something got written, it can have been truncated now */
- wsi->could_have_pending = 1;
-
- switch (m) {
- case LWS_SSL_CAPABLE_ERROR:
- /* we're going to close, let close know sends aren't possible */
- wsi->socket_is_permanently_unusable = 1;
- return -1;
- case LWS_SSL_CAPABLE_MORE_SERVICE:
- /*
- * nothing got sent, not fatal. Retry the whole thing later,
- * ie, implying treat it was a truncated send so it gets
- * retried
- */
- m = 0;
- break;
- }
-
- /*
- * we were sending this from buflist_out? Then not sending everything
- * is a small matter of advancing ourselves only by the amount we did
- * send in the buflist.
- */
- if (lws_has_buffered_out(wsi)) {
- if (m) {
- lwsl_info("%p partial adv %d (vs %ld)\n", wsi, m,
- (long)real_len);
- lws_buflist_use_segment(&wsi->buflist_out, m);
- }
-
- if (!lws_has_buffered_out(wsi)) {
- lwsl_info("%s: wsi %p: buflist_out flushed\n",
- __func__, wsi);
-
- m = (int)real_len;
- if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) {
- lwsl_info("*%p signalling to close now\n", wsi);
- return -1; /* retry closing now */
- }
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
-#if !defined(LWS_WITHOUT_SERVER)
- if (wsi->http.deferred_transaction_completed) {
- lwsl_notice("%s: partial completed, doing "
- "deferred transaction completed\n",
- __func__);
- wsi->http.deferred_transaction_completed = 0;
- return lws_http_transaction_completed(wsi) ?
- -1 : (int)real_len;
- }
-#endif
-#endif
- }
- /* always callback on writeable */
- lws_callback_on_writable(wsi);
-
- return m;
- }
-
-#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
- if (wsi->http.comp_ctx.may_have_more)
- lws_callback_on_writable(wsi);
-#endif
-
- if (m == real_len)
- /* what we just sent went out cleanly */
- return m;
-
- /*
- * We were not able to send everything... and we were not sending from
- * an existing buflist_out. So we are starting a fresh buflist_out, by
- * buffering the unsent remainder on it.
- * (it will get first priority next time the socket is writable).
- */
- lwsl_debug("%p new partial sent %d from %lu total\n", wsi, m,
- (unsigned long)real_len);
-
- lws_buflist_append_segment(&wsi->buflist_out, buf + m, real_len - m);
-
- lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITE_PARTIALS, 1);
- lws_stats_atomic_bump(wsi->context, pt,
- LWSSTATS_B_PARTIALS_ACCEPTED_PARTS, m);
-
-#if !defined(LWS_WITH_ESP32)
- if (lws_wsi_is_udp(wsi)) {
- /* stash original destination for fulfilling UDP partials */
- wsi->udp->sa_pending = wsi->udp->sa;
- wsi->udp->salen_pending = wsi->udp->salen;
- }
-#endif
-
- /* since something buffered, force it to get another chance to send */
- lws_callback_on_writable(wsi);
-
- return (int)real_len;
-}
-
-LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len,
- enum lws_write_protocol wp)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-
- lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_API_LWS_WRITE, 1);
-
- if ((int)len < 0) {
- lwsl_err("%s: suspicious len int %d, ulong %lu\n", __func__,
- (int)len, (unsigned long)len);
- return -1;
- }
-
- lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_B_WRITE, len);
-
-#ifdef LWS_WITH_ACCESS_LOG
- wsi->http.access_log.sent += len;
-#endif
- if (wsi->vhost)
- wsi->vhost->conn_stats.tx += len;
-
- assert(wsi->role_ops);
- if (!wsi->role_ops->write_role_protocol)
- return lws_issue_raw(wsi, buf, len);
-
- return wsi->role_ops->write_role_protocol(wsi, buf, len, &wp);
-}
-
-LWS_VISIBLE int
-lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len)
-{
- struct lws_context *context = wsi->context;
- struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
- int n = 0;
-
- lws_stats_atomic_bump(context, pt, LWSSTATS_C_API_READ, 1);
-
- if (lws_wsi_is_udp(wsi)) {
-#if !defined(LWS_WITH_ESP32)
- wsi->udp->salen = sizeof(wsi->udp->sa);
- n = recvfrom(wsi->desc.sockfd, (char *)buf, len, 0,
- &wsi->udp->sa, &wsi->udp->salen);
-#endif
- } else
- n = recv(wsi->desc.sockfd, (char *)buf, len, 0);
-
- if (n >= 0) {
-
- if (!n && wsi->unix_skt)
- return LWS_SSL_CAPABLE_ERROR;
-
- if (wsi->vhost)
- wsi->vhost->conn_stats.rx += n;
- lws_stats_atomic_bump(context, pt, LWSSTATS_B_READ, n);
-
- return n;
- }
-
- if (LWS_ERRNO == LWS_EAGAIN ||
- LWS_ERRNO == LWS_EWOULDBLOCK ||
- LWS_ERRNO == LWS_EINTR)
- return LWS_SSL_CAPABLE_MORE_SERVICE;
-
- lwsl_info("error on reading from skt : %d\n", LWS_ERRNO);
- return LWS_SSL_CAPABLE_ERROR;
-}
-
-LWS_VISIBLE int
-lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len)
-{
- int n = 0;
-
- if (lws_wsi_is_udp(wsi)) {
-#if !defined(LWS_WITH_ESP32)
- if (lws_has_buffered_out(wsi))
- n = sendto(wsi->desc.sockfd, (const char *)buf,
- len, 0, &wsi->udp->sa_pending,
- wsi->udp->salen_pending);
- else
- n = sendto(wsi->desc.sockfd, (const char *)buf,
- len, 0, &wsi->udp->sa, wsi->udp->salen);
-#endif
- } else
- n = send(wsi->desc.sockfd, (char *)buf, len, MSG_NOSIGNAL);
-// lwsl_info("%s: sent len %d result %d", __func__, len, n);
- if (n >= 0)
- return n;
-
- if (LWS_ERRNO == LWS_EAGAIN ||
- LWS_ERRNO == LWS_EWOULDBLOCK ||
- LWS_ERRNO == LWS_EINTR) {
- if (LWS_ERRNO == LWS_EWOULDBLOCK) {
- lws_set_blocking_send(wsi);
- }
-
- return LWS_SSL_CAPABLE_MORE_SERVICE;
- }
-
- lwsl_debug("ERROR writing len %d to skt fd %d err %d / errno %d\n",
- len, wsi->desc.sockfd, n, LWS_ERRNO);
-
- return LWS_SSL_CAPABLE_ERROR;
-}
-
-LWS_VISIBLE int
-lws_ssl_pending_no_ssl(struct lws *wsi)
-{
- (void)wsi;
-#if defined(LWS_WITH_ESP32)
- return 100;
-#else
- return 0;
-#endif
-}
diff --git a/thirdparty/libwebsockets/lib/core/pollfd.c b/thirdparty/libwebsockets/lib/core/pollfd.c
deleted file mode 100644
index 834298577a..0000000000
--- a/thirdparty/libwebsockets/lib/core/pollfd.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-
-#include "core/private.h"
-
-int
-_lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
-{
-#if !defined(LWS_WITH_LIBUV) && !defined(LWS_WITH_LIBEV) && !defined(LWS_WITH_LIBEVENT)
- volatile struct lws_context_per_thread *vpt;
-#endif
- struct lws_context_per_thread *pt;
- struct lws_context *context;
- int ret = 0, pa_events = 1;
- struct lws_pollfd *pfd;
- int sampled_tid, tid;
-
- if (!wsi)
- return 0;
-
- assert(wsi->position_in_fds_table == LWS_NO_FDS_POS ||
- wsi->position_in_fds_table >= 0);
-
- if (wsi->position_in_fds_table == LWS_NO_FDS_POS)
- return 0;
-
- if (((volatile struct lws *)wsi)->handling_pollout &&
- !_and && _or == LWS_POLLOUT) {
- /*
- * Happening alongside service thread handling POLLOUT.
- * The danger is when he is finished, he will disable POLLOUT,
- * countermanding what we changed here.
- *
- * Instead of changing the fds, inform the service thread
- * what happened, and ask it to leave POLLOUT active on exit
- */
- ((volatile struct lws *)wsi)->leave_pollout_active = 1;
- /*
- * by definition service thread is not in poll wait, so no need
- * to cancel service
- */
-
- lwsl_debug("%s: using leave_pollout_active\n", __func__);
-
- return 0;
- }
-
- context = wsi->context;
- pt = &context->pt[(int)wsi->tsi];
-
- assert(wsi->position_in_fds_table < (int)pt->fds_count);
-
-#if !defined(LWS_WITH_LIBUV) && \
- !defined(LWS_WITH_LIBEV) && \
- !defined(LWS_WITH_LIBEVENT)
- /*
- * This only applies when we use the default poll() event loop.
- *
- * BSD can revert pa->events at any time, when the kernel decides to
- * exit from poll(). We can't protect against it using locking.
- *
- * Therefore we must check first if the service thread is in poll()
- * wait; if so, we know we must be being called from a foreign thread,
- * and we must keep a strictly ordered list of changes we made instead
- * of trying to apply them, since when poll() exits, which may happen
- * at any time it would revert our changes.
- *
- * The plat code will apply them when it leaves the poll() wait
- * before doing anything else.
- */
-
- vpt = (volatile struct lws_context_per_thread *)pt;
-
- vpt->foreign_spinlock = 1;
- lws_memory_barrier();
-
- if (vpt->inside_poll) {
- struct lws_foreign_thread_pollfd *ftp, **ftp1;
- /*
- * We are certainly a foreign thread trying to change events
- * while the service thread is in the poll() wait.
- *
- * Create a list of changes to be applied after poll() exit,
- * instead of trying to apply them now.
- */
- ftp = lws_malloc(sizeof(*ftp), "ftp");
- if (!ftp) {
- vpt->foreign_spinlock = 0;
- lws_memory_barrier();
- ret = -1;
- goto bail;
- }
-
- ftp->_and = _and;
- ftp->_or = _or;
- ftp->fd_index = wsi->position_in_fds_table;
- ftp->next = NULL;
-
- /* place at END of list to maintain order */
- ftp1 = (struct lws_foreign_thread_pollfd **)
- &vpt->foreign_pfd_list;
- while (*ftp1)
- ftp1 = &((*ftp1)->next);
-
- *ftp1 = ftp;
- vpt->foreign_spinlock = 0;
- lws_memory_barrier();
- lws_cancel_service_pt(wsi);
-
- return 0;
- }
-
- vpt->foreign_spinlock = 0;
- lws_memory_barrier();
-#endif
-
- pfd = &pt->fds[wsi->position_in_fds_table];
- pa->fd = wsi->desc.sockfd;
- lwsl_debug("%s: wsi %p: fd %d events %d -> %d\n", __func__, wsi,
- pa->fd, pfd->events, (pfd->events & ~_and) | _or);
- pa->prev_events = pfd->events;
- pa->events = pfd->events = (pfd->events & ~_and) | _or;
-
- if (wsi->http2_substream)
- return 0;
-
- if (wsi->vhost &&
- wsi->vhost->protocols[0].callback(wsi,
- LWS_CALLBACK_CHANGE_MODE_POLL_FD,
- wsi->user_space, (void *)pa, 0)) {
- ret = -1;
- goto bail;
- }
-
- if (context->event_loop_ops->io) {
- if (_and & LWS_POLLIN)
- context->event_loop_ops->io(wsi,
- LWS_EV_STOP | LWS_EV_READ);
-
- if (_or & LWS_POLLIN)
- context->event_loop_ops->io(wsi,
- LWS_EV_START | LWS_EV_READ);
-
- if (_and & LWS_POLLOUT)
- context->event_loop_ops->io(wsi,
- LWS_EV_STOP | LWS_EV_WRITE);
-
- if (_or & LWS_POLLOUT)
- context->event_loop_ops->io(wsi,
- LWS_EV_START | LWS_EV_WRITE);
- }
-
- /*
- * if we changed something in this pollfd...
- * ... and we're running in a different thread context
- * than the service thread...
- * ... and the service thread is waiting ...
- * then cancel it to force a restart with our changed events
- */
- pa_events = pa->prev_events != pa->events;
-
- if (pa_events) {
- if (lws_plat_change_pollfd(context, wsi, pfd)) {
- lwsl_info("%s failed\n", __func__);
- ret = -1;
- goto bail;
- }
- sampled_tid = pt->service_tid;
- if (sampled_tid && wsi->vhost) {
- tid = wsi->vhost->protocols[0].callback(wsi,
- LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
- if (tid == -1) {
- ret = -1;
- goto bail;
- }
- if (tid != sampled_tid)
- lws_cancel_service_pt(wsi);
- }
- }
-
-bail:
- return ret;
-}
-
-#ifndef LWS_NO_SERVER
-/*
- * Enable or disable listen sockets on this pt globally...
- * it's modulated according to the pt having space for a new accept.
- */
-static void
-lws_accept_modulation(struct lws_context *context,
- struct lws_context_per_thread *pt, int allow)
-{
- struct lws_vhost *vh = context->vhost_list;
- 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);
- }
- vh = vh->vhost_next;
- }
-}
-#endif
-
-int
-__insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi)
-{
- struct lws_pollargs pa = { wsi->desc.sockfd, LWS_POLLIN, 0 };
- struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
- int ret = 0;
-
-
- lwsl_debug("%s: %p: tsi=%d, sock=%d, pos-in-fds=%d\n",
- __func__, wsi, wsi->tsi, wsi->desc.sockfd, pt->fds_count);
-
- if ((unsigned int)pt->fds_count >= context->fd_limit_per_thread) {
- lwsl_err("Too many fds (%d vs %d)\n", context->max_fds,
- context->fd_limit_per_thread );
- return 1;
- }
-
-#if !defined(_WIN32)
- if (wsi->desc.sockfd - lws_plat_socket_offset() >= context->max_fds) {
- lwsl_err("Socket fd %d is too high (%d) offset %d\n",
- wsi->desc.sockfd, context->max_fds,
- lws_plat_socket_offset());
- return 1;
- }
-#endif
-
- assert(wsi);
- assert(wsi->event_pipe || wsi->vhost);
- assert(lws_socket_is_valid(wsi->desc.sockfd));
-
- if (wsi->vhost &&
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
- wsi->user_space, (void *) &pa, 1))
- return -1;
-
- pt->count_conns++;
- insert_wsi(context, wsi);
- wsi->position_in_fds_table = pt->fds_count;
-
- pt->fds[wsi->position_in_fds_table].fd = wsi->desc.sockfd;
- pt->fds[wsi->position_in_fds_table].events = LWS_POLLIN;
- pa.events = pt->fds[pt->fds_count].events;
-
- lws_plat_insert_socket_into_fds(context, wsi);
-
- /* external POLL support via protocol 0 */
- if (wsi->vhost &&
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_ADD_POLL_FD,
- wsi->user_space, (void *) &pa, 0))
- ret = -1;
-#ifndef LWS_NO_SERVER
- /* if no more room, defeat accepts on this thread */
- if ((unsigned int)pt->fds_count == context->fd_limit_per_thread - 1)
- lws_accept_modulation(context, pt, 0);
-#endif
-
- if (wsi->vhost &&
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
- wsi->user_space, (void *)&pa, 1))
- ret = -1;
-
- return ret;
-}
-
-int
-__remove_wsi_socket_from_fds(struct lws *wsi)
-{
- struct lws_context *context = wsi->context;
- struct lws_pollargs pa = { wsi->desc.sockfd, 0, 0 };
- struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
- struct lws *end_wsi;
- int v;
- int m, ret = 0;
-
-#if !defined(_WIN32)
- if (wsi->desc.sockfd - lws_plat_socket_offset() > context->max_fds) {
- lwsl_err("fd %d too high (%d)\n", wsi->desc.sockfd,
- context->max_fds);
- return 1;
- }
-#endif
-
- if (wsi->vhost &&
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
- wsi->user_space, (void *)&pa, 1))
- return -1;
-
- lws_same_vh_protocol_remove(wsi);
-
- /* the guy who is to be deleted's slot index in pt->fds */
- m = wsi->position_in_fds_table;
-
- /* these are the only valid possibilities for position_in_fds_table */
- assert(m == LWS_NO_FDS_POS || (m >= 0 &&
- (unsigned int)m < pt->fds_count));
-
- if (context->event_loop_ops->io)
- context->event_loop_ops->io(wsi,
- LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE |
- LWS_EV_PREPARE_DELETION);
-
- lwsl_debug("%s: wsi=%p, skt=%d, fds pos=%d, end guy pos=%d, endfd=%d\n",
- __func__, wsi, wsi->desc.sockfd, wsi->position_in_fds_table,
- pt->fds_count, pt->fds[pt->fds_count].fd);
-
- if (m != LWS_NO_FDS_POS) {
-
- /* have the last guy take up the now vacant slot */
- pt->fds[m] = pt->fds[pt->fds_count - 1];
- /* this decrements pt->fds_count */
- lws_plat_delete_socket_from_fds(context, wsi, m);
- pt->count_conns--;
- v = (int) pt->fds[m].fd;
- /* end guy's "position in fds table" is now the deletion
- * guy's old one */
- end_wsi = wsi_from_fd(context, v);
- if (!end_wsi) {
- lwsl_err("no wsi for fd %d pos %d, pt->fds_count=%d\n",
- (int)pt->fds[m].fd, m, pt->fds_count);
- assert(0);
- } else
- end_wsi->position_in_fds_table = m;
-
- /* deletion guy's lws_lookup entry needs nuking */
- delete_from_fd(context, wsi->desc.sockfd);
-
- /* removed wsi has no position any more */
- wsi->position_in_fds_table = LWS_NO_FDS_POS;
- }
-
- /* remove also from external POLL support via protocol 0 */
- if (lws_socket_is_valid(wsi->desc.sockfd) && wsi->vhost &&
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_DEL_POLL_FD,
- wsi->user_space, (void *) &pa, 0))
- ret = -1;
-
-#ifndef LWS_NO_SERVER
- if (!context->being_destroyed &&
- /* if this made some room, accept connects on this thread */
- (unsigned int)pt->fds_count < context->fd_limit_per_thread - 1)
- lws_accept_modulation(context, pt, 1);
-#endif
-
- if (wsi->vhost &&
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
- wsi->user_space, (void *) &pa, 1))
- ret = -1;
-
- return ret;
-}
-
-int
-__lws_change_pollfd(struct lws *wsi, int _and, int _or)
-{
- struct lws_context *context;
- struct lws_pollargs pa;
- int ret = 0;
-
- if (!wsi || (!wsi->protocol && !wsi->event_pipe) ||
- wsi->position_in_fds_table == LWS_NO_FDS_POS)
- return 0;
-
- context = lws_get_context(wsi);
- if (!context)
- return 1;
-
- if (wsi->vhost &&
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_LOCK_POLL,
- wsi->user_space, (void *) &pa, 0))
- return -1;
-
- ret = _lws_change_pollfd(wsi, _and, _or, &pa);
- if (wsi->vhost &&
- wsi->vhost->protocols[0].callback(wsi, LWS_CALLBACK_UNLOCK_POLL,
- wsi->user_space, (void *) &pa, 0))
- ret = -1;
-
- return ret;
-}
-
-int
-lws_change_pollfd(struct lws *wsi, int _and, int _or)
-{
- struct lws_context_per_thread *pt;
- int ret = 0;
-
- pt = &wsi->context->pt[(int)wsi->tsi];
-
- lws_pt_lock(pt, __func__);
- ret = __lws_change_pollfd(wsi, _and, _or);
- lws_pt_unlock(pt);
-
- return ret;
-}
-
-LWS_VISIBLE int
-lws_callback_on_writable(struct lws *wsi)
-{
- struct lws_context_per_thread *pt;
-
- if (lwsi_state(wsi) == LRS_SHUTDOWN)
- return 0;
-
- if (wsi->socket_is_permanently_unusable)
- return 0;
-
- pt = &wsi->context->pt[(int)wsi->tsi];
-
- lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB_REQ, 1);
-#if defined(LWS_WITH_STATS)
- if (!wsi->active_writable_req_us) {
- wsi->active_writable_req_us = lws_time_in_microseconds();
- lws_stats_atomic_bump(wsi->context, pt,
- LWSSTATS_C_WRITEABLE_CB_EFF_REQ, 1);
- }
-#endif
-
-
- if (wsi->role_ops->callback_on_writable) {
- if (wsi->role_ops->callback_on_writable(wsi))
- return 1;
- wsi = lws_get_network_wsi(wsi);
- }
-
- if (wsi->position_in_fds_table == LWS_NO_FDS_POS) {
- lwsl_debug("%s: failed to find socket %d\n", __func__,
- wsi->desc.sockfd);
- return -1;
- }
-
- if (__lws_change_pollfd(wsi, 0, LWS_POLLOUT))
- return -1;
-
- return 1;
-}
-
-
-/*
- * stitch protocol choice into the vh protocol linked list
- * We always insert ourselves at the start of the list
- *
- * X <-> B
- * X <-> pAn <-> pB
- *
- * Illegal to attach more than once without detach inbetween
- */
-void
-lws_same_vh_protocol_insert(struct lws *wsi, int n)
-{
- lws_vhost_lock(wsi->vhost);
-
- if (!lws_dll_is_null(&wsi->same_vh_protocol))
- lws_dll_lws_remove(&wsi->same_vh_protocol);
-
- lws_dll_lws_add_front(&wsi->same_vh_protocol,
- &wsi->vhost->same_vh_protocol_heads[n]);
-
- lws_vhost_unlock(wsi->vhost);
-}
-
-void
-__lws_same_vh_protocol_remove(struct lws *wsi)
-{
- if (!lws_dll_is_null(&wsi->same_vh_protocol))
- lws_dll_lws_remove(&wsi->same_vh_protocol);
-}
-
-void
-lws_same_vh_protocol_remove(struct lws *wsi)
-{
- if (!wsi->vhost)
- return;
-
- lws_vhost_lock(wsi->vhost);
-
- __lws_same_vh_protocol_remove(wsi);
-
- lws_vhost_unlock(wsi->vhost);
-}
-
-
-LWS_VISIBLE int
-lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
- const struct lws_protocols *protocol)
-{
- struct lws *wsi;
- int n;
-
- if (protocol < vhost->protocols ||
- protocol >= (vhost->protocols + vhost->count_protocols)) {
- lwsl_err("%s: protocol %p is not from vhost %p (%p - %p)\n",
- __func__, protocol, vhost->protocols, vhost,
- (vhost->protocols + vhost->count_protocols));
-
- return -1;
- }
-
- n = (int)(protocol - vhost->protocols);
-
- lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
- vhost->same_vh_protocol_heads[n].next) {
- wsi = lws_container_of(d, struct lws, same_vh_protocol);
-
- assert(wsi->protocol == protocol);
- lws_callback_on_writable(wsi);
-
- } lws_end_foreach_dll_safe(d, d1);
-
- return 0;
-}
-
-LWS_VISIBLE int
-lws_callback_on_writable_all_protocol(const struct lws_context *context,
- const struct lws_protocols *protocol)
-{
- struct lws_vhost *vhost;
- int n;
-
- if (!context)
- return 0;
-
- vhost = context->vhost_list;
-
- while (vhost) {
- for (n = 0; n < vhost->count_protocols; n++)
- if (protocol->callback ==
- vhost->protocols[n].callback &&
- !strcmp(protocol->name, vhost->protocols[n].name))
- break;
- if (n != vhost->count_protocols)
- lws_callback_on_writable_all_protocol_vhost(
- vhost, &vhost->protocols[n]);
-
- vhost = vhost->vhost_next;
- }
-
- return 0;
-}
diff --git a/thirdparty/libwebsockets/lib/core/private.h b/thirdparty/libwebsockets/lib/core/private.h
deleted file mode 100644
index c1a0a661b1..0000000000
--- a/thirdparty/libwebsockets/lib/core/private.h
+++ /dev/null
@@ -1,1573 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-
-#include "lws_config.h"
-#include "lws_config_private.h"
-
-#if defined(LWS_WITH_CGI) && defined(LWS_HAVE_VFORK)
- #define _GNU_SOURCE
-#endif
-
-#if defined(__COVERITY__) && !defined(LWS_COVERITY_WORKAROUND)
- #define LWS_COVERITY_WORKAROUND
- typedef float _Float32;
- typedef float _Float64;
- typedef float _Float128;
- typedef float _Float32x;
- typedef float _Float64x;
- typedef float _Float128x;
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <ctype.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <inttypes.h>
-#include <assert.h>
-
-#ifdef LWS_HAVE_SYS_TYPES_H
- #include <sys/types.h>
-#endif
-#ifdef LWS_HAVE_SYS_STAT_H
- #include <sys/stat.h>
-#endif
-
-#if LWS_MAX_SMP > 1
- #include <pthread.h>
-#endif
-
-#ifndef LWS_DEF_HEADER_LEN
-#define LWS_DEF_HEADER_LEN 4096
-#endif
-#ifndef LWS_DEF_HEADER_POOL
-#define LWS_DEF_HEADER_POOL 4
-#endif
-#ifndef LWS_MAX_PROTOCOLS
-#define LWS_MAX_PROTOCOLS 5
-#endif
-#ifndef LWS_MAX_EXTENSIONS_ACTIVE
-#define LWS_MAX_EXTENSIONS_ACTIVE 1
-#endif
-#ifndef LWS_MAX_EXT_OFFERS
-#define LWS_MAX_EXT_OFFERS 8
-#endif
-#ifndef SPEC_LATEST_SUPPORTED
-#define SPEC_LATEST_SUPPORTED 13
-#endif
-#ifndef AWAITING_TIMEOUT
-#define AWAITING_TIMEOUT 20
-#endif
-#ifndef CIPHERS_LIST_STRING
-#define CIPHERS_LIST_STRING "DEFAULT"
-#endif
-#ifndef LWS_SOMAXCONN
-#define LWS_SOMAXCONN SOMAXCONN
-#endif
-
-#define MAX_WEBSOCKET_04_KEY_LEN 128
-
-#ifndef SYSTEM_RANDOM_FILEPATH
-#define SYSTEM_RANDOM_FILEPATH "/dev/urandom"
-#endif
-
-#define LWS_H2_RX_SCRATCH_SIZE 512
-
-#define lws_socket_is_valid(x) (x != LWS_SOCK_INVALID)
-
-#ifndef LWS_HAVE_STRERROR
- #define strerror(x) ""
-#endif
-
- /*
- *
- * ------ private platform defines ------
- *
- */
-
-#if defined(LWS_WITH_ESP32)
- #include "plat/esp32/private.h"
-#else
- #if defined(WIN32) || defined(_WIN32)
- #include "plat/windows/private.h"
- #else
- #if defined(LWS_PLAT_OPTEE)
- #include "plat/optee/private.h"
- #else
- #include "plat/unix/private.h"
- #endif
- #endif
-#endif
-
-#ifndef LWS_HAVE_BZERO
- #ifndef bzero
- #define bzero(b, len) (memset((b), '\0', (len)), (void) 0)
- #endif
-#endif
-
- /*
- *
- * ------ public api ------
- *
- */
-
-#include "libwebsockets.h"
-
-
-#include "tls/private.h"
-
-#if defined(WIN32) || defined(_WIN32)
- // Visual studio older than 2015 and WIN_CE has only _stricmp
- #if (defined(_MSC_VER) && _MSC_VER < 1900) || defined(_WIN32_WCE)
- #define strcasecmp _stricmp
- #elif !defined(__MINGW32__)
- #define strcasecmp stricmp
- #endif
- #define getdtablesize() 30000
-#endif
-
-#ifndef LWS_ARRAY_SIZE
-#define LWS_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * All lws_tls...() functions must return this type, converting the
- * native backend result and doing the extra work to determine which one
- * as needed.
- *
- * Native TLS backend return codes are NOT ALLOWED outside the backend.
- *
- * Non-SSL mode also uses these types.
- */
-enum lws_ssl_capable_status {
- LWS_SSL_CAPABLE_ERROR = -1, /* it failed */
- LWS_SSL_CAPABLE_DONE = 0, /* it succeeded */
- LWS_SSL_CAPABLE_MORE_SERVICE_READ = -2, /* retry WANT_READ */
- LWS_SSL_CAPABLE_MORE_SERVICE_WRITE = -3, /* retry WANT_WRITE */
- LWS_SSL_CAPABLE_MORE_SERVICE = -4, /* general retry */
-};
-
-#if defined(__clang__)
-#define lws_memory_barrier() __sync_synchronize()
-#elif defined(__GNUC__)
-#define lws_memory_barrier() __sync_synchronize()
-#else
-#define lws_memory_barrier()
-#endif
-
-/*
- *
- * ------ roles ------
- *
- */
-
-#include "roles/private.h"
-
-/* null-terminated array of pointers to roles lws built with */
-extern const struct lws_role_ops *available_roles[];
-
-#define LWS_FOR_EVERY_AVAILABLE_ROLE_START(xx) { \
- const struct lws_role_ops **ppxx = available_roles; \
- while (*ppxx) { \
- const struct lws_role_ops *xx = *ppxx++;
-
-#define LWS_FOR_EVERY_AVAILABLE_ROLE_END }}
-
-/*
- *
- * ------ event_loop ops ------
- *
- */
-
-#include "event-libs/private.h"
-
-/* enums of socks version */
-enum socks_version {
- SOCKS_VERSION_4 = 4,
- SOCKS_VERSION_5 = 5
-};
-
-/* enums of subnegotiation version */
-enum socks_subnegotiation_version {
- SOCKS_SUBNEGOTIATION_VERSION_1 = 1,
-};
-
-/* enums of socks commands */
-enum socks_command {
- SOCKS_COMMAND_CONNECT = 1,
- SOCKS_COMMAND_BIND = 2,
- SOCKS_COMMAND_UDP_ASSOCIATE = 3
-};
-
-/* enums of socks address type */
-enum socks_atyp {
- SOCKS_ATYP_IPV4 = 1,
- SOCKS_ATYP_DOMAINNAME = 3,
- SOCKS_ATYP_IPV6 = 4
-};
-
-/* enums of socks authentication methods */
-enum socks_auth_method {
- SOCKS_AUTH_NO_AUTH = 0,
- SOCKS_AUTH_GSSAPI = 1,
- SOCKS_AUTH_USERNAME_PASSWORD = 2
-};
-
-/* enums of subnegotiation status */
-enum socks_subnegotiation_status {
- SOCKS_SUBNEGOTIATION_STATUS_SUCCESS = 0,
-};
-
-/* enums of socks request reply */
-enum socks_request_reply {
- SOCKS_REQUEST_REPLY_SUCCESS = 0,
- SOCKS_REQUEST_REPLY_FAILURE_GENERAL = 1,
- SOCKS_REQUEST_REPLY_CONNECTION_NOT_ALLOWED = 2,
- SOCKS_REQUEST_REPLY_NETWORK_UNREACHABLE = 3,
- SOCKS_REQUEST_REPLY_HOST_UNREACHABLE = 4,
- SOCKS_REQUEST_REPLY_CONNECTION_REFUSED = 5,
- SOCKS_REQUEST_REPLY_TTL_EXPIRED = 6,
- SOCKS_REQUEST_REPLY_COMMAND_NOT_SUPPORTED = 7,
- SOCKS_REQUEST_REPLY_ATYP_NOT_SUPPORTED = 8
-};
-
-/* enums used to generate socks messages */
-enum socks_msg_type {
- /* greeting */
- SOCKS_MSG_GREETING,
- /* credential, user name and password */
- SOCKS_MSG_USERNAME_PASSWORD,
- /* connect command */
- SOCKS_MSG_CONNECT
-};
-
-enum {
- LWS_RXFLOW_ALLOW = (1 << 0),
- LWS_RXFLOW_PENDING_CHANGE = (1 << 1),
-};
-
-struct lws_ring {
- void *buf;
- void (*destroy_element)(void *element);
- uint32_t buflen;
- uint32_t element_len;
- uint32_t head;
- uint32_t oldest_tail;
-};
-
-struct lws_protocols;
-struct lws;
-
-struct lws_io_watcher {
-#ifdef LWS_WITH_LIBEV
- struct lws_io_watcher_libev ev;
-#endif
-#ifdef LWS_WITH_LIBUV
- struct lws_io_watcher_libuv uv;
-#endif
-#ifdef LWS_WITH_LIBEVENT
- struct lws_io_watcher_libevent event;
-#endif
- struct lws_context *context;
-
- uint8_t actual_events;
-};
-
-struct lws_signal_watcher {
-#ifdef LWS_WITH_LIBEV
- struct lws_signal_watcher_libev ev;
-#endif
-#ifdef LWS_WITH_LIBUV
- struct lws_signal_watcher_libuv uv;
-#endif
-#ifdef LWS_WITH_LIBEVENT
- struct lws_signal_watcher_libevent event;
-#endif
- struct lws_context *context;
-};
-
-struct lws_foreign_thread_pollfd {
- struct lws_foreign_thread_pollfd *next;
- int fd_index;
- int _and;
- int _or;
-};
-
-#if LWS_MAX_SMP > 1
-
-struct lws_mutex_refcount {
- pthread_mutex_t lock;
- pthread_t lock_owner;
- const char *last_lock_reason;
- char lock_depth;
- char metadata;
-};
-
-void
-lws_mutex_refcount_init(struct lws_mutex_refcount *mr);
-
-void
-lws_mutex_refcount_destroy(struct lws_mutex_refcount *mr);
-
-void
-lws_mutex_refcount_lock(struct lws_mutex_refcount *mr, const char *reason);
-
-void
-lws_mutex_refcount_unlock(struct lws_mutex_refcount *mr);
-#endif
-
-#define LWS_HRTIMER_NOWAIT (0x7fffffffffffffffll)
-
-/*
- * so we can have n connections being serviced simultaneously,
- * these things need to be isolated per-thread.
- */
-
-struct lws_context_per_thread {
-#if LWS_MAX_SMP > 1
- pthread_mutex_t lock_stats;
- struct lws_mutex_refcount mr;
- pthread_t self;
-#endif
-
- struct lws_context *context;
-
- /*
- * usable by anything in the service code, but only if the scope
- * does not last longer than the service action (since next service
- * of any socket can likewise use it and overwrite)
- */
- unsigned char *serv_buf;
-
- struct lws_dll_lws dll_head_timeout;
- struct lws_dll_lws dll_head_hrtimer;
- struct lws_dll_lws dll_head_buflist; /* guys with pending rxflow */
-
-#if defined(LWS_WITH_TLS)
- struct lws_pt_tls tls;
-#endif
-
- struct lws_pollfd *fds;
- volatile struct lws_foreign_thread_pollfd * volatile foreign_pfd_list;
-#ifdef _WIN32
- WSAEVENT events;
-#endif
- lws_sockfd_type dummy_pipe_fds[2];
- struct lws *pipe_wsi;
-
- /* --- role based members --- */
-
-#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
- struct lws_pt_role_ws ws;
-#endif
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- struct lws_pt_role_http http;
-#endif
-#if defined(LWS_ROLE_DBUS)
- struct lws_pt_role_dbus dbus;
-#endif
-
- /* --- event library based members --- */
-
-#if defined(LWS_WITH_LIBEV)
- struct lws_pt_eventlibs_libev ev;
-#endif
-#if defined(LWS_WITH_LIBUV)
- struct lws_pt_eventlibs_libuv uv;
-#endif
-#if defined(LWS_WITH_LIBEVENT)
- struct lws_pt_eventlibs_libevent event;
-#endif
-
-#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \
- defined(LWS_WITH_LIBEVENT)
- struct lws_signal_watcher w_sigint;
-#endif
-
- /* --- */
-
- unsigned long count_conns;
- unsigned int fds_count;
-
- /*
- * set to the Thread ID that's doing the service loop just before entry
- * to poll indicates service thread likely idling in poll()
- * volatile because other threads may check it as part of processing
- * for pollfd event change.
- */
- volatile int service_tid;
- int service_tid_detected;
-
- volatile unsigned char inside_poll;
- volatile unsigned char foreign_spinlock;
-
- unsigned char tid;
-
- unsigned char inside_service:1;
- unsigned char event_loop_foreign:1;
- unsigned char event_loop_destroy_processing_done:1;
-};
-
-struct lws_conn_stats {
- unsigned long long rx, tx;
- unsigned long h1_conn, h1_trans, h2_trans, ws_upg, h2_alpn, h2_subs,
- h2_upg, rejected;
-};
-
-void
-lws_sum_stats(const struct lws_context *ctx, struct lws_conn_stats *cs);
-
-struct lws_timed_vh_protocol {
- struct lws_timed_vh_protocol *next;
- const struct lws_protocols *protocol;
- struct lws_vhost *vhost; /* only used for pending processing */
- time_t time;
- int reason;
- int tsi_req;
-};
-
-/*
- * virtual host -related context information
- * vhostwide SSL context
- * vhostwide proxy
- *
- * hierarchy:
- *
- * context -> vhost -> wsi
- *
- * incoming connection non-SSL vhost binding:
- *
- * listen socket -> wsi -> select vhost after first headers
- *
- * incoming connection SSL vhost binding:
- *
- * SSL SNI -> wsi -> bind after SSL negotiation
- */
-
-
-struct lws_vhost {
-#if !defined(LWS_WITHOUT_CLIENT)
- char proxy_basic_auth_token[128];
-#endif
-#if LWS_MAX_SMP > 1
- pthread_mutex_t lock;
- char close_flow_vs_tsi[LWS_MAX_SMP];
-#endif
-
-#if defined(LWS_ROLE_H2)
- struct lws_vhost_role_h2 h2;
-#endif
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- struct lws_vhost_role_http http;
-#endif
-#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
- struct lws_vhost_role_ws ws;
-#endif
-
-#if defined(LWS_WITH_SOCKS5)
- char socks_proxy_address[128];
- char socks_user[96];
- char socks_password[96];
-#endif
-#if defined(LWS_WITH_LIBEV)
- struct lws_io_watcher w_accept;
-#endif
- struct lws_conn_stats conn_stats;
- struct lws_context *context;
- struct lws_vhost *vhost_next;
-
- struct lws *lserv_wsi;
- const char *name;
- const char *iface;
-
- void (*finalize)(struct lws_vhost *vh, void *arg);
- void *finalize_arg;
-
-#if !defined(LWS_WITH_ESP32) && !defined(OPTEE_TA) && !defined(WIN32)
- int bind_iface;
-#endif
- const struct lws_protocols *protocols;
- void **protocol_vh_privs;
- const struct lws_protocol_vhost_options *pvo;
- const struct lws_protocol_vhost_options *headers;
- struct lws_dll_lws *same_vh_protocol_heads;
- struct lws_vhost *no_listener_vhost_list;
-#if !defined(LWS_NO_CLIENT)
- struct lws_dll_lws dll_active_client_conns;
-#endif
-
-#if defined(LWS_WITH_TLS)
- struct lws_vhost_tls tls;
-#endif
-
- struct lws_timed_vh_protocol *timed_vh_protocol_list;
- void *user;
-
- int listen_port;
-
-#if defined(LWS_WITH_SOCKS5)
- unsigned int socks_proxy_port;
-#endif
- unsigned int options;
- int count_protocols;
- int ka_time;
- int ka_probes;
- int ka_interval;
- int keepalive_timeout;
- int timeout_secs_ah_idle;
-
- int count_bound_wsi;
-
-#ifdef LWS_WITH_ACCESS_LOG
- int log_fd;
-#endif
-
- unsigned int created_vhost_protocols:1;
- unsigned int being_destroyed:1;
-
- unsigned char default_protocol_index;
- unsigned char raw_protocol_index;
-};
-
-void
-lws_vhost_bind_wsi(struct lws_vhost *vh, struct lws *wsi);
-void
-lws_vhost_unbind_wsi(struct lws *wsi);
-void
-__lws_vhost_destroy2(struct lws_vhost *vh);
-
-struct lws_deferred_free
-{
- struct lws_deferred_free *next;
- time_t deadline;
- void *payload;
-};
-
-typedef union {
-#ifdef LWS_WITH_IPV6
- struct sockaddr_in6 sa6;
-#endif
- struct sockaddr_in sa4;
-} sockaddr46;
-
-
-#if defined(LWS_WITH_PEER_LIMITS)
-struct lws_peer {
- struct lws_peer *next;
- struct lws_peer *peer_wait_list;
-
- time_t time_created;
- time_t time_closed_all;
-
- uint8_t addr[32];
- uint32_t hash;
- uint32_t count_wsi;
- uint32_t total_wsi;
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- struct lws_peer_role_http http;
-#endif
-
- uint8_t af;
-};
-#endif
-
-/*
- * the rest is managed per-context, that includes
- *
- * - processwide single fd -> wsi lookup
- * - contextwide headers pool
- */
-
-struct lws_context {
- time_t last_timeout_check_s;
- time_t last_ws_ping_pong_check_s;
- time_t time_up;
- time_t time_discontiguity;
- time_t time_fixup;
- const struct lws_plat_file_ops *fops;
- struct lws_plat_file_ops fops_platform;
- struct lws_context **pcontext_finalize;
-
- const struct lws_tls_ops *tls_ops;
-
-#if defined(LWS_WITH_HTTP2)
- struct http2_settings set;
-#endif
-#if defined(LWS_WITH_ZIP_FOPS)
- struct lws_plat_file_ops fops_zip;
-#endif
- struct lws_context_per_thread pt[LWS_MAX_SMP];
- struct lws_conn_stats conn_stats;
-#if LWS_MAX_SMP > 1
- struct lws_mutex_refcount mr;
-#endif
-#ifdef _WIN32
-/* different implementation between unix and windows */
- struct lws_fd_hashtable fd_hashtable[FD_HASHTABLE_MODULUS];
-#else
- struct lws **lws_lookup; /* fd to wsi */
-#endif
- struct lws_vhost *vhost_list;
- struct lws_vhost *no_listener_vhost_list;
- struct lws_vhost *vhost_pending_destruction_list;
- struct lws_plugin *plugin_list;
- struct lws_deferred_free *deferred_free_list;
-
-#if defined(LWS_WITH_THREADPOOL)
- struct lws_threadpool *tp_list_head;
-#endif
-
-#if defined(LWS_WITH_PEER_LIMITS)
- struct lws_peer **pl_hash_table;
- struct lws_peer *peer_wait_list;
- time_t next_cull;
-#endif
-
- void *external_baggage_free_on_destroy;
- const struct lws_token_limits *token_limits;
- void *user_space;
- const struct lws_protocol_vhost_options *reject_service_keywords;
- lws_reload_func deprecation_cb;
- void (*eventlib_signal_cb)(void *event_lib_handle, int signum);
-
-#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
- cap_value_t caps[4];
- char count_caps;
-#endif
-
-#if defined(LWS_WITH_LIBEV)
- struct lws_context_eventlibs_libev ev;
-#endif
-#if defined(LWS_WITH_LIBUV)
- struct lws_context_eventlibs_libuv uv;
-#endif
-#if defined(LWS_WITH_LIBEVENT)
- struct lws_context_eventlibs_libevent event;
-#endif
- struct lws_event_loop_ops *event_loop_ops;
-
-
-#if defined(LWS_WITH_TLS)
- struct lws_context_tls tls;
-#endif
-
- char canonical_hostname[128];
- const char *server_string;
-
-#ifdef LWS_LATENCY
- unsigned long worst_latency;
- char worst_latency_info[256];
-#endif
-
-#if defined(LWS_WITH_STATS)
- uint64_t lws_stats[LWSSTATS_SIZE];
- uint64_t last_dump;
- int updated;
-#endif
-#if defined(LWS_WITH_ESP32)
- unsigned long time_last_state_dump;
- uint32_t last_free_heap;
-#endif
-
- int max_fds;
- int count_event_loop_static_asset_handles;
- int started_with_parent;
- int uid, gid;
-
- int fd_random;
-
- int count_wsi_allocated;
- int count_cgi_spawned;
- unsigned int options;
- unsigned int fd_limit_per_thread;
- unsigned int timeout_secs;
- unsigned int pt_serv_buf_size;
- int max_http_header_data;
- int max_http_header_pool;
- int simultaneous_ssl_restriction;
- int simultaneous_ssl;
-#if defined(LWS_WITH_PEER_LIMITS)
- uint32_t pl_hash_elements; /* protected by context->lock */
- uint32_t count_peers; /* protected by context->lock */
- unsigned short ip_limit_ah;
- unsigned short ip_limit_wsi;
-#endif
- unsigned int deprecated:1;
- unsigned int being_destroyed:1;
- unsigned int being_destroyed1:1;
- unsigned int being_destroyed2:1;
- unsigned int requested_kill:1;
- unsigned int protocol_init_done:1;
- unsigned int doing_protocol_init:1;
- unsigned int done_protocol_destroy_cb:1;
- unsigned int finalize_destroy_after_internal_loops_stopped:1;
-
- short count_threads;
- short plugin_protocol_count;
- short plugin_extension_count;
- short server_string_len;
- unsigned short ws_ping_pong_interval;
- unsigned short deprecation_pending_listen_close_count;
-
- uint8_t max_fi;
-};
-
-int
-lws_check_deferred_free(struct lws_context *context, int tsi, int force);
-
-#define lws_get_context_protocol(ctx, x) ctx->vhost_list->protocols[x]
-#define lws_get_vh_protocol(vh, x) vh->protocols[x]
-
-LWS_EXTERN void
-__lws_close_free_wsi_final(struct lws *wsi);
-LWS_EXTERN void
-lws_libuv_closehandle(struct lws *wsi);
-LWS_EXTERN int
-lws_libuv_check_watcher_active(struct lws *wsi);
-
-LWS_VISIBLE LWS_EXTERN int
-lws_plat_plugins_init(struct lws_context * context, const char * const *d);
-
-LWS_VISIBLE LWS_EXTERN int
-lws_plat_plugins_destroy(struct lws_context * context);
-
-LWS_EXTERN void
-lws_restart_ws_ping_pong_timer(struct lws *wsi);
-
-struct lws *
-lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);
-
-int
-lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);
-
-void
-lws_vhost_destroy1(struct lws_vhost *vh);
-
-enum {
- LWS_EV_READ = (1 << 0),
- LWS_EV_WRITE = (1 << 1),
- LWS_EV_START = (1 << 2),
- LWS_EV_STOP = (1 << 3),
-
- LWS_EV_PREPARE_DELETION = (1u << 31),
-};
-
-
-#if defined(LWS_WITH_ESP32)
-LWS_EXTERN int
-lws_find_string_in_file(const char *filename, const char *str, int stringlen);
-#endif
-
-#ifdef LWS_WITH_IPV6
-#define LWS_IPV6_ENABLED(vh) \
- (!lws_check_opt(vh->context->options, LWS_SERVER_OPTION_DISABLE_IPV6) && \
- !lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_IPV6))
-#else
-#define LWS_IPV6_ENABLED(context) (0)
-#endif
-
-#ifdef LWS_WITH_UNIX_SOCK
-#define LWS_UNIX_SOCK_ENABLED(vhost) \
- (vhost->options & LWS_SERVER_OPTION_UNIX_SOCK)
-#else
-#define LWS_UNIX_SOCK_ENABLED(vhost) (0)
-#endif
-
-enum uri_path_states {
- URIPS_IDLE,
- URIPS_SEEN_SLASH,
- URIPS_SEEN_SLASH_DOT,
- URIPS_SEEN_SLASH_DOT_DOT,
-};
-
-enum uri_esc_states {
- URIES_IDLE,
- URIES_SEEN_PERCENT,
- URIES_SEEN_PERCENT_H1,
-};
-
-
-#ifndef LWS_NO_CLIENT
-struct client_info_stash {
- char *address;
- char *path;
- char *host;
- char *origin;
- char *protocol;
- char *method;
- char *iface;
- char *alpn;
-};
-#endif
-
-
-signed char char_to_hex(const char c);
-
-
-struct lws_buflist {
- struct lws_buflist *next;
-
- size_t len;
- size_t pos;
-
- uint8_t buf[1]; /* true length of this is set by the oversize malloc */
-};
-
-#define lws_wsi_is_udp(___wsi) (!!___wsi->udp)
-
-#define LWS_H2_FRAME_HEADER_LENGTH 9
-
-
-struct lws {
- /* structs */
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- struct _lws_http_mode_related http;
-#endif
-#if defined(LWS_ROLE_H2)
- struct _lws_h2_related h2;
-#endif
-#if defined(LWS_ROLE_WS)
- struct _lws_websocket_related *ws; /* allocated if we upgrade to ws */
-#endif
-#if defined(LWS_ROLE_DBUS)
- struct _lws_dbus_mode_related dbus;
-#endif
-
- const struct lws_role_ops *role_ops;
- lws_wsi_state_t wsistate;
- lws_wsi_state_t wsistate_pre_close;
-
- /* lifetime members */
-
-#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \
- defined(LWS_WITH_LIBEVENT)
- struct lws_io_watcher w_read;
-#endif
-#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBEVENT)
- struct lws_io_watcher w_write;
-#endif
-
- /* pointers */
-
- struct lws_context *context;
- struct lws_vhost *vhost;
- struct lws *parent; /* points to parent, if any */
- struct lws *child_list; /* points to first child */
- struct lws *sibling_list; /* subsequent children at same level */
-
- const struct lws_protocols *protocol;
- struct lws_dll_lws same_vh_protocol;
-
- struct lws_dll_lws dll_timeout;
- struct lws_dll_lws dll_hrtimer;
- struct lws_dll_lws dll_buflist; /* guys with pending rxflow */
-
-#if defined(LWS_WITH_THREADPOOL)
- struct lws_threadpool_task *tp_task;
-#endif
-
-#if defined(LWS_WITH_PEER_LIMITS)
- struct lws_peer *peer;
-#endif
-
- struct lws_udp *udp;
-#ifndef LWS_NO_CLIENT
- struct client_info_stash *stash;
- char *client_hostname_copy;
- struct lws_dll_lws dll_active_client_conns;
- struct lws_dll_lws dll_client_transaction_queue_head;
- struct lws_dll_lws dll_client_transaction_queue;
-#endif
- void *user_space;
- void *opaque_parent_data;
-
- struct lws_buflist *buflist; /* input-side buflist */
- struct lws_buflist *buflist_out; /* output-side buflist */
-
-#if defined(LWS_WITH_TLS)
- struct lws_lws_tls tls;
-#endif
-
- lws_sock_file_fd_type desc; /* .filefd / .sockfd */
-#if defined(LWS_WITH_STATS)
- uint64_t active_writable_req_us;
-#if defined(LWS_WITH_TLS)
- uint64_t accept_start_us;
-#endif
-#endif
-
- lws_usec_t pending_timer; /* hrtimer fires */
- time_t pending_timeout_set; /* second-resolution timeout start */
-
-#ifdef LWS_LATENCY
- unsigned long action_start;
- unsigned long latency_start;
-#endif
-
- /* ints */
-#define LWS_NO_FDS_POS (-1)
- int position_in_fds_table;
-
-#ifndef LWS_NO_CLIENT
- int chunk_remaining;
-#endif
- unsigned int cache_secs;
-
- unsigned int hdr_parsing_completed:1;
- unsigned int http2_substream:1;
- unsigned int upgraded_to_http2:1;
- unsigned int h2_stream_carries_ws:1;
- unsigned int seen_nonpseudoheader:1;
- unsigned int listener:1;
- unsigned int user_space_externally_allocated:1;
- unsigned int socket_is_permanently_unusable:1;
- unsigned int rxflow_change_to:2;
- unsigned int conn_stat_done:1;
- unsigned int cache_reuse:1;
- unsigned int cache_revalidate:1;
- unsigned int cache_intermediaries:1;
- unsigned int favoured_pollin:1;
- unsigned int sending_chunked:1;
- unsigned int interpreting:1;
- unsigned int already_did_cce:1;
- unsigned int told_user_closed:1;
- unsigned int told_event_loop_closed:1;
- unsigned int waiting_to_send_close_frame:1;
- unsigned int close_needs_ack:1;
- unsigned int ipv6:1;
- unsigned int parent_pending_cb_on_writable:1;
- unsigned int cgi_stdout_zero_length:1;
- unsigned int seen_zero_length_recv:1;
- unsigned int rxflow_will_be_applied:1;
- unsigned int event_pipe:1;
- unsigned int handling_404:1;
- unsigned int protocol_bind_balance:1;
- unsigned int unix_skt:1;
-
- unsigned int could_have_pending:1; /* detect back-to-back writes */
- unsigned int outer_will_close:1;
- unsigned int shadow:1; /* we do not control fd lifecycle at all */
-
-#ifdef LWS_WITH_ACCESS_LOG
- unsigned int access_log_pending:1;
-#endif
-#ifndef LWS_NO_CLIENT
- unsigned int do_ws:1; /* whether we are doing http or ws flow */
- unsigned int chunked:1; /* if the clientside connection is chunked */
- unsigned int client_rx_avail:1;
- unsigned int client_http_body_pending:1;
- unsigned int transaction_from_pipeline_queue:1;
- unsigned int keepalive_active:1;
- unsigned int keepalive_rejected:1;
- unsigned int client_pipeline:1;
- unsigned int client_h2_alpn:1;
- unsigned int client_h2_substream:1;
-#endif
-
-#ifdef _WIN32
- unsigned int sock_send_blocking:1;
-#endif
-
-#ifndef LWS_NO_CLIENT
- unsigned short c_port;
-#endif
- unsigned short pending_timeout_limit;
-
- /* chars */
-
- char lws_rx_parse_state; /* enum lws_rx_parse_state */
- char rx_frame_type; /* enum lws_write_protocol */
- char pending_timeout; /* enum pending_timeout */
- char tsi; /* thread service index we belong to */
- char protocol_interpret_idx;
- char redirects;
- uint8_t rxflow_bitmap;
-#ifdef LWS_WITH_CGI
- char cgi_channel; /* which of stdin/out/err */
- char hdr_state;
-#endif
-#ifndef LWS_NO_CLIENT
- char chunk_parser; /* enum lws_chunk_parser */
-#endif
-#if defined(LWS_WITH_CGI) || !defined(LWS_NO_CLIENT)
- char reason_bf; /* internal writeable callback reason bitfield */
-#endif
-#if defined(LWS_WITH_STATS) && defined(LWS_WITH_TLS)
- char seen_rx;
-#endif
- uint8_t ws_over_h2_count;
- /* volatile to make sure code is aware other thread can change */
- volatile char handling_pollout;
- volatile char leave_pollout_active;
-};
-
-LWS_EXTERN char *
-lws_strdup(const char *s);
-
-#define lws_is_flowcontrolled(w) (!!(wsi->rxflow_bitmap))
-
-void
-lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt);
-
-LWS_EXTERN int log_level;
-
-LWS_EXTERN int
-lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
- const char *iface);
-
-#if defined(LWS_WITH_IPV6)
-LWS_EXTERN unsigned long
-lws_get_addr_scope(const char *ipaddr);
-#endif
-
-LWS_EXTERN void
-lws_close_free_wsi(struct lws *wsi, enum lws_close_status, const char *caller);
-LWS_EXTERN void
-__lws_close_free_wsi(struct lws *wsi, enum lws_close_status, const char *caller);
-
-LWS_EXTERN void
-__lws_free_wsi(struct lws *wsi);
-
-LWS_EXTERN int
-__remove_wsi_socket_from_fds(struct lws *wsi);
-LWS_EXTERN int
-lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len);
-
-#ifndef LWS_LATENCY
-static LWS_INLINE void
-lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
- int ret, int completion) {
- do {
- (void)context; (void)wsi; (void)action; (void)ret;
- (void)completion;
- } while (0);
-}
-static LWS_INLINE void
-lws_latency_pre(struct lws_context *context, struct lws *wsi) {
- do { (void)context; (void)wsi; } while (0);
-}
-#else
-#define lws_latency_pre(_context, _wsi) lws_latency(_context, _wsi, NULL, 0, 0)
-extern void
-lws_latency(struct lws_context *context, struct lws *wsi, const char *action,
- int ret, int completion);
-#endif
-
-static LWS_INLINE int
-lws_has_buffered_out(struct lws *wsi) { return !!wsi->buflist_out; }
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ws_client_rx_sm(struct lws *wsi, unsigned char c);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_parse(struct lws *wsi, unsigned char *buf, int *len);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_parse_urldecode(struct lws *wsi, uint8_t *_c);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_http_action(struct lws *wsi);
-
-LWS_EXTERN int
-lws_b64_selftest(void);
-
-LWS_EXTERN int
-lws_service_flag_pending(struct lws_context *context, int tsi);
-
-LWS_EXTERN int
-__lws_timed_callback_remove(struct lws_vhost *vh, struct lws_timed_vh_protocol *p);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-__insert_wsi_socket_into_fds(struct lws_context *context, struct lws *wsi);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_issue_raw(struct lws *wsi, unsigned char *buf, size_t len);
-
-LWS_EXTERN void
-lws_remove_from_timeout_list(struct lws *wsi);
-
-LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
-lws_client_connect_2(struct lws *wsi);
-
-LWS_VISIBLE struct lws * LWS_WARN_UNUSED_RESULT
-lws_client_reset(struct lws **wsi, int ssl, const char *address, int port,
- const char *path, const char *host);
-
-LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
-lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi);
-
-LWS_EXTERN char * LWS_WARN_UNUSED_RESULT
-lws_generate_client_handshake(struct lws *wsi, char *pkt);
-
-LWS_EXTERN int
-lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd);
-
-LWS_EXTERN struct lws *
-lws_http_client_connect_via_info2(struct lws *wsi);
-
-
-
-LWS_EXTERN void
-lws_client_stash_destroy(struct lws *wsi);
-
-/*
- * EXTENSIONS
- */
-
-#if defined(LWS_WITHOUT_EXTENSIONS)
-#define lws_any_extension_handled(_a, _b, _c, _d) (0)
-#define lws_ext_cb_active(_a, _b, _c, _d) (0)
-#define lws_ext_cb_all_exts(_a, _b, _c, _d, _e) (0)
-#define lws_issue_raw_ext_access lws_issue_raw
-#define lws_context_init_extensions(_a, _b)
-#endif
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_client_interpret_server_handshake(struct lws *wsi);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ws_rx_sm(struct lws *wsi, char already_processed, unsigned char c);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_issue_raw_ext_access(struct lws *wsi, unsigned char *buf, size_t len);
-
-LWS_EXTERN void
-lws_role_transition(struct lws *wsi, enum lwsi_role role, enum lwsi_state state,
- struct lws_role_ops *ops);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-user_callback_handle_rxflow(lws_callback_function, struct lws *wsi,
- enum lws_callback_reasons reason, void *user,
- void *in, size_t len);
-
-LWS_EXTERN int
-lws_plat_set_socket_options(struct lws_vhost *vhost, lws_sockfd_type fd,
- int unix_skt);
-
-LWS_EXTERN int
-lws_plat_check_connection_error(struct lws *wsi);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_header_table_attach(struct lws *wsi, int autoservice);
-
-LWS_EXTERN int
-lws_header_table_detach(struct lws *wsi, int autoservice);
-LWS_EXTERN int
-__lws_header_table_detach(struct lws *wsi, int autoservice);
-
-LWS_EXTERN void
-lws_header_table_reset(struct lws *wsi, int autoservice);
-
-void
-__lws_header_table_reset(struct lws *wsi, int autoservice);
-
-LWS_EXTERN char * LWS_WARN_UNUSED_RESULT
-lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ensure_user_space(struct lws *wsi);
-
-LWS_EXTERN int
-lws_change_pollfd(struct lws *wsi, int _and, int _or);
-
-#ifndef LWS_NO_SERVER
- int _lws_vhost_init_server(const struct lws_context_creation_info *info,
- struct lws_vhost *vhost);
- LWS_EXTERN struct lws_vhost *
- lws_select_vhost(struct lws_context *context, int port, const char *servername);
- LWS_EXTERN int LWS_WARN_UNUSED_RESULT
- lws_parse_ws(struct lws *wsi, unsigned char **buf, size_t len);
- LWS_EXTERN void
- lws_server_get_canonical_hostname(struct lws_context *context,
- const struct lws_context_creation_info *info);
-#else
- #define _lws_vhost_init_server(_a, _b) (0)
- #define lws_parse_ws(_a, _b, _c) (0)
- #define lws_server_get_canonical_hostname(_a, _b)
-#endif
-
-#ifndef LWS_NO_DAEMONIZE
- LWS_EXTERN int get_daemonize_pid();
-#else
- #define get_daemonize_pid() (0)
-#endif
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-interface_to_sa(struct lws_vhost *vh, const char *ifname,
- struct sockaddr_in *addr, size_t addrlen);
-LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
-
-#if !defined(LWS_WITH_TLS)
- #define LWS_SSL_ENABLED(context) (0)
- #define lws_context_init_server_ssl(_a, _b) (0)
- #define lws_ssl_destroy(_a)
- #define lws_context_init_alpn(_a)
- #define lws_ssl_capable_read lws_ssl_capable_read_no_ssl
- #define lws_ssl_capable_write lws_ssl_capable_write_no_ssl
- #define lws_ssl_pending lws_ssl_pending_no_ssl
- #define lws_server_socket_service_ssl(_b, _c) (0)
- #define lws_ssl_close(_a) (0)
- #define lws_ssl_context_destroy(_a)
- #define lws_ssl_SSL_CTX_destroy(_a)
- #define lws_ssl_remove_wsi_from_buffered_list(_a)
- #define __lws_ssl_remove_wsi_from_buffered_list(_a)
- #define lws_context_init_ssl_library(_a)
- #define lws_tls_check_all_cert_lifetimes(_a)
- #define lws_tls_acme_sni_cert_destroy(_a)
-#endif
-
-
-#if LWS_MAX_SMP > 1
-
-static LWS_INLINE void
-lws_pt_mutex_init(struct lws_context_per_thread *pt)
-{
- lws_mutex_refcount_init(&pt->mr);
- pthread_mutex_init(&pt->lock_stats, NULL);
-}
-
-static LWS_INLINE void
-lws_pt_mutex_destroy(struct lws_context_per_thread *pt)
-{
- pthread_mutex_destroy(&pt->lock_stats);
- lws_mutex_refcount_destroy(&pt->mr);
-}
-
-#define lws_pt_lock(pt, reason) lws_mutex_refcount_lock(&pt->mr, reason)
-#define lws_pt_unlock(pt) lws_mutex_refcount_unlock(&pt->mr)
-
-static LWS_INLINE void
-lws_pt_stats_lock(struct lws_context_per_thread *pt)
-{
- pthread_mutex_lock(&pt->lock_stats);
-}
-
-static LWS_INLINE void
-lws_pt_stats_unlock(struct lws_context_per_thread *pt)
-{
- pthread_mutex_unlock(&pt->lock_stats);
-}
-
-#define lws_context_lock(c, reason) lws_mutex_refcount_lock(&c->mr, reason)
-#define lws_context_unlock(c) lws_mutex_refcount_unlock(&c->mr)
-
-static LWS_INLINE void
-lws_vhost_lock(struct lws_vhost *vhost)
-{
- pthread_mutex_lock(&vhost->lock);
-}
-
-static LWS_INLINE void
-lws_vhost_unlock(struct lws_vhost *vhost)
-{
- pthread_mutex_unlock(&vhost->lock);
-}
-
-
-#else
-#define lws_pt_mutex_init(_a) (void)(_a)
-#define lws_pt_mutex_destroy(_a) (void)(_a)
-#define lws_pt_lock(_a, b) (void)(_a)
-#define lws_pt_unlock(_a) (void)(_a)
-#define lws_context_lock(_a, _b) (void)(_a)
-#define lws_context_unlock(_a) (void)(_a)
-#define lws_vhost_lock(_a) (void)(_a)
-#define lws_vhost_unlock(_a) (void)(_a)
-#define lws_pt_stats_lock(_a) (void)(_a)
-#define lws_pt_stats_unlock(_a) (void)(_a)
-#endif
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ssl_capable_write_no_ssl(struct lws *wsi, unsigned char *buf, int len);
-
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_ssl_pending_no_ssl(struct lws *wsi);
-
-int
-lws_tls_check_cert_lifetime(struct lws_vhost *vhost);
-
-int lws_jws_selftest(void);
-
-
-#ifndef LWS_NO_CLIENT
-LWS_EXTERN int lws_client_socket_service(struct lws *wsi,
- struct lws_pollfd *pollfd,
- struct lws *wsi_conn);
-LWS_EXTERN struct lws *
-lws_client_wsi_effective(struct lws *wsi);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_http_transaction_completed_client(struct lws *wsi);
-#if !defined(LWS_WITH_TLS)
- #define lws_context_init_client_ssl(_a, _b) (0)
-#endif
-LWS_EXTERN void
-lws_decode_ssl_error(void);
-#else
-#define lws_context_init_client_ssl(_a, _b) (0)
-#endif
-
-LWS_EXTERN int
-__lws_rx_flow_control(struct lws *wsi);
-
-LWS_EXTERN int
-_lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa);
-
-#ifndef LWS_NO_SERVER
-LWS_EXTERN int
-lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len);
-#else
-#define lws_server_socket_service(_b, _c) (0)
-#define lws_handshake_server(_a, _b, _c) (0)
-#endif
-
-#ifdef LWS_WITH_ACCESS_LOG
-LWS_EXTERN int
-lws_access_log(struct lws *wsi);
-LWS_EXTERN void
-lws_prepare_access_log_info(struct lws *wsi, char *uri_ptr, int len, int meth);
-#else
-#define lws_access_log(_a)
-#endif
-
-LWS_EXTERN int
-lws_cgi_kill_terminated(struct lws_context_per_thread *pt);
-
-LWS_EXTERN void
-lws_cgi_remove_and_kill(struct lws *wsi);
-
-int
-lws_protocol_init(struct lws_context *context);
-
-int
-lws_bind_protocol(struct lws *wsi, const struct lws_protocols *p,
- const char *reason);
-
-const struct lws_http_mount *
-lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len);
-
-/*
- * custom allocator
- */
-LWS_EXTERN void *
-lws_realloc(void *ptr, size_t size, const char *reason);
-
-LWS_EXTERN void * LWS_WARN_UNUSED_RESULT
-lws_zalloc(size_t size, const char *reason);
-
-#ifdef LWS_PLAT_OPTEE
-void *lws_malloc(size_t size, const char *reason);
-void lws_free(void *p);
-#define lws_free_set_NULL(P) do { lws_free(P); (P) = NULL; } while(0)
-#else
-#define lws_malloc(S, R) lws_realloc(NULL, S, R)
-#define lws_free(P) lws_realloc(P, 0, "lws_free")
-#define lws_free_set_NULL(P) do { lws_realloc(P, 0, "free"); (P) = NULL; } while(0)
-#endif
-
-int
-lws_plat_pipe_create(struct lws *wsi);
-int
-lws_plat_pipe_signal(struct lws *wsi);
-void
-lws_plat_pipe_close(struct lws *wsi);
-int
-lws_create_event_pipes(struct lws_context *context);
-
-int
-lws_plat_apply_FD_CLOEXEC(int n);
-
-const struct lws_plat_file_ops *
-lws_vfs_select_fops(const struct lws_plat_file_ops *fops, const char *vfs_path,
- const char **vpath);
-
-/* lws_plat_ */
-LWS_EXTERN void
-lws_plat_delete_socket_from_fds(struct lws_context *context,
- struct lws *wsi, int m);
-LWS_EXTERN void
-lws_plat_insert_socket_into_fds(struct lws_context *context,
- struct lws *wsi);
-LWS_EXTERN void
-lws_plat_service_periodic(struct lws_context *context);
-
-LWS_EXTERN int
-lws_plat_change_pollfd(struct lws_context *context, struct lws *wsi,
- struct lws_pollfd *pfd);
-LWS_EXTERN void
-lws_add_wsi_to_draining_ext_list(struct lws *wsi);
-LWS_EXTERN void
-lws_remove_wsi_from_draining_ext_list(struct lws *wsi);
-LWS_EXTERN int
-lws_plat_context_early_init(void);
-LWS_EXTERN void
-lws_plat_context_early_destroy(struct lws_context *context);
-LWS_EXTERN void
-lws_plat_context_late_destroy(struct lws_context *context);
-LWS_EXTERN int
-lws_poll_listen_fd(struct lws_pollfd *fd);
-LWS_EXTERN int
-lws_plat_service(struct lws_context *context, int timeout_ms);
-LWS_EXTERN LWS_VISIBLE int
-_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi);
-
-LWS_EXTERN int
-lws_pthread_self_to_tsi(struct lws_context *context);
-
-LWS_EXTERN int
-lws_plat_init(struct lws_context *context,
- const struct lws_context_creation_info *info);
-LWS_EXTERN void
-lws_plat_drop_app_privileges(const struct lws_context_creation_info *info);
-LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT
-lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_plat_inet_pton(int af, const char *src, void *dst);
-
-LWS_EXTERN int
-lws_check_byte_utf8(unsigned char state, unsigned char c);
-LWS_EXTERN int LWS_WARN_UNUSED_RESULT
-lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len);
-LWS_EXTERN int alloc_file(struct lws_context *context, const char *filename,
- uint8_t **buf, lws_filepos_t *amount);
-
-
-LWS_EXTERN void
-lws_same_vh_protocol_remove(struct lws *wsi);
-LWS_EXTERN void
-__lws_same_vh_protocol_remove(struct lws *wsi);
-LWS_EXTERN void
-lws_same_vh_protocol_insert(struct lws *wsi, int n);
-
-LWS_EXTERN int
-lws_broadcast(struct lws_context *context, int reason, void *in, size_t len);
-
-#if defined(LWS_WITH_STATS)
- void
- lws_stats_atomic_bump(struct lws_context * context,
- struct lws_context_per_thread *pt, int index, uint64_t bump);
- void
- lws_stats_atomic_max(struct lws_context * context,
- struct lws_context_per_thread *pt, int index, uint64_t val);
-#else
- static LWS_INLINE uint64_t lws_stats_atomic_bump(struct lws_context * context,
- struct lws_context_per_thread *pt, int index, uint64_t bump) {
- (void)context; (void)pt; (void)index; (void)bump; return 0; }
- static LWS_INLINE uint64_t lws_stats_atomic_max(struct lws_context * context,
- struct lws_context_per_thread *pt, int index, uint64_t val) {
- (void)context; (void)pt; (void)index; (void)val; return 0; }
-#endif
-
-/* socks */
-void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,
- ssize_t *msg_len);
-
-#if defined(LWS_WITH_PEER_LIMITS)
-void
-lws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer);
-int
-lws_peer_confirm_ah_attach_ok(struct lws_context *context,
- struct lws_peer *peer);
-void
-lws_peer_track_ah_detach(struct lws_context *context, struct lws_peer *peer);
-void
-lws_peer_cull_peer_wait_list(struct lws_context *context);
-struct lws_peer *
-lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd);
-void
-lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,
- struct lws *wsi);
-void
-lws_peer_dump_from_wsi(struct lws *wsi);
-#endif
-
-#ifdef LWS_WITH_HUBBUB
-hubbub_error
-html_parser_cb(const hubbub_token *token, void *pw);
-#endif
-
-int
-lws_threadpool_tsi_context(struct lws_context *context, int tsi);
-
-void
-__lws_remove_from_timeout_list(struct lws *wsi);
-
-lws_usec_t
-__lws_hrtimer_service(struct lws_context_per_thread *pt);
-
-void
-__lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs);
-int
-__lws_change_pollfd(struct lws *wsi, int _and, int _or);
-
-
-int
-lws_callback_as_writeable(struct lws *wsi);
-int
-lws_buflist_aware_read(struct lws_context_per_thread *pt, struct lws *wsi,
- struct lws_tokens *ebuf);
-int
-lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
- int buffered);
-
-
-char *
-lws_generate_client_ws_handshake(struct lws *wsi, char *p, const char *conn1);
-int
-lws_client_ws_upgrade(struct lws *wsi, const char **cce);
-int
-lws_create_client_ws_object(const struct lws_client_connect_info *i,
- struct lws *wsi);
-int
-lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len);
-int
-lws_role_call_alpn_negotiated(struct lws *wsi, const char *alpn);
-int
-lws_tls_server_conn_alpn(struct lws *wsi);
-
-int
-lws_ws_client_rx_sm_block(struct lws *wsi, unsigned char **buf, size_t len);
-void
-lws_destroy_event_pipe(struct lws *wsi);
-void
-lws_context_destroy2(struct lws_context *context);
-int
-lws_role_call_client_bind(struct lws *wsi,
- const struct lws_client_connect_info *i);
-void
-lws_remove_child_from_any_parent(struct lws *wsi);
-
-#ifdef __cplusplus
-};
-#endif
diff --git a/thirdparty/libwebsockets/lib/core/service.c b/thirdparty/libwebsockets/lib/core/service.c
deleted file mode 100644
index ef251409cb..0000000000
--- a/thirdparty/libwebsockets/lib/core/service.c
+++ /dev/null
@@ -1,1114 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation:
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301 USA
- */
-
-#include "core/private.h"
-
-int
-lws_callback_as_writeable(struct lws *wsi)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
- int n, m;
-
- lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1);
-#if defined(LWS_WITH_STATS)
- if (wsi->active_writable_req_us) {
- uint64_t ul = lws_time_in_microseconds() -
- wsi->active_writable_req_us;
-
- lws_stats_atomic_bump(wsi->context, pt,
- LWSSTATS_MS_WRITABLE_DELAY, ul);
- lws_stats_atomic_max(wsi->context, pt,
- LWSSTATS_MS_WORST_WRITABLE_DELAY, ul);
- wsi->active_writable_req_us = 0;
- }
-#endif
-
- n = wsi->role_ops->writeable_cb[lwsi_role_server(wsi)];
-
- m = user_callback_handle_rxflow(wsi->protocol->callback,
- wsi, (enum lws_callback_reasons) n,
- wsi->user_space, NULL, 0);
-
- return m;
-}
-
-LWS_VISIBLE int
-lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd)
-{
- volatile struct lws *vwsi = (volatile struct lws *)wsi;
- int n;
-
- //lwsl_notice("%s: %p\n", __func__, wsi);
-
- vwsi->leave_pollout_active = 0;
- vwsi->handling_pollout = 1;
- /*
- * if another thread wants POLLOUT on us, from here on while
- * handling_pollout is set, he will only set leave_pollout_active.
- * If we are going to disable POLLOUT, we will check that first.
- */
- wsi->could_have_pending = 0; /* clear back-to-back write detection */
-
- /*
- * user callback is lowest priority to get these notifications
- * actually, since other pending things cannot be disordered
- *
- * Priority 1: pending truncated sends are incomplete ws fragments
- * If anything else sent first the protocol would be
- * corrupted.
- *
- * These are post- any compression transform
- */
-
- if (lws_has_buffered_out(wsi)) {
- //lwsl_notice("%s: completing partial\n", __func__);
- if (lws_issue_raw(wsi, NULL, 0) < 0) {
- lwsl_info("%s signalling to close\n", __func__);
- goto bail_die;
- }
- /* leave POLLOUT active either way */
- goto bail_ok;
- } else
- if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) {
- wsi->socket_is_permanently_unusable = 1;
- goto bail_die; /* retry closing now */
- }
-
- /* Priority 2: pre- compression transform */
-
-#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
- if (wsi->http.comp_ctx.buflist_comp ||
- wsi->http.comp_ctx.may_have_more) {
- enum lws_write_protocol wp = LWS_WRITE_HTTP;
-
- lwsl_info("%s: completing comp partial (buflist_comp %p, may %d)\n",
- __func__, wsi->http.comp_ctx.buflist_comp,
- wsi->http.comp_ctx.may_have_more
- );
-
- if (wsi->role_ops->write_role_protocol(wsi, NULL, 0, &wp) < 0) {
- lwsl_info("%s signalling to close\n", __func__);
- goto bail_die;
- }
- lws_callback_on_writable(wsi);
-
- goto bail_ok;
- }
-#endif
-
-#ifdef LWS_WITH_CGI
- /*
- * A cgi master's wire protocol remains h1 or h2. He is just getting
- * his data from his child cgis.
- */
- if (wsi->http.cgi) {
- /* also one shot */
- if (pollfd)
- if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
- lwsl_info("failed at set pollfd\n");
- return 1;
- }
- goto user_service_go_again;
- }
-#endif
-
- /* if we got here, we should have wire protocol ops set on the wsi */
- assert(wsi->role_ops);
-
- if (!wsi->role_ops->handle_POLLOUT)
- goto bail_ok;
-
- switch ((wsi->role_ops->handle_POLLOUT)(wsi)) {
- case LWS_HP_RET_BAIL_OK:
- goto bail_ok;
- case LWS_HP_RET_BAIL_DIE:
- goto bail_die;
- case LWS_HP_RET_USER_SERVICE:
- break;
- default:
- assert(0);
- }
-
- /* one shot */
-
- if (pollfd) {
- int eff = vwsi->leave_pollout_active;
-
- if (!eff) {
- if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
- lwsl_info("failed at set pollfd\n");
- goto bail_die;
- }
- }
-
- vwsi->handling_pollout = 0;
-
- /* cannot get leave_pollout_active set after the above */
- if (!eff && wsi->leave_pollout_active) {
- /*
- * got set inbetween sampling eff and clearing
- * handling_pollout, force POLLOUT on
- */
- lwsl_debug("leave_pollout_active\n");
- if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) {
- lwsl_info("failed at set pollfd\n");
- goto bail_die;
- }
- }
-
- vwsi->leave_pollout_active = 0;
- }
-
- if (lwsi_role_client(wsi) &&
- !wsi->hdr_parsing_completed &&
- lwsi_state(wsi) != LRS_H2_WAITING_TO_SEND_HEADERS &&
- lwsi_state(wsi) != LRS_ISSUE_HTTP_BODY
- )
- goto bail_ok;
-
-
-#ifdef LWS_WITH_CGI
-user_service_go_again:
-#endif
-
- if (wsi->role_ops->perform_user_POLLOUT) {
- if (wsi->role_ops->perform_user_POLLOUT(wsi) == -1)
- goto bail_die;
- else
- goto bail_ok;
- }
-
- lwsl_debug("%s: %p: non mux: wsistate 0x%x, ops %s\n", __func__, wsi,
- wsi->wsistate, wsi->role_ops->name);
-
- vwsi = (volatile struct lws *)wsi;
- vwsi->leave_pollout_active = 0;
-
- n = lws_callback_as_writeable(wsi);
- vwsi->handling_pollout = 0;
-
- if (vwsi->leave_pollout_active)
- lws_change_pollfd(wsi, 0, LWS_POLLOUT);
-
- return n;
-
- /*
- * since these don't disable the POLLOUT, they are always doing the
- * right thing for leave_pollout_active whether it was set or not.
- */
-
-bail_ok:
- vwsi->handling_pollout = 0;
- vwsi->leave_pollout_active = 0;
-
- return 0;
-
-bail_die:
- vwsi->handling_pollout = 0;
- vwsi->leave_pollout_active = 0;
-
- return -1;
-}
-
-static int
-__lws_service_timeout_check(struct lws *wsi, time_t sec)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- int n = 0;
-#endif
-
- (void)n;
-
- /*
- * if we went beyond the allowed time, kill the
- * connection
- */
- if (wsi->dll_timeout.prev &&
- lws_compare_time_t(wsi->context, sec, wsi->pending_timeout_set) >
- wsi->pending_timeout_limit) {
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- if (wsi->desc.sockfd != LWS_SOCK_INVALID &&
- wsi->position_in_fds_table >= 0)
- n = pt->fds[wsi->position_in_fds_table].events;
-#endif
-
- lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_TIMEOUTS, 1);
-
- /* no need to log normal idle keepalive timeout */
- if (wsi->pending_timeout != PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE)
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- lwsl_info("wsi %p: TIMEDOUT WAITING on %d "
- "(did hdr %d, ah %p, wl %d, pfd "
- "events %d) %llu vs %llu\n",
- (void *)wsi, wsi->pending_timeout,
- wsi->hdr_parsing_completed, wsi->http.ah,
- pt->http.ah_wait_list_length, n,
- (unsigned long long)sec,
- (unsigned long long)wsi->pending_timeout_limit);
-#if defined(LWS_WITH_CGI)
- if (wsi->http.cgi)
- lwsl_notice("CGI timeout: %s\n", wsi->http.cgi->summary);
-#endif
-#else
- lwsl_info("wsi %p: TIMEDOUT WAITING on %d ", (void *)wsi,
- wsi->pending_timeout);
-#endif
-
- /*
- * Since he failed a timeout, he already had a chance to do
- * something and was unable to... that includes situations like
- * half closed connections. So process this "failed timeout"
- * close as a violent death and don't try to do protocol
- * cleanup like flush partials.
- */
- wsi->socket_is_permanently_unusable = 1;
- if (lwsi_state(wsi) == LRS_WAITING_SSL && wsi->protocol)
- wsi->protocol->callback(wsi,
- LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
- wsi->user_space,
- (void *)"Timed out waiting SSL", 21);
-
- __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "timeout");
-
- return 1;
- }
-
- return 0;
-}
-
-int lws_rxflow_cache(struct lws *wsi, unsigned char *buf, int n, int len)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
- uint8_t *buffered;
- size_t blen;
- int ret = 0, m;
-
- /* his RX is flowcontrolled, don't send remaining now */
- blen = lws_buflist_next_segment_len(&wsi->buflist, &buffered);
- if (blen) {
- if (buf >= buffered && buf + len <= buffered + blen) {
- /* rxflow while we were spilling prev rxflow */
- lwsl_info("%s: staying in rxflow buf\n", __func__);
-
- return 1;
- }
- ret = 1;
- }
-
- /* a new rxflow, buffer it and warn caller */
-
- m = lws_buflist_append_segment(&wsi->buflist, buf + n, len - n);
-
- if (m < 0)
- return -1;
- if (m) {
- lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
- lws_dll_lws_add_front(&wsi->dll_buflist, &pt->dll_head_buflist);
- }
-
- return ret;
-}
-
-/* this is used by the platform service code to stop us waiting for network
- * activity in poll() when we have something that already needs service
- */
-
-LWS_VISIBLE LWS_EXTERN int
-lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
-{
- struct lws_context_per_thread *pt = &context->pt[tsi];
-
- /*
- * Figure out if we really want to wait in poll()... we only need to
- * wait if really nothing already to do and we have to wait for
- * something from network
- */
-#if defined(LWS_ROLE_WS) && !defined(LWS_WITHOUT_EXTENSIONS)
- /* 1) if we know we are draining rx ext, do not wait in poll */
- if (pt->ws.rx_draining_ext_list)
- return 0;
-#endif
-
- /* 2) if we know we have non-network pending data,
- * do not wait in poll */
-
- if (pt->context->tls_ops &&
- pt->context->tls_ops->fake_POLLIN_for_buffered &&
- pt->context->tls_ops->fake_POLLIN_for_buffered(pt))
- return 0;
-
- /*
- * 3) If there is any wsi with rxflow buffered and in a state to process
- * it, we should not wait in poll
- */
-
- lws_start_foreach_dll(struct lws_dll_lws *, d,
- pt->dll_head_buflist.next) {
- struct lws *wsi = lws_container_of(d, struct lws, dll_buflist);
-
- if (lwsi_state(wsi) != LRS_DEFERRING_ACTION)
- return 0;
-
- /*
- * 4) If any guys with http compression to spill, we shouldn't wait in
- * poll but hurry along and service them
- */
-
- } lws_end_foreach_dll(d);
-
- return timeout_ms;
-}
-
-/*
- * POLLIN said there is something... we must read it, and either use it; or
- * if other material already in the buflist append it and return the buflist
- * head material.
- */
-int
-lws_buflist_aware_read(struct lws_context_per_thread *pt, struct lws *wsi,
- struct lws_tokens *ebuf)
-{
- int n, prior = (int)lws_buflist_next_segment_len(&wsi->buflist, NULL);
-
- ebuf->token = (char *)pt->serv_buf;
- ebuf->len = lws_ssl_capable_read(wsi, pt->serv_buf,
- wsi->context->pt_serv_buf_size);
-
- if (ebuf->len == LWS_SSL_CAPABLE_MORE_SERVICE && prior)
- goto get_from_buflist;
-
- if (ebuf->len <= 0)
- return 0;
-
- /* nothing in buflist already? Then just use what we read */
-
- if (!prior)
- return 0;
-
- /* stash what we read */
-
- n = lws_buflist_append_segment(&wsi->buflist, (uint8_t *)ebuf->token,
- ebuf->len);
- if (n < 0)
- return -1;
- if (n) {
- lwsl_debug("%s: added %p to rxflow list\n", __func__, wsi);
- lws_dll_lws_add_front(&wsi->dll_buflist, &pt->dll_head_buflist);
- }
-
- /* get the first buflist guy in line */
-
-get_from_buflist:
-
- ebuf->len = (int)lws_buflist_next_segment_len(&wsi->buflist,
- (uint8_t **)&ebuf->token);
-
- return 1; /* came from buflist */
-}
-
-int
-lws_buflist_aware_consume(struct lws *wsi, struct lws_tokens *ebuf, int used,
- int buffered)
-{
- struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
- int m;
-
- /* it's in the buflist; we didn't use any */
-
- if (!used && buffered)
- return 0;
-
- if (used && buffered) {
- m = lws_buflist_use_segment(&wsi->buflist, used);
- lwsl_info("%s: draining rxflow: used %d, next %d\n",
- __func__, used, m);
- if (m)
- return 0;
-
- lwsl_info("%s: removed %p from dll_buflist\n", __func__, wsi);
- lws_dll_lws_remove(&wsi->dll_buflist);
-
- return 0;
- }
-
- /* any remainder goes on the buflist */
-
- if (used != ebuf->len) {
- m = lws_buflist_append_segment(&wsi->buflist,
- (uint8_t *)ebuf->token + used,
- ebuf->len - used);
- if (m < 0)
- return 1; /* OOM */
- if (m) {
- lwsl_debug("%s: added %p to rxflow list\n",
- __func__, wsi);
- lws_dll_lws_add_front(&wsi->dll_buflist,
- &pt->dll_head_buflist);
- }
- }
-
- return 0;
-}
-
-void
-lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt)
-{
- struct lws_pollfd pfd;
-
- if (!pt->dll_head_buflist.next)
- return;
-
- /*
- * service all guys with pending rxflow that reached a state they can
- * accept the pending data
- */
-
- lws_pt_lock(pt, __func__);
-
- lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
- pt->dll_head_buflist.next) {
- struct lws *wsi = lws_container_of(d, struct lws, dll_buflist);
-
- pfd.events = LWS_POLLIN;
- pfd.revents = LWS_POLLIN;
- pfd.fd = -1;
-
- lwsl_debug("%s: rxflow processing: %p 0x%x\n", __func__, wsi,
- wsi->wsistate);
-
- if (!lws_is_flowcontrolled(wsi) &&
- lwsi_state(wsi) != LRS_DEFERRING_ACTION &&
- (wsi->role_ops->handle_POLLIN)(pt, wsi, &pfd) ==
- LWS_HPI_RET_PLEASE_CLOSE_ME)
- lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
- "close_and_handled");
-
- } lws_end_foreach_dll_safe(d, d1);
-
- lws_pt_unlock(pt);
-}
-
-/*
- * guys that need POLLIN service again without waiting for network action
- * can force POLLIN here if not flowcontrolled, so they will get service.
- *
- * Return nonzero if anybody got their POLLIN faked
- */
-int
-lws_service_flag_pending(struct lws_context *context, int tsi)
-{
- struct lws_context_per_thread *pt = &context->pt[tsi];
- int forced = 0;
-
- lws_pt_lock(pt, __func__);
-
- /*
- * 1) If there is any wsi with a buflist and in a state to process
- * it, we should not wait in poll
- */
-
- lws_start_foreach_dll(struct lws_dll_lws *, d, pt->dll_head_buflist.next) {
- struct lws *wsi = lws_container_of(d, struct lws, dll_buflist);
-
- if (lwsi_state(wsi) != LRS_DEFERRING_ACTION) {
- forced = 1;
- break;
- }
- } lws_end_foreach_dll(d);
-
-#if defined(LWS_ROLE_WS)
- forced |= role_ops_ws.service_flag_pending(context, tsi);
-#endif
-
-#if defined(LWS_WITH_TLS)
- /*
- * 2) For all guys with buffered SSL read data already saved up, if they
- * are not flowcontrolled, fake their POLLIN status so they'll get
- * service to use up the buffered incoming data, even though their
- * network socket may have nothing
- */
- lws_start_foreach_dll_safe(struct lws_dll_lws *, p, p1,
- pt->tls.pending_tls_head.next) {
- struct lws *wsi = lws_container_of(p, struct lws,
- tls.pending_tls_list);
-
- pt->fds[wsi->position_in_fds_table].revents |=
- pt->fds[wsi->position_in_fds_table].events & LWS_POLLIN;
- if (pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN) {
- forced = 1;
- /*
- * he's going to get serviced now, take him off the
- * list of guys with buffered SSL. If he still has some
- * at the end of the service, he'll get put back on the
- * list then.
- */
- __lws_ssl_remove_wsi_from_buffered_list(wsi);
- }
-
- } lws_end_foreach_dll_safe(p, p1);
-#endif
-
- lws_pt_unlock(pt);
-
- return forced;
-}
-
-static int
-lws_service_periodic_checks(struct lws_context *context,
- struct lws_pollfd *pollfd, int tsi)
-{
- struct lws_context_per_thread *pt = &context->pt[tsi];
- struct lws_timed_vh_protocol *tmr;
- lws_sockfd_type our_fd = 0, tmp_fd;
- struct lws *wsi;
- int timed_out = 0;
- time_t now;
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- struct allocated_headers *ah;
- int n, m;
-#endif
-
- if (!context->protocol_init_done)
- if (lws_protocol_init(context)) {
- lwsl_err("%s: lws_protocol_init failed\n", __func__);
- return -1;
- }
-
- time(&now);
-
- /*
- * handle case that system time was uninitialized when lws started
- * at boot, and got initialized a little later
- */
- if (context->time_up < 1464083026 && now > 1464083026)
- context->time_up = now;
-
- if (context->last_timeout_check_s &&
- now - context->last_timeout_check_s > 100) {
- /*
- * There has been a discontiguity. Any stored time that is
- * less than context->time_discontiguity should have context->
- * time_fixup added to it.
- *
- * Some platforms with no RTC will experience this as a normal
- * event when ntp sets their clock, but we can have started
- * long before that with a 0-based unix time.
- */
-
- context->time_discontiguity = now;
- context->time_fixup = now - context->last_timeout_check_s;
-
- lwsl_notice("time discontiguity: at old time %llus, "
- "new time %llus: +%llus\n",
- (unsigned long long)context->last_timeout_check_s,
- (unsigned long long)context->time_discontiguity,
- (unsigned long long)context->time_fixup);
-
- context->last_timeout_check_s = now - 1;
- }
-
- if (!lws_compare_time_t(context, context->last_timeout_check_s, now))
- return 0;
-
- context->last_timeout_check_s = now;
-
-#if defined(LWS_WITH_STATS)
- if (!tsi && now - context->last_dump > 10) {
- lws_stats_log_dump(context);
- context->last_dump = now;
- }
-#endif
-
- lws_plat_service_periodic(context);
- lws_check_deferred_free(context, tsi, 0);
-
-#if defined(LWS_WITH_PEER_LIMITS)
- lws_peer_cull_peer_wait_list(context);
-#endif
-
- /* retire unused deprecated context */
-#if !defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_ESP32)
-#if !defined(_WIN32)
- if (context->deprecated && !context->count_wsi_allocated) {
- lwsl_notice("%s: ending deprecated context\n", __func__);
- kill(getpid(), SIGINT);
- return 0;
- }
-#endif
-#endif
- /* global timeout check once per second */
-
- if (pollfd)
- our_fd = pollfd->fd;
-
- /*
- * Phase 1: check every wsi on our pt's timeout check list
- */
-
- lws_pt_lock(pt, __func__);
-
- lws_start_foreach_dll_safe(struct lws_dll_lws *, d, d1,
- context->pt[tsi].dll_head_timeout.next) {
- wsi = lws_container_of(d, struct lws, dll_timeout);
- tmp_fd = wsi->desc.sockfd;
- if (__lws_service_timeout_check(wsi, now)) {
- /* he did time out... */
- if (tmp_fd == our_fd)
- /* it was the guy we came to service! */
- timed_out = 1;
- /* he's gone, no need to mark as handled */
- }
- } lws_end_foreach_dll_safe(d, d1);
-
-#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- /*
- * Phase 2: double-check active ah timeouts independent of wsi
- * timeout status
- */
-
- ah = pt->http.ah_list;
- while (ah) {
- int len;
- char buf[256];
- const unsigned char *c;
-
- if (!ah->in_use || !ah->wsi || !ah->assigned ||
- (ah->wsi->vhost &&
- lws_compare_time_t(context, now, ah->assigned) <
- ah->wsi->vhost->timeout_secs_ah_idle + 360)) {
- ah = ah->next;
- continue;
- }
-
- /*
- * a single ah session somehow got held for
- * an unreasonable amount of time.
- *
- * Dump info on the connection...
- */
- wsi = ah->wsi;
- buf[0] = '\0';
-#if !defined(LWS_PLAT_OPTEE)
- lws_get_peer_simple(wsi, buf, sizeof(buf));
-#else
- buf[0] = '\0';
-#endif
- lwsl_notice("ah excessive hold: wsi %p\n"
- " peer address: %s\n"
- " ah pos %u\n",
- wsi, buf, ah->pos);
- buf[0] = '\0';
- m = 0;
- do {
- c = lws_token_to_string(m);
- if (!c)
- break;
- if (!(*c))
- break;
-
- len = lws_hdr_total_length(wsi, m);
- if (!len || len > (int)sizeof(buf) - 1) {
- m++;
- continue;
- }
-
- if (lws_hdr_copy(wsi, buf, sizeof buf, m) > 0) {
- buf[sizeof(buf) - 1] = '\0';
-
- lwsl_notice(" %s = %s\n",
- (const char *)c, buf);
- }
- m++;
- } while (1);
-
- /* explicitly detach the ah */
- lws_header_table_detach(wsi, 0);
-
- /* ... and then drop the connection */
-
- m = 0;
- if (wsi->desc.sockfd == our_fd) {
- m = timed_out;
-
- /* it was the guy we came to service! */
- timed_out = 1;
- }
-
- if (!m) /* if he didn't already timeout */
- __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
- "excessive ah");
-
- ah = pt->http.ah_list;
- }
-#endif
- lws_pt_unlock(pt);
-
-#if 0
- {
- char s[300], *p = s;
-
- for (n = 0; n < context->count_threads; n++)
- p += sprintf(p, " %7lu (%5d), ",
- context->pt[n].count_conns,
- context->pt[n].fds_count);
-
- lwsl_notice("load: %s\n", s);
- }
-#endif
- /*
- * Phase 3: vhost / protocol timer callbacks
- */
-
- /* 3a: lock, collect, and remove vh timers that are pending */
-
- lws_context_lock(context, "expired vh timers"); /* context ---------- */
-
- n = 0;
-
- /*
- * first, under the context lock, get a count of the number of
- * expired timers so we can allocate for them (or not, cleanly)
- */
-
- lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) {
-
- if (v->timed_vh_protocol_list) {
-
- lws_start_foreach_ll_safe(struct lws_timed_vh_protocol *,
- q, v->timed_vh_protocol_list, next) {
- if (now >= q->time && q->tsi_req == tsi)
- n++;
- } lws_end_foreach_ll_safe(q);
- }
-
- } lws_end_foreach_ll(v, vhost_next);
-
- /* if nothing to do, unlock and move on to the next vhost */
-
- if (!n) {
- lws_context_unlock(context); /* ----------- context */
- goto vh_timers_done;
- }
-
- /*
- * attempt to do the wsi and timer info allocation
- * first en bloc. If it fails, we can just skip the rest and
- * the timers will still be pending next time.
- */
-
- wsi = lws_zalloc(sizeof(*wsi), "cbwsi");
- if (!wsi) {
- /*
- * at this point, we haven't cleared any vhost
- * timers. We can fail out and retry cleanly
- * next periodic check
- */
- lws_context_unlock(context); /* ----------- context */
- goto vh_timers_done;
- }
- wsi->context = context;
-
- tmr = lws_zalloc(sizeof(*tmr) * n, "cbtmr");
- if (!tmr) {
- /* again OOM here can be handled cleanly */
- lws_free(wsi);
- lws_context_unlock(context); /* ----------- context */
- goto vh_timers_done;
- }
-
- /* so we have the allocation for n pending timers... */
-
- m = 0;
- lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) {
-
- if (v->timed_vh_protocol_list) {
-
- lws_vhost_lock(v); /* vhost ------------------------- */
-
- lws_start_foreach_ll_safe(struct lws_timed_vh_protocol *,
- q, v->timed_vh_protocol_list, next) {
-
- /* only do n */
- if (m == n)
- break;
-
- if (now >= q->time && q->tsi_req == tsi) {
-
- /*
- * tmr is an allocated array.
- * Ignore the linked-list.
- */
- tmr[m].vhost = v;
- tmr[m].protocol = q->protocol;
- tmr[m++].reason = q->reason;
-
- /* take the timer out now we took
- * responsibility */
- __lws_timed_callback_remove(v, q);
- }
-
- } lws_end_foreach_ll_safe(q);
-
- lws_vhost_unlock(v); /* ----------------------- vhost */
- }
-
- } lws_end_foreach_ll(v, vhost_next);
- lws_context_unlock(context); /* ---------------------------- context */
-
- /* 3b: call the vh timer callbacks outside any lock */
-
- for (m = 0; m < n; m++) {
-
- wsi->vhost = tmr[m].vhost; /* not a real bound wsi */
- wsi->protocol = tmr[m].protocol;
-
- lwsl_debug("%s: timed cb: vh %s, protocol %s, reason %d\n",
- __func__, tmr[m].vhost->name, tmr[m].protocol->name,
- tmr[m].reason);
- tmr[m].protocol->callback(wsi, tmr[m].reason, NULL, NULL, 0);
- }
-
- lws_free(tmr);
- lws_free(wsi);
-
-vh_timers_done:
-
- /*
- * Phase 4: check for unconfigured vhosts due to required
- * interface missing before
- */
-
- lws_context_lock(context, "periodic checks");
- lws_start_foreach_llp(struct lws_vhost **, pv,
- context->no_listener_vhost_list) {
- struct lws_vhost *v = *pv;
- lwsl_debug("deferred iface: checking if on vh %s\n", (*pv)->name);
- if (_lws_vhost_init_server(NULL, *pv) == 0) {
- /* became happy */
- lwsl_notice("vh %s: became connected\n", v->name);
- *pv = v->no_listener_vhost_list;
- v->no_listener_vhost_list = NULL;
- break;
- }
- } lws_end_foreach_llp(pv, no_listener_vhost_list);
- lws_context_unlock(context);
-
- /*
- * Phase 5: role periodic checks
- */
-#if defined(LWS_ROLE_WS)
- role_ops_ws.periodic_checks(context, tsi, now);
-#endif
-#if defined(LWS_ROLE_CGI)
- role_ops_cgi.periodic_checks(context, tsi, now);
-#endif
-
- /*
- * Phase 6: check the remaining cert lifetime daily
- */
-
- if (context->tls_ops &&
- context->tls_ops->periodic_housekeeping)
- context->tls_ops->periodic_housekeeping(context, now);
-
- return 0;
-}
-
-LWS_VISIBLE int
-lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd,
- int tsi)
-{
- struct lws_context_per_thread *pt = &context->pt[tsi];
- struct lws *wsi;
-
- if (!context || context->being_destroyed1)
- return -1;
-
- /* the case there's no pollfd to service, we just want to do periodic */
- if (!pollfd) {
- lws_service_periodic_checks(context, pollfd, tsi);
- return -2;
- }
-
- /* no, here to service a socket descriptor */
- wsi = wsi_from_fd(context, pollfd->fd);
- if (!wsi)
- /* not lws connection ... leave revents alone and return */
- return 0;
-
- /*
- * so that caller can tell we handled, past here we need to
- * zero down pollfd->revents after handling
- */
-
- /* handle session socket closed */
-
- if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
- (pollfd->revents & LWS_POLLHUP)) {
- wsi->socket_is_permanently_unusable = 1;
- lwsl_debug("Session Socket %p (fd=%d) dead\n",
- (void *)wsi, pollfd->fd);
-
- goto close_and_handled;
- }
-
-#ifdef _WIN32
- if (pollfd->revents & LWS_POLLOUT)
- wsi->sock_send_blocking = FALSE;
-#endif
-
- if ((!(pollfd->revents & pollfd->events & LWS_POLLIN)) &&
- (pollfd->revents & LWS_POLLHUP)) {
- lwsl_debug("pollhup\n");
- wsi->socket_is_permanently_unusable = 1;
- goto close_and_handled;
- }
-
-#if defined(LWS_WITH_TLS)
- if (lwsi_state(wsi) == LRS_SHUTDOWN &&
- lws_is_ssl(wsi) && wsi->tls.ssl) {
- switch (__lws_tls_shutdown(wsi)) {
- case LWS_SSL_CAPABLE_DONE:
- case LWS_SSL_CAPABLE_ERROR:
- goto close_and_handled;
-
- case LWS_SSL_CAPABLE_MORE_SERVICE_READ:
- case LWS_SSL_CAPABLE_MORE_SERVICE_WRITE:
- case LWS_SSL_CAPABLE_MORE_SERVICE:
- goto handled;
- }
- }
-#endif
- wsi->could_have_pending = 0; /* clear back-to-back write detection */
-
- /* okay, what we came here to do... */
-
- /* if we got here, we should have wire protocol ops set on the wsi */
- assert(wsi->role_ops);
-
- // lwsl_notice("%s: %s: wsistate 0x%x\n", __func__, wsi->role_ops->name,
- // wsi->wsistate);
-
- switch ((wsi->role_ops->handle_POLLIN)(pt, wsi, pollfd)) {
- case LWS_HPI_RET_WSI_ALREADY_DIED:
- return 1;
- case LWS_HPI_RET_HANDLED:
- break;
- case LWS_HPI_RET_PLEASE_CLOSE_ME:
-close_and_handled:
- lwsl_debug("%p: Close and handled\n", wsi);
- lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
- "close_and_handled");
-#if defined(_DEBUG) && defined(LWS_WITH_LIBUV)
- /*
- * confirm close has no problem being called again while
- * it waits for libuv service to complete the first async
- * close
- */
- if (context->event_loop_ops == &event_loop_ops_uv)
- lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS,
- "close_and_handled uv repeat test");
-#endif
- /*
- * pollfd may point to something else after the close
- * due to pollfd swapping scheme on delete on some platforms
- * we can't clear revents now because it'd be the wrong guy's
- * revents
- */
- return 1;
- default:
- assert(0);
- }
-#if defined(LWS_WITH_TLS)
-handled:
-#endif
- pollfd->revents = 0;
-
- /* check the timeout situation if we didn't in the last second */
- lws_service_periodic_checks(context, pollfd, tsi);
-
- lws_pt_lock(pt, __func__);
- __lws_hrtimer_service(pt);
- lws_pt_unlock(pt);
-
- return 0;
-}
-
-LWS_VISIBLE int
-lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd)
-{
- return lws_service_fd_tsi(context, pollfd, 0);
-}
-
-LWS_VISIBLE int
-lws_service(struct lws_context *context, int timeout_ms)
-{
- struct lws_context_per_thread *pt = &context->pt[0];
- int n;
-
- if (!context)
- return 1;
-
- pt->inside_service = 1;
-
- if (context->event_loop_ops->run_pt) {
- /* we are configured for an event loop */
- context->event_loop_ops->run_pt(context, 0);
-
- pt->inside_service = 0;
-
- return 1;
- }
- n = lws_plat_service(context, timeout_ms);
-
- pt->inside_service = 0;
-
- return n;
-}
-
-LWS_VISIBLE int
-lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
-{
- struct lws_context_per_thread *pt = &context->pt[tsi];
- int n;
-
- pt->inside_service = 1;
-#if LWS_MAX_SMP > 1
- pt->self = pthread_self();
-#endif
-
- if (context->event_loop_ops->run_pt) {
- /* we are configured for an event loop */
- context->event_loop_ops->run_pt(context, tsi);
-
- pt->inside_service = 0;
-
- return 1;
- }
-
- n = _lws_plat_service_tsi(context, timeout_ms, tsi);
-
- pt->inside_service = 0;
-
- return n;
-}