From b063b3bab67e54b956b93907a327126a9997b633 Mon Sep 17 00:00:00 2001 From: Erik Fleckstein Date: Mon, 21 Mar 2022 14:53:19 +0100 Subject: [PATCH] mqtt: Use string lengths not JSON struct sizes for payload limits. --- software/src/config.cpp | 39 ++++++++++++++++++++++++++++++ software/src/config.h | 1 + software/src/modules/mqtt/mqtt.cpp | 4 +-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/software/src/config.cpp b/software/src/config.cpp index 1bf68d5d1..63dc19814 100644 --- a/software/src/config.cpp +++ b/software/src/config.cpp @@ -18,6 +18,7 @@ */ #include "config.h" +#include "math.h" struct printer { void operator()(const Config::ConfString &x) const { Serial.println("string"); } @@ -167,6 +168,40 @@ struct to_json { const std::vector &keys_to_censor; }; +struct string_length_visitor { + size_t operator()(const Config::ConfString &x) { + return x.maxChars + 3; // "" and null terminator + } + size_t operator()(const Config::ConfFloat &x) { + return 42; // Educated guess + } + size_t operator()(const Config::ConfInt &x) { + return 11; + } + size_t operator()(const Config::ConfUint &x) { + return 10; + } + size_t operator()(const Config::ConfBool &x) { + return 5; + } + size_t operator()(std::nullptr_t x) { + return 4; + } + size_t operator()(const Config::ConfArray &x) + { + return strict_variant::apply_visitor(string_length_visitor{}, x.prototype->value) * x.maxElements + (x.maxElements + 1); //[,] and n-1 , + } + size_t operator()(const Config::ConfObject &x) + { + size_t sum = 2; // { and } + for (size_t i = 0; i < x.value.size(); ++i) { + sum += x.value[i].first.length() + 3; // "" and null terminator + sum += strict_variant::apply_visitor(string_length_visitor{}, x.value[i].second.value);; + } + return sum; + } +}; + struct json_length_visitor { size_t operator()(const Config::ConfString &x) { return zero_copy ? 0 : (x.maxChars + 1); @@ -692,6 +727,10 @@ size_t Config::json_size(bool zero_copy) const { return strict_variant::apply_visitor(json_length_visitor{zero_copy}, value); } +size_t Config::max_string_length() const { + return strict_variant::apply_visitor(string_length_visitor{}, value); +} + void Config::save_to_file(File file) { DynamicJsonDocument doc(json_size(false)); diff --git a/software/src/config.h b/software/src/config.h index 3eeb03c5e..5befbf51f 100644 --- a/software/src/config.h +++ b/software/src/config.h @@ -380,6 +380,7 @@ struct Config { } */ size_t json_size(bool zero_copy) const; + size_t max_string_length() const; void save_to_file(File file); diff --git a/software/src/modules/mqtt/mqtt.cpp b/software/src/modules/mqtt/mqtt.cpp index fdb815b7d..72a70d9ed 100644 --- a/software/src/modules/mqtt/mqtt.cpp +++ b/software/src/modules/mqtt/mqtt.cpp @@ -73,7 +73,7 @@ void Mqtt::subscribe(String topic_suffix, uint32_t max_payload_length, std::func void Mqtt::addCommand(size_t commandIdx, const CommandRegistration ®) { - auto req_size = reg.config->json_size(true); + auto req_size = reg.config->max_string_length(); if (req_size > MQTT_RECV_BUFFER_SIZE) { logger.printfln("MQTT: Recv buf is %u bytes. %s requires %u. Bump MQTT_RECV_BUFFER_SIZE! Not subscribing!", MQTT_RECV_BUFFER_SIZE, reg.path.c_str(), req_size); return; @@ -84,7 +84,7 @@ void Mqtt::addCommand(size_t commandIdx, const CommandRegistration ®) if (mqtt_state.get("connection_state")->asInt() != (int)MqttConnectionState::CONNECTED) return; - subscribe(reg.path, reg.config->json_size(true), [reg, commandIdx](char *payload, size_t payload_len){ + subscribe(reg.path, reg.config->max_string_length(), [reg, commandIdx](char *payload, size_t payload_len){ String reason = api.getCommandBlockedReason(commandIdx); if (reason != "") { logger.printfln("MQTT: Command %s is blocked: %s", reg.path.c_str(), reason.c_str());