"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",
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)
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)
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)
# 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)
get_filename_component(OPENSSL_EXECUTABLE_PATH ${OPENSSL_EXECUTABLE} DIRECTORY)\r
message(VERBOSE "OPENSSL_EXECUTABLE_PATH=${OPENSSL_EXECUTABLE_PATH}")\r
set(OPENSSL_EXECUTABLE_BIN_PATH "")\r
- string(REGEX MATCH "^(.*)/tools/openssl$" REGEX_MATCH ${OPENSSL_EXECUTABLE_PATH})\r
+ string(REGEX MATCH "^(.*)/tools/openssl$" REGEX_MATCH "${OPENSSL_EXECUTABLE_PATH}")\r
message(DEBUG "REGEX_MATCH=\"${REGEX_MATCH}\"")\r
message(DEBUG "CMAKE_MATCH_1=\"${CMAKE_MATCH_1}\"")\r
if (NOT ${REGEX_MATCH} EQUAL "")\r
include(CheckIncludeFile)
include(CheckCSourceCompiles)
-include(LwsCheckRequirements)
set(requirements 1)
#include <mbedtls/ssl.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/version.h>
#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 <openssl/ssl.h>
* 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 ---^ ******/
*
* 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);
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
/**< 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;
/**
//@{
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;
} 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
* 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);
* \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
* 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);
//@}
#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,
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 {
#include <lwip/sockets.h>
#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;
uint8_t birth_qos;
uint8_t birth_retain;
uint8_t aws_iot;
+ uint8_t retain;
} mqtt;
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
$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)
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}
"
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;
}
} 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)
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;
}
#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;
}
/* 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...
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);
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
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;
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
#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);
_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,
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++;
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 &&
((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);
/* 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;
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;
}
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
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
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 {
if (cx->refcount_cb)
cx->refcount_cb(cx, _new);
+
+#if LWS_MAX_SMP > 1
+ lws_pthread_mutex_unlock(&cx->refcount_lock);
+#endif
}
void
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
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) {
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,
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;
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)
+++ /dev/null
-// 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__ */
#include "FreeRTOS_IP.h"
#endif
#include "timers.h"
+#if defined(LWS_ESP_PLATFORM)
#include <esp_attr.h>
+#endif
#include <semphr.h>
#else
#include "freertos/timers.h"
+#if defined(LWS_ESP_PLATFORM)
#include <esp_attr.h>
+#endif
#include <esp_system.h>
#include <esp_task_wdt.h>
#endif
{
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
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);
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)
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)
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;
}
int
lws_plat_destroy_dl(struct lws_plugin *p)
{
- return uv_dlclose(&p->u.lib);
+ uv_dlclose(&p->u.lib);
+
+ return 0;
}
#endif
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;
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;
* 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);
}
{
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;
/* 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,
// 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;
}
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 |
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;
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 +
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);
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
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;
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__);
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]);
(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)
static const char * const paths_vhosts[] = {
"vhosts[]",
- "vhosts[].mounts[]",
"vhosts[].name",
"vhosts[].port",
"vhosts[].interface",
"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[]",
"vhosts[].ssl-option-set",
"vhosts[].ssl-option-clear",
"vhosts[].mounts[].pmo[].*",
+ "vhosts[].mounts[].pmo[]",
"vhosts[].headers[].*",
"vhosts[].headers[]",
"vhosts[].client-ssl-key",
enum lejp_vhost_paths {
LEJPVP,
- LEJPVP_MOUNTS,
LEJPVP_NAME,
LEJPVP_PORT,
LEJPVP_INTERFACE,
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,
LEJPVP_SSL_OPTION_SET,
LEJPVP_SSL_OPTION_CLEAR,
LEJPVP_PMO,
+ LEJPVP_PM_baseO,
LEJPVP_HEADERS_NAME,
LEJPVP_HEADERS,
LEJPVP_CLIENT_SSL_KEY,
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);
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)
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);
lwsl_info("%s: query string %d longer "
"than we can handle\n", __func__,
na);
-
+ lws_free(rpath);
return -1;
}
#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
"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)));
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)
{
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)
{
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)
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)
* 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;
}
/* 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);
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;
}
(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;
(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;
#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,
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;
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;
};
/*
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 */
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;
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) {
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
;
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.
#include <private-lib-core.h>
+#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)
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 */
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;
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.
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));
"s[].*.mqtt_topic",
"s[].*.mqtt_subscribe",
"s[].*.mqtt_qos",
+ "s[].*.mqtt_retain",
"s[].*.mqtt_keep_alive",
"s[].*.mqtt_clean_start",
"s[].*.mqtt_will_topic",
LSSPPT_MQTT_TOPIC,
LSSPPT_MQTT_SUBSCRIBE,
LSSPPT_MQTT_QOS,
+ LSSPPT_MQTT_RETAIN,
LSSPPT_MQTT_KEEPALIVE,
LSSPPT_MQTT_CLEAN_START,
LSSPPT_MQTT_WILL_TOPIC,
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;
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)
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,
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;
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) {
// 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);
*/
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
#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;
/*
* libwebsockets - small server side websockets and web server implementation
*
- * Copyright (C) 2019 - 2021 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
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
}
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;
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;
}
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] ... */
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]) {
/*
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)
/*
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)
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);
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)
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;
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;
}
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;
{
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;
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);
void *
lws_sspc_to_user_object(struct lws_sspc_handle *h)
{
- return (void *)&h[1];
+ return (void *)(h + 1);
}
void
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);
[LWSSSCS_POLL] = (1 << LWSSSCS_CONNECTING) |
(1 << LWSSSCS_TIMEOUT) |
+ (1 << LWSSSCS_ALL_RETRIES_FAILED) |
(1 << LWSSSCS_DESTROYING),
[LWSSSCS_ALL_RETRIES_FAILED] = (1 << LWSSSCS_CONNECTING) |
(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) |
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;
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;
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);
void *
lws_ss_to_user_object(struct lws_ss_handle *h)
{
- return (void *)&h[1];
+ return (void *)(h + 1);
}
void
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
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) {
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.")
# 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 <mbedtls/x509_crt.h>\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 <mbedtls/ssl.h>\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 <mbedtls/x509_crt.h>\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 <mbedtls/ssl.h>\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)
}
} 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;
}
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);
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);
/*
* libwebsockets - small server side websockets and web server implementation
*
- * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2022 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
(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++; \
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;
}
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;
}
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)) {
#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);
* 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;
}
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;
}
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;
}
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);
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);
{
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);
}
*/
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;
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);
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;
}
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;
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;
}
}
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:
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: {
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;
}
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:
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;
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;
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);
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);
}
//#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)
{
return 0;
}
-#endif
/**
* @brief create SSL low-level object
#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);
{
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)
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;
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
}
else
*len = 0;
#else
+ fprintf(stderr, "mbedtls_ssl_conf_alpn_protocols absent\n");
*len = 0;
#endif
}
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)
__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
(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;
/*
* libwebsockets - small server side websockets and web server implementation
*
- * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2022 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
/* 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)
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
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
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:
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;
}
--- /dev/null
+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()
--- /dev/null
+/*
+ * lws-minimal-raw-client
+ *
+ * Written in 2010-2022 by Andy Green <andy@warmcat.com>
+ *
+ * This file is made available under the Creative Commons CC0 1.0
+ * Universal Public Domain Dedication.
+ *
+ * This demonstrates connecting a "raw" client connection
+ */
+
+#include <libwebsockets.h>
+#include <string.h>
+#include <signal.h>
+#if !defined(WIN32)
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#if !defined(WIN32)
+#include <unistd.h>
+#endif
+#include <errno.h>
+
+#include <assert.h>
+
+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;
+}
#include <libwebsockets.h>
+typedef struct lws_map_item lws_map_item_t;
+
/* custom key and comparator for test 3 */
typedef struct mykey {
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 = {
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;
{
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) {
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;
{
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)
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) {
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);
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;
/*
* libwebsockets ACME client protocol plugin
*
- * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010 - 2022 Andy Green <andy@warmcat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* 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)
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
/*
* ...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));
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);
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;
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
* 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;
}
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;
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;
}
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;
}
",\"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",
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;
}
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;
}
"}",
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;
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;
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],
&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;
break;
case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE:
- lwsl_notice("LWS_CALLBACK_CLIENT_HTTP_WRITEABLE\n");
if (!ac)
break;
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;
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;
/* 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:
{
break;
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
- lwsl_notice("%s: COMPLETED_CLIENT_HTTP\n", __func__);
if (!ac)
return -1;
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.
*
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 */
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;
}
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),
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 */
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
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,
&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;
}
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);
goto failed;
}
- lwsl_notice("Challenge passed\n");
+ lwsl_vhost_notice(vhd->vhost, "ACME challenge passed");
/*
* The challenge was validated... so delete the
&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;
}
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;
}
&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;
}
&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;
}
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);
* 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;
}
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]);
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);
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;
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);
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;
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;
/* 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;
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;
/*
#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) {