mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
LWS_WITH_NETWORK: cmake option for no network code
This commit is contained in:
parent
9b5e45d383
commit
84a57540ab
40 changed files with 6557 additions and 6007 deletions
|
@ -11,6 +11,7 @@ env:
|
|||
- LWS_METHOD=noserver CMAKE_ARGS="-DLWS_WITHOUT_SERVER=ON -DLWS_WITH_MINIMAL_EXAMPLES=1"
|
||||
- LWS_METHOD=noclient CMAKE_ARGS="-DLWS_WITHOUT_CLIENT=ON -DLWS_WITH_MINIMAL_EXAMPLES=1"
|
||||
- LWS_METHOD=noext CMAKE_ARGS="-DLWS_WITHOUT_EXTENSIONS=ON -DLWS_WITH_MINIMAL_EXAMPLES=1"
|
||||
- LWS_METHOD=nonetwork CMAKE_ARGS="-DLWS_WITH_NETWORK=0"
|
||||
- LWS_METHOD=libev CMAKE_ARGS="-DLWS_WITH_LIBEV=ON"
|
||||
- LWS_METHOD=noipv6 CMAKE_ARGS="-DLWS_IPV6=OFF"
|
||||
- LWS_METHOD=nossl CMAKE_ARGS="-DLWS_WITH_SSL=OFF"
|
||||
|
|
221
CMakeLists.txt
221
CMakeLists.txt
|
@ -22,6 +22,7 @@ option(LWS_FOR_GITOHASHI "Enable features recommended for use with gitohashi" OF
|
|||
#
|
||||
# Major individual features
|
||||
#
|
||||
option(LWS_WITH_NETWORK "Compile with network-related code" ON)
|
||||
option(LWS_ROLE_H1 "Compile with support for http/1 (needed for ws)" ON)
|
||||
option(LWS_ROLE_WS "Compile with support for websockets" ON)
|
||||
option(LWS_ROLE_DBUS "Compile with support for DBUS" OFF)
|
||||
|
@ -159,6 +160,28 @@ if(LWS_WITH_DISTRO_RECOMMENDED)
|
|||
set(LWS_WITH_JOSE 1)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITH_NETWORK)
|
||||
set(LWS_ROLE_H1 0)
|
||||
set(LWS_ROLE_WS 0)
|
||||
set(LWS_ROLE_RAW 0)
|
||||
set(LWS_WITHOUT_EXTENSIONS 1)
|
||||
set(LWS_WITHOUT_SERVER 1)
|
||||
set(LWS_WITHOUT_CLIENT 1)
|
||||
set(LWS_WITH_HTTP2 0)
|
||||
set(LWS_WITH_SOCKS5 0)
|
||||
set(LWS_UNIX_SOCK 0)
|
||||
set(LWS_WITH_HTTP_PROXY 0)
|
||||
set(LWS_WITH_PLUGINS 0)
|
||||
set(LWS_WITH_LWSWS 0)
|
||||
set(LWS_WITH_CGI 0)
|
||||
set(LWS_ROLE_RAW_PROXY 0)
|
||||
set(LWS_WITH_PEER_LIMITS 0)
|
||||
set(LWS_WITH_GENERIC_SESSIONS 0)
|
||||
set(LWS_WITH_HTTP_STREAM_COMPRESSION 0)
|
||||
set(LWS_WITH_HTTP_BROTLI 0)
|
||||
set(LWS_WITH_POLL 0)
|
||||
endif()
|
||||
|
||||
# do you care about this? Then send me a patch where it disables it on travis
|
||||
# but allows it on APPLE
|
||||
if (APPLE)
|
||||
|
@ -414,10 +437,6 @@ if (LWS_WITH_CYASSL)
|
|||
set(LWS_WOLFSSL_INCLUDE_DIRS ${LWS_CYASSL_INCLUDE_DIRS} CACHE PATH "Path to wolfSSL/CyaSSL header files" FORCE)
|
||||
endif()
|
||||
|
||||
if (LWS_WITHOUT_CLIENT AND LWS_WITHOUT_SERVER)
|
||||
message(FATAL_ERROR "Makes no sense to compile with neither client nor server.")
|
||||
endif()
|
||||
|
||||
if (NOT (LWS_WITH_STATIC OR LWS_WITH_SHARED))
|
||||
message(FATAL_ERROR "Makes no sense to compile with neither static nor shared libraries.")
|
||||
endif()
|
||||
|
@ -863,15 +882,35 @@ set(HDR_PUBLIC
|
|||
set(SOURCES
|
||||
lib/core/alloc.c
|
||||
lib/core/context.c
|
||||
lib/core/dummy-callback.c
|
||||
lib/core/libwebsockets.c
|
||||
lib/core/output.c
|
||||
lib/core/pollfd.c
|
||||
lib/core/service.c
|
||||
lib/core/logs.c
|
||||
lib/misc/base64-decode.c
|
||||
lib/core/vfs.c
|
||||
lib/misc/lws-ring.c
|
||||
lib/core/adopt.c
|
||||
lib/roles/pipe/ops-pipe.c)
|
||||
)
|
||||
|
||||
if (LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/core-net/dummy-callback.c
|
||||
lib/core-net/output.c
|
||||
lib/core-net/close.c
|
||||
lib/core-net/network.c
|
||||
lib/core-net/vhost.c
|
||||
lib/core-net/pollfd.c
|
||||
lib/core-net/service.c
|
||||
lib/core-net/stats.c
|
||||
lib/core-net/wsi.c
|
||||
lib/core-net/wsi-timeout.c
|
||||
lib/core-net/adopt.c
|
||||
lib/roles/pipe/ops-pipe.c
|
||||
)
|
||||
|
||||
if (LWS_WITH_STATS)
|
||||
list(APPEND SOURCES
|
||||
lib/core-net/stats.c
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_THREADPOOL AND UNIX AND LWS_HAVE_PTHREAD_H)
|
||||
list(APPEND SOURCES lib/misc/threadpool/threadpool.c)
|
||||
|
@ -962,94 +1001,113 @@ endif()
|
|||
|
||||
if (NOT LWS_WITHOUT_CLIENT)
|
||||
list(APPEND SOURCES
|
||||
lib/core/connect.c
|
||||
lib/core-net/connect.c
|
||||
lib/core-net/client.c
|
||||
lib/roles/http/client/client.c
|
||||
lib/roles/http/client/client-handshake.c)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_SERVER)
|
||||
list(APPEND SOURCES
|
||||
lib/core-net/server.c
|
||||
lib/roles/listen/ops-listen.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_MBEDTLS)
|
||||
set(LWS_WITH_SSL ON)
|
||||
|
||||
list(APPEND HDR_PRIVATE
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl3.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_cert.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_code.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_dbg.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_lib.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_methods.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_pkey.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_stack.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_types.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/tls1.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/x509_vfy.h)
|
||||
|
||||
list(APPEND HDR_PRIVATE
|
||||
lib/tls/mbedtls/wrapper/include/openssl/ssl.h)
|
||||
|
||||
list(APPEND HDR_PRIVATE
|
||||
lib/tls/mbedtls/wrapper/include/platform/ssl_pm.h
|
||||
lib/tls/mbedtls/wrapper/include/platform/ssl_port.h)
|
||||
|
||||
include_directories(lib/tls/mbedtls/wrapper/include)
|
||||
include_directories(lib/tls/mbedtls/wrapper/include/platform)
|
||||
include_directories(lib/tls/mbedtls/wrapper/include/internal)
|
||||
include_directories(lib/tls/mbedtls/wrapper/include/openssl)
|
||||
|
||||
list(APPEND SOURCES
|
||||
lib/tls/mbedtls/wrapper/library/ssl_cert.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_lib.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_methods.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_pkey.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_stack.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_x509.c)
|
||||
|
||||
list(APPEND SOURCES
|
||||
lib/tls/mbedtls/wrapper/platform/ssl_pm.c
|
||||
lib/tls/mbedtls/wrapper/platform/ssl_port.c)
|
||||
|
||||
if (LWS_WITH_NETWORK)
|
||||
list(APPEND HDR_PRIVATE
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl3.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_cert.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_code.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_dbg.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_lib.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_methods.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_pkey.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_stack.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_types.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/tls1.h
|
||||
lib/tls/mbedtls/wrapper/include/internal/x509_vfy.h)
|
||||
|
||||
list(APPEND HDR_PRIVATE
|
||||
lib/tls/mbedtls/wrapper/include/openssl/ssl.h)
|
||||
|
||||
list(APPEND HDR_PRIVATE
|
||||
lib/tls/mbedtls/wrapper/include/platform/ssl_pm.h
|
||||
lib/tls/mbedtls/wrapper/include/platform/ssl_port.h)
|
||||
|
||||
list(APPEND SOURCES
|
||||
lib/tls/mbedtls/wrapper/library/ssl_cert.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_lib.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_methods.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_pkey.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_stack.c
|
||||
lib/tls/mbedtls/wrapper/library/ssl_x509.c)
|
||||
|
||||
list(APPEND SOURCES
|
||||
lib/tls/mbedtls/wrapper/platform/ssl_pm.c
|
||||
lib/tls/mbedtls/wrapper/platform/ssl_port.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_SSL)
|
||||
list(APPEND SOURCES
|
||||
lib/tls/tls.c
|
||||
)
|
||||
if (LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/tls/tls-network.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_MBEDTLS)
|
||||
if (LWS_WITH_MBEDTLS)
|
||||
list(APPEND SOURCES
|
||||
lib/tls/mbedtls/tls.c
|
||||
lib/tls/mbedtls/x509.c
|
||||
)
|
||||
if (LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/tls/mbedtls/ssl.c
|
||||
lib/tls/mbedtls/x509.c
|
||||
)
|
||||
if (LWS_WITH_GENCRYPTO)
|
||||
list(APPEND SOURCES
|
||||
lib/tls/mbedtls/lws-genhash.c
|
||||
lib/tls/mbedtls/lws-genrsa.c
|
||||
lib/tls/mbedtls/lws-genaes.c
|
||||
lib/tls/lws-genec-common.c
|
||||
lib/tls/mbedtls/lws-genec.c
|
||||
lib/tls/mbedtls/lws-gencrypto.c
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
endif()
|
||||
if (LWS_WITH_GENCRYPTO)
|
||||
list(APPEND SOURCES
|
||||
lib/tls/mbedtls/lws-genhash.c
|
||||
lib/tls/mbedtls/lws-genrsa.c
|
||||
lib/tls/mbedtls/lws-genaes.c
|
||||
lib/tls/lws-genec-common.c
|
||||
lib/tls/mbedtls/lws-genec.c
|
||||
lib/tls/mbedtls/lws-gencrypto.c
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
list(APPEND SOURCES
|
||||
lib/tls/openssl/tls.c
|
||||
lib/tls/openssl/x509.c
|
||||
)
|
||||
if (LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/tls/openssl/ssl.c
|
||||
lib/tls/openssl/x509.c
|
||||
)
|
||||
if (LWS_WITH_GENCRYPTO)
|
||||
list(APPEND SOURCES
|
||||
lib/tls/openssl/lws-genhash.c
|
||||
lib/tls/openssl/lws-genrsa.c
|
||||
lib/tls/openssl/lws-genaes.c
|
||||
lib/tls/lws-genec-common.c
|
||||
lib/tls/openssl/lws-genec.c
|
||||
lib/tls/openssl/lws-gencrypto.c
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
if (LWS_WITH_GENCRYPTO)
|
||||
list(APPEND SOURCES
|
||||
lib/tls/openssl/lws-genhash.c
|
||||
lib/tls/openssl/lws-genrsa.c
|
||||
lib/tls/openssl/lws-genaes.c
|
||||
lib/tls/lws-genec-common.c
|
||||
lib/tls/openssl/lws-genec.c
|
||||
lib/tls/openssl/lws-gencrypto.c
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_SERVER)
|
||||
list(APPEND SOURCES
|
||||
|
@ -1105,6 +1163,11 @@ else()
|
|||
list(APPEND SOURCES
|
||||
lib/plat/optee/lws-plat-optee.c
|
||||
)
|
||||
if (LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/plat/optee/network.c
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
if (LWS_WITH_ESP32)
|
||||
list(APPEND SOURCES
|
||||
|
@ -1120,14 +1183,18 @@ else()
|
|||
else()
|
||||
list(APPEND SOURCES
|
||||
lib/plat/unix/unix-caps.c
|
||||
lib/plat/unix/unix-fds.c
|
||||
lib/plat/unix/unix-file.c
|
||||
lib/plat/unix/unix-misc.c
|
||||
lib/plat/unix/unix-init.c
|
||||
lib/plat/unix/unix-pipe.c
|
||||
lib/plat/unix/unix-service.c
|
||||
lib/plat/unix/unix-sockets.c
|
||||
)
|
||||
if (LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/plat/unix/unix-pipe.c
|
||||
lib/plat/unix/unix-service.c
|
||||
lib/plat/unix/unix-sockets.c
|
||||
lib/plat/unix/unix-fds.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_PLUGINS AND LWS_WITH_LIBUV)
|
||||
list(APPEND SOURCES lib/plat/unix/unix-plugins.c)
|
||||
|
@ -1155,22 +1222,22 @@ if (LWS_WITH_HTTP_PROXY)
|
|||
lib/roles/http/server/rewrite.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_POLL)
|
||||
if (LWS_WITH_POLL AND LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/event-libs/poll/poll.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBUV)
|
||||
if (LWS_WITH_LIBUV AND LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/event-libs/libuv/libuv.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEVENT)
|
||||
if (LWS_WITH_LIBEVENT AND LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/event-libs/libevent/libevent.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
if (LWS_WITH_LIBEV AND LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
lib/event-libs/libev/libev.c)
|
||||
endif()
|
||||
|
@ -1179,7 +1246,7 @@ if (LWS_WITH_LEJP)
|
|||
list(APPEND SOURCES
|
||||
lib/misc/lejp.c)
|
||||
endif()
|
||||
if (LWS_WITH_LEJP_CONF)
|
||||
if (LWS_WITH_LEJP_CONF AND LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
"lib/roles/http/server/lejp-conf.c"
|
||||
)
|
||||
|
|
|
@ -18,6 +18,12 @@ News
|
|||
|
||||
## New features on master
|
||||
|
||||
- `LWS_WITH_NETWORK` cmake option (default on) allows one-step removal of vhost,
|
||||
wsi, roles, event loop and all network-related code from the build. This
|
||||
enables use-cases where you actually need unrelated features like JOSE or FTS
|
||||
compactly. lws_context still exists and if tls is enabled, the tls-related code
|
||||
is still built so the crypto is available, just nothing related to network.
|
||||
|
||||
- New Crypto-agile APIs + JOSE / JWS / JWE / JWK support... apis work exactly
|
||||
the same with OpenSSL or mbedTLS tls library backends, and allow key cycling
|
||||
and crypto algorithm changes while allowing for grace periods
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
#cmakedefine LWS_WITH_LIBUV
|
||||
#cmakedefine LWS_WITH_LWSAC
|
||||
#cmakedefine LWS_WITH_MBEDTLS
|
||||
#cmakedefine LWS_WITH_NETWORK
|
||||
#cmakedefine LWS_WITH_NO_LOGS
|
||||
#cmakedefine LWS_WITHOUT_CLIENT
|
||||
#cmakedefine LWS_WITHOUT_EXTENSIONS
|
||||
|
|
85
lib/core-net/client.c
Normal file
85
lib/core-net/client.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 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"
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
518
lib/core-net/close.c
Normal file
518
lib/core-net/close.c
Normal file
|
@ -0,0 +1,518 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 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_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_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;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
457
lib/core-net/network.c
Normal file
457
lib/core-net/network.c
Normal file
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 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_ESP32) && !defined(LWS_PLAT_OPTEE)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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) && !defined(LWS_PLAT_OPTEE)
|
||||
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) && !defined(LWS_PLAT_OPTEE)
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
|
||||
|
1048
lib/core-net/private.h
Normal file
1048
lib/core-net/private.h
Normal file
File diff suppressed because it is too large
Load diff
299
lib/core-net/server.c
Normal file
299
lib/core-net/server.c
Normal file
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 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_SERVER_STATUS)
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
|
@ -347,6 +347,7 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
|
|||
return 0;
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
/* 2) if we know we have non-network pending data,
|
||||
* do not wait in poll */
|
||||
|
||||
|
@ -354,6 +355,7 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
|
|||
pt->context->tls_ops->fake_POLLIN_for_buffered &&
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered(pt))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 3) If there is any wsi with rxflow buffered and in a state to process
|
||||
|
@ -921,6 +923,7 @@ vh_timers_done:
|
|||
role_ops_cgi.periodic_checks(context, tsi, now);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
/*
|
||||
* Phase 6: check the remaining cert lifetime daily
|
||||
*/
|
||||
|
@ -928,6 +931,7 @@ vh_timers_done:
|
|||
if (context->tls_ops &&
|
||||
context->tls_ops->periodic_housekeeping)
|
||||
context->tls_ops->periodic_housekeeping(context, now);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
263
lib/core-net/stats.c
Normal file
263
lib/core-net/stats.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 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_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
|
||||
|
||||
|
1241
lib/core-net/vhost.c
Normal file
1241
lib/core-net/vhost.c
Normal file
File diff suppressed because it is too large
Load diff
251
lib/core-net/wsi-timeout.c
Normal file
251
lib/core-net/wsi-timeout.c
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 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_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_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 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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
883
lib/core-net/wsi.c
Normal file
883
lib/core-net/wsi.c
Normal file
|
@ -0,0 +1,883 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 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 (_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
|
||||
|
||||
|
||||
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 ---------- */
|
||||
}
|
||||
|
||||
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 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 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
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,
|
||||
const 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 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;
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
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_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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 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 void *
|
||||
lws_get_opaque_user_data(const struct lws *wsi)
|
||||
{
|
||||
return wsi->opaque_user_data;
|
||||
}
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_set_opaque_user_data(struct lws *wsi, void *data)
|
||||
{
|
||||
wsi->opaque_user_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_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;
|
||||
}
|
||||
|
||||
LWS_VISIBLE lws_sockfd_type
|
||||
lws_get_socket_fd(struct lws *wsi)
|
||||
{
|
||||
if (!wsi)
|
||||
return -1;
|
||||
return wsi->desc.sockfd;
|
||||
}
|
||||
|
||||
|
||||
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 LWS_EXTERN struct lws_context *
|
||||
lws_get_context(const struct lws *wsi)
|
||||
{
|
||||
return wsi->context;
|
||||
}
|
||||
|
||||
#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_WARN_UNUSED_RESULT
|
||||
lws_raw_transaction_completed(struct lws *wsi)
|
||||
{
|
||||
if (lws_has_buffered_out(wsi)) {
|
||||
/*
|
||||
* ...so he tried to send something large, but it went out
|
||||
* as a partial, but he immediately called us to say he wants
|
||||
* to close the connection.
|
||||
*
|
||||
* Defer the close until the last part of the partial is sent.
|
||||
*
|
||||
*/
|
||||
lwsl_debug("%s: %p: deferring due to partial\n", __func__, wsi);
|
||||
wsi->close_when_buffered_out_drained = 1;
|
||||
lws_callback_on_writable(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
1257
lib/core/context.c
1257
lib/core/context.c
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
273
lib/core/logs.c
Normal file
273
lib/core/logs.c
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 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
|
||||
|
||||
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
|
||||
|
||||
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) {
|
||||
_lws_log(hexdump_level, "(hexdump: zero length)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vbuf) {
|
||||
_lws_log(hexdump_level, "(hexdump: trying to dump %d at NULL)\n",
|
||||
(int)len);
|
||||
return;
|
||||
}
|
||||
|
||||
_lws_log(hexdump_level, "\n");
|
||||
|
||||
for (n = 0; n < len;) {
|
||||
unsigned int start = n, m;
|
||||
char line[80], *p = line;
|
||||
|
||||
p += snprintf(p, 10, "%04X: ", start);
|
||||
|
||||
for (m = 0; m < 16 && n < len; m++)
|
||||
p += snprintf(p, 5, "%02X ", buf[n++]);
|
||||
while (m++ < 16)
|
||||
p += snprintf(p, 5, " ");
|
||||
|
||||
p += snprintf(p, 6, " ");
|
||||
|
||||
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
|
||||
}
|
1030
lib/core/private.h
1030
lib/core/private.h
File diff suppressed because it is too large
Load diff
134
lib/core/vfs.c
Normal file
134
lib/core/vfs.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 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"
|
||||
|
||||
|
||||
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_VISIBLE struct lws_plat_file_ops *
|
||||
lws_get_fops(struct lws_context *context)
|
||||
{
|
||||
return (struct lws_plat_file_ops *)context->fops;
|
||||
}
|
||||
|
|
@ -1,31 +1,10 @@
|
|||
#include "core/private.h"
|
||||
|
||||
/*
|
||||
* included from libwebsockets.c for OPTEE builds
|
||||
*/
|
||||
|
||||
int lws_plat_apply_FD_CLOEXEC(int n)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_pipe_create(struct lws *wsi)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_pipe_signal(struct lws *wsi)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_pipe_close(struct lws *wsi)
|
||||
{
|
||||
}
|
||||
|
||||
void TEE_GenerateRandom(void *randomBuffer, uint32_t randomBufferLen);
|
||||
|
||||
uint64_t
|
||||
|
@ -42,58 +21,6 @@ lws_get_random(struct lws_context *context, void *buf, int len)
|
|||
return len;
|
||||
}
|
||||
#endif
|
||||
LWS_VISIBLE int
|
||||
lws_send_pipe_choked(struct lws *wsi)
|
||||
{
|
||||
struct lws *wsi_eff;
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
wsi_eff = lws_get_network_wsi(wsi);
|
||||
#else
|
||||
wsi_eff = wsi;
|
||||
#endif
|
||||
|
||||
/* the fact we checked implies we avoided back-to-back writes */
|
||||
wsi_eff->could_have_pending = 0;
|
||||
|
||||
/* treat the fact we got a truncated send pending as if we're choked */
|
||||
if (lws_has_buffered_out(wsi_eff)
|
||||
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
||||
|| wsi->http.comp_ctx.buflist_comp ||
|
||||
wsi->http.comp_ctx.may_have_more
|
||||
#endif
|
||||
)
|
||||
return 1;
|
||||
|
||||
#if 0
|
||||
struct lws_pollfd fds;
|
||||
|
||||
/* treat the fact we got a truncated send pending as if we're choked */
|
||||
if (lws_has_buffered_out(wsi))
|
||||
return 1;
|
||||
|
||||
fds.fd = wsi->desc.sockfd;
|
||||
fds.events = POLLOUT;
|
||||
fds.revents = 0;
|
||||
|
||||
if (poll(&fds, 1, 0) != 1)
|
||||
return 1;
|
||||
|
||||
if ((fds.revents & POLLOUT) == 0)
|
||||
return 1;
|
||||
#endif
|
||||
/* okay to send another packet without blocking */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_poll_listen_fd(struct lws_pollfd *fd)
|
||||
{
|
||||
// return poll(fd, 1, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void lwsl_emit_syslog(int level, const char *line)
|
||||
|
@ -102,114 +29,6 @@ void lwsl_emit_syslog(int level, const char *line)
|
|||
}
|
||||
#endif
|
||||
|
||||
LWS_EXTERN int
|
||||
_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int n = -1, m, c;
|
||||
//char buf;
|
||||
|
||||
/* stay dead once we are dead */
|
||||
|
||||
if (!context || !context->vhost_list)
|
||||
return 1;
|
||||
|
||||
pt = &context->pt[tsi];
|
||||
|
||||
if (timeout_ms < 0)
|
||||
goto faked_service;
|
||||
|
||||
if (!pt->service_tid_detected) {
|
||||
struct lws _lws;
|
||||
|
||||
memset(&_lws, 0, sizeof(_lws));
|
||||
_lws.context = context;
|
||||
|
||||
pt->service_tid = context->vhost_list->protocols[0].callback(
|
||||
&_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
|
||||
pt->service_tid_detected = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* is there anybody with pending stuff that needs service forcing?
|
||||
*/
|
||||
if (!lws_service_adjust_timeout(context, 1, tsi)) {
|
||||
lwsl_notice("%s: doing forced service\n", __func__);
|
||||
/* -1 timeout means just do forced service */
|
||||
_lws_plat_service_tsi(context, -1, pt->tid);
|
||||
/* still somebody left who wants forced service? */
|
||||
if (!lws_service_adjust_timeout(context, 1, pt->tid))
|
||||
/* yes... come back again quickly */
|
||||
timeout_ms = 0;
|
||||
}
|
||||
|
||||
n = poll(pt->fds, pt->fds_count, timeout_ms);
|
||||
|
||||
m = 0;
|
||||
|
||||
if (pt->context->tls_ops &&
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered)
|
||||
m = pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
|
||||
|
||||
if (/*!pt->ws.rx_draining_ext_list && */!m && !n) { /* nothing to do */
|
||||
lws_service_fd_tsi(context, NULL, tsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
faked_service:
|
||||
m = lws_service_flag_pending(context, tsi);
|
||||
if (m)
|
||||
c = -1; /* unknown limit */
|
||||
else
|
||||
if (n < 0) {
|
||||
if (LWS_ERRNO != LWS_EINTR)
|
||||
return -1;
|
||||
return 0;
|
||||
} else
|
||||
c = n;
|
||||
|
||||
/* any socket with events to service? */
|
||||
for (n = 0; n < (int)pt->fds_count && c; n++) {
|
||||
if (!pt->fds[n].revents)
|
||||
continue;
|
||||
|
||||
c--;
|
||||
#if 0
|
||||
if (pt->fds[n].fd == pt->dummy_pipe_fds[0]) {
|
||||
if (read(pt->fds[n].fd, &buf, 1) != 1)
|
||||
lwsl_err("Cannot read from dummy pipe.");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
/* if something closed, retry this slot */
|
||||
if (m)
|
||||
n--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_check_connection_error(struct lws *wsi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_service(struct lws_context *context, int timeout_ms)
|
||||
{
|
||||
return _lws_plat_service_tsi(context, timeout_ms, 0);
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_drop_app_privileges(const struct lws_context_creation_info *info)
|
||||
{
|
||||
|
@ -229,60 +48,10 @@ lws_plat_context_early_destroy(struct lws_context *context)
|
|||
void
|
||||
lws_plat_context_late_destroy(struct lws_context *context)
|
||||
{
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
if (context->lws_lookup)
|
||||
lws_free(context->lws_lookup);
|
||||
}
|
||||
|
||||
/* cast a struct sockaddr_in6 * into addr for ipv6 */
|
||||
|
||||
int
|
||||
lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
|
||||
size_t addrlen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
pt->fds[pt->fds_count++].revents = 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_delete_socket_from_fds(struct lws_context *context,
|
||||
struct lws *wsi, int m)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
pt->fds_count--;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_service_periodic(struct lws_context *context)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_change_pollfd(struct lws_context *context,
|
||||
struct lws *wsi, struct lws_pollfd *pfd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
//return inet_ntop(af, src, dst, cnt);
|
||||
return "lws_plat_inet_ntop";
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
//return inet_pton(af, src, dst);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
lws_fop_fd_t
|
||||
|
@ -325,6 +94,7 @@ int
|
|||
lws_plat_init(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
/* master context has the global fd lookup array */
|
||||
context->lws_lookup = lws_zalloc(sizeof(struct lws *) *
|
||||
context->max_fds, "lws_lookup");
|
||||
|
@ -336,7 +106,7 @@ lws_plat_init(struct lws_context *context,
|
|||
|
||||
lwsl_notice(" mem: platform fd map: %5lu bytes\n",
|
||||
(long)sizeof(struct lws *) * context->max_fds);
|
||||
|
||||
#endif
|
||||
#ifdef LWS_WITH_PLUGINS
|
||||
if (info->plugin_dirs)
|
||||
lws_plat_plugins_init(context, info->plugin_dirs);
|
||||
|
@ -345,13 +115,6 @@ lws_plat_init(struct lws_context *context,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
|
||||
int len)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_write_file(const char *filename, void *buf, int len)
|
||||
{
|
||||
|
|
227
lib/plat/optee/network.c
Normal file
227
lib/plat/optee/network.c
Normal file
|
@ -0,0 +1,227 @@
|
|||
#include "core/private.h"
|
||||
|
||||
|
||||
int
|
||||
lws_plat_pipe_create(struct lws *wsi)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_pipe_signal(struct lws *wsi)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_pipe_close(struct lws *wsi)
|
||||
{
|
||||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_send_pipe_choked(struct lws *wsi)
|
||||
{
|
||||
struct lws *wsi_eff;
|
||||
|
||||
#if defined(LWS_WITH_HTTP2)
|
||||
wsi_eff = lws_get_network_wsi(wsi);
|
||||
#else
|
||||
wsi_eff = wsi;
|
||||
#endif
|
||||
|
||||
/* the fact we checked implies we avoided back-to-back writes */
|
||||
wsi_eff->could_have_pending = 0;
|
||||
|
||||
/* treat the fact we got a truncated send pending as if we're choked */
|
||||
if (lws_has_buffered_out(wsi_eff)
|
||||
#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
|
||||
|| wsi->http.comp_ctx.buflist_comp ||
|
||||
wsi->http.comp_ctx.may_have_more
|
||||
#endif
|
||||
)
|
||||
return 1;
|
||||
|
||||
/* okay to send another packet without blocking */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_poll_listen_fd(struct lws_pollfd *fd)
|
||||
{
|
||||
// return poll(fd, 1, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
LWS_EXTERN int
|
||||
_lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int n = -1, m, c;
|
||||
//char buf;
|
||||
|
||||
/* stay dead once we are dead */
|
||||
|
||||
if (!context || !context->vhost_list)
|
||||
return 1;
|
||||
|
||||
pt = &context->pt[tsi];
|
||||
|
||||
if (timeout_ms < 0)
|
||||
goto faked_service;
|
||||
|
||||
if (!pt->service_tid_detected) {
|
||||
struct lws _lws;
|
||||
|
||||
memset(&_lws, 0, sizeof(_lws));
|
||||
_lws.context = context;
|
||||
|
||||
pt->service_tid = context->vhost_list->protocols[0].callback(
|
||||
&_lws, LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
|
||||
pt->service_tid_detected = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* is there anybody with pending stuff that needs service forcing?
|
||||
*/
|
||||
if (!lws_service_adjust_timeout(context, 1, tsi)) {
|
||||
lwsl_notice("%s: doing forced service\n", __func__);
|
||||
/* -1 timeout means just do forced service */
|
||||
_lws_plat_service_tsi(context, -1, pt->tid);
|
||||
/* still somebody left who wants forced service? */
|
||||
if (!lws_service_adjust_timeout(context, 1, pt->tid))
|
||||
/* yes... come back again quickly */
|
||||
timeout_ms = 0;
|
||||
}
|
||||
|
||||
n = poll(pt->fds, pt->fds_count, timeout_ms);
|
||||
|
||||
m = 0;
|
||||
|
||||
if (pt->context->tls_ops &&
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered)
|
||||
m = pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
|
||||
|
||||
if (/*!pt->ws.rx_draining_ext_list && */!m && !n) { /* nothing to do */
|
||||
lws_service_fd_tsi(context, NULL, tsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
faked_service:
|
||||
m = lws_service_flag_pending(context, tsi);
|
||||
if (m)
|
||||
c = -1; /* unknown limit */
|
||||
else
|
||||
if (n < 0) {
|
||||
if (LWS_ERRNO != LWS_EINTR)
|
||||
return -1;
|
||||
return 0;
|
||||
} else
|
||||
c = n;
|
||||
|
||||
/* any socket with events to service? */
|
||||
for (n = 0; n < (int)pt->fds_count && c; n++) {
|
||||
if (!pt->fds[n].revents)
|
||||
continue;
|
||||
|
||||
c--;
|
||||
#if 0
|
||||
if (pt->fds[n].fd == pt->dummy_pipe_fds[0]) {
|
||||
if (read(pt->fds[n].fd, &buf, 1) != 1)
|
||||
lwsl_err("Cannot read from dummy pipe.");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
m = lws_service_fd_tsi(context, &pt->fds[n], tsi);
|
||||
if (m < 0)
|
||||
return -1;
|
||||
/* if something closed, retry this slot */
|
||||
if (m)
|
||||
n--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_check_connection_error(struct lws *wsi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_service(struct lws_context *context, int timeout_ms)
|
||||
{
|
||||
return _lws_plat_service_tsi(context, timeout_ms, 0);
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_plat_write_cert(struct lws_vhost *vhost, int is_key, int fd, void *buf,
|
||||
int len)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* cast a struct sockaddr_in6 * into addr for ipv6 */
|
||||
|
||||
int
|
||||
lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
|
||||
size_t addrlen)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
pt->fds[pt->fds_count++].revents = 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_delete_socket_from_fds(struct lws_context *context,
|
||||
struct lws *wsi, int m)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
|
||||
pt->fds_count--;
|
||||
}
|
||||
|
||||
void
|
||||
lws_plat_service_periodic(struct lws_context *context)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_change_pollfd(struct lws_context *context,
|
||||
struct lws *wsi, struct lws_pollfd *pfd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
|
||||
{
|
||||
//return inet_ntop(af, src, dst, cnt);
|
||||
return "lws_plat_inet_ntop";
|
||||
}
|
||||
|
||||
int
|
||||
lws_plat_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
//return inet_pton(af, src, dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ lws_plat_init(struct lws_context *context,
|
|||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
/* master context has the global fd lookup array */
|
||||
context->lws_lookup = lws_zalloc(sizeof(struct lws *) *
|
||||
context->max_fds, "lws_lookup");
|
||||
|
@ -47,6 +47,7 @@ lws_plat_init(struct lws_context *context,
|
|||
|
||||
lwsl_info(" mem: platform fd map: %5lu bytes\n",
|
||||
(unsigned long)(sizeof(struct lws *) * context->max_fds));
|
||||
#endif
|
||||
fd = lws_open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
|
||||
|
||||
context->fd_random = fd;
|
||||
|
@ -86,10 +87,10 @@ lws_plat_context_late_destroy(struct lws_context *context)
|
|||
if (context->plugin_list)
|
||||
lws_plat_plugins_destroy(context);
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
if (context->lws_lookup)
|
||||
lws_free(context->lws_lookup);
|
||||
|
||||
#endif
|
||||
if (!context->fd_random)
|
||||
lwsl_err("ZERO RANDOM FD\n");
|
||||
if (context->fd_random != LWS_INVALID_FILE)
|
||||
|
|
|
@ -135,9 +135,11 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
|||
m |= !!pt->ws.rx_draining_ext_list;
|
||||
#endif
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
if (pt->context->tls_ops &&
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered)
|
||||
m |= pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
|
||||
#endif
|
||||
|
||||
if (!m && !n) { /* nothing to do */
|
||||
lws_service_fd_tsi(context, NULL, tsi);
|
||||
|
|
|
@ -142,9 +142,11 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
|
|||
if (ev == WSA_WAIT_EVENT_0) {
|
||||
unsigned int eIdx;
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
if (pt->context->tls_ops &&
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered)
|
||||
pt->context->tls_ops->fake_POLLIN_for_buffered(pt);
|
||||
#endif
|
||||
|
||||
for (eIdx = 0; eIdx < pt->fds_count; ++eIdx) {
|
||||
unsigned int err;
|
||||
|
|
|
@ -665,21 +665,6 @@ lws_http_client_http_response(struct lws *_wsi)
|
|||
return resp;
|
||||
}
|
||||
#endif
|
||||
#if defined(LWS_PLAT_OPTEE)
|
||||
char *
|
||||
strrchr(const char *s, int c)
|
||||
{
|
||||
char *hit = NULL;
|
||||
|
||||
while (*s)
|
||||
if (*(s++) == (char)c)
|
||||
hit = (char *)s - 1;
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
#define atoll atoi
|
||||
#endif
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
int
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* libwebsockets - mbedTLS-specific lws apis
|
||||
*
|
||||
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2010 - 2019 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
|
||||
|
@ -22,22 +22,6 @@
|
|||
#include "core/private.h"
|
||||
#include "tls/mbedtls/private.h"
|
||||
|
||||
void
|
||||
lws_tls_err_describe(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
lws_context_init_ssl_library(const struct lws_context_creation_info *info)
|
||||
{
|
||||
lwsl_info(" Compiled with MbedTLS support\n");
|
||||
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
|
||||
lwsl_info(" SSL disabled: no "
|
||||
"LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost)
|
||||
|
|
40
lib/tls/mbedtls/tls.c
Normal file
40
lib/tls/mbedtls/tls.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* libwebsockets - mbedTLS-specific lws apis
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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"
|
||||
#include "tls/mbedtls/private.h"
|
||||
|
||||
void
|
||||
lws_tls_err_describe(void)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
lws_context_init_ssl_library(const struct lws_context_creation_info *info)
|
||||
{
|
||||
lwsl_info(" Compiled with MbedTLS support\n");
|
||||
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT))
|
||||
lwsl_info(" SSL disabled: no "
|
||||
"LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -160,6 +160,7 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
int
|
||||
lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len)
|
||||
|
@ -194,6 +195,7 @@ lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
|
|||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type,
|
||||
|
|
|
@ -60,60 +60,6 @@ int lws_ssl_get_error(struct lws *wsi, int n)
|
|||
return m;
|
||||
}
|
||||
|
||||
char* lws_ssl_get_error_string(int status, int ret, char *buf, size_t len) {
|
||||
switch (status) {
|
||||
case SSL_ERROR_NONE:
|
||||
return lws_strncpy(buf, "SSL_ERROR_NONE", len);
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return lws_strncpy(buf, "SSL_ERROR_ZERO_RETURN", len);
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_READ", len);
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_WRITE", len);
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_CONNECT", len);
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_ACCEPT", len);
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_X509_LOOKUP", len);
|
||||
case SSL_ERROR_SYSCALL:
|
||||
switch (ret) {
|
||||
case 0:
|
||||
lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: EOF");
|
||||
return buf;
|
||||
case -1:
|
||||
#ifndef LWS_PLAT_OPTEE
|
||||
lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %s",
|
||||
strerror(errno));
|
||||
#else
|
||||
lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %d", errno);
|
||||
#endif
|
||||
return buf;
|
||||
default:
|
||||
return strncpy(buf, "SSL_ERROR_SYSCALL", len);
|
||||
}
|
||||
case SSL_ERROR_SSL:
|
||||
return "SSL_ERROR_SSL";
|
||||
default:
|
||||
return "SSL_ERROR_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lws_tls_err_describe(void)
|
||||
{
|
||||
char buf[128];
|
||||
unsigned long l;
|
||||
|
||||
do {
|
||||
l = ERR_get_error();
|
||||
if (!l)
|
||||
break;
|
||||
ERR_error_string_n(l, buf, sizeof(buf));
|
||||
lwsl_info(" openssl error: %s\n", buf);
|
||||
} while (l);
|
||||
lwsl_info("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
lws_context_init_ssl_pem_passwd_cb(char * buf, int size, int rwflag,
|
||||
|
@ -144,49 +90,6 @@ lws_ssl_bind_passphrase(SSL_CTX *ssl_ctx,
|
|||
lws_context_init_ssl_pem_passwd_cb);
|
||||
}
|
||||
|
||||
int
|
||||
lws_context_init_ssl_library(const struct lws_context_creation_info *info)
|
||||
{
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
lwsl_info(" Compiled with CyaSSL support\n");
|
||||
#else
|
||||
lwsl_info(" Compiled with wolfSSL support\n");
|
||||
#endif
|
||||
#else
|
||||
#if defined(LWS_WITH_BORINGSSL)
|
||||
lwsl_info(" Compiled with BoringSSL support\n");
|
||||
#else
|
||||
lwsl_info(" Compiled with OpenSSL support\n");
|
||||
#endif
|
||||
#endif
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
|
||||
lwsl_info(" SSL disabled: no "
|
||||
"LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* basic openssl init */
|
||||
|
||||
lwsl_info("Doing SSL library init\n");
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
#else
|
||||
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
#endif
|
||||
|
||||
openssl_websocket_private_data_index =
|
||||
SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL);
|
||||
|
||||
openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0,
|
||||
NULL, NULL, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost)
|
||||
{
|
||||
|
|
126
lib/tls/openssl/tls.c
Normal file
126
lib/tls/openssl/tls.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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"
|
||||
#include "tls/openssl/private.h"
|
||||
|
||||
extern int openssl_websocket_private_data_index,
|
||||
openssl_SSL_CTX_private_data_index;
|
||||
|
||||
char* lws_ssl_get_error_string(int status, int ret, char *buf, size_t len) {
|
||||
switch (status) {
|
||||
case SSL_ERROR_NONE:
|
||||
return lws_strncpy(buf, "SSL_ERROR_NONE", len);
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return lws_strncpy(buf, "SSL_ERROR_ZERO_RETURN", len);
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_READ", len);
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_WRITE", len);
|
||||
case SSL_ERROR_WANT_CONNECT:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_CONNECT", len);
|
||||
case SSL_ERROR_WANT_ACCEPT:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_ACCEPT", len);
|
||||
case SSL_ERROR_WANT_X509_LOOKUP:
|
||||
return lws_strncpy(buf, "SSL_ERROR_WANT_X509_LOOKUP", len);
|
||||
case SSL_ERROR_SYSCALL:
|
||||
switch (ret) {
|
||||
case 0:
|
||||
lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: EOF");
|
||||
return buf;
|
||||
case -1:
|
||||
#ifndef LWS_PLAT_OPTEE
|
||||
lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %s",
|
||||
strerror(errno));
|
||||
#else
|
||||
lws_snprintf(buf, len, "SSL_ERROR_SYSCALL: %d", errno);
|
||||
#endif
|
||||
return buf;
|
||||
default:
|
||||
return strncpy(buf, "SSL_ERROR_SYSCALL", len);
|
||||
}
|
||||
case SSL_ERROR_SSL:
|
||||
return "SSL_ERROR_SSL";
|
||||
default:
|
||||
return "SSL_ERROR_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lws_tls_err_describe(void)
|
||||
{
|
||||
char buf[128];
|
||||
unsigned long l;
|
||||
|
||||
do {
|
||||
l = ERR_get_error();
|
||||
if (!l)
|
||||
break;
|
||||
ERR_error_string_n(l, buf, sizeof(buf));
|
||||
lwsl_info(" openssl error: %s\n", buf);
|
||||
} while (l);
|
||||
lwsl_info("\n");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_context_init_ssl_library(const struct lws_context_creation_info *info)
|
||||
{
|
||||
#ifdef USE_WOLFSSL
|
||||
#ifdef USE_OLD_CYASSL
|
||||
lwsl_info(" Compiled with CyaSSL support\n");
|
||||
#else
|
||||
lwsl_info(" Compiled with wolfSSL support\n");
|
||||
#endif
|
||||
#else
|
||||
#if defined(LWS_WITH_BORINGSSL)
|
||||
lwsl_info(" Compiled with BoringSSL support\n");
|
||||
#else
|
||||
lwsl_info(" Compiled with OpenSSL support\n");
|
||||
#endif
|
||||
#endif
|
||||
if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT)) {
|
||||
lwsl_info(" SSL disabled: no "
|
||||
"LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* basic openssl init */
|
||||
|
||||
lwsl_info("Doing SSL library init\n");
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
#else
|
||||
OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
#endif
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
openssl_websocket_private_data_index =
|
||||
SSL_get_ex_new_index(0, "lws", NULL, NULL, NULL);
|
||||
|
||||
openssl_SSL_CTX_private_data_index = SSL_CTX_get_ex_new_index(0,
|
||||
NULL, NULL, NULL, NULL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* libwebsockets - mbedTLS-specific lws apis
|
||||
* libwebsockets - OpenSSL-specific lws apis
|
||||
*
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2010 - 2019 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
|
||||
|
@ -167,6 +167,14 @@ lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len)
|
||||
{
|
||||
return lws_tls_openssl_cert_info(x509->cert, type, buf, len);
|
||||
}
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
int
|
||||
lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len)
|
||||
|
@ -182,12 +190,7 @@ lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
|
|||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
lws_x509_info(struct lws_x509_cert *x509, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len)
|
||||
{
|
||||
return lws_tls_openssl_cert_info(x509->cert, type, buf, len);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
|
||||
|
@ -219,6 +222,7 @@ lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
|
|||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_x509_create(struct lws_x509_cert **x509)
|
||||
|
|
189
lib/tls/private-network.h
Normal file
189
lib/tls/private-network.h
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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
|
||||
*
|
||||
* This is included from core/private.h if LWS_WITH_TLS
|
||||
*/
|
||||
|
||||
struct lws_context_per_thread;
|
||||
struct lws_tls_ops {
|
||||
int (*fake_POLLIN_for_buffered)(struct lws_context_per_thread *pt);
|
||||
int (*periodic_housekeeping)(struct lws_context *context, time_t now);
|
||||
};
|
||||
|
||||
struct lws_context_tls {
|
||||
char alpn_discovered[32];
|
||||
const char *alpn_default;
|
||||
time_t last_cert_check_s;
|
||||
};
|
||||
|
||||
struct lws_pt_tls {
|
||||
struct lws_dll_lws pending_tls_head;
|
||||
};
|
||||
|
||||
struct lws_tls_ss_pieces;
|
||||
|
||||
struct alpn_ctx {
|
||||
uint8_t data[23];
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
struct lws_vhost_tls {
|
||||
lws_tls_ctx *ssl_ctx;
|
||||
lws_tls_ctx *ssl_client_ctx;
|
||||
const char *alpn;
|
||||
struct lws_tls_ss_pieces *ss; /* for acme tls certs */
|
||||
char *alloc_cert_path;
|
||||
char *key_path;
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
lws_tls_x509 *x509_client_CA;
|
||||
#endif
|
||||
char ecdh_curve[16];
|
||||
struct alpn_ctx alpn_ctx;
|
||||
|
||||
int use_ssl;
|
||||
int allow_non_ssl_on_ssl_port;
|
||||
int ssl_info_event_mask;
|
||||
|
||||
unsigned int user_supplied_ssl_ctx:1;
|
||||
unsigned int skipped_certs:1;
|
||||
};
|
||||
|
||||
struct lws_lws_tls {
|
||||
lws_tls_conn *ssl;
|
||||
lws_tls_bio *client_bio;
|
||||
struct lws_dll_lws pending_tls_list;
|
||||
unsigned int use_ssl;
|
||||
unsigned int redirect_to_https:1;
|
||||
};
|
||||
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_context_init_alpn(struct lws_vhost *vhost);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_pending(struct lws *wsi);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_server_socket_service_ssl(struct lws *new_wsi, lws_sockfd_type accept_fd);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_close(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_context_destroy(struct lws_context *context);
|
||||
void
|
||||
__lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi);
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_bio_create(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_connect1(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_connect2(struct lws *wsi, char *errbuf, int len);
|
||||
LWS_EXTERN int
|
||||
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt);
|
||||
LWS_EXTERN int
|
||||
lws_gate_accepts(struct lws_context *context, int on);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_bind_passphrase(lws_tls_ctx *ssl_ctx,
|
||||
const struct lws_context_creation_info *info);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
|
||||
const char *cert, const char *private_key,
|
||||
const char *mem_cert, size_t len_mem_cert,
|
||||
const char *mem_privkey, size_t mem_privkey_len);
|
||||
LWS_EXTERN enum lws_tls_extant
|
||||
lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
|
||||
const char *private_key);
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
LWS_EXTERN int
|
||||
lws_context_init_server_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
void
|
||||
lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost);
|
||||
#else
|
||||
#define lws_context_init_server_ssl(_a, _b) (0)
|
||||
#define lws_tls_acme_sni_cert_destroy(_a)
|
||||
#endif
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost);
|
||||
|
||||
/*
|
||||
* lws_tls_ abstract backend implementations
|
||||
*/
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_client_cert_verify_config(struct lws_vhost *vh);
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost, struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_server_accept(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_server_abort_connection(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
__lws_tls_shutdown(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_client_connect(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len);
|
||||
LWS_EXTERN int
|
||||
lws_tls_client_create_vhost_context(struct lws_vhost *vh,
|
||||
const struct lws_context_creation_info *info,
|
||||
const char *cipher_list,
|
||||
const char *ca_filepath,
|
||||
const void *ca_mem,
|
||||
unsigned int ca_mem_len,
|
||||
const char *cert_filepath,
|
||||
const void *cert_mem,
|
||||
unsigned int cert_mem_len,
|
||||
const char *private_key_filepath);
|
||||
|
||||
LWS_EXTERN lws_tls_ctx *
|
||||
lws_tls_ctx_from_wsi(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_get_error(struct lws *wsi, int n);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_context_init_client_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
|
||||
|
||||
int
|
||||
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -21,6 +21,10 @@
|
|||
* This is included from core/private.h if LWS_WITH_TLS
|
||||
*/
|
||||
|
||||
#if !defined(__LWS_TLS_PRIVATE_H__)
|
||||
#define __LWS_TLS_PRIVATE_H__
|
||||
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
|
||||
#if defined(USE_WOLFSSL)
|
||||
|
@ -102,12 +106,6 @@ enum lws_tls_extant {
|
|||
LWS_TLS_EXTANT_ALTERNATIVE
|
||||
};
|
||||
|
||||
struct lws_context_per_thread;
|
||||
|
||||
struct lws_tls_ops {
|
||||
int (*fake_POLLIN_for_buffered)(struct lws_context_per_thread *pt);
|
||||
int (*periodic_housekeeping)(struct lws_context *context, time_t now);
|
||||
};
|
||||
|
||||
#if defined(LWS_WITH_TLS)
|
||||
|
||||
|
@ -116,190 +114,42 @@ typedef SSL_CTX lws_tls_ctx;
|
|||
typedef BIO lws_tls_bio;
|
||||
typedef X509 lws_tls_x509;
|
||||
|
||||
#if defined(LWS_WITH_NETWORK)
|
||||
#include "tls/private-network.h"
|
||||
#endif
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_context_init_ssl_library(const struct lws_context_creation_info *info);
|
||||
#define LWS_SSL_ENABLED(context) (context->tls.use_ssl)
|
||||
|
||||
extern const struct lws_tls_ops tls_ops_openssl, tls_ops_mbedtls;
|
||||
|
||||
struct lws_context_tls {
|
||||
char alpn_discovered[32];
|
||||
const char *alpn_default;
|
||||
time_t last_cert_check_s;
|
||||
};
|
||||
|
||||
struct lws_pt_tls {
|
||||
struct lws_dll_lws pending_tls_head;
|
||||
};
|
||||
|
||||
struct lws_tls_ss_pieces;
|
||||
|
||||
struct alpn_ctx {
|
||||
uint8_t data[23];
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
struct lws_vhost_tls {
|
||||
lws_tls_ctx *ssl_ctx;
|
||||
lws_tls_ctx *ssl_client_ctx;
|
||||
const char *alpn;
|
||||
struct lws_tls_ss_pieces *ss; /* for acme tls certs */
|
||||
char *alloc_cert_path;
|
||||
char *key_path;
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
lws_tls_x509 *x509_client_CA;
|
||||
#endif
|
||||
char ecdh_curve[16];
|
||||
struct alpn_ctx alpn_ctx;
|
||||
|
||||
int use_ssl;
|
||||
int allow_non_ssl_on_ssl_port;
|
||||
int ssl_info_event_mask;
|
||||
|
||||
unsigned int user_supplied_ssl_ctx:1;
|
||||
unsigned int skipped_certs:1;
|
||||
};
|
||||
|
||||
struct lws_lws_tls {
|
||||
lws_tls_conn *ssl;
|
||||
lws_tls_bio *client_bio;
|
||||
struct lws_dll_lws pending_tls_list;
|
||||
unsigned int use_ssl;
|
||||
unsigned int redirect_to_https:1;
|
||||
};
|
||||
|
||||
struct lws_ec_valid_curves {
|
||||
int id;
|
||||
const char *jwa_name; /* list terminates with NULL jwa_name */
|
||||
};
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_context_init_alpn(struct lws_vhost *vhost);
|
||||
LWS_EXTERN enum lws_tls_extant
|
||||
lws_tls_use_any_upgrade_check_extant(const char *name);
|
||||
LWS_EXTERN int openssl_websocket_private_data_index;
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_capable_read(struct lws *wsi, unsigned char *buf, int len);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_capable_write(struct lws *wsi, unsigned char *buf, int len);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_ssl_pending(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_context_init_ssl_library(const struct lws_context_creation_info *info);
|
||||
LWS_EXTERN int LWS_WARN_UNUSED_RESULT
|
||||
lws_server_socket_service_ssl(struct lws *new_wsi, lws_sockfd_type accept_fd);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_close(struct lws *wsi);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_context_destroy(struct lws_context *context);
|
||||
void
|
||||
__lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi);
|
||||
LWS_VISIBLE void
|
||||
lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_bio_create(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_connect1(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_client_connect2(struct lws *wsi, char *errbuf, int len);
|
||||
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_tls_err_describe(void);
|
||||
LWS_EXTERN int
|
||||
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt);
|
||||
LWS_EXTERN int
|
||||
lws_gate_accepts(struct lws_context *context, int on);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_bind_passphrase(lws_tls_ctx *ssl_ctx,
|
||||
const struct lws_context_creation_info *info);
|
||||
LWS_EXTERN void
|
||||
lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_tls_openssl_cert_info(X509 *x509, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len);
|
||||
LWS_EXTERN int
|
||||
lws_tls_check_all_cert_lifetimes(struct lws_context *context);
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi,
|
||||
const char *cert, const char *private_key,
|
||||
const char *mem_cert, size_t len_mem_cert,
|
||||
const char *mem_privkey, size_t mem_privkey_len);
|
||||
LWS_EXTERN enum lws_tls_extant
|
||||
lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
|
||||
const char *private_key);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_tls_alloc_pem_to_der_file(struct lws_context *context, const char *filename,
|
||||
const char *inbuf, lws_filepos_t inlen,
|
||||
uint8_t **buf, lws_filepos_t *amount);
|
||||
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
LWS_EXTERN int
|
||||
lws_context_init_server_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
void
|
||||
lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost);
|
||||
#else
|
||||
#define lws_context_init_server_ssl(_a, _b) (0)
|
||||
#define lws_tls_acme_sni_cert_destroy(_a)
|
||||
#endif
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost);
|
||||
LWS_EXTERN char *
|
||||
lws_ssl_get_error_string(int status, int ret, char *buf, size_t len);
|
||||
|
||||
/*
|
||||
* lws_tls_ abstract backend implementations
|
||||
*/
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_client_cert_verify_config(struct lws_vhost *vh);
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost, struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_server_accept(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_server_abort_connection(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
__lws_tls_shutdown(struct lws *wsi);
|
||||
|
||||
LWS_EXTERN enum lws_ssl_capable_status
|
||||
lws_tls_client_connect(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len);
|
||||
LWS_EXTERN int
|
||||
lws_tls_client_create_vhost_context(struct lws_vhost *vh,
|
||||
const struct lws_context_creation_info *info,
|
||||
const char *cipher_list,
|
||||
const char *ca_filepath,
|
||||
const void *ca_mem,
|
||||
unsigned int ca_mem_len,
|
||||
const char *cert_filepath,
|
||||
const void *cert_mem,
|
||||
unsigned int cert_mem_len,
|
||||
const char *private_key_filepath);
|
||||
|
||||
LWS_EXTERN lws_tls_ctx *
|
||||
lws_tls_ctx_from_wsi(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
lws_ssl_get_error(struct lws *wsi, int n);
|
||||
|
||||
LWS_EXTERN int
|
||||
lws_context_init_client_ssl(const struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
|
||||
LWS_EXTERN void
|
||||
lws_ssl_info_callback(const lws_tls_conn *ssl, int where, int ret);
|
||||
|
||||
int
|
||||
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt);
|
||||
|
||||
int
|
||||
lws_gencrypto_bits_to_bytes(int bits);
|
||||
|
||||
|
@ -324,3 +174,4 @@ lws_genec_confirm_curve_allowed_by_tls_id(const char *allowed, int id,
|
|||
struct lws_jwk *jwk);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
255
lib/tls/tls-network.c
Normal file
255
lib/tls/tls-network.c
Normal file
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 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"
|
||||
|
||||
/*
|
||||
* fakes POLLIN on all tls guys with buffered rx
|
||||
*
|
||||
* returns nonzero if any tls guys had POLLIN faked
|
||||
*/
|
||||
|
||||
int
|
||||
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
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;
|
||||
ret |= pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN;
|
||||
|
||||
} lws_end_foreach_dll_safe(p, p1);
|
||||
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
void
|
||||
__lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
|
||||
{
|
||||
if (lws_dll_is_null(&wsi->tls.pending_tls_list))
|
||||
return;
|
||||
|
||||
lws_dll_lws_remove(&wsi->tls.pending_tls_list);
|
||||
}
|
||||
|
||||
void
|
||||
lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
__lws_ssl_remove_wsi_from_buffered_list(wsi);
|
||||
lws_pt_unlock(pt);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_tls_check_cert_lifetime(struct lws_vhost *v)
|
||||
{
|
||||
time_t now = (time_t)lws_now_secs(), life = 0;
|
||||
struct lws_acme_cert_aging_args caa;
|
||||
union lws_tls_cert_info_results ir;
|
||||
int n;
|
||||
|
||||
if (v->tls.ssl_ctx && !v->tls.skipped_certs) {
|
||||
|
||||
if (now < 1542933698) /* Nov 23 2018 00:42 UTC */
|
||||
/* our clock is wrong and we can't judge the certs */
|
||||
return -1;
|
||||
|
||||
n = lws_tls_vhost_cert_info(v, LWS_TLS_CERT_INFO_VALIDITY_TO,
|
||||
&ir, 0);
|
||||
if (n)
|
||||
return 1;
|
||||
|
||||
life = (ir.time - now) / (24 * 3600);
|
||||
lwsl_notice(" vhost %s: cert expiry: %dd\n", v->name,
|
||||
(int)life);
|
||||
} else
|
||||
lwsl_notice(" vhost %s: no cert\n", v->name);
|
||||
|
||||
memset(&caa, 0, sizeof(caa));
|
||||
caa.vh = v;
|
||||
lws_broadcast(v->context, LWS_CALLBACK_VHOST_CERT_AGING, (void *)&caa,
|
||||
(size_t)(ssize_t)life);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_check_all_cert_lifetimes(struct lws_context *context)
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
|
||||
while (v) {
|
||||
if (lws_tls_check_cert_lifetime(v) < 0)
|
||||
return -1;
|
||||
v = v->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* LWS_TLS_EXTANT_NO : skip adding the cert
|
||||
* LWS_TLS_EXTANT_YES : use the cert and private key paths normally
|
||||
* LWS_TLS_EXTANT_ALTERNATIVE: normal paths not usable, try alternate if poss
|
||||
*/
|
||||
enum lws_tls_extant
|
||||
lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
|
||||
const char *private_key)
|
||||
{
|
||||
int n, m;
|
||||
|
||||
/*
|
||||
* The user code can choose to either pass the cert and
|
||||
* key filepaths using the info members like this, or it can
|
||||
* leave them NULL; force the vhost SSL_CTX init using the info
|
||||
* options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and
|
||||
* set up the cert himself using the user callback
|
||||
* LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which
|
||||
* happened just above and has the vhost SSL_CTX * in the user
|
||||
* parameter.
|
||||
*/
|
||||
|
||||
if (!cert || !private_key)
|
||||
return LWS_TLS_EXTANT_NO;
|
||||
|
||||
n = lws_tls_use_any_upgrade_check_extant(cert);
|
||||
if (n == LWS_TLS_EXTANT_ALTERNATIVE)
|
||||
return LWS_TLS_EXTANT_ALTERNATIVE;
|
||||
m = lws_tls_use_any_upgrade_check_extant(private_key);
|
||||
if (m == LWS_TLS_EXTANT_ALTERNATIVE)
|
||||
return LWS_TLS_EXTANT_ALTERNATIVE;
|
||||
|
||||
if ((n == LWS_TLS_EXTANT_NO || m == LWS_TLS_EXTANT_NO) &&
|
||||
(vhost->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) {
|
||||
lwsl_notice("Ignoring missing %s or %s\n", cert, private_key);
|
||||
vhost->tls.skipped_certs = 1;
|
||||
|
||||
return LWS_TLS_EXTANT_NO;
|
||||
}
|
||||
|
||||
/*
|
||||
* the cert + key exist
|
||||
*/
|
||||
|
||||
return LWS_TLS_EXTANT_YES;
|
||||
}
|
||||
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
/*
|
||||
* update the cert for every vhost using the given path
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_tls_cert_updated(struct lws_context *context, const char *certpath,
|
||||
const char *keypath,
|
||||
const char *mem_cert, size_t len_mem_cert,
|
||||
const char *mem_privkey, size_t len_mem_privkey)
|
||||
{
|
||||
struct lws wsi;
|
||||
|
||||
wsi.context = context;
|
||||
|
||||
lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) {
|
||||
wsi.vhost = v; /* not a real bound wsi */
|
||||
if (v->tls.alloc_cert_path && v->tls.key_path &&
|
||||
!strcmp(v->tls.alloc_cert_path, certpath) &&
|
||||
!strcmp(v->tls.key_path, keypath)) {
|
||||
lws_tls_server_certs_load(v, &wsi, certpath, keypath,
|
||||
mem_cert, len_mem_cert,
|
||||
mem_privkey, len_mem_privkey);
|
||||
|
||||
if (v->tls.skipped_certs)
|
||||
lwsl_notice("%s: vhost %s: cert unset\n",
|
||||
__func__, v->name);
|
||||
}
|
||||
} lws_end_foreach_ll(v, vhost_next);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_gate_accepts(struct lws_context *context, int on)
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
|
||||
lwsl_notice("%s: on = %d\n", __func__, on);
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
context->updated = 1;
|
||||
#endif
|
||||
|
||||
while (v) {
|
||||
if (v->tls.use_ssl && v->lserv_wsi &&
|
||||
lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
|
||||
(LWS_POLLIN) * on))
|
||||
lwsl_notice("Unable to set accept POLLIN %d\n", on);
|
||||
|
||||
v = v->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */
|
||||
|
||||
int
|
||||
lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len)
|
||||
{
|
||||
uint8_t *oos = os, *plen = NULL;
|
||||
|
||||
while (*comma && len > 1) {
|
||||
if (!plen && *comma == ' ') {
|
||||
comma++;
|
||||
continue;
|
||||
}
|
||||
if (!plen) {
|
||||
plen = os++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (*comma == ',') {
|
||||
*plen = lws_ptr_diff(os, plen + 1);
|
||||
plen = NULL;
|
||||
comma++;
|
||||
} else {
|
||||
*os++ = *comma++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (plen)
|
||||
*plen = lws_ptr_diff(os, plen + 1);
|
||||
|
||||
return lws_ptr_diff(os, oos);
|
||||
}
|
||||
|
||||
|
||||
|
231
lib/tls/tls.c
231
lib/tls/tls.c
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
|
||||
* Copyright (C) 2010 - 2019 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
|
||||
|
@ -20,50 +20,7 @@
|
|||
*/
|
||||
|
||||
#include "core/private.h"
|
||||
|
||||
/*
|
||||
* fakes POLLIN on all tls guys with buffered rx
|
||||
*
|
||||
* returns nonzero if any tls guys had POLLIN faked
|
||||
*/
|
||||
|
||||
int
|
||||
lws_tls_fake_POLLIN_for_buffered(struct lws_context_per_thread *pt)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
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;
|
||||
ret |= pt->fds[wsi->position_in_fds_table].revents & LWS_POLLIN;
|
||||
|
||||
} lws_end_foreach_dll_safe(p, p1);
|
||||
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
void
|
||||
__lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
|
||||
{
|
||||
if (lws_dll_is_null(&wsi->tls.pending_tls_list))
|
||||
return;
|
||||
|
||||
lws_dll_lws_remove(&wsi->tls.pending_tls_list);
|
||||
}
|
||||
|
||||
void
|
||||
lws_ssl_remove_wsi_from_buffered_list(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
__lws_ssl_remove_wsi_from_buffered_list(wsi);
|
||||
lws_pt_unlock(pt);
|
||||
}
|
||||
#include "tls/private.h"
|
||||
|
||||
#if defined(LWS_WITH_ESP32)
|
||||
int alloc_file(struct lws_context *context, const char *filename, uint8_t **buf,
|
||||
|
@ -216,52 +173,6 @@ bail:
|
|||
return 4;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_check_cert_lifetime(struct lws_vhost *v)
|
||||
{
|
||||
time_t now = (time_t)lws_now_secs(), life = 0;
|
||||
struct lws_acme_cert_aging_args caa;
|
||||
union lws_tls_cert_info_results ir;
|
||||
int n;
|
||||
|
||||
if (v->tls.ssl_ctx && !v->tls.skipped_certs) {
|
||||
|
||||
if (now < 1542933698) /* Nov 23 2018 00:42 UTC */
|
||||
/* our clock is wrong and we can't judge the certs */
|
||||
return -1;
|
||||
|
||||
n = lws_tls_vhost_cert_info(v, LWS_TLS_CERT_INFO_VALIDITY_TO,
|
||||
&ir, 0);
|
||||
if (n)
|
||||
return 1;
|
||||
|
||||
life = (ir.time - now) / (24 * 3600);
|
||||
lwsl_notice(" vhost %s: cert expiry: %dd\n", v->name,
|
||||
(int)life);
|
||||
} else
|
||||
lwsl_notice(" vhost %s: no cert\n", v->name);
|
||||
|
||||
memset(&caa, 0, sizeof(caa));
|
||||
caa.vh = v;
|
||||
lws_broadcast(v->context, LWS_CALLBACK_VHOST_CERT_AGING, (void *)&caa,
|
||||
(size_t)(ssize_t)life);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_tls_check_all_cert_lifetimes(struct lws_context *context)
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
|
||||
while (v) {
|
||||
if (lws_tls_check_cert_lifetime(v) < 0)
|
||||
return -1;
|
||||
v = v->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE)
|
||||
static int
|
||||
lws_tls_extant(const char *name)
|
||||
|
@ -365,141 +276,3 @@ lws_tls_use_any_upgrade_check_extant(const char *name)
|
|||
#endif
|
||||
return LWS_TLS_EXTANT_YES;
|
||||
}
|
||||
|
||||
/*
|
||||
* LWS_TLS_EXTANT_NO : skip adding the cert
|
||||
* LWS_TLS_EXTANT_YES : use the cert and private key paths normally
|
||||
* LWS_TLS_EXTANT_ALTERNATIVE: normal paths not usable, try alternate if poss
|
||||
*/
|
||||
enum lws_tls_extant
|
||||
lws_tls_generic_cert_checks(struct lws_vhost *vhost, const char *cert,
|
||||
const char *private_key)
|
||||
{
|
||||
int n, m;
|
||||
|
||||
/*
|
||||
* The user code can choose to either pass the cert and
|
||||
* key filepaths using the info members like this, or it can
|
||||
* leave them NULL; force the vhost SSL_CTX init using the info
|
||||
* options flag LWS_SERVER_OPTION_CREATE_VHOST_SSL_CTX; and
|
||||
* set up the cert himself using the user callback
|
||||
* LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, which
|
||||
* happened just above and has the vhost SSL_CTX * in the user
|
||||
* parameter.
|
||||
*/
|
||||
|
||||
if (!cert || !private_key)
|
||||
return LWS_TLS_EXTANT_NO;
|
||||
|
||||
n = lws_tls_use_any_upgrade_check_extant(cert);
|
||||
if (n == LWS_TLS_EXTANT_ALTERNATIVE)
|
||||
return LWS_TLS_EXTANT_ALTERNATIVE;
|
||||
m = lws_tls_use_any_upgrade_check_extant(private_key);
|
||||
if (m == LWS_TLS_EXTANT_ALTERNATIVE)
|
||||
return LWS_TLS_EXTANT_ALTERNATIVE;
|
||||
|
||||
if ((n == LWS_TLS_EXTANT_NO || m == LWS_TLS_EXTANT_NO) &&
|
||||
(vhost->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) {
|
||||
lwsl_notice("Ignoring missing %s or %s\n", cert, private_key);
|
||||
vhost->tls.skipped_certs = 1;
|
||||
|
||||
return LWS_TLS_EXTANT_NO;
|
||||
}
|
||||
|
||||
/*
|
||||
* the cert + key exist
|
||||
*/
|
||||
|
||||
return LWS_TLS_EXTANT_YES;
|
||||
}
|
||||
|
||||
#if !defined(LWS_NO_SERVER)
|
||||
/*
|
||||
* update the cert for every vhost using the given path
|
||||
*/
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_tls_cert_updated(struct lws_context *context, const char *certpath,
|
||||
const char *keypath,
|
||||
const char *mem_cert, size_t len_mem_cert,
|
||||
const char *mem_privkey, size_t len_mem_privkey)
|
||||
{
|
||||
struct lws wsi;
|
||||
|
||||
wsi.context = context;
|
||||
|
||||
lws_start_foreach_ll(struct lws_vhost *, v, context->vhost_list) {
|
||||
wsi.vhost = v; /* not a real bound wsi */
|
||||
if (v->tls.alloc_cert_path && v->tls.key_path &&
|
||||
!strcmp(v->tls.alloc_cert_path, certpath) &&
|
||||
!strcmp(v->tls.key_path, keypath)) {
|
||||
lws_tls_server_certs_load(v, &wsi, certpath, keypath,
|
||||
mem_cert, len_mem_cert,
|
||||
mem_privkey, len_mem_privkey);
|
||||
|
||||
if (v->tls.skipped_certs)
|
||||
lwsl_notice("%s: vhost %s: cert unset\n",
|
||||
__func__, v->name);
|
||||
}
|
||||
} lws_end_foreach_ll(v, vhost_next);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_gate_accepts(struct lws_context *context, int on)
|
||||
{
|
||||
struct lws_vhost *v = context->vhost_list;
|
||||
|
||||
lwsl_notice("%s: on = %d\n", __func__, on);
|
||||
|
||||
#if defined(LWS_WITH_STATS)
|
||||
context->updated = 1;
|
||||
#endif
|
||||
|
||||
while (v) {
|
||||
if (v->tls.use_ssl && v->lserv_wsi &&
|
||||
lws_change_pollfd(v->lserv_wsi, (LWS_POLLIN) * !on,
|
||||
(LWS_POLLIN) * on))
|
||||
lwsl_notice("Unable to set accept POLLIN %d\n", on);
|
||||
|
||||
v = v->vhost_next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* comma-separated alpn list, like "h2,http/1.1" to openssl alpn format */
|
||||
|
||||
int
|
||||
lws_alpn_comma_to_openssl(const char *comma, uint8_t *os, int len)
|
||||
{
|
||||
uint8_t *oos = os, *plen = NULL;
|
||||
|
||||
while (*comma && len > 1) {
|
||||
if (!plen && *comma == ' ') {
|
||||
comma++;
|
||||
continue;
|
||||
}
|
||||
if (!plen) {
|
||||
plen = os++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (*comma == ',') {
|
||||
*plen = lws_ptr_diff(os, plen + 1);
|
||||
plen = NULL;
|
||||
comma++;
|
||||
} else {
|
||||
*os++ = *comma++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
if (plen)
|
||||
*plen = lws_ptr_diff(os, plen + 1);
|
||||
|
||||
return lws_ptr_diff(os, oos);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue