mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-10-28 11:14:58 +00:00
fix(mqtt): 8 KB MQTT task stack when TLS verifies a CA certificate
On boards with PSRAM the MQTT client runs in its own task with a 5120 byte stack. Verifying an EC certificate chain against a CA, such as Let's Encrypt ISRG Root X2, needs about 6 KB, so the task overflowed and the board boot looped on every connect. The espMqttClient constructors now take the stack size, and startClient() passes EMSESP_MQTT_STACKSIZE_CA (8192) when TLS is on with a CA, keeping the 5120 default for insecure TLS and plain MQTT. The client is recreated when that changes. The stack usage log reports against the size the task was created with.
This commit is contained in:
@@ -71,6 +71,7 @@ This release is based on the latest Espressif/Arduino core version 3. It brings
|
|||||||
- a second boiler monitor `0xE4` carrying `0xFFFF` cleared a valid `pc0Flow`. That empty value is now ignored [#3224](https://github.com/emsesp/EMS-ESP32/issues/3224)
|
- a second boiler monitor `0xE4` carrying `0xFFFF` cleared a valid `pc0Flow`. That empty value is now ignored [#3224](https://github.com/emsesp/EMS-ESP32/issues/3224)
|
||||||
- writing a negative custom entity value was always 1 too high because float-to-int rounding always added +0.5. Negative values now round the same way as positive ones [#3297](https://github.com/emsesp/EMS-ESP32/issues/3297)
|
- writing a negative custom entity value was always 1 too high because float-to-int rounding always added +0.5. Negative values now round the same way as positive ones [#3297](https://github.com/emsesp/EMS-ESP32/issues/3297)
|
||||||
- after a cold boot, SoftAP fallback no longer abandons STA forever. If a home WiFi SSID is configured, EMS-ESP keeps retrying STA while the captive portal is up so a late-booting router (e.g. after a power outage) can still be joined; SoftAP stops once STA gets an IP
|
- after a cold boot, SoftAP fallback no longer abandons STA forever. If a home WiFi SSID is configured, EMS-ESP keeps retrying STA while the captive portal is up so a late-booting router (e.g. after a power outage) can still be joined; SoftAP stops once STA gets an IP
|
||||||
|
- MQTT with TLS and a CA certificate crashed on every connect (a boot loop) on boards with PSRAM when the broker's certificate chain is EC, such as Let's Encrypt ISRG Root X2: verifying it needs about 6 KB of stack and the MQTT task only had 5120 bytes. The MQTT task now gets an 8 KB stack when TLS verifies a CA certificate, and keeps 5120 bytes for insecure TLS and plain MQTT
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ using espMqttClientInternals::PacketType;
|
|||||||
using espMqttClientTypes::DisconnectReason;
|
using espMqttClientTypes::DisconnectReason;
|
||||||
using espMqttClientTypes::Error;
|
using espMqttClientTypes::Error;
|
||||||
|
|
||||||
MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority, uint8_t core)
|
MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority, uint8_t core, uint32_t stackSize)
|
||||||
: _useInternalTask(useInternalTask)
|
: _useInternalTask(useInternalTask)
|
||||||
, _transport(nullptr)
|
, _transport(nullptr)
|
||||||
, _onConnectCallback(nullptr)
|
, _onConnectCallback(nullptr)
|
||||||
@@ -55,6 +55,7 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
|
|||||||
, _disconnectReason(DisconnectReason::TCP_DISCONNECTED)
|
, _disconnectReason(DisconnectReason::TCP_DISCONNECTED)
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
#if defined(ARDUINO_ARCH_ESP32) && ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||||
, _highWaterMark(4294967295)
|
, _highWaterMark(4294967295)
|
||||||
|
, _stackSize(stackSize)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
EMC_GENERATE_CLIENTID(_generatedClientId);
|
EMC_GENERATE_CLIENTID(_generatedClientId);
|
||||||
@@ -64,12 +65,12 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
|
|||||||
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
||||||
#ifdef CONFIG_FREERTOS_UNICORE
|
#ifdef CONFIG_FREERTOS_UNICORE
|
||||||
// no core to pin to on single-core targets (S2, C3, C6)
|
// no core to pin to on single-core targets (S2, C3, C6)
|
||||||
xTaskCreate((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle);
|
xTaskCreate((TaskFunction_t)_loop, "mqttclient", stackSize, this, priority, &_taskHandle);
|
||||||
#else
|
#else
|
||||||
if (core > 1) {
|
if (core > 1) {
|
||||||
xTaskCreate((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle);
|
xTaskCreate((TaskFunction_t)_loop, "mqttclient", stackSize, this, priority, &_taskHandle);
|
||||||
} else {
|
} else {
|
||||||
xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", EMC_TASK_STACK_SIZE, this, priority, &_taskHandle, core);
|
xTaskCreatePinnedToCore((TaskFunction_t)_loop, "mqttclient", stackSize, this, priority, &_taskHandle, core);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -77,6 +78,7 @@ MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint
|
|||||||
(void) useInternalTask;
|
(void) useInternalTask;
|
||||||
(void) priority;
|
(void) priority;
|
||||||
(void) core;
|
(void) core;
|
||||||
|
(void) stackSize;
|
||||||
#endif
|
#endif
|
||||||
_clientId = _generatedClientId;
|
_clientId = _generatedClientId;
|
||||||
_core = core;
|
_core = core;
|
||||||
@@ -320,7 +322,7 @@ void MqttClient::loop() {
|
|||||||
size_t waterMark = uxTaskGetStackHighWaterMark(NULL);
|
size_t waterMark = uxTaskGetStackHighWaterMark(NULL);
|
||||||
if (waterMark < _highWaterMark) {
|
if (waterMark < _highWaterMark) {
|
||||||
_highWaterMark = waterMark;
|
_highWaterMark = waterMark;
|
||||||
emc_log_i("Stack usage: %zu/%i", EMC_TASK_STACK_SIZE - _highWaterMark, EMC_TASK_STACK_SIZE);
|
emc_log_i("Stack usage: %zu/%zu", _stackSize - _highWaterMark, _stackSize);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class MqttClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1);
|
explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1, uint32_t stackSize = EMC_TASK_STACK_SIZE);
|
||||||
espMqttClientTypes::UseInternalTask _useInternalTask;
|
espMqttClientTypes::UseInternalTask _useInternalTask;
|
||||||
espMqttClientInternals::Transport* _transport;
|
espMqttClientInternals::Transport* _transport;
|
||||||
|
|
||||||
@@ -207,6 +207,7 @@ class MqttClient {
|
|||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||||
size_t _highWaterMark;
|
size_t _highWaterMark;
|
||||||
|
size_t _stackSize;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -208,8 +208,8 @@ class MqttClientSetup : public MqttClient {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit MqttClientSetup(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1)
|
explicit MqttClientSetup(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1, uint32_t stackSize = EMC_TASK_STACK_SIZE)
|
||||||
: MqttClient(useInternalTask, priority, core) {
|
: MqttClient(useInternalTask, priority, core, stackSize) {
|
||||||
#if EMC_MULTIPLE_CALLBACKS
|
#if EMC_MULTIPLE_CALLBACKS
|
||||||
_onConnectCallback = [this](bool sessionPresent) {
|
_onConnectCallback = [this](bool sessionPresent) {
|
||||||
for (auto callback : _onConnectCallbacks) if (callback.first) callback.first(sessionPresent);
|
for (auto callback : _onConnectCallbacks) if (callback.first) callback.first(sessionPresent);
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ espMqttClient::espMqttClient(espMqttClientTypes::UseInternalTask useInternalTask
|
|||||||
_transport = &_client;
|
_transport = &_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
espMqttClient::espMqttClient(uint8_t priority, uint8_t core)
|
espMqttClient::espMqttClient(uint8_t priority, uint8_t core, uint32_t stackSize)
|
||||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::YES, priority, core)
|
: MqttClientSetup(espMqttClientTypes::UseInternalTask::YES, priority, core, stackSize)
|
||||||
, _client() {
|
, _client() {
|
||||||
_transport = &_client;
|
_transport = &_client;
|
||||||
}
|
}
|
||||||
@@ -27,8 +27,8 @@ espMqttClientSecure::espMqttClientSecure(espMqttClientTypes::UseInternalTask use
|
|||||||
_transport = &_client;
|
_transport = &_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
espMqttClientSecure::espMqttClientSecure(uint8_t priority, uint8_t core)
|
espMqttClientSecure::espMqttClientSecure(uint8_t priority, uint8_t core, uint32_t stackSize)
|
||||||
: MqttClientSetup(espMqttClientTypes::UseInternalTask::YES, priority, core)
|
: MqttClientSetup(espMqttClientTypes::UseInternalTask::YES, priority, core, stackSize)
|
||||||
, _client() {
|
, _client() {
|
||||||
_transport = &_client;
|
_transport = &_client;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class espMqttClientSecure : public MqttClientSetup<espMqttClientSecure> {
|
|||||||
class espMqttClient : public MqttClientSetup<espMqttClient> {
|
class espMqttClient : public MqttClientSetup<espMqttClient> {
|
||||||
public:
|
public:
|
||||||
explicit espMqttClient(espMqttClientTypes::UseInternalTask useInternalTask);
|
explicit espMqttClient(espMqttClientTypes::UseInternalTask useInternalTask);
|
||||||
explicit espMqttClient(uint8_t priority = 1, uint8_t core = 1);
|
explicit espMqttClient(uint8_t priority = 1, uint8_t core = 1, uint32_t stackSize = EMC_TASK_STACK_SIZE);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
espMqttClientInternals::ClientSync _client;
|
espMqttClientInternals::ClientSync _client;
|
||||||
@@ -57,7 +57,7 @@ class espMqttClient : public MqttClientSetup<espMqttClient> {
|
|||||||
class espMqttClientSecure : public MqttClientSetup<espMqttClientSecure> {
|
class espMqttClientSecure : public MqttClientSetup<espMqttClientSecure> {
|
||||||
public:
|
public:
|
||||||
explicit espMqttClientSecure(espMqttClientTypes::UseInternalTask useInternalTask);
|
explicit espMqttClientSecure(espMqttClientTypes::UseInternalTask useInternalTask);
|
||||||
explicit espMqttClientSecure(uint8_t priority = 1, uint8_t core = 1);
|
explicit espMqttClientSecure(uint8_t priority = 1, uint8_t core = 1, uint32_t stackSize = EMC_TASK_STACK_SIZE);
|
||||||
espMqttClientSecure & setInsecure();
|
espMqttClientSecure & setInsecure();
|
||||||
espMqttClientSecure & setCACert(const char * rootCA);
|
espMqttClientSecure & setCACert(const char * rootCA);
|
||||||
espMqttClientSecure & setCertificate(const char * clientCa);
|
espMqttClientSecure & setCertificate(const char * clientCa);
|
||||||
|
|||||||
@@ -33,9 +33,12 @@ void MqttSettingsService::begin() {
|
|||||||
|
|
||||||
void MqttSettingsService::startClient() {
|
void MqttSettingsService::startClient() {
|
||||||
static bool isSecure = false;
|
static bool isSecure = false;
|
||||||
|
static uint32_t stackSize = EMC_TASK_STACK_SIZE;
|
||||||
|
// only verifying a CA chain needs the larger stack, insecure TLS and plain MQTT fit in the default
|
||||||
|
const uint32_t wantStack = (_state.enableTLS && _state.rootCA != "insecure") ? EMSESP_MQTT_STACKSIZE_CA : EMC_TASK_STACK_SIZE;
|
||||||
if (_mqttClient) {
|
if (_mqttClient) {
|
||||||
// do we need to change the client?
|
// do we need to change the client?
|
||||||
if ((isSecure && _state.enableTLS) || (!isSecure && !_state.enableTLS)) {
|
if (isSecure == _state.enableTLS && stackSize == wantStack) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,12 +46,14 @@ void MqttSettingsService::startClient() {
|
|||||||
_mqttClient = nullptr;
|
_mqttClient = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stackSize = wantStack;
|
||||||
|
|
||||||
if (_state.enableTLS) {
|
if (_state.enableTLS) {
|
||||||
isSecure = true;
|
isSecure = true;
|
||||||
if (emsesp::EMSESP::system_.PSram() == 0) {
|
if (emsesp::EMSESP::system_.PSram() == 0) {
|
||||||
_mqttClient = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
|
_mqttClient = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
|
||||||
} else {
|
} else {
|
||||||
_mqttClient = new espMqttClientSecure(EMSESP_MQTT_PRIORITY, EMSESP_MQTT_RUNNING_CORE);
|
_mqttClient = new espMqttClientSecure(EMSESP_MQTT_PRIORITY, EMSESP_MQTT_RUNNING_CORE, wantStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_mqttClient) {
|
if (!_mqttClient) {
|
||||||
|
|||||||
@@ -60,6 +60,11 @@
|
|||||||
#define EMC_TASK_STACK_SIZE EMSESP_MQTT_STACKSIZE
|
#define EMC_TASK_STACK_SIZE EMSESP_MQTT_STACKSIZE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// MQTT task stack when TLS verifies the broker against a CA. BearSSL needs ~6 KB to verify an EC (P-384, P-521) chain
|
||||||
|
#ifndef EMSESP_MQTT_STACKSIZE_CA
|
||||||
|
#define EMSESP_MQTT_STACKSIZE_CA 8192
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef EMSESP_MQTT_PRIORITY
|
#ifndef EMSESP_MQTT_PRIORITY
|
||||||
#define EMSESP_MQTT_PRIORITY 1
|
#define EMSESP_MQTT_PRIORITY 1
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user