From 43031c8c350eb4f0a830f6f11cb61d3cf0a2609e Mon Sep 17 00:00:00 2001 From: cheoleun moon Date: Mon, 27 Feb 2023 12:18:20 +0900 Subject: [PATCH] Imported Upstream version 4.3.2 Change-Id: I2116066af6e0d095bb4d5f7be34d86b13c137ad2 --- .sai.json | 4 +- CMakeLists.txt | 15 +- cmake/FindOpenSSLbins.cmake | 2 +- cmake/libwebsockets-config.cmake.in | 1 - include/libwebsockets.h | 7 + include/libwebsockets/lws-callbacks.h | 5 + include/libwebsockets/lws-http.h | 2 - include/libwebsockets/lws-logs.h | 8 + include/libwebsockets/lws-map.h | 16 +- include/libwebsockets/lws-mqtt.h | 24 + include/libwebsockets/lws-network-helper.h | 3 +- .../libwebsockets/lws-secure-streams-policy.h | 1 + lib/CMakeLists.txt | 10 +- lib/core-net/adopt.c | 4 + lib/core-net/client/connect3.c | 26 +- lib/core-net/close.c | 2 +- lib/core-net/dummy-callback.c | 26 +- lib/core-net/private-lib-core-net.h | 4 +- lib/core-net/route.c | 17 +- lib/core-net/sorted-usec-list.c | 6 + lib/core-net/wsi-timeout.c | 7 +- lib/core/context.c | 21 +- lib/core/logs.c | 29 + lib/core/private-lib-core.h | 2 +- lib/cose/cose_sign.c | 19 +- lib/misc/lejp.c | 2 +- lib/plat/freertos/esp32/esp_attr.h | 58 -- lib/plat/freertos/private-lib-plat-freertos.h | 4 + lib/plat/unix/unix-sockets.c | 8 +- lib/plat/windows/windows-plugins.c | 6 +- lib/plat/windows/windows-sockets.c | 4 +- lib/roles/cgi/cgi-server.c | 11 +- lib/roles/h1/ops-h1.c | 4 +- lib/roles/h2/http2.c | 6 + lib/roles/h2/ops-h2.c | 11 +- lib/roles/http/compression/stream.c | 2 +- lib/roles/http/cookie.c | 20 +- lib/roles/http/header.c | 9 +- lib/roles/http/server/lejp-conf.c | 16 +- lib/roles/http/server/server.c | 19 +- lib/roles/mqtt/mqtt.c | 244 ++++---- lib/roles/mqtt/private-lib-roles-mqtt.h | 10 +- lib/roles/netlink/ops-netlink.c | 21 +- lib/roles/pipe/ops-pipe.c | 2 +- lib/roles/raw-skt/ops-raw-skt.c | 74 ++- lib/secure-streams/README.md | 4 + lib/secure-streams/policy-common.c | 2 +- lib/secure-streams/policy-json.c | 7 + .../private-lib-secure-streams.h | 5 + lib/secure-streams/protocols/ss-h1.c | 25 +- lib/secure-streams/protocols/ss-h2.c | 4 +- lib/secure-streams/protocols/ss-mqtt.c | 525 ++++++++++++++++-- lib/secure-streams/secure-streams-client.c | 8 +- lib/secure-streams/secure-streams-process.c | 1 + lib/secure-streams/secure-streams.c | 23 +- lib/system/metrics/metrics.c | 4 +- lib/tls/CMakeLists.txt | 48 +- lib/tls/lws-genec-common.c | 2 +- lib/tls/mbedtls/mbedtls-client.c | 9 +- lib/tls/mbedtls/mbedtls-extensions.c | 82 +-- lib/tls/mbedtls/mbedtls-x509.c | 88 +-- lib/tls/mbedtls/wrapper/platform/ssl_pm.c | 14 +- lib/tls/openssl/openssl-client.c | 52 +- lib/tls/openssl/openssl-server.c | 54 +- lib/tls/openssl/openssl-session.c | 13 +- lib/tls/tls-client.c | 6 + lib/tls/tls-server.c | 4 +- .../raw/minimal-raw-client/CMakeLists.txt | 23 + .../raw/minimal-raw-client/main.c | 214 +++++++ .../api-tests/api-test-lws_map/main.c | 2 + .../esp32/esp-heltec-wb32/main/devices.c | 5 +- .../minimal-http-client-multi.c | 2 +- .../minimal-http-client-post.c | 2 +- .../minimal-http-server-custom-headers.c | 2 +- .../minimal-http-server-dynamic.c | 2 +- .../minimal-http-server.c | 2 +- .../minimal-secure-streams.c | 32 +- .../acme-client/protocol_lws_acme_client.c | 240 ++++---- plugins/deaddrop/protocol_lws_deaddrop.c | 2 +- plugins/protocol_fulltext_demo.c | 2 +- plugins/protocol_lws_openmetrics_export.c | 2 +- plugins/ssh-base/sshd.c | 2 +- test-apps/test-client.c | 2 +- 83 files changed, 1675 insertions(+), 633 deletions(-) delete mode 100644 lib/plat/freertos/esp32/esp_attr.h create mode 100644 minimal-examples-lowlevel/raw/minimal-raw-client/CMakeLists.txt create mode 100644 minimal-examples-lowlevel/raw/minimal-raw-client/main.c diff --git a/.sai.json b/.sai.json index 7ac992e1..3d349e94 100644 --- a/.sai.json +++ b/.sai.json @@ -243,11 +243,11 @@ "mbedtls": { "cmake": "-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_JOSE=1 -DCMAKE_BUILD_TYPE=DEBUG", # no distro -devel package for mbedtls - "platforms": "not linux-centos-7/x86_64-amd/gcc, not linux-centos-8/x86_64-amd/gcc" + "platforms": "not linux-centos-7/x86_64-amd/gcc, not linux-centos-8/x86_64-amd/gcc, not linux-ubuntu-xenial/x86_64-amd/gcc" }, "mbedtls-metrics": { "cmake": "-DLWS_WITH_MBEDTLS=1 -DLWS_WITH_HTTP2=1 -DLWS_WITH_LWSWS=1 -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_JOSE=1 -DCMAKE_BUILD_TYPE=DEBUG -DLWS_WITH_SYS_METRICS=1", - "platforms": "not linux-centos-7/x86_64-amd/gcc, not linux-centos-8/x86_64-amd/gcc" + "platforms": "not linux-centos-7/x86_64-amd/gcc, not linux-centos-8/x86_64-amd/gcc, not linux-ubuntu-xenial/x86_64-amd/gcc" }, "noserver": { "cmake": "-DLWS_WITHOUT_SERVER=ON -DLWS_WITH_MINIMAL_EXAMPLES=1 -DLWS_WITH_SECURE_STREAMS=1", diff --git a/CMakeLists.txt b/CMakeLists.txt index c4cd2949..166d48a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,10 @@ if (ESP_PLATFORM) endif() # it's at this point any toolchain file is brought in -project(libwebsockets C CXX) +project(libwebsockets C) +if (LWS_WITH_SECURE_STREAMS_CPP) + enable_language(CXX) +endif() include(CTest) if (ESP_PLATFORM) @@ -179,7 +182,7 @@ option(LWS_WITH_SSL "Include SSL support (defaults to OpenSSL or similar, mbedTL option(LWS_WITH_MBEDTLS "Use mbedTLS (>=2.0) replacement for OpenSSL. When setting this, you also may need to specify LWS_MBEDTLS_LIBRARIES and LWS_MBEDTLS_INCLUDE_DIRS" OFF) option(LWS_WITH_BORINGSSL "Use BoringSSL replacement for OpenSSL" OFF) option(LWS_WITH_CYASSL "Use CyaSSL replacement for OpenSSL. When setting this, you also need to specify LWS_CYASSL_LIBRARIES and LWS_CYASSL_INCLUDE_DIRS" OFF) -option(LWS_WITH_WOLFSSL "Use wolfSSL replacement for OpenSSL. When setting this, you also need to specify LWS_WOLFSSL_LIBRARIES and LWS_WOLFSSL_INCLUDE_DIRS" OFF) +option(LWS_WITH_WOLFSSL "Use wolfSSL replacement for OpenSSL. When setting this, you also may need to specify LWS_WOLFSSL_LIBRARIES and LWS_WOLFSSL_INCLUDE_DIRS" OFF) option(LWS_SSL_CLIENT_USE_OS_CA_CERTS "SSL support should make use of the OS-installed CA root certs" ON) option(LWS_TLS_LOG_PLAINTEXT_RX "For debugging log the received plaintext as soon as decrypted" OFF) option(LWS_TLS_LOG_PLAINTEXT_TX "For debugging log the transmitted plaintext just before encryption" OFF) @@ -407,7 +410,7 @@ set(CPACK_RPM_PACKAGE_LICENSE "MIT") set(CPACK_PACKAGE_NAME "${PACKAGE}") set(CPACK_PACKAGE_VERSION_MAJOR "4") set(CPACK_PACKAGE_VERSION_MINOR "3") -set(CPACK_PACKAGE_VERSION_PATCH_NUMBER "0") +set(CPACK_PACKAGE_VERSION_PATCH_NUMBER "2") set(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH_NUMBER}-${LWS_BUILD_HASH}") set(CPACK_PACKAGE_RELEASE 1) @@ -849,7 +852,11 @@ if (MSVC) # Fail the build if any warnings add_compile_options(/W3 /WX) # Unbreak MSVC broken preprocessor __VA_ARGS__ behaviour - add_compile_options(/Zc:preprocessor /experimental:preprocessor /wd5105) + if (MSVC_VERSION GREATER 1925) + add_compile_options(/Zc:preprocessor /wd5105) + else() + add_compile_options(/experimental:preprocessor /wd5105) + endif() endif(MSVC) if (MINGW) diff --git a/cmake/FindOpenSSLbins.cmake b/cmake/FindOpenSSLbins.cmake index 3f32994a..3d791f46 100644 --- a/cmake/FindOpenSSLbins.cmake +++ b/cmake/FindOpenSSLbins.cmake @@ -44,7 +44,7 @@ if(OPENSSL_FOUND) get_filename_component(OPENSSL_EXECUTABLE_PATH ${OPENSSL_EXECUTABLE} DIRECTORY) message(VERBOSE "OPENSSL_EXECUTABLE_PATH=${OPENSSL_EXECUTABLE_PATH}") set(OPENSSL_EXECUTABLE_BIN_PATH "") - string(REGEX MATCH "^(.*)/tools/openssl$" REGEX_MATCH ${OPENSSL_EXECUTABLE_PATH}) + string(REGEX MATCH "^(.*)/tools/openssl$" REGEX_MATCH "${OPENSSL_EXECUTABLE_PATH}") message(DEBUG "REGEX_MATCH=\"${REGEX_MATCH}\"") message(DEBUG "CMAKE_MATCH_1=\"${CMAKE_MATCH_1}\"") if (NOT ${REGEX_MATCH} EQUAL "") diff --git a/cmake/libwebsockets-config.cmake.in b/cmake/libwebsockets-config.cmake.in index 6247b2cb..8ba97e6f 100644 --- a/cmake/libwebsockets-config.cmake.in +++ b/cmake/libwebsockets-config.cmake.in @@ -32,6 +32,5 @@ endforeach() include(CheckIncludeFile) include(CheckCSourceCompiles) -include(LwsCheckRequirements) set(requirements 1) diff --git a/include/libwebsockets.h b/include/libwebsockets.h index 4409ee27..8fb98c34 100644 --- a/include/libwebsockets.h +++ b/include/libwebsockets.h @@ -291,11 +291,18 @@ typedef int suseconds_t; #include #include #include +#include #if !defined(MBEDTLS_PRIVATE) #define MBEDTLS_PRIVATE(_q) _q #endif +#if (MBEDTLS_VERSION_MAJOR == 3) && (MBEDTLS_VERSION_MINOR == 0) +#define MBEDTLS_PRIVATE_V30_ONLY(_q) MBEDTLS_PRIVATE(_q) +#else +#define MBEDTLS_PRIVATE_V30_ONLY(_q) _q +#endif + #endif #else #include diff --git a/include/libwebsockets/lws-callbacks.h b/include/libwebsockets/lws-callbacks.h index 62848fa5..fd36f7c7 100644 --- a/include/libwebsockets/lws-callbacks.h +++ b/include/libwebsockets/lws-callbacks.h @@ -887,6 +887,11 @@ enum lws_callback_reasons { * the _UNSUBSCRIBED one if we timed out waiting for a UNSUBACK. * Return nonzero to close the wsi. */ + LWS_CALLBACK_MQTT_SHADOW_TIMEOUT = 212, + /**< When a Device Shadow is sent, this callback is generated if we + * timed out waiting for a response from AWS IoT. + * Return nonzero to close the wsi. + */ /****** add new things just above ---^ ******/ diff --git a/include/libwebsockets/lws-http.h b/include/libwebsockets/lws-http.h index 2c5bd64d..85767589 100644 --- a/include/libwebsockets/lws-http.h +++ b/include/libwebsockets/lws-http.h @@ -534,8 +534,6 @@ lws_hdr_custom_name_foreach(struct lws *wsi, lws_hdr_custom_fe_cb_t cb, void *op * * Use this in place of lws_get_urlarg_by_name() that does not return an * explicit length. - * - * Use lws_get_urlarg_by_name_safe() instead of this, which returns the length. */ LWS_VISIBLE LWS_EXTERN int lws_get_urlarg_by_name_safe(struct lws *wsi, const char *name, char *buf, int len); diff --git a/include/libwebsockets/lws-logs.h b/include/libwebsockets/lws-logs.h index 3f21b810..795ba55c 100644 --- a/include/libwebsockets/lws-logs.h +++ b/include/libwebsockets/lws-logs.h @@ -82,6 +82,11 @@ typedef struct lws_log_cx { lws_log_emit_t emit; /* legacy emit function */ lws_log_emit_cx_t emit_cx; /* LLLF_LOG_CONTEXT_AWARE */ } u; + +#if LWS_MAX_SMP > 1 + pthread_mutex_t refcount_lock; +#endif + lws_log_use_cx_t refcount_cb; /**< NULL, or a function called after each change to .refcount below, * this enables implementing side-effects like opening and closing @@ -99,6 +104,9 @@ typedef struct lws_log_cx { /**< mask of log levels we want to emit in this context */ int32_t refcount; /**< refcount of objects bound to this log context */ +#if LWS_MAX_SMP > 1 + char inited; +#endif } lws_log_cx_t; /** diff --git a/include/libwebsockets/lws-map.h b/include/libwebsockets/lws-map.h index 4462881b..cf2368a0 100644 --- a/include/libwebsockets/lws-map.h +++ b/include/libwebsockets/lws-map.h @@ -43,7 +43,7 @@ //@{ typedef struct lws_map lws_map_t; -typedef struct lws_map_item lws_map_item_t; +struct lws_map_item; typedef void * lws_map_key_t; typedef void * lws_map_value_t; @@ -76,13 +76,13 @@ typedef struct lws_map_info { } lws_map_info_t; LWS_VISIBLE LWS_EXTERN const void * -lws_map_item_key(lws_map_item_t *_item); +lws_map_item_key(struct lws_map_item *_item); LWS_VISIBLE LWS_EXTERN const void * -lws_map_item_value(lws_map_item_t *_item); +lws_map_item_value(struct lws_map_item *_item); LWS_VISIBLE LWS_EXTERN size_t -lws_map_item_key_len(lws_map_item_t *_item); +lws_map_item_key_len(struct lws_map_item *_item); LWS_VISIBLE LWS_EXTERN size_t -lws_map_item_value_len(lws_map_item_t *_item); +lws_map_item_value_len(struct lws_map_item *_item); /* * Helpers for C string keys case @@ -158,7 +158,7 @@ lws_map_destroy(lws_map_t **pmap); * creating and adding the new one. */ -LWS_VISIBLE LWS_EXTERN lws_map_item_t * +LWS_VISIBLE LWS_EXTERN struct lws_map_item * lws_map_item_create(lws_map_t *map, const lws_map_key_t key, size_t keylen, const lws_map_value_t value, size_t valuelen); @@ -169,7 +169,7 @@ lws_map_item_create(lws_map_t *map, * \param item: the item in the map to remove and free */ LWS_VISIBLE LWS_EXTERN void -lws_map_item_destroy(lws_map_item_t *item); +lws_map_item_destroy(struct lws_map_item *item); /** * lws_map_item_lookup() - look for a item with the given key in the map @@ -182,7 +182,7 @@ lws_map_item_destroy(lws_map_item_t *item); * functions. */ -LWS_VISIBLE LWS_EXTERN lws_map_item_t * +LWS_VISIBLE LWS_EXTERN struct lws_map_item * lws_map_item_lookup(lws_map_t *map, const lws_map_key_t key, size_t keylen); //@} diff --git a/include/libwebsockets/lws-mqtt.h b/include/libwebsockets/lws-mqtt.h index 22865801..cbf8b363 100644 --- a/include/libwebsockets/lws-mqtt.h +++ b/include/libwebsockets/lws-mqtt.h @@ -42,6 +42,29 @@ typedef struct lws_mqtt_str_st lws_mqtt_str_t; #define LWS_MQTT_RANDOM_CIDLEN 23 /* 3.1.3.1-5: Server MUST... between 1 and 23 chars... */ +#define LWS_MQTT_SHADOW_MAX_THING_LEN 128 +#define LWS_MQTT_SHADOW_MAX_SHADOW_LEN 64 +#define LWS_MQTT_SHADOW_UPDATE_STR "/update" +#define LWS_MQTT_SHADOW_DELETE_STR "/delete" +#define LWS_MQTT_SHADOW_GET_STR "/get" +#define LWS_MQTT_SHADOW_RESP_ACCEPTED_STR "/accepted" +#define LWS_MQTT_SHADOW_RESP_REJECTED_STR "/rejected" +#define LWS_MQTT_SHADOW_RESP_DELTA_STR "/delta" +#define LWS_MQTT_SHADOW_RESP_DOCUMENT_STR "/documents" +#define LWS_MQTT_SHADOW_UPDATE_ACCEPTED_STR LWS_MQTT_SHADOW_UPDATE_STR LWS_MQTT_SHADOW_RESP_ACCEPTED_STR +#define LWS_MQTT_SHADOW_UPDATE_REJECTED_STR LWS_MQTT_SHADOW_UPDATE_STR LWS_MQTT_SHADOW_RESP_REJECTED_STR +#define LWS_MQTT_SHADOW_UPDATE_DELTA_STR LWS_MQTT_SHADOW_UPDATE_STR LWS_MQTT_SHADOW_RESP_DELTA_STR +#define LWS_MQTT_SHADOW_UPDATE_DOCUMENT_STR LWS_MQTT_SHADOW_UPDATE_STR LWS_MQTT_SHADOW_RESP_DOCUMENT_STR +#define LWS_MQTT_SHADOW_DELETE_ACCEPTED_STR LWS_MQTT_SHADOW_DELETE_STR LWS_MQTT_SHADOW_RESP_ACCEPTED_STR +#define LWS_MQTT_SHADOW_DELETE_REJECTED_STR LWS_MQTT_SHADOW_DELETE_STR LWS_MQTT_SHADOW_RESP_REJECTED_STR +#define LWS_MQTT_SHADOW_GET_ACCEPTED_STR LWS_MQTT_SHADOW_GET_STR LWS_MQTT_SHADOW_RESP_ACCEPTED_STR +#define LWS_MQTT_SHADOW_GET_REJECTED_STR LWS_MQTT_SHADOW_GET_STR LWS_MQTT_SHADOW_RESP_REJECTED_STR +#define LWS_MQTT_SHADOW_PREFIX_FORMAT "$aws/things/%s" +#define LWS_MQTT_SHADOW_NAMED_SHADOW_TOPIC_FORMAT LWS_MQTT_SHADOW_PREFIX_FORMAT "/shadow/name/%s%s" +#define LWS_MQTT_SHADOW_UNNAMED_SHADOW_TOPIC_FORMAT LWS_MQTT_SHADOW_PREFIX_FORMAT "/shadow%s" +#define LWS_MQTT_SHADOW_UNNAMED_TOPIC_MATCH "$aws/things/+/shadow/+" +#define LWS_MQTT_SHADOW_NAMED_TOPIC_MATCH "$aws/things/+/shadow/name/+/+" + typedef enum { QOS0, QOS1, @@ -114,6 +137,7 @@ typedef struct lws_mqtt_publish_param_s { 0 */ uint8_t dup:1; /* Retried PUBLISH, for QoS > 0 */ + uint8_t retain:1; /* Retained message */ } lws_mqtt_publish_param_t; typedef struct topic_elem { diff --git a/include/libwebsockets/lws-network-helper.h b/include/libwebsockets/lws-network-helper.h index 20a32253..09308b8b 100644 --- a/include/libwebsockets/lws-network-helper.h +++ b/include/libwebsockets/lws-network-helper.h @@ -33,7 +33,8 @@ #include #endif -typedef uint8_t lws_route_uidx_t; +/* cope with large amounts of route information */ +typedef uint16_t lws_route_uidx_t; typedef struct lws_dns_score { uint8_t precedence; diff --git a/include/libwebsockets/lws-secure-streams-policy.h b/include/libwebsockets/lws-secure-streams-policy.h index 863140d7..2c81f9fd 100644 --- a/include/libwebsockets/lws-secure-streams-policy.h +++ b/include/libwebsockets/lws-secure-streams-policy.h @@ -323,6 +323,7 @@ typedef struct lws_ss_policy { uint8_t birth_qos; uint8_t birth_retain; uint8_t aws_iot; + uint8_t retain; } mqtt; diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c55c6198..19dc0cf6 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -38,7 +38,8 @@ set(LWS_LIB_INCLUDES "") if (LWS_PLAT_FREERTOS) add_subdir_include_dirs(plat/freertos) if (ESP_PLATFORM) - include_directories($ENV{IDF_PATH}/components/freertos/include + list(APPEND LWS_ESP_IDF_DIRS + $ENV{IDF_PATH}/components/freertos/include $ENV{IDF_PATH}/components/esp_hw_support/include/soc/ $ENV{IDF_PATH}/components/esp_common/include $ENV{IDF_PATH}/components/esp_timer/include @@ -71,7 +72,12 @@ if (LWS_PLAT_FREERTOS) $ENV{IDF_PATH}/components/lwip/lwip/src/include $ENV{IDF_PATH}/components/lwip/lwip/src/include/lwip $ENV{IDF_PATH}/components/newlib/platform_include ) + + include_directories(${LWS_ESP_IDF_DIRS}) + + list(APPEND CMAKE_REQUIRED_INCLUDES ${LWS_ESP_IDF_DIRS}) endif() + else() if (LWS_PLAT_OPTEE) @@ -334,7 +340,7 @@ Name: libwebsockets_static Description: Websockets server and client static library Version: ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH} -Libs: -L\${libdir} -lwebsockets_static +Libs: -L\${libdir} -l:libwebsockets${CMAKE_STATIC_LIBRARY_SUFFIX} Libs.private: Cflags: -I\${includedir} " diff --git a/lib/core-net/adopt.c b/lib/core-net/adopt.c index e4119451..579f4bfe 100644 --- a/lib/core-net/adopt.c +++ b/lib/core-net/adopt.c @@ -847,12 +847,16 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port, lws_snprintf(buf, sizeof(buf), "%u", port); n = getaddrinfo(ads, buf, &h, &r); if (n) { + +#if (_LWS_ENABLED_LOGS & LLL_INFO) #if !defined(LWS_PLAT_FREERTOS) lwsl_info("%s: getaddrinfo error: %s\n", __func__, gai_strerror(n)); #else + lwsl_info("%s: getaddrinfo error: %s\n", __func__, strerror(n)); +#endif #endif //freeaddrinfo(r); goto bail1; diff --git a/lib/core-net/client/connect3.c b/lib/core-net/client/connect3.c index a3102165..b7523303 100644 --- a/lib/core-net/client/connect3.c +++ b/lib/core-net/client/connect3.c @@ -71,7 +71,7 @@ typedef enum { } lcccr_t; static lcccr_t -lws_client_connect_check(struct lws *wsi) +lws_client_connect_check(struct lws *wsi, int *real_errno) { int en = 0; #if !defined(WIN32) @@ -98,12 +98,14 @@ lws_client_connect_check(struct lws *wsi) lwsl_wsi_notice(wsi, "getsockopt fd %d says e %d", wsi->desc.sockfd, e); + *real_errno = e; + return LCCCR_FAILED; } #else - if (!connect(wsi->desc.sockfd, NULL, 0)) + if (!connect(wsi->desc.sockfd, (const struct sockaddr *)&wsi->sa46_peer.sa4, 0)) return LCCCR_CONNECTED; en = LWS_ERRNO; @@ -125,7 +127,8 @@ lws_client_connect_check(struct lws *wsi) } #endif - lwsl_wsi_notice(wsi, "connect check take as FAILED: errno %d", en); + lwsl_wsi_notice(wsi, "connect check FAILED: %d", + *real_errno || en); return LCCCR_FAILED; } @@ -231,7 +234,15 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads, /* no dns results and no ongoing timeout for one */ goto connect_to; - switch (lws_client_connect_check(wsi)) { + /* + * If the connection failed, the OS-level errno may be + * something like EINPROGRESS rather than the actual problem + * that prevented a connection. This value will represent the + * “real” problem that we should report to the caller. + */ + int real_errno = 0; + + switch (lws_client_connect_check(wsi, &real_errno)) { case LCCCR_CONNECTED: /* * Oh, it has happened... @@ -240,8 +251,11 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads, case LCCCR_CONTINUE: return NULL; default: - lws_snprintf(dcce, sizeof(dcce), "conn fail: errno %d", - LWS_ERRNO); + if (!real_errno) + real_errno = LWS_ERRNO; + lws_snprintf(dcce, sizeof(dcce), "conn fail: %d", + real_errno); + cce = dcce; lwsl_wsi_debug(wsi, "%s", dcce); lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO); diff --git a/lib/core-net/close.c b/lib/core-net/close.c index 1d92b390..a8dd7209 100644 --- a/lib/core-net/close.c +++ b/lib/core-net/close.c @@ -560,7 +560,7 @@ just_kill_connection: lwsl_wsi_debug(wsi, "real just_kill_connection A: (sockfd %d)", wsi->desc.sockfd); -#if defined(LWS_WITH_THREADPOOL) +#if defined(LWS_WITH_THREADPOOL) && defined(LWS_HAVE_PTHREAD_H) lws_threadpool_wsi_closing(wsi); #endif diff --git a/lib/core-net/dummy-callback.c b/lib/core-net/dummy-callback.c index 9552af5a..d36000fa 100644 --- a/lib/core-net/dummy-callback.c +++ b/lib/core-net/dummy-callback.c @@ -686,21 +686,23 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_CGI_TERMINATED: - lwsl_wsi_debug(wsi, "CGI_TERMINATED: %d %" PRIu64, + if (wsi->http.cgi) { + lwsl_wsi_debug(wsi, "CGI_TERMINATED: %d %" PRIu64, wsi->http.cgi->explicitly_chunked, (uint64_t)wsi->http.cgi->content_length); - if (!(wsi->http.cgi->explicitly_chunked && wsi->mux_substream) && - !wsi->http.cgi->content_length) { - /* send terminating chunk */ - lwsl_wsi_debug(wsi, "LWS_CALLBACK_CGI_TERMINATED: ending"); - wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END; - lws_callback_on_writable(wsi); - lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3); - break; - } - if (wsi->mux_substream && !wsi->cgi_stdout_zero_length) - lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0, + if (!(wsi->http.cgi->explicitly_chunked && wsi->mux_substream) && + !wsi->http.cgi->content_length) { + /* send terminating chunk */ + lwsl_wsi_debug(wsi, "LWS_CALLBACK_CGI_TERMINATED: ending"); + wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END; + lws_callback_on_writable(wsi); + lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3); + break; + } + if (wsi->mux_substream && !wsi->cgi_stdout_zero_length) + lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0, LWS_WRITE_HTTP_FINAL); + } #if defined(LWS_WITH_SERVER) if (lws_http_transaction_completed(wsi)) return -1; diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index 2d3f73ab..0b3561f7 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -706,7 +706,7 @@ struct lws { lws_log_cx_t *log_cx; -#if defined(LWS_WITH_THREADPOOL) +#if defined(LWS_WITH_THREADPOOL) && defined(LWS_HAVE_PTHREAD_H) lws_dll2_owner_t tp_task_owner; /* struct lws_threadpool_task */ #endif @@ -1375,7 +1375,7 @@ _lws_routing_table_dump(struct lws_context *cx); #define LRR_IGNORE_PRI (1 << 0) #define LRR_MATCH_SRC (1 << 1) -#define LRR_JUST_CHECK (1 << 2) +#define LRR_MATCH_DST (1 << 2) lws_route_t * _lws_route_remove(struct lws_context_per_thread *pt, lws_route_t *robj, int flags); diff --git a/lib/core-net/route.c b/lib/core-net/route.c index 2a851521..c9fdc2ba 100644 --- a/lib/core-net/route.c +++ b/lib/core-net/route.c @@ -38,25 +38,30 @@ void _lws_routing_entry_dump(struct lws_context *cx, lws_route_t *rou) { char sa[48], fin[192], *end = &fin[sizeof(fin)]; + char *it = fin; + int n; fin[0] = '\0'; if (rou->dest.sa4.sin_family) { lws_sa46_write_numeric_address(&rou->dest, sa, sizeof(sa)); - lws_snprintf(fin, lws_ptr_diff_size_t(end, fin), + n = lws_snprintf(it, lws_ptr_diff_size_t(end, it), "dst: %s/%d, ", sa, rou->dest_len); + it = it + n; } if (rou->src.sa4.sin_family) { lws_sa46_write_numeric_address(&rou->src, sa, sizeof(sa)); - lws_snprintf(fin, lws_ptr_diff_size_t(end, fin), + n = lws_snprintf(it, lws_ptr_diff_size_t(end, it), "src: %s/%d, ", sa, rou->src_len); + it = it + n; } if (rou->gateway.sa4.sin_family) { lws_sa46_write_numeric_address(&rou->gateway, sa, sizeof(sa)); - lws_snprintf(fin, lws_ptr_diff_size_t(end, fin), + n = lws_snprintf(it, lws_ptr_diff_size_t(end, it), "gw: %s, ", sa); + it = it + n; } lwsl_cx_info(cx, " %s ifidx: %d, pri: %d, proto: %d\n", fin, @@ -98,7 +103,7 @@ _lws_routing_table_dump(struct lws_context *cx) lws_route_uidx_t _lws_route_get_uidx(struct lws_context *cx) { - uint8_t ou; + lws_route_uidx_t ou; if (!cx->route_uidx) cx->route_uidx++; @@ -141,7 +146,7 @@ _lws_route_remove(struct lws_context_per_thread *pt, lws_route_t *robj, int flag lws_route_t *rou = lws_container_of(d, lws_route_t, list); if ((!(flags & LRR_MATCH_SRC) || !lws_sa46_compare_ads(&robj->src, &rou->src)) && - ((flags & LRR_MATCH_SRC) || !lws_sa46_compare_ads(&robj->dest, &rou->dest)) && + (!(flags & LRR_MATCH_DST) || !lws_sa46_compare_ads(&robj->dest, &rou->dest)) && (!robj->gateway.sa4.sin_family || !lws_sa46_compare_ads(&robj->gateway, &rou->gateway)) && robj->dest_len <= rou->dest_len && @@ -149,8 +154,6 @@ _lws_route_remove(struct lws_context_per_thread *pt, lws_route_t *robj, int flag ((flags & LRR_IGNORE_PRI) || robj->priority == rou->priority) ) { - if (flags & LRR_JUST_CHECK) - return rou; lwsl_cx_info(pt->context, "deleting route"); _lws_route_pt_close_route_users(pt, robj->uidx); lws_dll2_remove(&rou->list); diff --git a/lib/core-net/sorted-usec-list.c b/lib/core-net/sorted-usec-list.c index e9b9c1f6..d9af0f11 100644 --- a/lib/core-net/sorted-usec-list.c +++ b/lib/core-net/sorted-usec-list.c @@ -146,6 +146,12 @@ __lws_sul_service_ripe(lws_dll2_owner_t *own, int own_len, lws_usec_t usnow) /* his moment has come... remove him from his owning list */ + if (!hit->cb) { + lwsl_err("%s: sul with NULL callback (did not cancel on destory?)\n", __func__); + + return 0; + } + lws_dll2_remove(&hit->list); hit->us = 0; diff --git a/lib/core-net/wsi-timeout.c b/lib/core-net/wsi-timeout.c index bbaed54c..b72f134f 100644 --- a/lib/core-net/wsi-timeout.c +++ b/lib/core-net/wsi-timeout.c @@ -206,14 +206,15 @@ lws_validity_cb(lws_sorted_usec_list_t *sul) if (wsi->validity_hup) { lwsl_wsi_info(wsi, "validity too old"); - struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + struct lws_context *cx = wsi->a.context; + struct lws_context_per_thread *pt = &cx->pt[(int)wsi->tsi]; - lws_context_lock(wsi->a.context, __func__); + lws_context_lock(cx, __func__); lws_pt_lock(pt, __func__); __lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "validity timeout"); lws_pt_unlock(pt); - lws_context_unlock(wsi->a.context); + lws_context_unlock(cx); return; } diff --git a/lib/core/context.c b/lib/core/context.c index fb684e51..af818ebe 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -2009,15 +2009,18 @@ next: lws_plat_context_late_destroy(context); #if defined(LWS_WITH_PEER_LIMITS) - for (nu = 0; nu < context->pl_hash_elements; nu++) { - lws_start_foreach_llp(struct lws_peer **, peer, - context->pl_hash_table[nu]) { - struct lws_peer *df = *peer; - *peer = df->next; - lws_free(df); - continue; - } lws_end_foreach_llp(peer, next); - } + if (context->pl_hash_table) + for (nu = 0; nu < context->pl_hash_elements; nu++) { + if (!context->pl_hash_table[nu]) + continue; + lws_start_foreach_llp(struct lws_peer **, peer, + context->pl_hash_table[nu]) { + struct lws_peer *df = *peer; + *peer = df->next; + lws_free(df); + continue; + } lws_end_foreach_llp(peer, next); + } lws_free(context->pl_hash_table); #endif diff --git a/lib/core/logs.c b/lib/core/logs.c index a13c8419..27b7b9fa 100644 --- a/lib/core/logs.c +++ b/lib/core/logs.c @@ -242,6 +242,16 @@ lwsl_timestamp(int level, char *p, size_t len) n = lws_snprintf(p, len, "[%llu:%04d] %c: ", (unsigned long long) now / 10000, (int)(now % 10000), log_level_names[n]); + +#if defined(LWS_PLAT_FREERTOS) + n += lws_snprintf(p + n, len - n, "%6u: ", +#if defined(LWS_AMAZON_RTOS) + (unsigned int)xPortGetFreeHeapSize()); +#else + (unsigned int)esp_get_free_heap_size()); +#endif +#endif + return n; } #else @@ -506,9 +516,24 @@ int lwsl_visible_cx(lws_log_cx_t *cx, int level) void lwsl_refcount_cx(lws_log_cx_t *cx, int _new) { +#if LWS_MAX_SMP > 1 + volatile lws_log_cx_t *vcx = (volatile lws_log_cx_t *)cx; +#endif + if (!cx) return; +#if LWS_MAX_SMP > 1 + if (!vcx->inited) { + vcx->inited = 1; + lws_pthread_mutex_init(&cx->refcount_lock); + vcx->inited = 2; + } + while (vcx->inited != 2) + ; + lws_pthread_mutex_lock(&cx->refcount_lock); +#endif + if (_new > 0) cx->refcount++; else { @@ -518,6 +543,10 @@ lwsl_refcount_cx(lws_log_cx_t *cx, int _new) if (cx->refcount_cb) cx->refcount_cb(cx, _new); + +#if LWS_MAX_SMP > 1 + lws_pthread_mutex_unlock(&cx->refcount_lock); +#endif } void diff --git a/lib/core/private-lib-core.h b/lib/core/private-lib-core.h index 8ba08520..6cdc91cf 100644 --- a/lib/core/private-lib-core.h +++ b/lib/core/private-lib-core.h @@ -625,7 +625,7 @@ struct lws_context { mbedtls_ctr_drbg_context mcdc; #endif -#if defined(LWS_WITH_THREADPOOL) +#if defined(LWS_WITH_THREADPOOL) && defined(LWS_HAVE_PTHREAD_H) struct lws_threadpool *tp_list_head; #endif diff --git a/lib/cose/cose_sign.c b/lib/cose/cose_sign.c index d7ae64f3..7c624de5 100644 --- a/lib/cose/cose_sign.c +++ b/lib/cose/cose_sign.c @@ -209,9 +209,12 @@ lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc, lws_lec_init(&lec, lbuf, sizeof(lbuf)); - /* we know it will fit */ - lws_lec_printf(&lec, "{1:%lld}", + /* we know it will fit... but coverity doesn't */ + ret = lws_lec_printf(&lec, "{1:%lld}", (long long)alg->cose_alg); + if (ret != LWS_LECPCTX_RET_FINISHED) + return ret; + lws_lec_scratch(&lec); if (!csc->subsequent) { @@ -293,9 +296,11 @@ lws_cose_sign_payload_chunk(struct lws_cose_sign_context *csc, lws_lec_init(&lec, lbuf, sizeof(lbuf)); - /* we know it will fit */ - lws_lec_printf(&lec, "{1:%lld}", + /* we know it will fit... but coverity doesn't... */ + ret = lws_lec_printf(&lec, "{1:%lld}", (long long)alg->cose_alg); + if (ret != LWS_LECPCTX_RET_FINISHED) + return ret; lws_lec_init(&lec1, lb, sizeof(lb)); lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, @@ -454,8 +459,10 @@ inner_protected: lws_lec_init(&lec1, lb, sizeof(lb)); lws_lec_int(&lec1, LWS_CBOR_MAJTYP_BSTR, 0, lec.used); - lws_lec_printf(csc->info.lec, "{1:%lld}", - (long long)csc->alg->cose_alg); + if (lws_lec_printf(csc->info.lec, "{1:%lld}", + (long long)csc->alg->cose_alg) != LWS_LECPCTX_RET_FINISHED) + /* coverity */ + return 0; break; default: lec.used = 0; diff --git a/lib/misc/lejp.c b/lib/misc/lejp.c index cbce4ee4..b898c6f9 100644 --- a/lib/misc/lejp.c +++ b/lib/misc/lejp.c @@ -160,7 +160,7 @@ lejp_check_path_match(struct lejp_ctx *ctx) p = ctx->path; q = *((char **)(((char *)ctx->pst[ctx->pst_sp].paths) + ((unsigned int)n * s))); - +//lwsl_notice("%s: %s %s\n", __func__, p, q); while (*p && *q) { if (*q != '*') { if (*p != *q) diff --git a/lib/plat/freertos/esp32/esp_attr.h b/lib/plat/freertos/esp32/esp_attr.h deleted file mode 100644 index 5bf9a229..00000000 --- a/lib/plat/freertos/esp32/esp_attr.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef __ESP_ATTR_H__ -#define __ESP_ATTR_H__ - -#define ROMFN_ATTR - -//Normally, the linker script will put all code and rodata in flash, -//and all variables in shared RAM. These macros can be used to redirect -//particular functions/variables to other memory regions. - -// Forces code into IRAM instead of flash. -#define IRAM_ATTR __attribute__((section(".iram1"))) - -// Forces data into DRAM instead of flash -#define DRAM_ATTR __attribute__((section(".dram1"))) - -// Forces data to be 4 bytes aligned -#define WORD_ALIGNED_ATTR __attribute__((aligned(4))) - -// Forces data to be placed to DMA-capable places -#define DMA_ATTR WORD_ALIGNED_ATTR DRAM_ATTR - -// Forces a string into DRAM instead of flash -// Use as ets_printf(DRAM_STR("Hello world!\n")); -#define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;})) - -// Forces code into RTC fast memory. See "docs/deep-sleep-stub.rst" -#define RTC_IRAM_ATTR __attribute__((section(".rtc.text"))) - -// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst" -// Any variable marked with this attribute will keep its value -// during a deep sleep / wake cycle. -#define RTC_DATA_ATTR __attribute__((section(".rtc.data"))) - -// Forces read-only data into RTC slow memory. See "docs/deep-sleep-stub.rst" -#define RTC_RODATA_ATTR __attribute__((section(".rtc.rodata"))) - -// Forces data into noinit section to avoid initialization after restart. -#define __NOINIT_ATTR __attribute__((section(".noinit"))) - -// Forces data into RTC slow memory of .noinit section. -// Any variable marked with this attribute will keep its value -// after restart or during a deep sleep / wake cycle. -#define RTC_NOINIT_ATTR __attribute__((section(".rtc_noinit"))) - -#endif /* __ESP_ATTR_H__ */ diff --git a/lib/plat/freertos/private-lib-plat-freertos.h b/lib/plat/freertos/private-lib-plat-freertos.h index d544e2b1..67b83997 100644 --- a/lib/plat/freertos/private-lib-plat-freertos.h +++ b/lib/plat/freertos/private-lib-plat-freertos.h @@ -59,11 +59,15 @@ gai_strerror(int); #include "FreeRTOS_IP.h" #endif #include "timers.h" +#if defined(LWS_ESP_PLATFORM) #include +#endif #include #else #include "freertos/timers.h" +#if defined(LWS_ESP_PLATFORM) #include +#endif #include #include #endif diff --git a/lib/plat/unix/unix-sockets.c b/lib/plat/unix/unix-sockets.c index 07df994c..2c1b9569 100644 --- a/lib/plat/unix/unix-sockets.c +++ b/lib/plat/unix/unix-sockets.c @@ -216,7 +216,7 @@ lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags) { int optval = (int)pri, ret = 0, n; socklen_t optlen = sizeof(optval); -#if !defined(LWS_WITH_NO_LOGS) +#if (_LWS_ENABLED_LOGS & LLL_WARN) int en; #endif @@ -244,7 +244,7 @@ lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags) if (pri) { /* 0 is the default already */ if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (const void *)&optval, optlen) < 0) { -#if !defined(LWS_WITH_NO_LOGS) +#if (_LWS_ENABLED_LOGS & LLL_WARN) en = errno; lwsl_warn("%s: unable to set socket pri %d: errno %d\n", __func__, (int)pri, en); @@ -589,7 +589,7 @@ lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost) int lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len) { - int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE(fd); + int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE_V30_ONLY(fd); int ret; if (fd < 0) @@ -614,7 +614,7 @@ lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len) int lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len) { - int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE(fd); + int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE_V30_ONLY(fd); int ret; if (fd < 0) diff --git a/lib/plat/windows/windows-plugins.c b/lib/plat/windows/windows-plugins.c index b2153d67..313d58ff 100644 --- a/lib/plat/windows/windows-plugins.c +++ b/lib/plat/windows/windows-plugins.c @@ -66,7 +66,7 @@ lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath, if (uv_dlsym(&lib, sym, &v)) { uv_dlerror(&lib); lwsl_err("%s: Failed to get '%s' on %s: %s\n", - __func__, path, dent.name, lib.errmsg); + __func__, path, libpath, lib.errmsg); goto bail; } @@ -123,7 +123,9 @@ bail: int lws_plat_destroy_dl(struct lws_plugin *p) { - return uv_dlclose(&p->u.lib); + uv_dlclose(&p->u.lib); + + return 0; } #endif diff --git a/lib/plat/windows/windows-sockets.c b/lib/plat/windows/windows-sockets.c index ce9b7192..b0e15dd1 100644 --- a/lib/plat/windows/windows-sockets.c +++ b/lib/plat/windows/windows-sockets.c @@ -564,7 +564,7 @@ lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len) if (fd < 0) return MBEDTLS_ERR_NET_INVALID_CONTEXT; - ret = send(fd, buf, (unsigned int)len, 0); + ret = send(fd, (const char *)buf, (unsigned int)len, 0); if (ret >= 0) return ret; @@ -589,7 +589,7 @@ lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len) if (fd < 0) return MBEDTLS_ERR_NET_INVALID_CONTEXT; - ret = (int)recv(fd, buf, (unsigned int)len, 0); + ret = (int)recv(fd, (char *)buf, (unsigned int)len, 0); if (ret >= 0) return ret; diff --git a/lib/roles/cgi/cgi-server.c b/lib/roles/cgi/cgi-server.c index cd039e84..a6f04fa1 100644 --- a/lib/roles/cgi/cgi-server.c +++ b/lib/roles/cgi/cgi-server.c @@ -95,14 +95,16 @@ lws_cgi_reap_cb(void *opaque, lws_usec_t *accounting, siginfo_t *si, * The cgi has come to an end, by itself or with a signal... */ - lwsl_wsi_info(wsi, "post_in_expected %d", + if (wsi->http.cgi) + lwsl_wsi_info(wsi, "post_in_expected %d", (int)wsi->http.cgi->post_in_expected); /* * Grace period to handle the incoming stdout */ - lws_sul_schedule(wsi->a.context, wsi->tsi, &wsi->http.cgi->sul_grace, + if (wsi->http.cgi) + lws_sul_schedule(wsi->a.context, wsi->tsi, &wsi->http.cgi->sul_grace, lws_cgi_grace, 1 * LWS_US_PER_SEC); } @@ -907,7 +909,7 @@ lws_cgi_kill(struct lws *wsi) { struct lws_cgi_args args; pid_t pid; - int n, m; + int n, m = 0; if (!wsi->http.cgi || !wsi->http.cgi->lsp) return 0; @@ -919,7 +921,8 @@ lws_cgi_kill(struct lws *wsi) /* that has invalidated and NULL'd wsi->http.cgi->lsp */ if (pid != -1) { - m = wsi->http.cgi->being_closed; + if (wsi->http.cgi) + m = wsi->http.cgi->being_closed; n = user_callback_handle_rxflow(wsi->a.protocol->callback, wsi, LWS_CALLBACK_CGI_TERMINATED, wsi->user_space, (void *)&args, diff --git a/lib/roles/h1/ops-h1.c b/lib/roles/h1/ops-h1.c index 4590a497..769490fe 100644 --- a/lib/roles/h1/ops-h1.c +++ b/lib/roles/h1/ops-h1.c @@ -292,9 +292,11 @@ ws_mode: // assert(0); /* fallthru */ + case LRS_WAITING_CONNECT: /* observed on warmcat.com */ + break; + default: lwsl_err("%s: Unhandled state %d\n", __func__, lwsi_state(wsi)); - assert(0); goto bail; } diff --git a/lib/roles/h2/http2.c b/lib/roles/h2/http2.c index a09b97fc..58e7c107 100644 --- a/lib/roles/h2/http2.c +++ b/lib/roles/h2/http2.c @@ -431,6 +431,12 @@ lws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pps) struct lws *nwsi = lws_get_network_wsi(wsi); struct lws_h2_netconn *h2n = nwsi->h2.h2n; + if (!h2n) { + lwsl_warn("%s: null h2n\n", __func__); + lws_free(pps); + return; + } + pps->next = h2n->pps; h2n->pps = pps; lws_rx_flow_control(wsi, LWS_RXFLOW_REASON_APPLIES_DISABLE | diff --git a/lib/roles/h2/ops-h2.c b/lib/roles/h2/ops-h2.c index 989cb5b9..0f76d171 100644 --- a/lib/roles/h2/ops-h2.c +++ b/lib/roles/h2/ops-h2.c @@ -797,9 +797,9 @@ static int lws_h2_bind_for_post_before_action(struct lws *wsi) { const struct lws_http_mount *hit; + int uri_len = 0, methidx; char *uri_ptr = NULL; uint8_t *buffered; - int uri_len = 0; const char *p; size_t blen; @@ -850,7 +850,10 @@ lws_h2_bind_for_post_before_action(struct lws *wsi) if (lws_bind_protocol(wsi, pp, __func__)) return 1; } - if (lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len) >= 0) + + methidx = lws_http_get_uri_and_method(wsi, &uri_ptr, &uri_len); + + if (methidx >= 0) if (wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP, wsi->user_space, hit ? uri_ptr + @@ -860,6 +863,10 @@ lws_h2_bind_for_post_before_action(struct lws *wsi) uri_len))) return 1; +#if defined(LWS_WITH_ACCESS_LOG) + lws_prepare_access_log_info(wsi, uri_ptr, uri_len, methidx); +#endif + lwsl_info("%s: setting LRS_BODY from 0x%x (%s)\n", __func__, (int)wsi->wsistate, wsi->a.protocol->name); diff --git a/lib/roles/http/compression/stream.c b/lib/roles/http/compression/stream.c index 9898b76f..d4c72aa4 100644 --- a/lib/roles/http/compression/stream.c +++ b/lib/roles/http/compression/stream.c @@ -65,7 +65,7 @@ lws_http_compression_apply(struct lws *wsi, const char *name, for (n = 0; n < LWS_ARRAY_SIZE(lcs_available); n++) { /* if name is non-NULL, choose only that compression method */ - if (name && !strcmp(lcs_available[n]->encoding_name, name)) + if (name && strcmp(lcs_available[n]->encoding_name, name)) continue; /* * If we're the server, confirm that the client told us he could diff --git a/lib/roles/http/cookie.c b/lib/roles/http/cookie.c index 03b88ae0..1860e87d 100644 --- a/lib/roles/http/cookie.c +++ b/lib/roles/http/cookie.c @@ -281,6 +281,7 @@ static int lws_cookie_write_nsc(struct lws *wsi, struct lws_cookie *c) { char cache_name[LWS_COOKIE_MAX_CACHE_NAME_LEN]; + const char *ads, *path; struct lws_cache_ttl_lru *l1; struct client_info_stash *stash; char *cookie_string = NULL, *dl; @@ -297,11 +298,16 @@ lws_cookie_write_nsc(struct lws *wsi, struct lws_cookie *c) return -1; stash = wsi->stash ? wsi->stash : lws_get_network_wsi(wsi)->stash; - if (!stash || !stash->cis[CIS_ADDRESS] || - !stash->cis[CIS_PATH]) + if (stash) { + ads = stash->cis[CIS_ADDRESS]; + path = stash->cis[CIS_PATH]; + } else { + ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS); + path = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI); + } + if (!ads || !path) return -1; - if (!c->f[CE_NAME] || !c->f[CE_VALUE]) { lwsl_err("%s: malformed c\n", __func__); @@ -320,13 +326,13 @@ lws_cookie_write_nsc(struct lws *wsi, struct lws_cookie *c) if (!c->f[CE_DOMAIN]) { c->f[CE_HOSTONLY] = "T"; c->l[CE_HOSTONLY] = 1; - c->f[CE_DOMAIN] = stash->cis[CIS_ADDRESS]; - c->l[CE_DOMAIN] = strlen(c->f[CE_DOMAIN]); + c->f[CE_DOMAIN] = ads; + c->l[CE_DOMAIN] = strlen(ads); } if (!c->f[CE_PATH]) { - c->f[CE_PATH] = stash->cis[CIS_PATH]; - c->l[CE_PATH] = strlen(c->f[CE_PATH]); + c->f[CE_PATH] = path; + c->l[CE_PATH] = strlen(path); dl = memchr(c->f[CE_PATH], '?', c->l[CE_PATH]); if (dl) c->l[CE_PATH] = (size_t)(dl - c->f[CE_PATH]); diff --git a/lib/roles/http/header.c b/lib/roles/http/header.c index b0d54776..032bf6bd 100644 --- a/lib/roles/http/header.c +++ b/lib/roles/http/header.c @@ -78,10 +78,15 @@ lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name, (void)wsi; #endif if (name) { - while (*p < end && *name) + char has_colon = 0; + while (*p < end && *name) { + has_colon = has_colon || *name == ':'; *((*p)++) = *name++; - if (*p == end) + } + if (*p + (has_colon ? 1 : 2) >= end) return 1; + if (!has_colon) + *((*p)++) = ':'; *((*p)++) = ' '; } if (*p + length + 3 >= end) diff --git a/lib/roles/http/server/lejp-conf.c b/lib/roles/http/server/lejp-conf.c index 98392d4a..0f979cf2 100644 --- a/lib/roles/http/server/lejp-conf.c +++ b/lib/roles/http/server/lejp-conf.c @@ -71,7 +71,6 @@ enum lejp_global_paths { static const char * const paths_vhosts[] = { "vhosts[]", - "vhosts[].mounts[]", "vhosts[].name", "vhosts[].port", "vhosts[].interface", @@ -89,13 +88,17 @@ static const char * const paths_vhosts[] = { "vhosts[].mounts[].auth-mask", "vhosts[].mounts[].cgi-timeout", "vhosts[].mounts[].cgi-env[].*", + "vhosts[].mounts[].cgi-env[]", "vhosts[].mounts[].cache-max-age", "vhosts[].mounts[].cache-reuse", "vhosts[].mounts[].cache-revalidate", "vhosts[].mounts[].basic-auth", "vhosts[].mounts[].cache-intermediaries", "vhosts[].mounts[].extra-mimetypes.*", + "vhosts[].mounts[].extra-mimetypes", "vhosts[].mounts[].interpret.*", + "vhosts[].mounts[].interpret", + "vhosts[].mounts[]", "vhosts[].ws-protocols[].*.*", "vhosts[].ws-protocols[].*", "vhosts[].ws-protocols[]", @@ -108,6 +111,7 @@ static const char * const paths_vhosts[] = { "vhosts[].ssl-option-set", "vhosts[].ssl-option-clear", "vhosts[].mounts[].pmo[].*", + "vhosts[].mounts[].pmo[]", "vhosts[].headers[].*", "vhosts[].headers[]", "vhosts[].client-ssl-key", @@ -140,7 +144,6 @@ static const char * const paths_vhosts[] = { enum lejp_vhost_paths { LEJPVP, - LEJPVP_MOUNTS, LEJPVP_NAME, LEJPVP_PORT, LEJPVP_INTERFACE, @@ -158,13 +161,19 @@ enum lejp_vhost_paths { LEJPVP_DEFAULT_AUTH_MASK, LEJPVP_CGI_TIMEOUT, LEJPVP_CGI_ENV, + LEJPVP_CGI_ENV_base, LEJPVP_MOUNT_CACHE_MAX_AGE, LEJPVP_MOUNT_CACHE_REUSE, LEJPVP_MOUNT_CACHE_REVALIDATE, LEJPVP_MOUNT_BASIC_AUTH, LEJPVP_MOUNT_CACHE_INTERMEDIARIES, LEJPVP_MOUNT_EXTRA_MIMETYPES, + LEJPVP_MOUNT_EXTRA_MIMETYPES_base, LEJPVP_MOUNT_INTERPRET, + LEJPVP_MOUNT_INTERPRET_base, + + LEJPVP_MOUNTS, + LEJPVP_PROTOCOL_NAME_OPT, LEJPVP_PROTOCOL_NAME, LEJPVP_PROTOCOL, @@ -177,6 +186,7 @@ enum lejp_vhost_paths { LEJPVP_SSL_OPTION_SET, LEJPVP_SSL_OPTION_CLEAR, LEJPVP_PMO, + LEJPVP_PM_baseO, LEJPVP_HEADERS_NAME, LEJPVP_HEADERS, LEJPVP_CLIENT_SSL_KEY, @@ -937,6 +947,8 @@ lwsws_get_config(void *user, const char *f, const char * const *paths, struct lejp_ctx ctx; int n, m = 0, fd; + memset(&ctx, 0, sizeof(ctx)); + fd = lws_open(f, O_RDONLY); if (fd < 0) { lwsl_err("Cannot open %s\n", f); diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index c7eb94c3..c98bf0d6 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -1252,8 +1252,9 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit, struct lws_client_connect_info i; struct lws *cwsi; int n, na; - unsigned int max_http_header_data = wsi->a.context->max_http_header_data > 256 ? wsi->a.context->max_http_header_data : 256; - char rpath[max_http_header_data]; + unsigned int max_http_header_data = wsi->a.context->max_http_header_data > 256 ? + wsi->a.context->max_http_header_data : 256; + char *rpath = NULL; #if defined(LWS_ROLE_WS) if (ws) @@ -1320,6 +1321,12 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit, if (pcolon) i.port = atoi(pcolon + 1); + rpath = lws_malloc(max_http_header_data, __func__); + if (!rpath) + return -1; + + /* rpath needs cleaning after this... ---> */ + n = lws_snprintf(rpath, max_http_header_data - 1, "/%s/%s", pslash + 1, uri_ptr + hit->mountpoint_len) - 1; lws_clean_url(rpath); @@ -1341,7 +1348,7 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit, lwsl_info("%s: query string %d longer " "than we can handle\n", __func__, na); - + lws_free(rpath); return -1; } @@ -1371,9 +1378,8 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit, #endif { n = lws_hdr_total_length(wsi, WSI_TOKEN_HOST); - if (n > 0) { + if (n > 0) i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST); - } } #if 0 @@ -1467,9 +1473,10 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit, "The server is temporarily unable to service " "your request due to maintenance downtime or " "capacity problems. Please try again later."); - + lws_free(rpath); return 1; } + lws_free(rpath); lwsl_info("%s: setting proxy clientside on %s (parent %s)\n", __func__, lws_wsi_tag(cwsi), lws_wsi_tag(lws_get_parent(cwsi))); diff --git a/lib/roles/mqtt/mqtt.c b/lib/roles/mqtt/mqtt.c index 67d64dbc..aaac84b8 100644 --- a/lib/roles/mqtt/mqtt.c +++ b/lib/roles/mqtt/mqtt.c @@ -214,13 +214,6 @@ static const uint8_t map_flags[] = { LMQCP_LUT_FLAG_PACKET_ID_NONE | 0x00, }; -void -lws_mqttc_state_transition(lws_mqttc_t *c, lwsgs_mqtt_states_t s) -{ - lwsl_debug("%s: ep %p: state %d -> %d\n", __func__, c, c->estate, s); - c->estate = s; -} - static int lws_mqtt_pconsume(lws_mqtt_parser_t *par, int consumed) { @@ -277,74 +270,6 @@ lws_mqtt_set_client_established(struct lws *wsi) return 0; } - -static lws_mqtt_match_topic_return_t -lws_mqtt_is_topic_matched(const char* sub, const char* pub) -{ - const char *ppos = pub, *spos = sub; - - if (!ppos || !spos) { - return LMMTR_TOPIC_MATCH_ERROR; - } - - while (*spos) { - if (*ppos == '#' || *ppos == '+') { - lwsl_err("%s: PUBLISH to wildcard " - "topic \"%s\" not supported\n", - __func__, pub); - return LMMTR_TOPIC_MATCH_ERROR; - } - /* foo/+/bar == foo/xyz/bar ? */ - if (*spos == '+') { - /* Skip ahead */ - while (*ppos != '\0' && *ppos != '/') { - ppos++; - } - } else if (*spos == '#') { - return LMMTR_TOPIC_MATCH; - } else { - if (*ppos == '\0') { - /* foo/bar == foo/bar/# ? */ - if (!strncmp(spos, "/#", 2)) - return LMMTR_TOPIC_MATCH; - return LMMTR_TOPIC_NOMATCH; - /* Non-matching character */ - } else if (*ppos != *spos) { - return LMMTR_TOPIC_NOMATCH; - } - ppos++; - } - spos++; - } - - if (*spos == '\0' && *ppos == '\0') - return LMMTR_TOPIC_MATCH; - - return LMMTR_TOPIC_NOMATCH; -} - -lws_mqtt_subs_t* lws_mqtt_find_sub(struct _lws_mqtt_related* mqtt, - const char* ptopic) { - lws_mqtt_subs_t *s = mqtt->subs_head; - - while (s) { - /* SUB topic == PUB topic ? */ - /* foo/bar/xyz == foo/bar/xyz ? */ - if (!s->wildcard) { - if (!strcmp((const char*)s->topic, ptopic)) - return s; - } else { - if (lws_mqtt_is_topic_matched( - s->topic, ptopic) == LMMTR_TOPIC_MATCH) - return s; - } - - s = s->next; - } - - return NULL; -} - static lws_mqtt_validate_topic_return_t lws_mqtt_validate_topic(const char *topic, size_t topiclen, uint8_t awsiot) { @@ -477,6 +402,126 @@ lws_mqtt_client_remove_subs(struct _lws_mqtt_related *mqtt) return 1; } +/* + * This fires if the wsi did a PUBLISH under QoS1 or QoS2, but no PUBACK or + * PUBREC came before the timeout period + */ + +static void +lws_mqtt_publish_resend(struct lws_sorted_usec_list *sul) +{ + struct _lws_mqtt_related *mqtt = lws_container_of(sul, + struct _lws_mqtt_related, sul_qos_puback_pubrec_wait); + + lwsl_notice("%s: %s\n", __func__, lws_wsi_tag(mqtt->wsi)); + + if (mqtt->wsi->a.protocol->callback(mqtt->wsi, LWS_CALLBACK_MQTT_RESEND, + mqtt->wsi->user_space, NULL, 0)) + lws_set_timeout(mqtt->wsi, 1, LWS_TO_KILL_ASYNC); +} + +static void +lws_mqtt_unsuback_timeout(struct lws_sorted_usec_list *sul) +{ + struct _lws_mqtt_related *mqtt = lws_container_of(sul, + struct _lws_mqtt_related, sul_unsuback_wait); + + lwsl_debug("%s: %s\n", __func__, lws_wsi_tag(mqtt->wsi)); + + if (mqtt->wsi->a.protocol->callback(mqtt->wsi, + LWS_CALLBACK_MQTT_UNSUBSCRIBE_TIMEOUT, + mqtt->wsi->user_space, NULL, 0)) + lws_set_timeout(mqtt->wsi, 1, LWS_TO_KILL_ASYNC); +} + +static void +lws_mqtt_shadow_timeout(struct lws_sorted_usec_list *sul) +{ + struct _lws_mqtt_related *mqtt = lws_container_of(sul, + struct _lws_mqtt_related, sul_shadow_wait); + + lwsl_debug("%s: %s\n", __func__, lws_wsi_tag(mqtt->wsi)); + + if (mqtt->wsi->a.protocol->callback(mqtt->wsi, + LWS_CALLBACK_MQTT_SHADOW_TIMEOUT, + mqtt->wsi->user_space, NULL, 0)) + lws_set_timeout(mqtt->wsi, 1, LWS_TO_KILL_ASYNC); +} + +void +lws_mqttc_state_transition(lws_mqttc_t *c, lwsgs_mqtt_states_t s) +{ + lwsl_debug("%s: ep %p: state %d -> %d\n", __func__, c, c->estate, s); + c->estate = s; +} + +lws_mqtt_match_topic_return_t +lws_mqtt_is_topic_matched(const char* sub, const char* pub) +{ + const char *ppos = pub, *spos = sub; + + if (!ppos || !spos) { + return LMMTR_TOPIC_MATCH_ERROR; + } + + while (*spos) { + if (*ppos == '#' || *ppos == '+') { + lwsl_err("%s: PUBLISH to wildcard " + "topic \"%s\" not supported\n", + __func__, pub); + return LMMTR_TOPIC_MATCH_ERROR; + } + /* foo/+/bar == foo/xyz/bar ? */ + if (*spos == '+') { + /* Skip ahead */ + while (*ppos != '\0' && *ppos != '/') { + ppos++; + } + } else if (*spos == '#') { + return LMMTR_TOPIC_MATCH; + } else { + if (*ppos == '\0') { + /* foo/bar == foo/bar/# ? */ + if (!strncmp(spos, "/#", 2)) + return LMMTR_TOPIC_MATCH; + return LMMTR_TOPIC_NOMATCH; + /* Non-matching character */ + } else if (*ppos != *spos) { + return LMMTR_TOPIC_NOMATCH; + } + ppos++; + } + spos++; + } + + if (*spos == '\0' && *ppos == '\0') + return LMMTR_TOPIC_MATCH; + + return LMMTR_TOPIC_NOMATCH; +} + +lws_mqtt_subs_t* lws_mqtt_find_sub(struct _lws_mqtt_related* mqtt, + const char* ptopic) { + lws_mqtt_subs_t *s = mqtt->subs_head; + + while (s) { + /* SUB topic == PUB topic ? */ + /* foo/bar/xyz == foo/bar/xyz ? */ + if (!s->wildcard) { + if (!strcmp((const char*)s->topic, ptopic)) + return s; + } else { + if (lws_mqtt_is_topic_matched( + s->topic, ptopic) == LMMTR_TOPIC_MATCH) + return s; + } + + s = s->next; + } + + return NULL; +} + int _lws_mqtt_rx_parser(struct lws *wsi, lws_mqtt_parser_t *par, const uint8_t *buf, size_t len) @@ -1908,38 +1953,6 @@ lws_mqtt_fill_fixed_header(uint8_t *p, lws_mqtt_control_packet_t ctrl_pkt_type, return 0; } -/* - * This fires if the wsi did a PUBLISH under QoS1 or QoS2, but no PUBACK or - * PUBREC came before the timeout period - */ - -static void -lws_mqtt_publish_resend(struct lws_sorted_usec_list *sul) -{ - struct _lws_mqtt_related *mqtt = lws_container_of(sul, - struct _lws_mqtt_related, sul_qos_puback_pubrec_wait); - - lwsl_notice("%s: %s\n", __func__, lws_wsi_tag(mqtt->wsi)); - - if (mqtt->wsi->a.protocol->callback(mqtt->wsi, LWS_CALLBACK_MQTT_RESEND, - mqtt->wsi->user_space, NULL, 0)) - lws_set_timeout(mqtt->wsi, 1, LWS_TO_KILL_ASYNC); -} - -static void -lws_mqtt_unsuback_timeout(struct lws_sorted_usec_list *sul) -{ - struct _lws_mqtt_related *mqtt = lws_container_of(sul, - struct _lws_mqtt_related, sul_unsuback_wait); - - lwsl_debug("%s: %s\n", __func__, lws_wsi_tag(mqtt->wsi)); - - if (mqtt->wsi->a.protocol->callback(mqtt->wsi, - LWS_CALLBACK_MQTT_UNSUBSCRIBE_TIMEOUT, - mqtt->wsi->user_space, NULL, 0)) - lws_set_timeout(mqtt->wsi, 1, LWS_TO_KILL_ASYNC); -} - int lws_mqtt_client_send_publish(struct lws *wsi, lws_mqtt_publish_param_t *pub, const void *buf, uint32_t len, int is_complete) @@ -1982,7 +1995,7 @@ lws_mqtt_client_send_publish(struct lws *wsi, lws_mqtt_publish_param_t *pub, * payload (if any) */ if (lws_mqtt_fill_fixed_header(p++, LMQCP_PUBLISH, - 0, pub->qos, 0)) { + pub->dup, pub->qos, pub->retain)) { lwsl_err("%s: Failed to fill fixed header\n", __func__); return 1; } @@ -2027,7 +2040,9 @@ lws_mqtt_client_send_publish(struct lws *wsi, lws_mqtt_publish_param_t *pub, /* Packet ID */ if (pub->qos != QOS0) { p = lws_mqtt_str_next(&mqtt_vh_payload, NULL); - wsi->mqtt->ack_pkt_id = pub->packet_id = ++nwsi->mqtt->pkt_id; + if (!pub->dup) + nwsi->mqtt->pkt_id++; + wsi->mqtt->ack_pkt_id = pub->packet_id = nwsi->mqtt->pkt_id; lwsl_debug("%s: pkt_id = %d\n", __func__, (int)wsi->mqtt->ack_pkt_id); lws_ser_wu16be(p, pub->packet_id); @@ -2091,6 +2106,13 @@ do_write: 3 * LWS_USEC_PER_SEC); } + if (wsi->mqtt->inside_shadow) { + wsi->mqtt->sul_shadow_wait.cb = lws_mqtt_shadow_timeout; + __lws_sul_insert_us(&pt->pt_sul_owner[wsi->conn_validity_wakesuspend], + &wsi->mqtt->sul_shadow_wait, + 60 * LWS_USEC_PER_SEC); + } + return 0; } @@ -2215,6 +2237,8 @@ lws_mqtt_client_send_subcribe(struct lws *wsi, lws_mqtt_subscribe_param_t *sub) (int)sub->packet_id); lws_ser_wu16be(p, wsi->mqtt->ack_pkt_id); + nwsi->mqtt->client.aws_iot = wsi->mqtt->client.aws_iot; + if (lws_mqtt_str_advance(&mqtt_vh_payload, 2)) return 1; @@ -2383,6 +2407,8 @@ lws_mqtt_client_send_unsubcribe(struct lws *wsi, (int)wsi->mqtt->ack_pkt_id); lws_ser_wu16be(p, wsi->mqtt->ack_pkt_id); + nwsi->mqtt->client.aws_iot = wsi->mqtt->client.aws_iot; + if (lws_mqtt_str_advance(&mqtt_vh_payload, 2)) return 1; diff --git a/lib/roles/mqtt/private-lib-roles-mqtt.h b/lib/roles/mqtt/private-lib-roles-mqtt.h index d89f3718..dc46a936 100644 --- a/lib/roles/mqtt/private-lib-roles-mqtt.h +++ b/lib/roles/mqtt/private-lib-roles-mqtt.h @@ -45,6 +45,7 @@ extern struct lws_role_ops role_ops_mqtt; #define LWS_MQTT_RESPONSE_TIMEOUT (3 * LWS_US_PER_SEC) #define LWS_MQTT_RETRY_CEILING (60 * LWS_US_PER_SEC) +#define LWS_MQTT_MAX_PUBLISH_RETRY (3) typedef enum { LMSPR_COMPLETED = 0, @@ -354,8 +355,9 @@ struct _lws_mqtt_related { lws_mqttc_t client; lws_sorted_usec_list_t sul_qos_puback_pubrec_wait; /* QoS1 puback or QoS2 pubrec wait TO */ lws_sorted_usec_list_t sul_qos1_puback_wait; /* QoS1 puback wait TO */ - lws_sorted_usec_list_t sul_unsuback_wait; /* QoS1 unsuback wait TO */ + lws_sorted_usec_list_t sul_unsuback_wait; /* unsuback wait TO */ lws_sorted_usec_list_t sul_qos2_pubrec_wait; /* QoS2 pubrec wait TO */ + lws_sorted_usec_list_t sul_shadow_wait; /* Device Shadow wait TO */ struct lws *wsi; /**< so sul can use lws_container_of */ lws_mqtt_subs_t *subs_head; /**< Linked-list of heap-allocated subscription objects */ void *rx_cpkt_param; @@ -382,6 +384,9 @@ struct _lws_mqtt_related { uint8_t done_subscribe:1; uint8_t done_birth:1; + uint8_t inside_shadow:1; + uint8_t done_shadow_subscribe:1; + uint8_t send_shadow_unsubscribe:1; }; /* @@ -437,5 +442,8 @@ lws_wsi_mqtt_adopt(struct lws *parent_wsi, struct lws *wsi); lws_mqtt_subs_t * lws_mqtt_find_sub(struct _lws_mqtt_related *mqtt, const char *topic); +lws_mqtt_match_topic_return_t +lws_mqtt_is_topic_matched(const char* sub, const char* pub); + #endif /* _PRIVATE_LIB_ROLES_MQTT */ diff --git a/lib/roles/netlink/ops-netlink.c b/lib/roles/netlink/ops-netlink.c index bb320483..fa3bf29a 100644 --- a/lib/roles/netlink/ops-netlink.c +++ b/lib/roles/netlink/ops-netlink.c @@ -259,6 +259,15 @@ rops_handle_POLLIN_netlink(struct lws_context_per_thread *pt, struct lws *wsi, lwsl_cx_netlink(cx, "RTA_SRC: %s", buf); break; case RTA_DST: + /* check if is local addr -> considering it as src addr too */ + if (rm->rtm_type == RTN_LOCAL && + ((rm->rtm_family == AF_INET && rm->rtm_dst_len == 32) || + (rm->rtm_family == AF_INET6 && rm->rtm_dst_len == 128))) { + lws_sa46_copy_address(&robj.src, RTA_DATA(ra), + rm->rtm_family); + lwsl_cx_netlink(cx, "Local addr: RTA_DST -> added to RTA_SRC"); + } + lws_sa46_copy_address(&robj.dest, RTA_DATA(ra), rm->rtm_family); robj.dest_len = rm->rtm_dst_len; @@ -362,9 +371,8 @@ ana: lws_pt_lock(pt, __func__); /* returns zero on match already in table */ - rmat = _lws_route_remove(pt, &robj, LRR_MATCH_SRC | - LRR_JUST_CHECK | - LRR_IGNORE_PRI); + rmat = _lws_route_remove(pt, &robj, h->nlmsg_type == RTM_NEWROUTE ? + LRR_MATCH_DST : LRR_MATCH_SRC | LRR_IGNORE_PRI); lws_pt_unlock(pt); if (rmat) { @@ -519,12 +527,9 @@ rops_pt_init_destroy_netlink(struct lws_context *context, memset(&sanl, 0, sizeof(sanl)); sanl.nl_family = AF_NETLINK; sanl.nl_pid = (uint32_t)getpid(); - sanl.nl_groups = (1 << (RTNLGRP_LINK - 1)) | - (1 << (RTNLGRP_IPV4_ROUTE - 1)) | - (1 << (RTNLGRP_IPV4_IFADDR - 1)) + sanl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR #if defined(LWS_WITH_IPV6) - | (1 << (RTNLGRP_IPV6_ROUTE - 1)) | - (1 << (RTNLGRP_IPV6_IFADDR - 1)) + | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR #endif ; diff --git a/lib/roles/pipe/ops-pipe.c b/lib/roles/pipe/ops-pipe.c index 4d39d311..ad54a04f 100644 --- a/lib/roles/pipe/ops-pipe.c +++ b/lib/roles/pipe/ops-pipe.c @@ -60,7 +60,7 @@ rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi, return LWS_HPI_RET_PLEASE_CLOSE_ME; #endif -#if defined(LWS_WITH_THREADPOOL) +#if defined(LWS_WITH_THREADPOOL) && defined(LWS_HAVE_PTHREAD_H) /* * threadpools that need to call for on_writable callbacks do it by * marking the task as needing one for its wsi, then cancelling service. diff --git a/lib/roles/raw-skt/ops-raw-skt.c b/lib/roles/raw-skt/ops-raw-skt.c index fd4fd341..453c64e7 100644 --- a/lib/roles/raw-skt/ops-raw-skt.c +++ b/lib/roles/raw-skt/ops-raw-skt.c @@ -24,6 +24,57 @@ #include +#if defined(LWS_WITH_CLIENT) +static int +lws_raw_skt_connect(struct lws *wsi) +{ + int n; +#if defined(LWS_WITH_TLS) + const char *cce = NULL; + char ccebuf[128]; + +#if !defined(LWS_WITH_SYS_ASYNC_DNS) + switch (lws_client_create_tls(wsi, &cce, 1)) { +#else + switch (lws_client_create_tls(wsi, &cce, 0)) { +#endif + case CCTLS_RETURN_ERROR: + lws_inform_client_conn_fail(wsi, (void *)cce, strlen(cce)); + return -1; + case CCTLS_RETURN_RETRY: + return 0; + case CCTLS_RETURN_DONE: + break; + } + + if (wsi->tls.use_ssl & LCCSCF_USE_SSL) { + n = lws_ssl_client_connect2(wsi, ccebuf, sizeof(ccebuf)); + if (n < 0) { + lws_inform_client_conn_fail(wsi, (void *)ccebuf, + strlen(ccebuf)); + + return -1; + } + if (n != 1) + return 0; /* wait */ + } +#endif + + n = user_callback_handle_rxflow(wsi->a.protocol->callback, + wsi, wsi->role_ops->adoption_cb[lwsi_role_server(wsi)], + wsi->user_space, NULL, 0); + if (n) { + lws_inform_client_conn_fail(wsi, (void *)"user", 4); + return 1; + } + + lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); + lwsi_set_state(wsi, LRS_ESTABLISHED); + + return 1; /* success */ +} +#endif + static int rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi, struct lws_pollfd *pollfd) @@ -82,6 +133,14 @@ rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi, case LRS_WAITING_CONNECT: goto nope; + case LRS_WAITING_SSL: +#if defined(LWS_WITH_CLIENT) + n = lws_raw_skt_connect(wsi); + if (n < 0) + goto fail; +#endif + break; + #if defined(LWS_WITH_SOCKS5) /* SOCKS Greeting Reply */ @@ -177,16 +236,21 @@ try_pollout: return LWS_HPI_RET_HANDLED; #if defined(LWS_WITH_CLIENT) - if (lwsi_state(wsi) == LRS_WAITING_CONNECT && - !lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL)) + if (lwsi_state(wsi) == LRS_WAITING_CONNECT) { + if (!lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL)) return LWS_HPI_RET_WSI_ALREADY_DIED; + + if (lws_raw_skt_connect(wsi) < 0) + goto fail; + } #endif + if (lwsi_state(wsi) == LRS_WAITING_SSL) + return LWS_HPI_RET_HANDLED; + /* one shot */ - if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { - lwsl_notice("%s a\n", __func__); + if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) goto fail; - } /* clear back-to-back write detection */ wsi->could_have_pending = 0; diff --git a/lib/secure-streams/README.md b/lib/secure-streams/README.md index b7a9c3d5..5d707aed 100644 --- a/lib/secure-streams/README.md +++ b/lib/secure-streams/README.md @@ -661,6 +661,10 @@ Set the topic this streamtype subscribes to Set the QOS level for this streamtype +### `mqtt_retain` + +Set to true if this streamtype should use MQTT's "retain" feature. + ### `mqtt_keep_alive` 16-bit number representing MQTT keep alive for the stream. diff --git a/lib/secure-streams/policy-common.c b/lib/secure-streams/policy-common.c index b782c1e5..a98abaea 100644 --- a/lib/secure-streams/policy-common.c +++ b/lib/secure-streams/policy-common.c @@ -177,7 +177,7 @@ lws_ss_get_metadata(struct lws_ss_handle *h, const char *name, return 0; } #if defined(LWS_WITH_SS_DIRECT_PROTOCOL_STR) - if (!(h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR)) + if (!(h->policy->flags & LWSSSPOLF_DIRECT_PROTO_STR) || !h->wsi) goto bail; n = lws_http_string_to_known_header(name, strlen(name)); diff --git a/lib/secure-streams/policy-json.c b/lib/secure-streams/policy-json.c index 7e5656f6..e230ce5e 100644 --- a/lib/secure-streams/policy-json.c +++ b/lib/secure-streams/policy-json.c @@ -111,6 +111,7 @@ static const char * const lejp_tokens_policy[] = { "s[].*.mqtt_topic", "s[].*.mqtt_subscribe", "s[].*.mqtt_qos", + "s[].*.mqtt_retain", "s[].*.mqtt_keep_alive", "s[].*.mqtt_clean_start", "s[].*.mqtt_will_topic", @@ -218,6 +219,7 @@ typedef enum { LSSPPT_MQTT_TOPIC, LSSPPT_MQTT_SUBSCRIBE, LSSPPT_MQTT_QOS, + LSSPPT_MQTT_RETAIN, LSSPPT_MQTT_KEEPALIVE, LSSPPT_MQTT_CLEAN_START, LSSPPT_MQTT_WILL_TOPIC, @@ -1020,6 +1022,11 @@ lws_ss_policy_parser_cb(struct lejp_ctx *ctx, char reason) a->curr[LTY_POLICY].p->u.mqtt.qos = (uint8_t)atoi(ctx->buf); break; + case LSSPPT_MQTT_RETAIN: + a->curr[LTY_POLICY].p->u.mqtt.retain = + reason == LEJPCB_VAL_TRUE; + break; + case LSSPPT_MQTT_KEEPALIVE: a->curr[LTY_POLICY].p->u.mqtt.keep_alive = (uint16_t)atoi(ctx->buf); break; diff --git a/lib/secure-streams/private-lib-secure-streams.h b/lib/secure-streams/private-lib-secure-streams.h index 6af59e47..cc2fc4cf 100644 --- a/lib/secure-streams/private-lib-secure-streams.h +++ b/lib/secure-streams/private-lib-secure-streams.h @@ -147,10 +147,15 @@ typedef struct lws_ss_handle { lws_mqtt_topic_elem_t topic_qos; lws_mqtt_topic_elem_t sub_top; lws_mqtt_subscribe_param_t sub_info; + lws_mqtt_subscribe_param_t shadow_sub; /* allocation that must be destroyed with conn */ void *heap_baggage; const char *subscribe_to; size_t subscribe_to_len; + struct lws_buflist *buflist_unacked; + uint32_t unacked_size; + uint8_t retry_count; + uint8_t send_unacked:1; } mqtt; #endif #if defined(LWS_WITH_SYS_SMD) diff --git a/lib/secure-streams/protocols/ss-h1.c b/lib/secure-streams/protocols/ss-h1.c index 9bfed470..d9ffe852 100644 --- a/lib/secure-streams/protocols/ss-h1.c +++ b/lib/secure-streams/protocols/ss-h1.c @@ -283,7 +283,7 @@ lws_apply_instant_metadata(lws_ss_handle_t *h, struct lws *wsi, uint8_t *buf, lwsl_debug("%s add header %s %s %d\n", __func__, imd->name, (char *)imd->value__may_own_heap, - imd->length); + (int)imd->length); if (lws_add_http_header_by_name(wsi, (const unsigned char *)imd->name, (const unsigned char *)imd->value__may_own_heap, @@ -467,16 +467,17 @@ secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user, r = lws_ss_event_helper(h, LWSSSCS_DISCONNECTED); if (r != LWSSSSRET_OK) return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); - } - /* already disconnected, no action for DISCONNECT_ME */ - r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE); - if (r) { - if (h->inside_connect) { - h->pending_ret = r; - break; - } + } else { + /* already disconnected, no action for DISCONNECT_ME */ + r = lws_ss_event_helper(h, LWSSSCS_UNREACHABLE); + if (r) { + if (h->inside_connect) { + h->pending_ret = r; + break; + } - return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); + return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); + } } h->wsi = NULL; @@ -560,6 +561,8 @@ secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user, return -1; lws_ss_assert_extant(wsi->a.context, wsi->tsi, h); + h->wsi = wsi; /* since we accept the wsi is bound to the SS, + * ensure the SS feels the same way about the wsi */ #if defined(LWS_WITH_CONMON) if (wsi->conmon.pcol == LWSCONMON_PCOL_NONE) { @@ -863,6 +866,8 @@ malformed: // lwsl_notice("%s: HTTP_READ: client side sent len %d fl 0x%x\n", // __func__, (int)len, (int)f); + h->wsi = wsi; /* since we accept the wsi is bound to the SS, + * ensure the SS feels the same way about the wsi */ r = h->info.rx(ss_to_userobj(h), (const uint8_t *)in, len, f); if (r != LWSSSSRET_OK) return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); diff --git a/lib/secure-streams/protocols/ss-h2.c b/lib/secure-streams/protocols/ss-h2.c index 3d1aa9c2..910067ab 100644 --- a/lib/secure-streams/protocols/ss-h2.c +++ b/lib/secure-streams/protocols/ss-h2.c @@ -52,7 +52,7 @@ secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user, */ lwsl_info("%s: reporting initial tx cr from server %d\n", __func__, wsi->txc.tx_cr); - ss_proxy_onward_txcr((void *)&h[1], wsi->txc.tx_cr); + ss_proxy_onward_txcr((void *)(h + 1), wsi->txc.tx_cr); } #endif @@ -106,7 +106,7 @@ secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user, #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) if (h->being_serialized) /* we are the proxy-side SS for a remote client */ - ss_proxy_onward_txcr((void *)&h[1], (int)len); + ss_proxy_onward_txcr((void *)(h + 1), (int)len); #endif break; diff --git a/lib/secure-streams/protocols/ss-mqtt.c b/lib/secure-streams/protocols/ss-mqtt.c index f13eea4a..8698bee4 100644 --- a/lib/secure-streams/protocols/ss-mqtt.c +++ b/lib/secure-streams/protocols/ss-mqtt.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2019 - 2021 Andy Green + * Copyright (C) 2019 - 2022 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -44,6 +44,7 @@ secstream_mqtt_cleanup(lws_ss_handle_t *h) lws_free(h->u.mqtt.sub_info.topic); h->u.mqtt.sub_info.topic = NULL; } + lws_buflist_destroy_all_segments(&h->u.mqtt.buflist_unacked); } static int @@ -141,9 +142,10 @@ secstream_mqtt_subscribe(struct lws *wsi) } static int -secstream_mqtt_publish(struct lws *wsi, uint8_t *buf, size_t buflen, - const char* topic, - lws_mqtt_qos_levels_t qos, int f) +secstream_mqtt_publish(struct lws *wsi, uint8_t *buf, size_t buf_len, + uint32_t payload_len, const char* topic, + lws_mqtt_qos_levels_t qos, uint8_t retain, uint8_t dup, + int f) { lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); size_t used_in, used_out, topic_limit; @@ -187,26 +189,290 @@ secstream_mqtt_publish(struct lws *wsi, uint8_t *buf, size_t buflen, mqpp.topic_len = (uint16_t)strlen(mqpp.topic); mqpp.packet_id = (uint16_t)(h->txord - 1); + mqpp.qos = qos; + mqpp.retain = !!retain; mqpp.payload = buf; - if (h->writeable_len) - mqpp.payload_len = (uint32_t)h->writeable_len; + mqpp.dup = !!dup; + if (payload_len) + mqpp.payload_len = payload_len; else - mqpp.payload_len = (uint32_t)buflen; + mqpp.payload_len = (uint32_t)buf_len; lwsl_notice("%s: payload len %d\n", __func__, (int)mqpp.payload_len); - mqpp.qos = h->policy->u.mqtt.qos; - if (lws_mqtt_client_send_publish(wsi, &mqpp, (const char *)buf, - (uint32_t)buflen, + (uint32_t)buf_len, f & LWSSS_FLAG_EOM)) { lwsl_notice("%s: failed to publish\n", __func__); lws_free(expbuf); return -1; } lws_free(expbuf); + + if ((mqpp.qos == QOS1 || mqpp.qos == QOS2) && buf_len > 0) { + if (lws_buflist_append_segment(&h->u.mqtt.buflist_unacked, + buf, buf_len) < 0) { + lwsl_notice("%s: failed to store unacked\n", __func__); + return -1; + } + } + + return 0; +} + +static int +secstream_mqtt_birth(struct lws *wsi, uint8_t *buf, size_t buflen) { + lws_strexp_t exp; + size_t used_in, used_out = 0; + lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); + + if (h->policy->u.mqtt.birth_message) { + lws_strexp_init(&exp, h, lws_ss_exp_cb_metadata, + (char *)buf, buflen); + if (lws_strexp_expand(&exp, h->policy->u.mqtt.birth_message, + strlen(h->policy->u.mqtt.birth_message), + &used_in, &used_out) != LSTRX_DONE) { + return 1; + } + } + wsi->mqtt->inside_birth = 1; + return secstream_mqtt_publish(wsi, buf, + used_out, 0, h->policy->u.mqtt.birth_topic, + h->policy->u.mqtt.birth_qos, + h->policy->u.mqtt.birth_retain, 0, + LWSSS_FLAG_EOM); +} + +static int +secstream_mqtt_resend(struct lws *wsi, uint8_t *buf) { + uint8_t *buffered; + size_t len; + int f = 0, r; + lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); + + len = lws_buflist_next_segment_len(&h->u.mqtt.buflist_unacked, + &buffered); + + if (h->u.mqtt.unacked_size <= len) + f |= LWSSS_FLAG_EOM; + + if (!len) { + /* when the message does not have payload */ + buffered = buf; + } else { + h->u.mqtt.unacked_size -= (uint32_t)len; + } + + if (wsi->mqtt->inside_birth) { + r = secstream_mqtt_publish(wsi, buffered, len, 0, + h->policy->u.mqtt.birth_topic, + h->policy->u.mqtt.birth_qos, + h->policy->u.mqtt.birth_retain, + 1, f); + } else { + r = secstream_mqtt_publish(wsi, buffered, len, + (uint32_t)h->writeable_len, + h->policy->u.mqtt.topic, + h->policy->u.mqtt.qos, + h->policy->u.mqtt.retain, 1, f); + } + if (len) + lws_buflist_use_segment(&h->u.mqtt.buflist_unacked, len); + + if (r) { + lws_buflist_destroy_all_segments(&h->u.mqtt.buflist_unacked); + h->u.mqtt.retry_count = h->u.mqtt.send_unacked = 0; + + if (wsi->mqtt->inside_birth) { + lwsl_err("%s: %s: failed to send Birth\n", __func__, + lws_ss_tag(h)); + return -1; + } else { + r = lws_ss_event_helper(h, LWSSSCS_QOS_NACK_REMOTE); + if (r != LWSSSSRET_OK) + return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); + } + } + return 0; +} + +static char * +expand_metadata(lws_ss_handle_t *h, const char* str, const char* post, size_t max_len) +{ + lws_strexp_t exp; + char *expbuf = NULL; + size_t used_in = 0, used_out = 0, post_len = 0; + + memset(&exp, 0, sizeof(exp)); + + if (post) + post_len = strlen(post); + + if (post_len > max_len) + return NULL; + + lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, NULL, + max_len - post_len); + + if (lws_strexp_expand(&exp, str, strlen(str), &used_in, + &used_out) != LSTRX_DONE) { + lwsl_err("%s, failed to expand %s", __func__, str); + + return NULL; + } + + expbuf = lws_malloc(used_out + 1 + post_len, __func__); + if (!expbuf) { + lwsl_err("%s, failed to allocate str_exp for %s", __func__, str); + + return NULL; + } + + lws_strexp_init(&exp, (void*)h, lws_ss_exp_cb_metadata, expbuf, + used_out + 1 + post_len); + + if (lws_strexp_expand(&exp, str, strlen(str), &used_in, + &used_out) != LSTRX_DONE) { + lwsl_err("%s, failed to expand str_exp %s\n", __func__, str); + lws_free(expbuf); + + return NULL; + } + if (post) + strcat(expbuf, post); + + return expbuf; +} + +static lws_mqtt_match_topic_return_t +secstream_mqtt_is_shadow_matched(struct lws *wsi, const char *topic) +{ + lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); + const char *match[] = { LWS_MQTT_SHADOW_UNNAMED_TOPIC_MATCH, + LWS_MQTT_SHADOW_NAMED_TOPIC_MATCH }; + char *expbuf = NULL; + unsigned int i = 0; + lws_mqtt_match_topic_return_t ret = LMMTR_TOPIC_NOMATCH; + + if (!topic) + return LMMTR_TOPIC_MATCH_ERROR; + + expbuf = expand_metadata(h, topic, NULL, LWS_MQTT_MAX_AWSIOT_TOPICLEN); + if (!expbuf) { + lwsl_wsi_warn(wsi, "Failed to expand Shadow topic"); + + return LMMTR_TOPIC_MATCH_ERROR; + } + for (i = 0; i < (sizeof(match) / sizeof(match[0])); i++) { + if (lws_mqtt_is_topic_matched( + match[i], expbuf) == LMMTR_TOPIC_MATCH) { + ret = LMMTR_TOPIC_MATCH; + break; + } + } + lws_free(expbuf); + + return ret; +} + +static void +secstream_mqtt_shadow_cleanup(struct lws *wsi) +{ + lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); + uint32_t i = 0; + + for (i = 0; i < h->u.mqtt.shadow_sub.num_topics; i++) + lws_free((void *)h->u.mqtt.shadow_sub.topic[i].name); + + h->u.mqtt.shadow_sub.num_topics = 0; + + if (h->u.mqtt.shadow_sub.topic) { + lws_free(h->u.mqtt.shadow_sub.topic); + h->u.mqtt.shadow_sub.topic = NULL; + } +} + +static lws_ss_state_return_t +secstream_mqtt_shadow_unsubscribe(struct lws *wsi) +{ + lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); + + if (h->u.mqtt.shadow_sub.num_topics == 0) { + wsi->mqtt->send_shadow_unsubscribe = 0; + wsi->mqtt->inside_shadow = 0; + wsi->mqtt->done_shadow_subscribe = 0; + + return LWSSSSRET_OK; + } + + if (lws_mqtt_client_send_unsubcribe(wsi, &h->u.mqtt.shadow_sub)) { + lwsl_wsi_err(wsi, "Failed to send MQTT unsubsribe"); + + return LWSSSSRET_DISCONNECT_ME; + } + /* Expect a UNSUBACK */ + if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { + lwsl_wsi_err(wsi, "Unable to set LWS_POLLIN"); + + return LWSSSSRET_DISCONNECT_ME; + } + wsi->mqtt->send_shadow_unsubscribe = 0; + + return LWSSSSRET_OK; +} + +static int +secstream_mqtt_shadow_subscribe(struct lws *wsi) +{ + lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); + char* expbuf = NULL; + const char *suffixes[] = { LWS_MQTT_SHADOW_RESP_ACCEPTED_STR, + LWS_MQTT_SHADOW_RESP_REJECTED_STR }; + unsigned int i, suffixes_len = sizeof(suffixes) / sizeof(suffixes[0]); + + if (!h->policy->u.mqtt.topic || wsi->mqtt->inside_shadow) + return 0; + + if (h->u.mqtt.shadow_sub.num_topics > 0) + secstream_mqtt_shadow_cleanup(wsi); + + memset(&h->u.mqtt.shadow_sub, 0, sizeof(lws_mqtt_subscribe_param_t)); + h->u.mqtt.shadow_sub.topic = lws_malloc( + sizeof(lws_mqtt_topic_elem_t) * suffixes_len, __func__); + if (!h->u.mqtt.shadow_sub.topic) { + lwsl_ss_err(h, "Failed to allocate Shadow topics"); + return -1; + } + h->u.mqtt.shadow_sub.num_topics = suffixes_len; + for (i = 0; i < suffixes_len; i++) { + expbuf = expand_metadata(h, h->policy->u.mqtt.topic, suffixes[i], + LWS_MQTT_MAX_AWSIOT_TOPICLEN); + if (!expbuf) { + lwsl_ss_err(h, "Failed to allocate Shadow topic"); + secstream_mqtt_shadow_cleanup(wsi); + + return -1; + } + h->u.mqtt.shadow_sub.topic[i].name = expbuf; + h->u.mqtt.shadow_sub.topic[i].qos = h->policy->u.mqtt.qos; + } + h->u.mqtt.shadow_sub.packet_id = (uint16_t)(h->txord - 1); + + if (lws_mqtt_client_send_subcribe(wsi, &h->u.mqtt.shadow_sub)) { + lwsl_wsi_notice(wsi, "Unable to subscribe Shadow topics"); + + return 0; + } + + /* Expect a SUBACK */ + if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { + lwsl_err("%s: Unable to set LWS_POLLIN\n", __func__); + return -1; + } + wsi->mqtt->inside_shadow = 1; + return 0; } @@ -215,12 +481,19 @@ secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); - lws_mqtt_publish_param_t *pmqpp; + size_t used_in = 0, used_out = 0, topic_len = 0; + lws_mqtt_publish_param_t *pmqpp = NULL; + lws_ss_state_return_t r = LWSSSSRET_OK; uint8_t buf[LWS_PRE + 1400]; - lws_ss_state_return_t r; size_t buflen = sizeof(buf) - LWS_PRE; + lws_ss_metadata_t *omd = NULL; + char *sub_topic = NULL; + lws_strexp_t exp; int f = 0; + memset(buf, 0, sizeof(buf)); + memset(&exp, 0, sizeof(exp)); + switch (reason) { /* because we are protocols[0] ... */ @@ -285,6 +558,23 @@ secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user, h->retry = 0; h->seqstate = SSSEQ_CONNECTED; + if (h->policy->u.mqtt.birth_topic && + !wsi->mqtt->done_birth) { + struct lws *nwsi = lws_get_network_wsi(wsi); + lws_start_foreach_ll(struct lws *, w, nwsi->mux.child_list) { + if (w != wsi && + (w->mqtt->done_birth || w->mqtt->inside_birth)) { + /* + * If any Birth was sent out or + * is pending on other stream, + * skip sending Birth. + */ + wsi->mqtt->done_birth = 1; + break; + } + } lws_end_foreach_ll(w, mux.sibling_list); + } + if (!h->policy->u.mqtt.subscribe || !h->policy->u.mqtt.subscribe[0]) { /* @@ -313,6 +603,17 @@ secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user, lws_callback_on_writable(wsi); break; } + + if (h->policy->u.mqtt.birth_topic && + !wsi->mqtt->done_birth) { + /* + * If a Birth is pending on the stream, then make + * sure the Birth is done before signaling the + * user application. + */ + lws_callback_on_writable(wsi); + break; + } lws_sul_cancel(&h->sul); #if defined(LWS_WITH_SYS_METRICS) /* @@ -342,19 +643,91 @@ secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user, h->subseq = 1; + if (wsi->mqtt->inside_shadow) { + /* + * When Shadow is used, the stream receives multiple + * topics including Shadow response, set received + * topic on the metadata + */ + lws_strexp_init(&exp, (void*)h, lws_ss_exp_cb_metadata, + NULL, (size_t)-1); + + if (lws_strexp_expand(&exp, h->policy->u.mqtt.subscribe, + strlen(h->policy->u.mqtt.subscribe), + &used_in, &used_out) != LSTRX_DONE) { + lwsl_err("%s, failed to expand subscribe topic", + __func__); + return -1; + } + omd = lws_ss_get_handle_metadata(h, exp.name); + + if (!omd) { + lwsl_err("%s, failed to find metadata for subscribe", + __func__); + return -1; + } + sub_topic = omd->value__may_own_heap; + topic_len = omd->length; + + _lws_ss_set_metadata(omd, exp.name, + (const void *)pmqpp->topic, + pmqpp->topic_len); + } + r = h->info.rx(ss_to_userobj(h), (const uint8_t *)pmqpp->payload, len, f); + + if (wsi->mqtt->inside_shadow) + _lws_ss_set_metadata(omd, exp.name, &sub_topic, + topic_len); + if (r != LWSSSSRET_OK) return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); + if (wsi->mqtt->inside_shadow) { + size_t acc_n = strlen(LWS_MQTT_SHADOW_RESP_ACCEPTED_STR); + size_t rej_n = strlen(LWS_MQTT_SHADOW_RESP_REJECTED_STR); + uint32_t i; + + for (i = 0; i < h->u.mqtt.shadow_sub.num_topics; i++) { + /* + * received response ('/accepted' or 'rejected') + * and clean up Shadow operation + */ + if (strncmp(h->u.mqtt.shadow_sub.topic[i].name, + pmqpp->topic, pmqpp->topic_len) || + (strlen(pmqpp->topic) < acc_n || + strlen(pmqpp->topic) < rej_n)) + continue; + + if (!strcmp(pmqpp->topic + + (strlen(pmqpp->topic) - acc_n), + LWS_MQTT_SHADOW_RESP_ACCEPTED_STR) || + !strcmp(pmqpp->topic + + (strlen(pmqpp->topic) - rej_n), + LWS_MQTT_SHADOW_RESP_REJECTED_STR)) { + lws_sul_cancel(&wsi->mqtt->sul_shadow_wait); + wsi->mqtt->send_shadow_unsubscribe = 1; + lws_callback_on_writable(wsi); + + return 0; + } + } + } return 0; /* don't passthru */ case LWS_CALLBACK_MQTT_SUBSCRIBED: + if (wsi->mqtt->inside_shadow) { + wsi->mqtt->done_shadow_subscribe = 1; + lws_callback_on_writable(wsi); + + return 0; + } /* - * Stream demanded a subscribe while connecting, once + * Stream demanded a subscribe without a Birth while connecting, once * done notify CONNECTED event to the application. */ - if (wsi->mqtt->done_subscribe == 0) { + if (!wsi->mqtt->done_subscribe && !h->policy->u.mqtt.birth_topic) { lws_sul_cancel(&h->sul); r = lws_ss_event_helper(h, LWSSSCS_CONNECTED); if (r != LWSSSSRET_OK) @@ -366,12 +739,22 @@ secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user, case LWS_CALLBACK_MQTT_ACK: lws_sul_cancel(&h->sul_timeout); + if (h->u.mqtt.send_unacked) { + lws_buflist_destroy_all_segments(&h->u.mqtt.buflist_unacked); + h->u.mqtt.retry_count = h->u.mqtt.send_unacked = 0; + } + if (wsi->mqtt->inside_birth) { /* - * Skip LWSSSCS_QOS_ACK_REMOTE for birth topic. + * Skip LWSSSCS_QOS_ACK_REMOTE for a Birth, notify + * CONNECTED event to the application. */ wsi->mqtt->inside_birth = 0; wsi->mqtt->done_birth = 1; + r = lws_ss_event_helper(h, LWSSSCS_CONNECTED); + if (r != LWSSSSRET_OK) + return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); + lws_callback_on_writable(wsi); break; } r = lws_ss_event_helper(h, LWSSSCS_QOS_ACK_REMOTE); @@ -379,6 +762,36 @@ secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user, return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); break; + case LWS_CALLBACK_MQTT_RESEND: + lws_sul_cancel(&h->sul_timeout); + if (h->u.mqtt.retry_count++ < LWS_MQTT_MAX_PUBLISH_RETRY) { + h->u.mqtt.unacked_size = + (uint32_t)lws_buflist_total_len(&h->u.mqtt.buflist_unacked); + if (h->u.mqtt.unacked_size) { + lwsl_notice("%s: %s: resend unacked message (%d/%d) \n", + __func__, lws_ss_tag(h), + h->u.mqtt.retry_count, + LWS_MQTT_MAX_PUBLISH_RETRY); + h->u.mqtt.send_unacked = 1; + lws_callback_on_writable(wsi); + break; + } + } + + lws_buflist_destroy_all_segments(&h->u.mqtt.buflist_unacked); + h->u.mqtt.retry_count = h->u.mqtt.send_unacked = 0; + + if (wsi->mqtt->inside_birth) { + lwsl_err("%s: %s: failed to send Birth\n", __func__, + lws_ss_tag(h)); + return -1; + } + + r = lws_ss_event_helper(h, LWSSSCS_QOS_NACK_REMOTE); + if (r != LWSSSSRET_OK) + return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); + break; + case LWS_CALLBACK_MQTT_CLIENT_WRITEABLE: { if (!h || !h->info.tx) @@ -393,27 +806,31 @@ secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user, if (!wsi->mqtt->done_subscribe && h->policy->u.mqtt.subscribe) return secstream_mqtt_subscribe(wsi); - if (!wsi->mqtt->done_birth && h->policy->u.mqtt.birth_topic) { - lws_strexp_t exp; - size_t used_in, used_out = 0; - if (h->policy->u.mqtt.birth_message) { - lws_strexp_init(&exp, h, lws_ss_exp_cb_metadata, - (char *)(buf + LWS_PRE), buflen); - if (lws_strexp_expand(&exp, h->policy->u.mqtt.birth_message, - strlen(h->policy->u.mqtt.birth_message), - &used_in, &used_out) != LSTRX_DONE) { - return 1; - } + if (h->u.mqtt.send_unacked) + return secstream_mqtt_resend(wsi, buf + LWS_PRE); + + if (!wsi->mqtt->done_birth && h->policy->u.mqtt.birth_topic) + return secstream_mqtt_birth(wsi, buf + LWS_PRE, buflen); + + if (h->policy->u.mqtt.aws_iot) { + if (secstream_mqtt_is_shadow_matched(wsi, + h->policy->u.mqtt.topic) == LMMTR_TOPIC_MATCH) { + if (!wsi->mqtt->done_shadow_subscribe) + return secstream_mqtt_shadow_subscribe(wsi); + if (wsi->mqtt->send_shadow_unsubscribe) + return secstream_mqtt_shadow_unsubscribe(wsi); } - wsi->mqtt->inside_birth = 1; - return secstream_mqtt_publish(wsi, buf + LWS_PRE, - used_out, h->policy->u.mqtt.birth_topic, - h->policy->u.mqtt.birth_qos, LWSSS_FLAG_EOM); } + r = h->info.tx(ss_to_userobj(h), h->txord++, buf + LWS_PRE, &buflen, &f); - if (r == LWSSSSRET_TX_DONT_SEND) + + if (r == LWSSSSRET_TX_DONT_SEND) { + if (wsi->mqtt->done_shadow_subscribe) { + return secstream_mqtt_shadow_unsubscribe(wsi); + } return 0; + } if (r == LWSSSSRET_DISCONNECT_ME) { lws_mqtt_subscribe_param_t lmsp; @@ -434,27 +851,65 @@ secstream_mqtt(struct lws *wsi, enum lws_callback_reasons reason, void *user, if (r < 0) return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); - return secstream_mqtt_publish(wsi, buf + LWS_PRE, buflen, - h->policy->u.mqtt.topic, - h->policy->u.mqtt.qos, f); + if (secstream_mqtt_publish(wsi, buf + LWS_PRE, buflen, + (uint32_t)h->writeable_len, + h->policy->u.mqtt.topic, + h->policy->u.mqtt.qos, + h->policy->u.mqtt.retain, 0, f) != 0) { + r = lws_ss_event_helper(h, LWSSSCS_QOS_NACK_REMOTE); + if (r != LWSSSSRET_OK) + return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); + } + return 0; } case LWS_CALLBACK_MQTT_UNSUBSCRIBED: { struct lws *nwsi = lws_get_network_wsi(wsi); + + if (wsi->mqtt->inside_shadow) { + secstream_mqtt_shadow_cleanup(wsi); + wsi->mqtt->inside_shadow = 0; + wsi->mqtt->done_shadow_subscribe = 0; + break; + } if (nwsi && (nwsi->mux.child_count == 1)) lws_mqtt_client_send_disconnect(nwsi); return -1; } case LWS_CALLBACK_MQTT_UNSUBSCRIBE_TIMEOUT: + if (!wsi->mqtt) + return -1; + + if (wsi->mqtt->inside_shadow) { + secstream_mqtt_shadow_cleanup(wsi); + wsi->mqtt->inside_shadow = 0; + wsi->mqtt->done_shadow_subscribe = 0; + lwsl_warn("%s: %s: Unsubscribe (Shadow) timeout.\n", + __func__, lws_ss_tag(h)); + break; + } + if (wsi->mqtt->inside_unsubscribe) { - lwsl_warn("%s: %s: Unsubscribe timout.\n", __func__, + lwsl_warn("%s: %s: Unsubscribe timeout.\n", __func__, lws_ss_tag(h)); return -1; } break; + case LWS_CALLBACK_MQTT_SHADOW_TIMEOUT: + if (!wsi->mqtt) + return -1; + + if (wsi->mqtt->inside_shadow) { + lwsl_warn("%s: %s: Shadow timeout.\n", __func__, + lws_ss_tag(h)); + wsi->mqtt->send_shadow_unsubscribe = 1; + lws_callback_on_writable(wsi); + } + break; + default: break; } diff --git a/lib/secure-streams/secure-streams-client.c b/lib/secure-streams/secure-streams-client.c index 76ea9522..075cf965 100644 --- a/lib/secure-streams/secure-streams-client.c +++ b/lib/secure-streams/secure-streams-client.c @@ -84,7 +84,7 @@ lws_sspc_event_helper(lws_sspc_handle_t *h, lws_ss_constate_t cs, return LWSSSSRET_OK; h->h_in_svc = h; - ret = h->ssi.state((void *)((uint8_t *)&h[1]), NULL, cs, flags); + ret = h->ssi.state((void *)((uint8_t *)(h + 1)), NULL, cs, flags); h->h_in_svc = NULL; return ret; @@ -201,7 +201,7 @@ callback_sspc_client(struct lws *wsi, enum lws_callback_reasons reason, { lws_sspc_handle_t *h = (lws_sspc_handle_t *)lws_get_opaque_user_data(wsi); size_t pktsize = wsi->a.context->max_http_header_data; - void *m = (void *)((uint8_t *)&h[1]); + void *m = (void *)((uint8_t *)(h + 1)); uint8_t *pkt = NULL, *p = NULL, *end = NULL; lws_ss_state_return_t r; uint64_t interval; @@ -661,7 +661,7 @@ lws_sspc_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi, ssi->streamtype); memcpy(&h->ssi, ssi, sizeof(*ssi)); - ua = (uint8_t *)&h[1]; + ua = (uint8_t *)(h + 1); memset(ua, 0, ssi->user_alloc); p = (char *)ua + ssi->user_alloc; memcpy(p, ssi->streamtype, strlen(ssi->streamtype) + 1); @@ -1070,7 +1070,7 @@ lws_sspc_cancel_timeout(struct lws_sspc_handle *h) void * lws_sspc_to_user_object(struct lws_sspc_handle *h) { - return (void *)&h[1]; + return (void *)(h + 1); } void diff --git a/lib/secure-streams/secure-streams-process.c b/lib/secure-streams/secure-streams-process.c index d5822b69..552e1d12 100644 --- a/lib/secure-streams/secure-streams-process.c +++ b/lib/secure-streams/secure-streams-process.c @@ -487,6 +487,7 @@ callback_ss_proxy(struct lws *wsi, enum lws_callback_reasons reason, ssi.state = ss_proxy_onward_state; ssi.flags = 0; + // coverity[uninit_use_in_call] n = lws_ss_deserialize_parse(&conn->parser, lws_get_context(wsi), conn->dsh, in, len, &conn->state, conn, &conn->ss, &ssi, 0); diff --git a/lib/secure-streams/secure-streams.c b/lib/secure-streams/secure-streams.c index 489543db..911f7132 100644 --- a/lib/secure-streams/secure-streams.c +++ b/lib/secure-streams/secure-streams.c @@ -136,6 +136,7 @@ const uint32_t ss_state_txn_validity[] = { [LWSSSCS_POLL] = (1 << LWSSSCS_CONNECTING) | (1 << LWSSSCS_TIMEOUT) | + (1 << LWSSSCS_ALL_RETRIES_FAILED) | (1 << LWSSSCS_DESTROYING), [LWSSSCS_ALL_RETRIES_FAILED] = (1 << LWSSSCS_CONNECTING) | @@ -146,11 +147,16 @@ const uint32_t ss_state_txn_validity[] = { (1 << LWSSSCS_TIMEOUT) | #if defined(LWS_ROLE_MQTT) (1 << LWSSSCS_QOS_ACK_REMOTE) | + (1 << LWSSSCS_QOS_NACK_REMOTE) | #endif (1 << LWSSSCS_DESTROYING), [LWSSSCS_QOS_NACK_REMOTE] = (1 << LWSSSCS_DISCONNECTED) | (1 << LWSSSCS_TIMEOUT) | +#if defined(LWS_ROLE_MQTT) + (1 << LWSSSCS_QOS_ACK_REMOTE) | + (1 << LWSSSCS_QOS_NACK_REMOTE) | +#endif (1 << LWSSSCS_DESTROYING), [LWSSSCS_QOS_ACK_LOCAL] = (1 << LWSSSCS_DISCONNECTED) | @@ -614,7 +620,7 @@ lws_smd_ss_cb(void *opaque, lws_smd_class_t _class, lws_ser_wu64be(p + 8, (uint64_t)timestamp); if (h->info.rx) - h->info.rx((void *)&h[1], p, len + LWS_SMD_SS_RX_HEADER_LEN, + h->info.rx((void *)(h + 1), p, len + LWS_SMD_SS_RX_HEADER_LEN, LWSSS_FLAG_SOM | LWSSS_FLAG_EOM); return 0; @@ -634,7 +640,7 @@ lws_ss_smd_tx_cb(lws_sorted_usec_list_t *sul) if (!h->info.tx) return; - n = h->info.tx(&h[1], h->txord++, buf, &len, &flags); + n = h->info.tx((h + 1), h->txord++, buf, &len, &flags); if (n) /* nonzero return means don't want to send anything */ return; @@ -1072,7 +1078,7 @@ lws_ss_create(struct lws_context *context, int tsi, const lws_ss_info_t *ssi, h->proxy_onward = 1; /* start of overallocated area */ - p = (char *)&h[1]; + p = (char *)(h + 1); /* set the handle pointer in the user data struct */ v = (void **)(p + ssi->handle_offset); @@ -1350,7 +1356,7 @@ fail_creation: void * lws_ss_to_user_object(struct lws_ss_handle *h) { - return (void *)&h[1]; + return (void *)(h + 1); } void @@ -1617,9 +1623,12 @@ _lws_ss_request_tx(lws_ss_handle_t *h) return LWSSSSRET_OK; h->seqstate = SSSEQ_TRY_CONNECT; - r = lws_ss_event_helper(h, LWSSSCS_POLL); - if (r) - return r; + if (h->prev_ss_state != LWSSSCS_POLL) { /* possible if we were created + * before we could action it */ + r = lws_ss_event_helper(h, LWSSSCS_POLL); + if (r) + return r; + } /* * Retries operate via lws_ss_request_tx(), explicitly ask for a diff --git a/lib/system/metrics/metrics.c b/lib/system/metrics/metrics.c index 92d5e0d0..1a978cca 100644 --- a/lib/system/metrics/metrics.c +++ b/lib/system/metrics/metrics.c @@ -437,11 +437,13 @@ int lws_metric_destroy(lws_metric_t **pmt, int keep) { lws_metric_t *mt = *pmt; - lws_metric_pub_t *pub = lws_metrics_priv_to_pub(mt); + lws_metric_pub_t *pub; if (!mt) return 0; + pub = lws_metrics_priv_to_pub(mt); + lws_dll2_remove(&mt->list); if (keep) { diff --git a/lib/tls/CMakeLists.txt b/lib/tls/CMakeLists.txt index fd3c27fa..fb9a75fe 100644 --- a/lib/tls/CMakeLists.txt +++ b/lib/tls/CMakeLists.txt @@ -69,6 +69,9 @@ endif() if (LWS_WITH_SSL AND LWS_WITH_WOLFSSL) if ("${LWS_WOLFSSL_LIBRARIES}" STREQUAL "" OR "${LWS_WOLFSSL_INCLUDE_DIRS}" STREQUAL "") + include (FindPkgConfig) + PKG_SEARCH_MODULE(LWS_WOLFSSL wolfssl) + if (NOT WOLFSSL_FOUND) if (LWS_WITH_CYASSL) message(FATAL_ERROR "You must set LWS_CYASSL_LIBRARIES and LWS_CYASSL_INCLUDE_DIRS when LWS_WITH_CYASSL is turned on.") @@ -375,22 +378,39 @@ if (LWS_WITH_MBEDTLS) # not supported in esp-idf openssl wrapper yet, but is in our version set(LWS_HAVE_X509_VERIFY_PARAM_set1_host 1 PARENT_SCOPE) endif() - set(CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY}) + set(CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY}) set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${MBEDTLS_INCLUDE_DIRS}) - CHECK_C_SOURCE_COMPILES("#include \nint main(void) { struct mbedtls_x509_crt c; c.authority_key_id.keyIdentifier.tag = MBEDTLS_ASN1_OCTET_STRING; return c.authority_key_id.keyIdentifier.tag; }\n" LWS_HAVE_MBEDTLS_AUTH_KEY_ID) - CHECK_C_SOURCE_COMPILES("#include \nint main(void) { void *v = (void *)mbedtls_ssl_set_verify; return !!v; }\n" LWS_HAVE_mbedtls_ssl_set_verify) - CHECK_FUNCTION_EXISTS(mbedtls_ssl_conf_alpn_protocols LWS_HAVE_mbedtls_ssl_conf_alpn_protocols PARENT_SCOPE) - CHECK_FUNCTION_EXISTS(mbedtls_ssl_get_alpn_protocol LWS_HAVE_mbedtls_ssl_get_alpn_protocol PARENT_SCOPE) - CHECK_FUNCTION_EXISTS(mbedtls_ssl_conf_sni LWS_HAVE_mbedtls_ssl_conf_sni PARENT_SCOPE) - CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_ca_chain LWS_HAVE_mbedtls_ssl_set_hs_ca_chain PARENT_SCOPE) - CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_own_cert LWS_HAVE_mbedtls_ssl_set_hs_own_cert PARENT_SCOPE) - CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_authmode LWS_HAVE_mbedtls_ssl_set_hs_authmode PARENT_SCOPE) - CHECK_FUNCTION_EXISTS(mbedtls_net_init LWS_HAVE_mbedtls_net_init PARENT_SCOPE) - CHECK_FUNCTION_EXISTS(mbedtls_x509_crt_parse_file LWS_HAVE_mbedtls_x509_crt_parse_file PARENT_SCOPE) # some embedded may lack filesystem - CHECK_FUNCTION_EXISTS(mbedtls_md_setup LWS_HAVE_mbedtls_md_setup PARENT_SCOPE) # not on xenial 2.2 - CHECK_FUNCTION_EXISTS(mbedtls_rsa_complete LWS_HAVE_mbedtls_rsa_complete PARENT_SCOPE) # not on xenial 2.2 - CHECK_FUNCTION_EXISTS(mbedtls_internal_aes_encrypt LWS_HAVE_mbedtls_internal_aes_encrypt PARENT_SCOPE) # not on xenial 2.2 + + if (ESP_PLATFORM) + # we know we should have things + set(LWS_HAVE_MBEDTLS_AUTH_KEY_ID 1 CACHE BOOL x) + set(LWS_HAVE_mbedtls_ssl_conf_alpn_protocols 1 CACHE BOOL x) + set(LWS_HAVE_mbedtls_ssl_get_alpn_protocol 1 CACHE BOOL x) + set(LWS_HAVE_mbedtls_ssl_conf_sni 1 CACHE BOOL x) + set(LWS_HAVE_mbedtls_ssl_set_hs_ca_chain 1 CACHE BOOL x) + set(LWS_HAVE_mbedtls_ssl_set_hs_own_cert 1 CACHE BOOL x) + set(LWS_HAVE_mbedtls_ssl_set_hs_authmode 1 CACHE BOOL x) + set(LWS_HAVE_mbedtls_net_init 1 CACHE BOOL x) + set(LWS_HAVE_mbedtls_x509_crt_parse_file 1 CACHE BOOL x) # some embedded may lack filesystem + set(LWS_HAVE_mbedtls_md_setup 1 CACHE BOOL x) # not on xenial 2.2 + set(LWS_HAVE_mbedtls_rsa_complete 1 CACHE BOOL x) # not on xenial 2.2 + set(LWS_HAVE_mbedtls_internal_aes_encrypt 1 CACHE BOOL x) # not on xenial 2.2 + else() + CHECK_C_SOURCE_COMPILES("#include \nint main(void) { struct mbedtls_x509_crt c; c.authority_key_id.keyIdentifier.tag = MBEDTLS_ASN1_OCTET_STRING; return c.authority_key_id.keyIdentifier.tag; }\n" LWS_HAVE_MBEDTLS_AUTH_KEY_ID) + CHECK_C_SOURCE_COMPILES("#include \nint main(void) { void *v = (void *)mbedtls_ssl_set_verify; return !!v; }\n" LWS_HAVE_mbedtls_ssl_set_verify) + CHECK_SYMBOL_EXISTS(mbedtls_ssl_conf_alpn_protocols LWS_HAVE_mbedtls_ssl_conf_alpn_protocols PARENT_SCOPE) + CHECK_FUNCTION_EXISTS(mbedtls_ssl_get_alpn_protocol LWS_HAVE_mbedtls_ssl_get_alpn_protocol PARENT_SCOPE) + CHECK_FUNCTION_EXISTS(mbedtls_ssl_conf_sni LWS_HAVE_mbedtls_ssl_conf_sni PARENT_SCOPE) + CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_ca_chain LWS_HAVE_mbedtls_ssl_set_hs_ca_chain PARENT_SCOPE) + CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_own_cert LWS_HAVE_mbedtls_ssl_set_hs_own_cert PARENT_SCOPE) + CHECK_FUNCTION_EXISTS(mbedtls_ssl_set_hs_authmode LWS_HAVE_mbedtls_ssl_set_hs_authmode PARENT_SCOPE) + CHECK_FUNCTION_EXISTS(mbedtls_net_init LWS_HAVE_mbedtls_net_init PARENT_SCOPE) + CHECK_FUNCTION_EXISTS(mbedtls_x509_crt_parse_file LWS_HAVE_mbedtls_x509_crt_parse_file PARENT_SCOPE) # some embedded may lack filesystem + CHECK_FUNCTION_EXISTS(mbedtls_md_setup LWS_HAVE_mbedtls_md_setup PARENT_SCOPE) # not on xenial 2.2 + CHECK_FUNCTION_EXISTS(mbedtls_rsa_complete LWS_HAVE_mbedtls_rsa_complete PARENT_SCOPE) # not on xenial 2.2 + CHECK_FUNCTION_EXISTS(mbedtls_internal_aes_encrypt LWS_HAVE_mbedtls_internal_aes_encrypt PARENT_SCOPE) # not on xenial 2.2 + endif() else() CHECK_FUNCTION_EXISTS(${VARIA}TLS_client_method LWS_HAVE_TLS_CLIENT_METHOD PARENT_SCOPE) CHECK_FUNCTION_EXISTS(${VARIA}TLSv1_2_client_method LWS_HAVE_TLSV1_2_CLIENT_METHOD PARENT_SCOPE) diff --git a/lib/tls/lws-genec-common.c b/lib/tls/lws-genec-common.c index 0ea3fb02..8b5d30b7 100644 --- a/lib/tls/lws-genec-common.c +++ b/lib/tls/lws-genec-common.c @@ -94,7 +94,7 @@ lws_genec_confirm_curve_allowed_by_tls_id(const char *allowed, int id, } } while (e > 0); - lwsl_err("%s: unsupported curve group nid %d\n", __func__, n); + lwsl_err("%s: unsupported curve group nid %d\n", __func__, id); return -1; } diff --git a/lib/tls/mbedtls/mbedtls-client.c b/lib/tls/mbedtls/mbedtls-client.c index c12bbd50..187e8605 100644 --- a/lib/tls/mbedtls/mbedtls-client.c +++ b/lib/tls/mbedtls/mbedtls-client.c @@ -137,12 +137,12 @@ lws_ssl_client_bio_create(struct lws *wsi) alpn_comma = hostname; } - lwsl_info("%s: %s: client conn sending ALPN list '%s'\n", - __func__, lws_wsi_tag(wsi), alpn_comma); - protos.len = (uint8_t)lws_alpn_comma_to_openssl(alpn_comma, protos.data, sizeof(protos.data) - 1); + lwsl_info("%s: %s: client conn sending ALPN list '%s' (protos.len %d)\n", + __func__, lws_wsi_tag(wsi), alpn_comma, protos.len); + /* with mbedtls, protos is not pointed to after exit from this call */ SSL_set_alpn_select_cb(wsi->tls.ssl, &protos); @@ -272,7 +272,8 @@ lws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen) if (!n) /* we don't know what he wants, but he says to retry */ return LWS_SSL_CAPABLE_MORE_SERVICE; - if (m == SSL_ERROR_SYSCALL && !en) + if (m == SSL_ERROR_SYSCALL && !en && n >= 0) /* otherwise we miss explicit failures and spin + * in hs state 17 until timeout... */ return LWS_SSL_CAPABLE_MORE_SERVICE; lws_snprintf(errbuf, elen, "mbedtls connect %d %d %d", n, m, en); diff --git a/lib/tls/mbedtls/mbedtls-extensions.c b/lib/tls/mbedtls/mbedtls-extensions.c index dc406e82..bf275eef 100644 --- a/lib/tls/mbedtls/mbedtls-extensions.c +++ b/lib/tls/mbedtls/mbedtls-extensions.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010 - 2021 Andy Green + * Copyright (C) 2010 - 2022 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -104,8 +104,8 @@ static const oid_x509_ext_t oid_x509_ext[] = { (const mbedtls_oid_descriptor_t *) p; \ if( p == NULL || oid == NULL ) return( NULL ); \ while( cur->MBEDTLS_PRIVATE(asn1) != NULL ) { \ - if( cur->MBEDTLS_PRIVATE(asn1_len) == oid->MBEDTLS_PRIVATE(len) && \ - memcmp( cur->MBEDTLS_PRIVATE(asn1), oid->MBEDTLS_PRIVATE(p), oid->MBEDTLS_PRIVATE(len) ) == 0 ) { \ + if( cur->MBEDTLS_PRIVATE(asn1_len) == oid->MBEDTLS_PRIVATE_V30_ONLY(len) && \ + memcmp( cur->MBEDTLS_PRIVATE(asn1), oid->MBEDTLS_PRIVATE_V30_ONLY(p), oid->MBEDTLS_PRIVATE_V30_ONLY(len) ) == 0 ) { \ return( p ); \ } \ p++; \ @@ -177,10 +177,10 @@ x509_get_skid(uint8_t **p, const uint8_t *end, mbedtls_x509_buf *skid) if (ret) return ret; - skid->MBEDTLS_PRIVATE(len) = len; - skid->MBEDTLS_PRIVATE(tag) = MBEDTLS_ASN1_OCTET_STRING; - skid->MBEDTLS_PRIVATE(p) = *p; - *p += len; + skid->MBEDTLS_PRIVATE_V30_ONLY(len) = len; + skid->MBEDTLS_PRIVATE_V30_ONLY(tag) = MBEDTLS_ASN1_OCTET_STRING; + skid->MBEDTLS_PRIVATE_V30_ONLY(p) = *p; + *p += len; return *p != end; } @@ -204,10 +204,10 @@ lws_x509_clean_name(mbedtls_x509_name *name) if (!name) return; - n1 = name->MBEDTLS_PRIVATE(next); + n1 = name->MBEDTLS_PRIVATE_V30_ONLY(next); while (n1) { - name = n1->MBEDTLS_PRIVATE(next); + name = n1->MBEDTLS_PRIVATE_V30_ONLY(next); free(n1); n1 = name; } @@ -222,7 +222,7 @@ lws_mbedtls_x509_parse_general_name(const mbedtls_x509_buf *name_buf, mbedtls_x509_name rfc822Name; int ret; - switch (name_buf->MBEDTLS_PRIVATE(tag) & + switch (name_buf->MBEDTLS_PRIVATE_V30_ONLY(tag) & (LWS_MBEDTLS_ASN1_TAG_CLASS_MASK | LWS_MBEDTLS_ASN1_TAG_VALUE_MASK)) { @@ -239,17 +239,17 @@ lws_mbedtls_x509_parse_general_name(const mbedtls_x509_buf *name_buf, #endif case MBEDTLS_ASN1_SEQUENCE | LWS_MBEDTLS_X509_SAN_RFC822_NAME: - bufferPointer = name_buf->MBEDTLS_PRIVATE(p); + bufferPointer = name_buf->MBEDTLS_PRIVATE_V30_ONLY(p); p = &bufferPointer; - end = name_buf->MBEDTLS_PRIVATE(p) + - name_buf->MBEDTLS_PRIVATE(len); + end = name_buf->MBEDTLS_PRIVATE_V30_ONLY(p) + + name_buf->MBEDTLS_PRIVATE_V30_ONLY(len); /* The leading ASN1 tag and length has been processed. * Stepping back with 2 bytes, because mbedtls_x509_get_name * expects the beginning of the SET tag */ *p = *p - 2; - rfc822Name.MBEDTLS_PRIVATE(next) = NULL; + rfc822Name.MBEDTLS_PRIVATE_V30_ONLY(next) = NULL; ret = mbedtls_x509_get_name( p, end, &rfc822Name ); if (ret) { lws_x509_clean_name(&rfc822Name); @@ -318,51 +318,51 @@ lws_x509_get_general_names(uint8_t **p, const uint8_t *end, * Check that the name is structured correctly. */ r = lws_mbedtls_x509_parse_general_name( - &cur->MBEDTLS_PRIVATE(buf), &dnb); + &cur->MBEDTLS_PRIVATE_V30_ONLY(buf), &dnb); /* * In case the extension is malformed, return an error, * and clear the allocated sequences. */ if (r && r != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) { - mbedtls_x509_sequence *seq_cur = name->MBEDTLS_PRIVATE(next); + mbedtls_x509_sequence *seq_cur = name->MBEDTLS_PRIVATE_V30_ONLY(next); mbedtls_x509_sequence *seq_prv; while( seq_cur != NULL ) { seq_prv = seq_cur; - seq_cur = seq_cur->MBEDTLS_PRIVATE(next); + seq_cur = seq_cur->MBEDTLS_PRIVATE_V30_ONLY(next); lws_explicit_bzero(seq_prv, sizeof(*seq_cur)); lws_free(seq_prv); } - name->MBEDTLS_PRIVATE(next) = NULL; + name->MBEDTLS_PRIVATE_V30_ONLY(next) = NULL; return r; } /* Allocate and assign next pointer */ - if (cur->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(p)) { - if (cur->MBEDTLS_PRIVATE(next)) + if (cur->MBEDTLS_PRIVATE_V30_ONLY(buf).MBEDTLS_PRIVATE_V30_ONLY(p)) { + if (cur->MBEDTLS_PRIVATE_V30_ONLY(next)) return 1; - cur->MBEDTLS_PRIVATE(next) = + cur->MBEDTLS_PRIVATE_V30_ONLY(next) = lws_zalloc(sizeof(*cur), __func__); - if (!cur->MBEDTLS_PRIVATE(next)) + if (!cur->MBEDTLS_PRIVATE_V30_ONLY(next)) return 1; - cur = cur->MBEDTLS_PRIVATE(next); + cur = cur->MBEDTLS_PRIVATE_V30_ONLY(next); } - buf = &(cur->MBEDTLS_PRIVATE(buf)); - buf->MBEDTLS_PRIVATE(tag) = tag; - buf->MBEDTLS_PRIVATE(p) = *p; - buf->MBEDTLS_PRIVATE(len) = tag_len; + buf = &(cur->MBEDTLS_PRIVATE_V30_ONLY(buf)); + buf->MBEDTLS_PRIVATE_V30_ONLY(tag) = tag; + buf->MBEDTLS_PRIVATE_V30_ONLY(p) = *p; + buf->MBEDTLS_PRIVATE_V30_ONLY(len) = tag_len; - *p += buf->MBEDTLS_PRIVATE(len); + *p += buf->MBEDTLS_PRIVATE_V30_ONLY(len); } /* Set final sequence entry's next pointer to NULL */ - cur->MBEDTLS_PRIVATE(next) = NULL; + cur->MBEDTLS_PRIVATE_V30_ONLY(next) = NULL; return *p != end; } @@ -380,9 +380,9 @@ x509_get_akid(uint8_t **p, uint8_t *end, lws_mbedtls_x509_authority *akid) r = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC); if (!r) { - akid->keyIdentifier.MBEDTLS_PRIVATE(len) = len; - akid->keyIdentifier.MBEDTLS_PRIVATE(p) = *p; - akid->keyIdentifier.MBEDTLS_PRIVATE(tag) = MBEDTLS_ASN1_OCTET_STRING; + akid->keyIdentifier.MBEDTLS_PRIVATE_V30_ONLY(len) = len; + akid->keyIdentifier.MBEDTLS_PRIVATE_V30_ONLY(p) = *p; + akid->keyIdentifier.MBEDTLS_PRIVATE_V30_ONLY(tag) = MBEDTLS_ASN1_OCTET_STRING; *p += len; } @@ -416,9 +416,9 @@ x509_get_akid(uint8_t **p, uint8_t *end, lws_mbedtls_x509_authority *akid) if (r) return r; - akid->authorityCertSerialNumber.MBEDTLS_PRIVATE(len) = len; - akid->authorityCertSerialNumber.MBEDTLS_PRIVATE(p) = *p; - akid->authorityCertSerialNumber.MBEDTLS_PRIVATE(tag) = MBEDTLS_ASN1_OCTET_STRING; + akid->authorityCertSerialNumber.MBEDTLS_PRIVATE_V30_ONLY(len) = len; + akid->authorityCertSerialNumber.MBEDTLS_PRIVATE_V30_ONLY(p) = *p; + akid->authorityCertSerialNumber.MBEDTLS_PRIVATE_V30_ONLY(tag) = MBEDTLS_ASN1_OCTET_STRING; *p += len; } @@ -434,9 +434,9 @@ int lws_x509_get_crt_ext(mbedtls_x509_crt *crt, mbedtls_x509_buf *skid, lws_mbedtls_x509_authority *akid) { - uint8_t *p = crt->MBEDTLS_PRIVATE(v3_ext).MBEDTLS_PRIVATE(p), + uint8_t *p = crt->MBEDTLS_PRIVATE_V30_ONLY(v3_ext).MBEDTLS_PRIVATE_V30_ONLY(p), *end_ext_data, *end_ext_octet; - const uint8_t *end = p + crt->MBEDTLS_PRIVATE(v3_ext).MBEDTLS_PRIVATE(len); + const uint8_t *end = p + crt->MBEDTLS_PRIVATE_V30_ONLY(v3_ext).MBEDTLS_PRIVATE_V30_ONLY(len); size_t len; int r = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); @@ -457,14 +457,14 @@ lws_x509_get_crt_ext(mbedtls_x509_crt *crt, mbedtls_x509_buf *skid, end_ext_data = p + len; /* Get extension ID */ - r = mbedtls_asn1_get_tag(&p, end_ext_data, &extn_oid.MBEDTLS_PRIVATE(len), + r = mbedtls_asn1_get_tag(&p, end_ext_data, &extn_oid.MBEDTLS_PRIVATE_V30_ONLY(len), MBEDTLS_ASN1_OID); if (r) return r; - extn_oid.MBEDTLS_PRIVATE(tag) = MBEDTLS_ASN1_OID; - extn_oid.MBEDTLS_PRIVATE(p) = p; - p += extn_oid.MBEDTLS_PRIVATE(len); + extn_oid.MBEDTLS_PRIVATE_V30_ONLY(tag) = MBEDTLS_ASN1_OID; + extn_oid.MBEDTLS_PRIVATE_V30_ONLY(p) = p; + p += extn_oid.MBEDTLS_PRIVATE_V30_ONLY(len); /* Get optional critical */ r = mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical); diff --git a/lib/tls/mbedtls/mbedtls-x509.c b/lib/tls/mbedtls/mbedtls-x509.c index 2dad865d..8b0ccd3f 100644 --- a/lib/tls/mbedtls/mbedtls-x509.c +++ b/lib/tls/mbedtls/mbedtls-x509.c @@ -49,17 +49,17 @@ lws_tls_mbedtls_time_to_unix(mbedtls_x509_time *xtime) { struct tm t; - if (!xtime || !xtime->MBEDTLS_PRIVATE(year) || xtime->MBEDTLS_PRIVATE(year) < 0) + if (!xtime || !xtime->MBEDTLS_PRIVATE_V30_ONLY(year) || xtime->MBEDTLS_PRIVATE_V30_ONLY(year) < 0) return (time_t)(long long)-1; memset(&t, 0, sizeof(t)); - t.tm_year = xtime->MBEDTLS_PRIVATE(year) - 1900; - t.tm_mon = xtime->MBEDTLS_PRIVATE(mon) - 1; /* mbedtls months are 1+, tm are 0+ */ - t.tm_mday = xtime->MBEDTLS_PRIVATE(day) - 1; /* mbedtls days are 1+, tm are 0+ */ - t.tm_hour = xtime->MBEDTLS_PRIVATE(hour); - t.tm_min = xtime->MBEDTLS_PRIVATE(min); - t.tm_sec = xtime->MBEDTLS_PRIVATE(sec); + t.tm_year = xtime->MBEDTLS_PRIVATE_V30_ONLY(year) - 1900; + t.tm_mon = xtime->MBEDTLS_PRIVATE_V30_ONLY(mon) - 1; /* mbedtls months are 1+, tm are 0+ */ + t.tm_mday = xtime->MBEDTLS_PRIVATE_V30_ONLY(day) - 1; /* mbedtls days are 1+, tm are 0+ */ + t.tm_hour = xtime->MBEDTLS_PRIVATE_V30_ONLY(hour); + t.tm_min = xtime->MBEDTLS_PRIVATE_V30_ONLY(min); + t.tm_sec = xtime->MBEDTLS_PRIVATE_V30_ONLY(sec); t.tm_isdst = -1; return mktime(&t); @@ -81,13 +81,13 @@ lws_tls_mbedtls_get_x509_name(mbedtls_x509_name *name, } */ lws_strnncpy(&buf->ns.name[buf->ns.len], - (const char *)name->MBEDTLS_PRIVATE(val).MBEDTLS_PRIVATE(p), - name->MBEDTLS_PRIVATE(val).MBEDTLS_PRIVATE(len), + (const char *)name->MBEDTLS_PRIVATE_V30_ONLY(val).MBEDTLS_PRIVATE_V30_ONLY(p), + name->MBEDTLS_PRIVATE_V30_ONLY(val).MBEDTLS_PRIVATE_V30_ONLY(len), len - (size_t)buf->ns.len); buf->ns.len = (int)strlen(buf->ns.name); r = 0; - name = name->MBEDTLS_PRIVATE(next); + name = name->MBEDTLS_PRIVATE_V30_ONLY(next); } return r; @@ -109,22 +109,22 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type, switch (type) { case LWS_TLS_CERT_INFO_VALIDITY_FROM: - buf->time = lws_tls_mbedtls_time_to_unix(&x509->MBEDTLS_PRIVATE(valid_from)); + buf->time = lws_tls_mbedtls_time_to_unix(&x509->MBEDTLS_PRIVATE_V30_ONLY(valid_from)); if (buf->time == (time_t)(long long)-1) return -1; break; case LWS_TLS_CERT_INFO_VALIDITY_TO: - buf->time = lws_tls_mbedtls_time_to_unix(&x509->MBEDTLS_PRIVATE(valid_to)); + buf->time = lws_tls_mbedtls_time_to_unix(&x509->MBEDTLS_PRIVATE_V30_ONLY(valid_to)); if (buf->time == (time_t)(long long)-1) return -1; break; case LWS_TLS_CERT_INFO_COMMON_NAME: - return lws_tls_mbedtls_get_x509_name(&x509->MBEDTLS_PRIVATE(subject), buf, len); + return lws_tls_mbedtls_get_x509_name(&x509->MBEDTLS_PRIVATE_V30_ONLY(subject), buf, len); case LWS_TLS_CERT_INFO_ISSUER_NAME: - return lws_tls_mbedtls_get_x509_name(&x509->MBEDTLS_PRIVATE(issuer), buf, len); + return lws_tls_mbedtls_get_x509_name(&x509->MBEDTLS_PRIVATE_V30_ONLY(issuer), buf, len); case LWS_TLS_CERT_INFO_USAGE: buf->usage = x509->MBEDTLS_PRIVATE(key_usage); @@ -135,10 +135,10 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type, char *p = buf->ns.name; size_t r = len, u; - switch (mbedtls_pk_get_type(&x509->MBEDTLS_PRIVATE(pk))) { + switch (mbedtls_pk_get_type(&x509->MBEDTLS_PRIVATE_V30_ONLY(pk))) { case MBEDTLS_PK_RSA: { - mbedtls_rsa_context *rsa = mbedtls_pk_rsa(x509->MBEDTLS_PRIVATE(pk)); + mbedtls_rsa_context *rsa = mbedtls_pk_rsa(x509->MBEDTLS_PRIVATE_V30_ONLY(pk)); if (mbedtls_mpi_write_string(&rsa->MBEDTLS_PRIVATE(N), 16, p, r, &u)) return -1; @@ -153,7 +153,7 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type, } case MBEDTLS_PK_ECKEY: { - mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(x509->MBEDTLS_PRIVATE(pk)); + mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(x509->MBEDTLS_PRIVATE_V30_ONLY(pk)); if (mbedtls_mpi_write_string(&ecp->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), 16, p, r, &u)) return -1; @@ -172,7 +172,7 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type, default: lwsl_notice("%s: x509 has unsupported pubkey type %d\n", __func__, - mbedtls_pk_get_type(&x509->MBEDTLS_PRIVATE(pk))); + mbedtls_pk_get_type(&x509->MBEDTLS_PRIVATE_V30_ONLY(pk))); return -1; } @@ -180,17 +180,17 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type, } case LWS_TLS_CERT_INFO_DER_RAW: - buf->ns.len = (int)x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len); + buf->ns.len = (int)x509->MBEDTLS_PRIVATE_V30_ONLY(raw).MBEDTLS_PRIVATE_V30_ONLY(len); - if (len < x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) + if (len < x509->MBEDTLS_PRIVATE_V30_ONLY(raw).MBEDTLS_PRIVATE_V30_ONLY(len)) /* * The buffer is too small and the attempt failed, but * the required object length is in buf->ns.len */ return -1; - memcpy(buf->ns.name, x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p), - x509->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)); + memcpy(buf->ns.name, x509->MBEDTLS_PRIVATE_V30_ONLY(raw).MBEDTLS_PRIVATE_V30_ONLY(p), + x509->MBEDTLS_PRIVATE_V30_ONLY(raw).MBEDTLS_PRIVATE_V30_ONLY(len)); break; case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID: @@ -199,13 +199,13 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type, memset(&skid, 0, sizeof(skid)); lws_x509_get_crt_ext(x509, &skid, &akid); - if (akid.keyIdentifier.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING) + if (akid.keyIdentifier.MBEDTLS_PRIVATE_V30_ONLY(tag) != MBEDTLS_ASN1_OCTET_STRING) return 1; - buf->ns.len = (int)akid.keyIdentifier.MBEDTLS_PRIVATE(len); - if (!akid.keyIdentifier.MBEDTLS_PRIVATE(p) || + buf->ns.len = (int)akid.keyIdentifier.MBEDTLS_PRIVATE_V30_ONLY(len); + if (!akid.keyIdentifier.MBEDTLS_PRIVATE_V30_ONLY(p) || len < (size_t)buf->ns.len) return -1; - memcpy(buf->ns.name, akid.keyIdentifier.MBEDTLS_PRIVATE(p), (size_t)buf->ns.len); + memcpy(buf->ns.name, akid.keyIdentifier.MBEDTLS_PRIVATE_V30_ONLY(p), (size_t)buf->ns.len); break; case LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID_ISSUER: { @@ -221,17 +221,17 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type, buf->ns.len = 0; while (ip) { - if (akid.keyIdentifier.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING || - !ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(p) || - ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) < 9 || - len < (size_t)ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) - 9u) + if (akid.keyIdentifier.MBEDTLS_PRIVATE_V30_ONLY(tag) != MBEDTLS_ASN1_OCTET_STRING || + !ip->MBEDTLS_PRIVATE_V30_ONLY(buf).MBEDTLS_PRIVATE_V30_ONLY(p) || + ip->MBEDTLS_PRIVATE_V30_ONLY(buf).MBEDTLS_PRIVATE_V30_ONLY(len) < 9 || + len < (size_t)ip->MBEDTLS_PRIVATE_V30_ONLY(buf).MBEDTLS_PRIVATE_V30_ONLY(len) - 9u) break; - memcpy(buf->ns.name + buf->ns.len, ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(p), - (size_t)ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) - 9); - buf->ns.len = buf->ns.len + (int)ip->MBEDTLS_PRIVATE(buf).MBEDTLS_PRIVATE(len) - 9; + memcpy(buf->ns.name + buf->ns.len, ip->MBEDTLS_PRIVATE_V30_ONLY(buf).MBEDTLS_PRIVATE_V30_ONLY(p), + (size_t)ip->MBEDTLS_PRIVATE_V30_ONLY(buf).MBEDTLS_PRIVATE_V30_ONLY(len) - 9); + buf->ns.len = buf->ns.len + (int)ip->MBEDTLS_PRIVATE_V30_ONLY(buf).MBEDTLS_PRIVATE_V30_ONLY(len) - 9; - ip = ip->MBEDTLS_PRIVATE(next); + ip = ip->MBEDTLS_PRIVATE_V30_ONLY(next); } break; } @@ -242,14 +242,14 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type, lws_x509_get_crt_ext(x509, &skid, &akid); - if (akid.authorityCertSerialNumber.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING) + if (akid.authorityCertSerialNumber.MBEDTLS_PRIVATE_V30_ONLY(tag) != MBEDTLS_ASN1_OCTET_STRING) return 1; - buf->ns.len = (int)akid.authorityCertSerialNumber.MBEDTLS_PRIVATE(len); - if (!akid.authorityCertSerialNumber.MBEDTLS_PRIVATE(p) || + buf->ns.len = (int)akid.authorityCertSerialNumber.MBEDTLS_PRIVATE_V30_ONLY(len); + if (!akid.authorityCertSerialNumber.MBEDTLS_PRIVATE_V30_ONLY(p) || len < (size_t)buf->ns.len) return -1; memcpy(buf->ns.name, akid.authorityCertSerialNumber. - MBEDTLS_PRIVATE(p), (size_t)buf->ns.len); + MBEDTLS_PRIVATE_V30_ONLY(p), (size_t)buf->ns.len); break; case LWS_TLS_CERT_INFO_SUBJECT_KEY_ID: @@ -259,12 +259,12 @@ lws_tls_mbedtls_cert_info(mbedtls_x509_crt *x509, enum lws_tls_cert_info type, lws_x509_get_crt_ext(x509, &skid, &akid); - if (skid.MBEDTLS_PRIVATE(tag) != MBEDTLS_ASN1_OCTET_STRING) + if (skid.MBEDTLS_PRIVATE_V30_ONLY(tag) != MBEDTLS_ASN1_OCTET_STRING) return 1; - buf->ns.len = (int)skid.MBEDTLS_PRIVATE(len); + buf->ns.len = (int)skid.MBEDTLS_PRIVATE_V30_ONLY(len); if (len < (size_t)buf->ns.len) return -1; - memcpy(buf->ns.name, skid.MBEDTLS_PRIVATE(p), (size_t)buf->ns.len); + memcpy(buf->ns.name, skid.MBEDTLS_PRIVATE_V30_ONLY(p), (size_t)buf->ns.len); break; default: return -1; @@ -379,7 +379,7 @@ int lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509, const char *curves, int rsa_min_bits) { - int kt = (int)mbedtls_pk_get_type(&x509->cert.MBEDTLS_PRIVATE(pk)), + int kt = (int)mbedtls_pk_get_type(&x509->cert.MBEDTLS_PRIVATE_V30_ONLY(pk)), n, count = 0, ret = -1; mbedtls_rsa_context *rsactx; mbedtls_ecp_keypair *ecpctx; @@ -391,7 +391,7 @@ lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509, case MBEDTLS_PK_RSA: lwsl_notice("%s: RSA key\n", __func__); jwk->kty = LWS_GENCRYPTO_KTY_RSA; - rsactx = mbedtls_pk_rsa(x509->cert.MBEDTLS_PRIVATE(pk)); + rsactx = mbedtls_pk_rsa(x509->cert.MBEDTLS_PRIVATE_V30_ONLY(pk)); mpi[LWS_GENCRYPTO_RSA_KEYEL_E] = &rsactx->MBEDTLS_PRIVATE(E); mpi[LWS_GENCRYPTO_RSA_KEYEL_N] = &rsactx->MBEDTLS_PRIVATE(N); @@ -409,7 +409,7 @@ lws_x509_public_to_jwk(struct lws_jwk *jwk, struct lws_x509_cert *x509, case MBEDTLS_PK_ECKEY: lwsl_notice("%s: EC key\n", __func__); jwk->kty = LWS_GENCRYPTO_KTY_EC; - ecpctx = mbedtls_pk_ec(x509->cert.MBEDTLS_PRIVATE(pk)); + ecpctx = mbedtls_pk_ec(x509->cert.MBEDTLS_PRIVATE_V30_ONLY(pk)); mpi[LWS_GENCRYPTO_EC_KEYEL_X] = &ecpctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X); mpi[LWS_GENCRYPTO_EC_KEYEL_D] = &ecpctx->MBEDTLS_PRIVATE(d); mpi[LWS_GENCRYPTO_EC_KEYEL_Y] = &ecpctx->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y); diff --git a/lib/tls/mbedtls/wrapper/platform/ssl_pm.c b/lib/tls/mbedtls/wrapper/platform/ssl_pm.c index 04354f6b..e8a0cb2d 100755 --- a/lib/tls/mbedtls/wrapper/platform/ssl_pm.c +++ b/lib/tls/mbedtls/wrapper/platform/ssl_pm.c @@ -98,7 +98,6 @@ static void ssl_platform_debug(void *ctx, int level, } //#endif -#if defined(LWS_HAVE_mbedtls_ssl_set_verify) static int lws_mbedtls_f_vrfy(void *opaque, mbedtls_x509_crt *x509, int state, uint32_t *pflags) { @@ -109,7 +108,6 @@ lws_mbedtls_f_vrfy(void *opaque, mbedtls_x509_crt *x509, int state, uint32_t *pf return 0; } -#endif /** * @brief create SSL low-level object @@ -151,6 +149,8 @@ int ssl_pm_new(SSL *ssl) #if defined(LWS_HAVE_mbedtls_ssl_set_verify) mbedtls_ssl_set_verify(&ssl_pm->ssl, lws_mbedtls_f_vrfy, ssl_pm); +#else + mbedtls_ssl_conf_verify(&ssl_pm->conf, lws_mbedtls_f_vrfy, ssl_pm); #endif ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, pers, pers_len); @@ -499,14 +499,13 @@ void ssl_pm_set_fd(SSL *ssl, int fd, int mode) { struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; - ssl_pm->fd.MBEDTLS_PRIVATE(fd) = fd; + ssl_pm->fd.MBEDTLS_PRIVATE_V30_ONLY(fd) = fd; } int ssl_pm_get_fd(const SSL *ssl, int mode) { struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; - - return ssl_pm->fd.MBEDTLS_PRIVATE(fd); + return ssl_pm->fd.MBEDTLS_PRIVATE_V30_ONLY(fd); } OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl) @@ -660,7 +659,7 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; if (!x509_pm->x509_crt) { - x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt)); + x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt) + 80); if (!x509_pm->x509_crt) { SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm->x509_crt)"); goto no_mem; @@ -874,6 +873,8 @@ void _ssl_set_alpn_list(const SSL *ssl) return; if (mbedtls_ssl_conf_alpn_protocols(&((struct ssl_pm *)(ssl->ssl_pm))->conf, ssl->ctx->alpn_protos)) fprintf(stderr, "mbedtls_ssl_conf_alpn_protocols failed\n"); +#else + fprintf(stderr, "mbedtls_ssl_conf_alpn_protocols absent\n"); #endif } @@ -889,6 +890,7 @@ void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data, else *len = 0; #else + fprintf(stderr, "mbedtls_ssl_conf_alpn_protocols absent\n"); *len = 0; #endif } diff --git a/lib/tls/openssl/openssl-client.c b/lib/tls/openssl/openssl-client.c index d8c56c51..6c8d5c1c 100644 --- a/lib/tls/openssl/openssl-client.c +++ b/lib/tls/openssl/openssl-client.c @@ -904,37 +904,67 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_RELEASE_BUFFERS); - if (info->ssl_client_options_set) - SSL_CTX_set_options(vh->tls.ssl_client_ctx, +#if !defined(USE_WOLFSSL) +#if defined(LWS_WITH_BORINGSSL) + uint32_t +#else +#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \ + !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ + unsigned long +#else + long +#endif +#endif +#else + long +#endif + ssl_client_options_set_value = #if !defined(USE_WOLFSSL) #if defined(LWS_WITH_BORINGSSL) (uint32_t) #else #if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \ !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ - (unsigned long) + (unsigned long) #else - (long) + (long) #endif #endif #endif - info->ssl_client_options_set); + info->ssl_client_options_set; + + if (info->ssl_client_options_set) + SSL_CTX_set_options(vh->tls.ssl_client_ctx, ssl_client_options_set_value); - /* SSL_clear_options introduced in 0.9.8m */ #if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL) - if (info->ssl_client_options_clear) - SSL_CTX_clear_options(vh->tls.ssl_client_ctx, + + /* SSL_clear_options introduced in 0.9.8m */ +#if defined(LWS_WITH_BORINGSSL) + uint32_t +#else +#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \ + !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ + unsigned long +#else + long +#endif +#endif + + ssl_client_options_clear_value = #if defined(LWS_WITH_BORINGSSL) (uint32_t) #else #if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \ !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ - (unsigned long) + (unsigned long) #else - (long) + (long) #endif #endif - info->ssl_client_options_clear); + info->ssl_client_options_clear; + + if (info->ssl_client_options_clear) + SSL_CTX_clear_options(vh->tls.ssl_client_ctx, ssl_client_options_clear_value); #endif if (cipher_list) diff --git a/lib/tls/openssl/openssl-server.c b/lib/tls/openssl/openssl-server.c index 94e88462..34a6ada2 100644 --- a/lib/tls/openssl/openssl-server.c +++ b/lib/tls/openssl/openssl-server.c @@ -579,8 +579,20 @@ lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info, __func__); } - if (info->ssl_options_set) - SSL_CTX_set_options(vhost->tls.ssl_ctx, +#if defined(USE_WOLFSSL) + long +#else +#if defined(LWS_WITH_BORINGSSL) + uint32_t +#else +#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ + unsigned long +#else + long +#endif +#endif +#endif + ssl_options_set_value = #if defined(USE_WOLFSSL) (long) #else @@ -588,32 +600,50 @@ lws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info, (uint32_t) #else #if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ - (unsigned long) + (unsigned long) #else - (long) + (long) #endif #endif #endif - info->ssl_options_set); + info->ssl_options_set; + + if (info->ssl_options_set) + SSL_CTX_set_options(vhost->tls.ssl_ctx, ssl_options_set_value); -/* SSL_clear_options introduced in 0.9.8m */ #if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL) - if (info->ssl_options_clear) - SSL_CTX_clear_options(vhost->tls.ssl_ctx, + +/* SSL_clear_options introduced in 0.9.8m */ #if defined(LWS_WITH_BORINGSSL) - (uint32_t) + uint32_t #else #if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER)/* not documented by openssl */ - (unsigned long) + unsigned long #else - (long) + long #endif #endif - info->ssl_options_clear); + + ssl_options_clear_value = +#if defined(LWS_WITH_BORINGSSL) + (uint32_t) +#else +#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER)/* not documented by openssl */ + (unsigned long) +#else + (long) +#endif #endif + info->ssl_options_clear; + + if (info->ssl_options_clear) { + SSL_CTX_clear_options(vhost->tls.ssl_ctx, ssl_options_clear_value); + } lwsl_info(" SSL options 0x%lX\n", (unsigned long)SSL_CTX_get_options(vhost->tls.ssl_ctx)); +#endif + if (!vhost->tls.use_ssl || (!info->ssl_cert_filepath && !info->server_ssl_cert_mem)) return 0; diff --git a/lib/tls/openssl/openssl-session.c b/lib/tls/openssl/openssl-session.c index d7dd04c6..e27a8f38 100644 --- a/lib/tls/openssl/openssl-session.c +++ b/lib/tls/openssl/openssl-session.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010 - 2021 Andy Green + * Copyright (C) 2010 - 2022 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -33,7 +33,12 @@ typedef struct lws_tls_session_cache_openssl { /* name is overallocated here */ } lws_tls_sco_t; -#define lwsl_tlssess lwsl_info +#define tlssess_loglevel LLL_INFO +#if (_LWS_ENABLED_LOGS & tlssess_loglevel) +#define lwsl_tlssess(...) _lws_log(tlssess_loglevel, __VA_ARGS__) +#else +#define lwsl_tlssess(...) +#endif static void __lws_tls_session_destroy(lws_tls_sco_t *ts) @@ -211,7 +216,7 @@ lws_tls_session_new_cb(SSL *ssl, SSL_SESSION *sess) struct lws_vhost *vh; lws_tls_sco_t *ts; long ttl; -#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG) +#if (_LWS_ENABLED_LOGS & tlssess_loglevel) const char *disposition = "reuse"; #endif @@ -247,7 +252,7 @@ lws_tls_session_new_cb(SSL *ssl, SSL_SESSION *sess) lws_tls_session_expiry_cb, ttl * LWS_US_PER_SEC); -#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG) +#if (_LWS_ENABLED_LOGS & tlssess_loglevel) disposition = "new"; #endif diff --git a/lib/tls/tls-client.c b/lib/tls/tls-client.c index 9d93a3da..5b29923f 100644 --- a/lib/tls/tls-client.c +++ b/lib/tls/tls-client.c @@ -66,6 +66,12 @@ lws_ssl_client_connect2(struct lws *wsi, char *errbuf, size_t len) switch (n) { case LWS_SSL_CAPABLE_ERROR: lws_tls_restrict_return_handshake(wsi); + + if (lws_tls_client_confirm_peer_cert(wsi, errbuf, len)) { + lws_metrics_caliper_report(wsi->cal_conn, METRES_NOGO); + return -1; + } + // lws_snprintf(errbuf, len, "client connect failed"); return -1; case LWS_SSL_CAPABLE_DONE: diff --git a/lib/tls/tls-server.c b/lib/tls/tls-server.c index dbb51783..05055f7e 100644 --- a/lib/tls/tls-server.c +++ b/lib/tls/tls-server.c @@ -113,12 +113,12 @@ lws_context_init_server_ssl(const struct lws_context_creation_info *info, if (vhost->tls.use_ssl) lws_context_init_alpn(vhost); - /* check certs once a day */ + /* check certs in a few seconds (after protocol init) and then once a day */ context->pt[0].sul_tls.cb = lws_sul_tls_cb; __lws_sul_insert_us(&context->pt[0].pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], &context->pt[0].sul_tls, - (lws_usec_t)24 * 3600 * LWS_US_PER_SEC); + (lws_usec_t)5 * LWS_US_PER_SEC); return 0; } diff --git a/minimal-examples-lowlevel/raw/minimal-raw-client/CMakeLists.txt b/minimal-examples-lowlevel/raw/minimal-raw-client/CMakeLists.txt new file mode 100644 index 00000000..4ff5c55c --- /dev/null +++ b/minimal-examples-lowlevel/raw/minimal-raw-client/CMakeLists.txt @@ -0,0 +1,23 @@ +project(lws-minimal-raw-client C) +cmake_minimum_required(VERSION 2.8.12) +find_package(libwebsockets CONFIG REQUIRED) +list(APPEND CMAKE_MODULE_PATH ${LWS_CMAKE_DIR}) +include(CheckCSourceCompiles) +include(LwsCheckRequirements) + +set(SAMP lws-minimal-raw-client) +set(SRCS main.c) + +set(requirements 1) +require_lws_config(LWS_WITH_CLIENT 1 requirements) + +if (requirements) + add_executable(${SAMP} ${SRCS}) + + if (websockets_shared) + target_link_libraries(${SAMP} websockets_shared ${LIBWEBSOCKETS_DEP_LIBS}) + add_dependencies(${SAMP} websockets_shared) + else() + target_link_libraries(${SAMP} websockets ${LIBWEBSOCKETS_DEP_LIBS}) + endif() +endif() diff --git a/minimal-examples-lowlevel/raw/minimal-raw-client/main.c b/minimal-examples-lowlevel/raw/minimal-raw-client/main.c new file mode 100644 index 00000000..db18a99e --- /dev/null +++ b/minimal-examples-lowlevel/raw/minimal-raw-client/main.c @@ -0,0 +1,214 @@ +/* + * lws-minimal-raw-client + * + * Written in 2010-2022 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * This demonstrates connecting a "raw" client connection + */ + +#include +#include +#include +#if !defined(WIN32) +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#if !defined(WIN32) +#include +#endif +#include + +#include + +static struct lws *raw_wsi, *stdin_wsi; +static uint8_t buf[LWS_PRE + 4096]; +static int waiting, interrupted; +static struct lws_context *context; +static int us_wait_after_input_close = LWS_USEC_PER_SEC / 10; + +static const char *server = "libwebsockets.org", *port = "443"; + +static int +callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + const char *cp = (const char *)in; + + switch (reason) { + + /* callbacks related to file descriptor */ + + case LWS_CALLBACK_RAW_ADOPT_FILE: + lwsl_user("LWS_CALLBACK_RAW_ADOPT_FILE\n"); + break; + + case LWS_CALLBACK_RAW_CLOSE_FILE: + lwsl_user("LWS_CALLBACK_RAW_CLOSE_FILE\n"); + /* stdin close, wait 1s then close the raw skt */ + stdin_wsi = NULL; /* invalid now we close */ + if (raw_wsi) + lws_set_timer_usecs(raw_wsi, us_wait_after_input_close); + else { + interrupted = 1; + lws_cancel_service(context); + } + break; + + case LWS_CALLBACK_RAW_RX_FILE: + lwsl_user("LWS_CALLBACK_RAW_RX_FILE\n"); + waiting = (int)read(0, buf, sizeof(buf)); + lwsl_notice("raw file read %d\n", waiting); + if (waiting < 0) + return -1; + + if (raw_wsi) + lws_callback_on_writable(raw_wsi); + lws_rx_flow_control(wsi, 0); + break; + + + /* callbacks related to raw socket descriptor */ + + case LWS_CALLBACK_RAW_ADOPT: + lwsl_user("LWS_CALLBACK_RAW_ADOPT\n"); + lws_callback_on_writable(wsi); + break; + + case LWS_CALLBACK_RAW_CONNECTED: + lwsl_user("LWS_CALLBACK_RAW_CONNECTED\n"); + break; + + case LWS_CALLBACK_RAW_CLOSE: + lwsl_user("LWS_CALLBACK_RAW_CLOSE\n"); + /* + * If the socket to the remote server closed, we must close + * and drop any remaining stdin + */ + interrupted = 1; + lws_cancel_service(context); + /* our pointer to this wsi is invalid now we close */ + raw_wsi = NULL; + break; + + case LWS_CALLBACK_RAW_RX: + lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len); + while (len--) + putchar(*cp++); + fflush(stdout); + break; + + case LWS_CALLBACK_RAW_WRITEABLE: + lwsl_user("LWS_CALLBACK_RAW_WRITEABLE\n"); + // lwsl_hexdump_info(buf, waiting); + if (!waiting) + break; + if (stdin_wsi) + lws_rx_flow_control(stdin_wsi, 1); + if (lws_write(wsi, buf, (unsigned int)waiting, LWS_WRITE_RAW) != waiting) { + lwsl_notice("%s: raw skt write failed\n", __func__); + + return -1; + } + break; + + case LWS_CALLBACK_TIMER: + lwsl_user("LWS_CALLBACK_TIMER\n"); + interrupted = 1; + lws_cancel_service(context); + return -1; + + default: + break; + } + + return 0; +} + +static struct lws_protocols protocols[] = { + { "raw-test", callback_raw_test, 0, 0, 0, NULL, 0 }, + LWS_PROTOCOL_LIST_TERM +}; + +static int +system_notify_cb(lws_state_manager_t *mgr, lws_state_notify_link_t *link, + int current, int target) +{ + struct lws_client_connect_info i; + + if (current != LWS_SYSTATE_OPERATIONAL || + target != LWS_SYSTATE_OPERATIONAL) + return 0; + + memset(&i, 0, sizeof i); + i.context = context; + i.method = "RAW"; + i.ssl_connection = LCCSCF_USE_SSL; + i.alpn = "http/1.1"; + i.address = server; + i.host = server; + i.port = atoi(port); + i.local_protocol_name = "raw-test"; + + waiting = lws_snprintf((char *)buf, sizeof(buf), "GET / HTTP/1.1\xaHost: libwebsockets.org\xa\xa"); + + if (!lws_client_connect_via_info(&i)) { + lwsl_err("Client creation failed\n"); + interrupted = 1; + } + + return 0; +} + +void sigint_handler(int sig) +{ + interrupted = 1; +} + +int main(int argc, const char **argv) +{ + struct lws_context_creation_info info; + const char *p; + int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE; + lws_state_notify_link_t notifier = { { NULL, NULL, NULL }, + system_notify_cb, "app" }; + lws_state_notify_link_t *na[] = { ¬ifier, NULL }; + + signal(SIGINT, sigint_handler); + + if ((p = lws_cmdline_option(argc, argv, "-d"))) + logs = atoi(p); + + lws_set_log_level(logs, NULL); + lwsl_user("LWS minimal raw client\n"); + + memset(&info, 0, sizeof info); + + info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + info.port = CONTEXT_PORT_NO_LISTEN_SERVER; + info.protocols = protocols; + info.register_notifier_list = na; + + context = lws_create_context(&info); + if (!context) { + lwsl_err("lws init failed\n"); + return 1; + } + + while (n >= 0 && !interrupted) + n = lws_service(context, 0); + + lwsl_user("%s: destroying context\n", __func__); + + lws_context_destroy(context); + + return 0; +} diff --git a/minimal-examples/api-tests/api-test-lws_map/main.c b/minimal-examples/api-tests/api-test-lws_map/main.c index 022c98a8..c17be818 100644 --- a/minimal-examples/api-tests/api-test-lws_map/main.c +++ b/minimal-examples/api-tests/api-test-lws_map/main.c @@ -11,6 +11,8 @@ #include +typedef struct lws_map_item lws_map_item_t; + /* custom key and comparator for test 3 */ typedef struct mykey { diff --git a/minimal-examples/embedded/esp32/esp-heltec-wb32/main/devices.c b/minimal-examples/embedded/esp32/esp-heltec-wb32/main/devices.c index a4dab2a0..da7cbe9c 100644 --- a/minimal-examples/embedded/esp32/esp-heltec-wb32/main/devices.c +++ b/minimal-examples/embedded/esp32/esp-heltec-wb32/main/devices.c @@ -31,7 +31,10 @@ lws_netdev_instance_wifi_t *wnd; static void esp32_i2c_delay(void) { - ets_delay_us(1); + volatile int n = 0; + + while (n < 20) + n++; } static const lws_bb_i2c_t li2c = { diff --git a/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c b/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c index d0d11f3f..f30ee589 100644 --- a/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c +++ b/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c @@ -167,7 +167,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { char buf[LWS_PRE + 1024], *start = &buf[LWS_PRE], *p = start, - *end = &buf[sizeof(buf) - LWS_PRE - 1]; + *end = &buf[sizeof(buf) - 1]; int n, idx = (int)(intptr_t)lws_get_opaque_user_data(wsi); struct pss *pss = (struct pss *)user; diff --git a/minimal-examples/http-client/minimal-http-client-post/minimal-http-client-post.c b/minimal-examples/http-client/minimal-http-client-post/minimal-http-client-post.c index 3bff115a..063f8f1c 100644 --- a/minimal-examples/http-client/minimal-http-client-post/minimal-http-client-post.c +++ b/minimal-examples/http-client/minimal-http-client-post/minimal-http-client-post.c @@ -30,7 +30,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, { struct pss *pss = (struct pss *)user; char buf[LWS_PRE + 1024], *start = &buf[LWS_PRE], *p = start, - *end = &buf[sizeof(buf) - LWS_PRE - 1]; + *end = &buf[sizeof(buf) - 1]; int n; switch (reason) { diff --git a/minimal-examples/http-server/minimal-http-server-custom-headers/minimal-http-server-custom-headers.c b/minimal-examples/http-server/minimal-http-server-custom-headers/minimal-http-server-custom-headers.c index d9a1f31a..4ffe32c1 100644 --- a/minimal-examples/http-server/minimal-http-server-custom-headers/minimal-http-server-custom-headers.c +++ b/minimal-examples/http-server/minimal-http-server-custom-headers/minimal-http-server-custom-headers.c @@ -37,7 +37,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start, - *end = &buf[sizeof(buf) - LWS_PRE - 1]; + *end = &buf[sizeof(buf) - 1]; struct pss *pss = (struct pss *)user; char value[32], *pr = &pss->result[LWS_PRE]; size_t e = sizeof(pss->result) - LWS_PRE; diff --git a/minimal-examples/http-server/minimal-http-server-dynamic/minimal-http-server-dynamic.c b/minimal-examples/http-server/minimal-http-server-dynamic/minimal-http-server-dynamic.c index f919146b..daade23b 100644 --- a/minimal-examples/http-server/minimal-http-server-dynamic/minimal-http-server-dynamic.c +++ b/minimal-examples/http-server/minimal-http-server-dynamic/minimal-http-server-dynamic.c @@ -42,7 +42,7 @@ callback_dynamic_http(struct lws *wsi, enum lws_callback_reasons reason, { struct pss *pss = (struct pss *)user; uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start, - *end = &buf[sizeof(buf) - LWS_PRE - 1]; + *end = &buf[sizeof(buf) - 1]; time_t t; int n; #if defined(LWS_HAVE_CTIME_R) diff --git a/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c b/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c index c5614e55..a47be0b2 100644 --- a/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c +++ b/minimal-examples/http-server/minimal-http-server-h2-long-poll/minimal-http-server.c @@ -57,7 +57,7 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, struct pss * pss = (struct pss *)user; uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE], *start = &buf[LWS_PRE], *p = start, - *end = p + sizeof(buf) - LWS_PRE; + *end = buf + sizeof(buf) - 1; int m, n; switch (reason) { diff --git a/minimal-examples/secure-streams/minimal-secure-streams-policy2c/minimal-secure-streams.c b/minimal-examples/secure-streams/minimal-secure-streams-policy2c/minimal-secure-streams.c index f3a0b699..bb86d3d3 100644 --- a/minimal-examples/secure-streams/minimal-secure-streams-policy2c/minimal-secure-streams.c +++ b/minimal-examples/secure-streams/minimal-secure-streams-policy2c/minimal-secure-streams.c @@ -573,7 +573,24 @@ int main(int argc, const char **argv) if (pol->u.mqtt.will_message) printf("\t\t\t.will_message = \"%s\",\n", pol->u.mqtt.will_message); - + if (pol->u.mqtt.will_qos) + printf("\t\t\t.will_qos = %u,\n", + pol->u.mqtt.will_qos); + if (pol->u.mqtt.will_retain) + printf("\t\t\t.will_retain = %u,\n", + pol->u.mqtt.will_retain); + if (pol->u.mqtt.birth_topic) + printf("\t\t\t.birth_topic = \"%s\",\n", + pol->u.mqtt.birth_topic); + if (pol->u.mqtt.birth_message) + printf("\t\t\t.birth_message = \"%s\",\n", + pol->u.mqtt.birth_message); + if (pol->u.mqtt.birth_qos) + printf("\t\t\t.birth_qos = %u,\n", + pol->u.mqtt.birth_qos); + if (pol->u.mqtt.birth_retain) + printf("\t\t\t.birth_retain = %u,\n", + pol->u.mqtt.birth_retain); if (pol->u.mqtt.keep_alive) printf("\t\t\t.keep_alive = %u,\n", pol->u.mqtt.keep_alive); @@ -583,13 +600,12 @@ int main(int argc, const char **argv) if (pol->u.mqtt.clean_start) printf("\t\t\t.clean_start = %u,\n", pol->u.mqtt.clean_start); - if (pol->u.mqtt.will_qos) - printf("\t\t\t.will_qos = %u,\n", - pol->u.mqtt.will_qos); - if (pol->u.mqtt.will_retain) - printf("\t\t\t.will_retain = %u,\n", - pol->u.mqtt.will_retain); - + if (pol->u.mqtt.aws_iot) + printf("\t\t\t.aws_iot = %u,\n", + pol->u.mqtt.aws_iot); + if (pol->u.mqtt.retain) + printf("\t\t\t.retain = %u,\n", + pol->u.mqtt.retain); printf("\t\t}\n\t},\n"); break; diff --git a/plugins/acme-client/protocol_lws_acme_client.c b/plugins/acme-client/protocol_lws_acme_client.c index d202085b..729c4482 100644 --- a/plugins/acme-client/protocol_lws_acme_client.c +++ b/plugins/acme-client/protocol_lws_acme_client.c @@ -1,7 +1,7 @@ /* * libwebsockets ACME client protocol plugin * - * Copyright (C) 2010 - 2019 Andy Green + * Copyright (C) 2010 - 2022 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -21,16 +21,9 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * - * Acme is in a big messy transition at the moment from a homebrewed api - * to an IETF one. The old repo for the homebrew api (they currently - * implement) is marked up as deprecated and "not accurate[ly] reflect[ing]" - * what they implement, but the IETF standard, currently at v7 is not yet - * implemented at let's encrypt (ETA Jan 2018). - * * This implementation follows draft 7 of the IETF standard, and falls back - * to whatever differences exist for Boulder's tls-sni-01 challenge. The - * tls-sni-02 support is there but nothing to test it against at the time of - * writing (Nov 1 2017). + * to whatever differences exist for Boulder's tls-sni-01 challenge. + * tls-sni-02 is also supported. */ #if !defined (LWS_PLUGIN_STATIC) @@ -143,16 +136,16 @@ callback_chall_http01(struct lws *wsi, enum lws_callback_reasons reason, struct lws_vhost *vhost = lws_get_vhost(wsi); struct acme_connection *ac = lws_vhost_user(vhost); uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start, - *end = &buf[sizeof(buf) - LWS_PRE - 1]; + *end = &buf[sizeof(buf) - 1]; int n; switch (reason) { case LWS_CALLBACK_HTTP: - lwsl_notice("%s: ca connection received, key_auth %s\n", - __func__, ac->key_auth); + lwsl_wsi_notice(wsi, "CA connection received, key_auth %s", + ac->key_auth); if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end)) { - lwsl_notice("%s: add status failed\n", __func__); + lwsl_wsi_warn(wsi, "add status failed"); return -1; } @@ -160,14 +153,13 @@ callback_chall_http01(struct lws *wsi, enum lws_callback_reasons reason, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/plain", 10, &p, end)) { - lwsl_notice("%s: add content_type failed\n", __func__); + lwsl_wsi_warn(wsi, "add content_type failed"); return -1; } n = (int)strlen(ac->key_auth); if (lws_add_http_header_content_length(wsi, (lws_filepos_t)n, &p, end)) { - lwsl_notice("%s: add content_length failed\n", - __func__); + lwsl_wsi_warn(wsi, "add content_length failed"); return -1; } @@ -175,13 +167,12 @@ callback_chall_http01(struct lws *wsi, enum lws_callback_reasons reason, WSI_TOKEN_HTTP_CONTENT_DISPOSITION, (unsigned char *)"attachment", 10, &p, end)) { - lwsl_notice("%s: add content_dispo failed\n", __func__); + lwsl_wsi_warn(wsi, "add content_dispo failed"); return -1; } if (lws_finalize_write_http_header(wsi, start, &p, end)) { - lwsl_notice("%s: finalize http header failed\n", - __func__); + lwsl_wsi_warn(wsi, "finalize http header failed"); return -1; } @@ -190,10 +181,10 @@ callback_chall_http01(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_HTTP_WRITEABLE: p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "%s", ac->key_auth); - lwsl_notice("%s: len %d\n", __func__, lws_ptr_diff(p, start)); + // lwsl_notice("%s: len %d\n", __func__, lws_ptr_diff(p, start)); if (lws_write(wsi, (uint8_t *)start, lws_ptr_diff_size_t(p, start), LWS_WRITE_HTTP_FINAL) != lws_ptr_diff(p, start)) { - lwsl_err("_write content failed\n"); + lwsl_wsi_err(wsi, "_write content failed"); return 1; } @@ -234,7 +225,7 @@ jws_create_packet(struct lws_jwe *jwe, const char *payload, size_t len, n = LWS_PRE + 2048; buf = malloc((unsigned int)n); if (!buf) { - lwsl_notice("%s: malloc %d failed\n", __func__, n); + lwsl_warn("%s: malloc %d failed\n", __func__, n); return -1; } @@ -680,14 +671,14 @@ lws_acme_load_create_auth_keys(struct per_vhost_data__lws_acme_client *vhd, n = lws_genrsa_new_keypair(vhd->context, &vhd->rsactx, LGRSAM_PKCS1_1_5, vhd->jwk.e, bits); if (n) { - lwsl_notice("failed to create keypair\n"); + lwsl_vhost_warn(vhd->vhost, "failed to create keypair"); return 1; } lwsl_notice("...keypair generated\n"); if (lws_jwk_save(&vhd->jwk, vhd->pvop[LWS_TLS_SET_AUTH_PATH])) { - lwsl_notice("unable to save %s\n", + lwsl_vhost_warn(vhd->vhost, "unable to save %s", vhd->pvop[LWS_TLS_SET_AUTH_PATH]); return 1; } @@ -709,8 +700,8 @@ lws_acme_start_acquisition(struct per_vhost_data__lws_acme_client *vhd, /* * ...well... we should try to do something about it then... */ - lwsl_notice("%s: ACME cert needs creating / updating: " - "vhost %s\n", __func__, lws_get_vhost_name(vhd->vhost)); + lwsl_vhost_notice(vhd->vhost, "ACME cert needs creating / updating: " + "vhost %s", lws_get_vhost_name(vhd->vhost)); vhd->ac = malloc(sizeof(*vhd->ac)); memset(vhd->ac, 0, sizeof(*vhd->ac)); @@ -795,11 +786,13 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, switch ((int)reason) { case LWS_CALLBACK_PROTOCOL_INIT: + if (vhd) + return 0; vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), lws_get_protocol(wsi), sizeof(struct per_vhost_data__lws_acme_client)); - if (vhd) - return 0; + if (!vhd) + return -1; vhd->context = lws_get_context(wsi); vhd->protocol = lws_get_protocol(wsi); @@ -867,7 +860,12 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, vhd->pvop[LWS_TLS_SET_CERT_PATH]); vhd->fd_updated_cert = lws_open(buf, LWS_O_WRONLY | LWS_O_CREAT | - LWS_O_TRUNC, 0600); + LWS_O_TRUNC + /*do not replace \n to \r\n on Windows */ + #ifdef WIN32 + | O_BINARY + #endif + , 0600); if (vhd->fd_updated_cert < 0) { lwsl_err("unable to create update cert file %s\n", buf); return -1; @@ -875,9 +873,14 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, lws_snprintf(buf, sizeof(buf) - 1, "%s.upd", vhd->pvop[LWS_TLS_SET_KEY_PATH]); vhd->fd_updated_key = lws_open(buf, LWS_O_WRONLY | LWS_O_CREAT | - LWS_O_TRUNC, 0600); + /*do not replace \n to \r\n on Windows */ + #ifdef WIN32 + O_BINARY | + #endif + LWS_O_TRUNC, 0600); if (vhd->fd_updated_key < 0) { - lwsl_err("unable to create update key file %s\n", buf); + lwsl_vhost_err(vhd->vhost, "unable to create update key file %s", buf); + return -1; } #endif @@ -929,35 +932,18 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, * Client */ - case LWS_CALLBACK_CLIENT_ESTABLISHED: - lwsl_notice("%s: CLIENT_ESTABLISHED\n", __func__); - break; - - case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: - lwsl_notice("%s: CLIENT_CONNECTION_ERROR: %p\n", __func__, wsi); - break; - - case LWS_CALLBACK_CLOSED_CLIENT_HTTP: - lwsl_notice("%s: CLOSED_CLIENT_HTTP: %p\n", __func__, wsi); - break; - - case LWS_CALLBACK_CLOSED: - lwsl_notice("%s: CLOSED: %p\n", __func__, wsi); - break; - case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: - lwsl_notice("%s: ESTABLISHED_CLIENT_HTTP:" - "%p, state:%d, status:%d\n", __func__, wsi, - ac->state, lws_http_client_http_response(wsi)); if (!ac) break; + ac->resp = (int)lws_http_client_http_response(wsi); + /* we get a new nonce each time */ if (lws_hdr_total_length(wsi, WSI_TOKEN_REPLAY_NONCE) && lws_hdr_copy(wsi, ac->replay_nonce, sizeof(ac->replay_nonce), WSI_TOKEN_REPLAY_NONCE) < 0) { - lwsl_notice("%s: nonce too large\n", __func__); + lwsl_vhost_warn(vhd->vhost, "nonce too large"); goto failed; } @@ -967,11 +953,12 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, lejp_construct(&ac->jctx, cb_dir, vhd, jdir_tok, LWS_ARRAY_SIZE(jdir_tok)); break; + case ACME_STATE_NEW_NONCE: /* - * we try to * register our keys next. - * It's OK if it ends up * they're already registered, - * this eliminates any * gaps where we stored the key + * we try to register our keys next. + * It's OK if it ends up they're already registered, + * this eliminates any gaps where we stored the key * but registration did not complete for some reason... */ ac->state = ACME_STATE_NEW_ACCOUNT; @@ -981,8 +968,7 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, cwsi = lws_acme_client_connect(vhd->context, vhd->vhost, &ac->cwsi, &ac->i, buf, "POST"); if (!cwsi) { - lwsl_notice("%s: failed to connect to acme\n", - __func__); + lwsl_vhost_warn(vhd->vhost, "failed to connect to acme"); goto failed; } @@ -991,28 +977,26 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, case ACME_STATE_NEW_ACCOUNT: if (!lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_LOCATION)) { - lwsl_notice("%s: no Location\n", __func__); + lwsl_vhost_warn(vhd->vhost, "no Location"); goto failed; } if (lws_hdr_copy(wsi, ac->acct_id, sizeof(ac->acct_id), WSI_TOKEN_HTTP_LOCATION) < 0) { - lwsl_notice("%s: Location too large\n", - __func__); + lwsl_vhost_warn(vhd->vhost, "Location too large"); goto failed; } ac->kid = ac->acct_id; - lwsl_notice("Location: %s\n", ac->acct_id); + lwsl_vhost_notice(vhd->vhost, "Location: %s", ac->acct_id); break; case ACME_STATE_NEW_ORDER: if (lws_hdr_copy(wsi, ac->order_url, sizeof(ac->order_url), WSI_TOKEN_HTTP_LOCATION) < 0) { - lwsl_notice("%s: missing cert location:\n", - __func__); + lwsl_vhost_warn(vhd->vhost, "missing cert location"); goto failed; } @@ -1061,7 +1045,6 @@ callback_acme_client(struct lws *wsi, enum lws_callback_reasons reason, ",\"contact\": [\"mailto:%s\"]}", vhd->pvop_active[LWS_TLS_REQ_ELEMENT_EMAIL]); - puts(start); strcpy(ac->active_url, ac->urls[JAD_NEW_ACCOUNT_URL]); pkt_add_hdrs: if (lws_gencrypto_jwe_alg_to_definition("RSA1_5", @@ -1096,7 +1079,7 @@ pkt_add_hdrs: WSI_TOKEN_HTTP_CONTENT_TYPE, (uint8_t *)content_type, 21, pp, pend)) { - lwsl_notice("could not add content type\n"); + lwsl_vhost_warn(vhd->vhost, "could not add content type"); goto failed; } @@ -1104,7 +1087,7 @@ pkt_add_hdrs: if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, (uint8_t *)buf, n, pp, pend)) { - lwsl_notice("could not add content length\n"); + lwsl_vhost_warn(vhd->vhost, "could not add content length"); goto failed; } @@ -1122,12 +1105,10 @@ pkt_add_hdrs: "}", vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME]); - puts(start); strcpy(ac->active_url, ac->urls[JAD_NEW_ORDER_URL]); goto pkt_add_hdrs; case ACME_STATE_AUTHZ: - puts(start); strcpy(ac->active_url, ac->authz_url); goto pkt_add_hdrs; @@ -1136,7 +1117,6 @@ pkt_add_hdrs: end = &buf[sizeof(buf) - 1]; p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{}"); - puts(start); strcpy(ac->active_url, ac->challenge_uri); goto pkt_add_hdrs; @@ -1147,7 +1127,7 @@ pkt_add_hdrs: case ACME_STATE_POLLING_CSR: if (ac->goes_around) break; - + lwsl_vhost_notice(vhd->vhost, "Generating ACME CSR... may take a little while"); p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "{\"csr\":\""); n = lws_tls_acme_sni_csr_create(vhd->context, &vhd->pvop_active[0], @@ -1155,12 +1135,11 @@ pkt_add_hdrs: &ac->alloc_privkey_pem, &ac->len_privkey_pem); if (n < 0) { - lwsl_notice("CSR generation failed\n"); + lwsl_vhost_warn(vhd->vhost, "CSR generation failed"); goto failed; } p += n; p += lws_snprintf(p, lws_ptr_diff_size_t(end, p), "\"}"); - puts(start); strcpy(ac->active_url, ac->finalize_url); goto pkt_add_hdrs; @@ -1175,7 +1154,6 @@ pkt_add_hdrs: break; case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE: - lwsl_notice("LWS_CALLBACK_CLIENT_HTTP_WRITEABLE\n"); if (!ac) break; @@ -1187,7 +1165,7 @@ pkt_add_hdrs: if (lws_write(wsi, (uint8_t *)ac->buf + LWS_PRE, (size_t)ac->len, LWS_WRITE_HTTP_FINAL) < 0) return -1; - lwsl_notice("wrote %d\n", ac->len); + ac->pos = ac->len; lws_client_http_body_pending(wsi, 0); break; @@ -1204,28 +1182,29 @@ pkt_add_hdrs: case ACME_STATE_AUTHZ: case ACME_STATE_NEW_ORDER: case ACME_STATE_DIRECTORY: - ((char *)in)[len] = '\0'; - puts(in); + m = lejp_parse(&ac->jctx, (uint8_t *)in, (int)len); if (m < 0 && m != LEJP_CONTINUE) { lwsl_notice("lejp parse failed %d\n", m); goto failed; } break; + case ACME_STATE_NEW_ACCOUNT: - ((char *)in)[len] = '\0'; - puts(in); break; + case ACME_STATE_DOWNLOAD_CERT: - ((char *)in)[len] = '\0'; - puts(in); - /* it should be the DER cert! */ - if ((unsigned int)ac->cpos + len > sizeof(ac->buf)) { - lwsl_notice("Incoming cert is too large!\n"); - goto failed; + /* + * It should be the DER cert... + * ACME 2.0 can send certs chain with 3 certs, store only first bytes + */ + if ((unsigned int)ac->cpos + len > sizeof(ac->buf)) + len = sizeof(ac->buf) - (unsigned int)ac->cpos; + + if (len) { + memcpy(&ac->buf[ac->cpos], in, len); + ac->cpos += (int)len; } - memcpy(&ac->buf[ac->cpos], in, len); - ac->cpos += (int)len; break; default: break; @@ -1234,9 +1213,9 @@ pkt_add_hdrs: /* unchunked content */ case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: - lwsl_notice("%s: LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n", __func__); if (!ac) return -1; + switch (ac->state) { default: { @@ -1252,7 +1231,6 @@ pkt_add_hdrs: break; case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: - lwsl_notice("%s: COMPLETED_CLIENT_HTTP\n", __func__); if (!ac) return -1; @@ -1281,7 +1259,7 @@ pkt_add_hdrs: case ACME_STATE_NEW_ACCOUNT: if ((ac->resp >= 200 && ac->resp < 299) || - ac->resp == 409) { + ac->resp == 409) { /* * Our account already existed, or exists now. * @@ -1324,8 +1302,7 @@ pkt_add_hdrs: vhd->vhost, &ac->cwsi, &ac->i, buf, "POST"); if (!cwsi) - lwsl_notice("%s: failed to connect\n", - __func__); + lwsl_notice("%s: failed to connect\n", __func__); return -1; /* close the completed client connection */ @@ -1335,13 +1312,12 @@ pkt_add_hdrs: lws_snprintf(buf, sizeof(buf), "Auth failed: %s", ac->detail); failreason = buf; - lwsl_notice("auth failed\n"); + lwsl_vhost_warn(vhd->vhost, "auth failed"); goto failed; } - lwsl_notice("chall: %s (%d)\n", ac->chall_token, - ac->resp); + lwsl_vhost_info(vhd->vhost, "chall: %s (%d)\n", ac->chall_token, ac->resp); if (!ac->chall_token[0]) { - lwsl_notice("no challenge\n"); + lwsl_vhost_warn(vhd->vhost, "no challenge"); goto failed; } @@ -1362,7 +1338,7 @@ pkt_add_hdrs: if (n < 0) goto failed; - lwsl_notice("key_auth: '%s'\n", ac->key_auth); + lwsl_vhost_notice(vhd->vhost, "key_auth: '%s'", ac->key_auth); lws_snprintf(ac->http01_mountpoint, sizeof(ac->http01_mountpoint), @@ -1378,8 +1354,7 @@ pkt_add_hdrs: ac->ci.mounts = &ac->mount; - /* listen on the same port as the vhost that triggered - * us */ + /* listen on the same port as the vhost that triggered us */ ac->ci.port = 80; /* make ourselves protocols[0] for the new vhost */ @@ -1396,7 +1371,7 @@ pkt_add_hdrs: if (!ac->vhost) goto failed; - lwsl_notice("challenge_uri %s\n", ac->challenge_uri); + lwsl_vhost_notice(vhd->vhost, "challenge_uri %s", ac->challenge_uri); /* * The challenge-specific vhost is up... let the ACME @@ -1408,14 +1383,14 @@ pkt_add_hdrs: ac->challenge_uri, "POST"); if (!cwsi) { - lwsl_notice("%s: connect failed\n", __func__); + lwsl_vhost_warn(vhd->vhost, "Connect failed"); goto failed; } return -1; /* close the completed client connection */ case ACME_STATE_START_CHALL: - lwsl_notice("%s: COMPLETED start chall: %s\n", - __func__, ac->challenge_uri); + lwsl_vhost_notice(vhd->vhost, "COMPLETED start chall: %s", + ac->challenge_uri); poll_again: ac->state = ACME_STATE_POLLING; lws_acme_report_status(vhd->vhost, LWS_CUS_CHALLENGE, @@ -1433,8 +1408,7 @@ poll_again: &ac->cwsi, &ac->i, buf, "POST"); if (!cwsi) { - lwsl_notice("%s: failed to connect to acme\n", - __func__); + lwsl_vhost_warn(vhd->vhost, "failed to connect to acme"); goto failed; } @@ -1443,18 +1417,14 @@ poll_again: case ACME_STATE_POLLING: if (ac->resp == 202 && strcmp(ac->status, "invalid") && - strcmp(ac->status, "valid")) { - lwsl_notice("status: %s\n", ac->status); + strcmp(ac->status, "valid")) goto poll_again; - } - if (!strcmp(ac->status, "pending")) { - lwsl_notice("status: %s\n", ac->status); + if (!strcmp(ac->status, "pending")) goto poll_again; - } if (!strcmp(ac->status, "invalid")) { - lwsl_notice("%s: Challenge failed\n", __func__); + lwsl_vhost_warn(vhd->vhost, "Challenge failed"); lws_snprintf(buf, sizeof(buf), "Challenge Invalid: %s", ac->detail); @@ -1462,7 +1432,7 @@ poll_again: goto failed; } - lwsl_notice("Challenge passed\n"); + lwsl_vhost_notice(vhd->vhost, "ACME challenge passed"); /* * The challenge was validated... so delete the @@ -1487,8 +1457,7 @@ poll_again: &ac->cwsi, &ac->i, buf, "POST"); if (!cwsi) { - lwsl_notice("%s: failed to connect to acme\n", - __func__); + lwsl_vhost_warn(vhd->vhost, "Failed to connect to acme"); goto failed; } @@ -1503,8 +1472,7 @@ poll_again: if (ac->resp != 200) { if (ac->goes_around++ == 30) { - lwsl_notice("%s: too many retries\n", - __func__); + lwsl_vhost_warn(vhd->vhost, "Too many retries"); goto failed; } @@ -1514,9 +1482,8 @@ poll_again: &ac->cwsi, &ac->i, buf, "POST"); if (!cwsi) { - lwsl_notice("%s: " - "failed to connect to acme\n", - __func__); + lwsl_vhost_warn(vhd->vhost, + "Failed to connect to acme"); goto failed; } @@ -1531,8 +1498,7 @@ poll_again: &ac->cwsi, &ac->i, buf, "POST"); if (!cwsi) { - lwsl_notice("%s: failed to connect to acme\n", - __func__); + lwsl_vhost_warn(vhd->vhost, "Failed to connect to acme"); goto failed; } @@ -1541,11 +1507,11 @@ poll_again: case ACME_STATE_DOWNLOAD_CERT: if (ac->resp != 200) { - lwsl_notice("download cert failed on resp %d\n", + lwsl_vhost_warn(vhd->vhost, "Download cert failed on resp %d", ac->resp); goto failed; } - lwsl_notice("The cert was sent..\n"); + lwsl_vhost_notice(vhd->vhost, "The cert was sent.."); lws_acme_report_status(vhd->vhost, LWS_CUS_ISSUE, NULL); @@ -1554,13 +1520,25 @@ poll_again: * ac->buf, length in ac->cpos; and the key in * ac->alloc_privkey_pem, length in * ac->len_privkey_pem. + * ACME 2.0 can send certs chain with 3 certs, we need save only first */ + { + char *end_cert = strstr(ac->buf, "END CERTIFICATE-----"); + + if (end_cert) { + ac->cpos = (int)(lws_ptr_diff_size_t(end_cert, ac->buf) + sizeof("END CERTIFICATE-----") - 1); + } else { + ac->cpos = 0; + lwsl_vhost_err(vhd->vhost, "Unable to find ACME cert!"); + goto failed; + } + } n = lws_plat_write_cert(vhd->vhost, 0, vhd->fd_updated_cert, ac->buf, (size_t)ac->cpos); if (n) { - lwsl_err("unable to write ACME cert! %d\n", n); + lwsl_vhost_err(vhd->vhost, "unable to write ACME cert! %d", n); goto failed; } @@ -1572,16 +1550,16 @@ poll_again: vhd->fd_updated_key, ac->alloc_privkey_pem, ac->len_privkey_pem)) { - lwsl_err("unable to write ACME key!\n"); + lwsl_vhost_err(vhd->vhost, "unable to write ACME key!"); goto failed; } /* * we have written the persistent copies */ - lwsl_notice("%s: Updated certs written for %s " - "to %s.upd and %s.upd\n", __func__, - vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME], + lwsl_vhost_notice(vhd->vhost, "Updated certs written for %s " + "to %s.upd and %s.upd", + vhd->pvop_active[LWS_TLS_REQ_ELEMENT_COMMON_NAME], vhd->pvop_active[LWS_TLS_SET_CERT_PATH], vhd->pvop_active[LWS_TLS_SET_KEY_PATH]); @@ -1593,7 +1571,7 @@ poll_again: ac->buf, (size_t)ac->cpos, ac->alloc_privkey_pem, ac->len_privkey_pem)) { - lwsl_notice("problem setting certs\n"); + lwsl_vhost_warn(vhd->vhost, "problem setting certs"); } lws_acme_finished(vhd); @@ -1615,7 +1593,7 @@ poll_again: ac->challenge_uri, "GET"); if (!cwsi) { - lwsl_notice("%s: failed to connect\n", __func__); + lwsl_vhost_warn(vhd->vhost, "Failed to connect"); goto failed; } break; @@ -1627,7 +1605,7 @@ poll_again: return 0; failed: - lwsl_notice("%s: failed out\n", __func__); + lwsl_vhost_warn(vhd->vhost, "Failed out"); lws_acme_report_status(vhd->vhost, LWS_CUS_FAILED, failreason); lws_acme_finished(vhd); diff --git a/plugins/deaddrop/protocol_lws_deaddrop.c b/plugins/deaddrop/protocol_lws_deaddrop.c index 79f736c0..0e51507b 100644 --- a/plugins/deaddrop/protocol_lws_deaddrop.c +++ b/plugins/deaddrop/protocol_lws_deaddrop.c @@ -383,7 +383,7 @@ callback_deaddrop(struct lws *wsi, enum lws_callback_reasons reason, struct pss_deaddrop *pss = (struct pss_deaddrop *)user; uint8_t buf[LWS_PRE + LWS_RECOMMENDED_MIN_HEADER_SPACE], *start = &buf[LWS_PRE], *p = start, - *end = &buf[sizeof(buf) - LWS_PRE - 1]; + *end = &buf[sizeof(buf) - 1]; char fname[256], *wp; const char *cp; int n, m, was; diff --git a/plugins/protocol_fulltext_demo.c b/plugins/protocol_fulltext_demo.c index 0d780993..35d91e19 100644 --- a/plugins/protocol_fulltext_demo.c +++ b/plugins/protocol_fulltext_demo.c @@ -65,7 +65,7 @@ callback_fts(struct lws *wsi, enum lws_callback_reasons reason, void *user, lws_get_protocol(wsi)); struct pss_fts_demo *pss = (struct pss_fts_demo *)user; uint8_t buf[LWS_PRE + 2048], *start = &buf[LWS_PRE], *p = start, - *end = &buf[sizeof(buf) - LWS_PRE - 1]; + *end = &buf[sizeof(buf) - 1]; struct lws_fts_search_params params; const char *ccp = (const char *)in; struct lws_fts_result *result; diff --git a/plugins/protocol_lws_openmetrics_export.c b/plugins/protocol_lws_openmetrics_export.c index f7fb6015..f6b1850b 100644 --- a/plugins/protocol_lws_openmetrics_export.c +++ b/plugins/protocol_lws_openmetrics_export.c @@ -971,7 +971,7 @@ callback_lws_openmetrics_prox_client(struct lws *wsi, /* the proxy server uri */ - if (lws_pvo_get_str(in, "ws-server-uri", &cp)) { + if (lws_pvo_get_str(in, "ws-server-uri", &cp) || !cp) { lwsl_warn("%s: ws-server-uri pvo required\n", __func__); return 0; diff --git a/plugins/ssh-base/sshd.c b/plugins/ssh-base/sshd.c index 90fa3d72..cab174f6 100644 --- a/plugins/ssh-base/sshd.c +++ b/plugins/ssh-base/sshd.c @@ -2014,7 +2014,7 @@ lws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason, const struct lws_protocol_vhost_options *pvo; const struct lws_protocols *prot; struct lws_ssh_channel *ch; - char lang[10]; + char lang[10] = ""; int n, m, o; /* diff --git a/test-apps/test-client.c b/test-apps/test-client.c index 640fa8a0..05d08ed7 100644 --- a/test-apps/test-client.c +++ b/test-apps/test-client.c @@ -125,7 +125,7 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, #endif #endif const char *which = "http"; - char which_wsi[10], buf[50 + LWS_PRE]; + char which_wsi[50], buf[80 + LWS_PRE]; int n; switch (reason) { -- 2.34.1