Prevent config corruption by checking whether memory allocation was successfull.

This commit is contained in:
Thomas Basler 2024-01-04 13:42:39 +01:00
parent c1fc907ecb
commit 4053e31a5e
14 changed files with 46 additions and 43 deletions

View File

@ -5,6 +5,7 @@
#include "WebApi_device.h"
#include "WebApi_devinfo.h"
#include "WebApi_dtu.h"
#include "WebApi_errors.h"
#include "WebApi_eventlog.h"
#include "WebApi_firmware.h"
#include "WebApi_gridprofile.h"
@ -34,6 +35,8 @@ public:
static void sendTooManyRequests(AsyncWebServerRequest* request);
static void writeConfig(JsonObject& retMsg, const WebApiError code = WebApiError::GenericSuccess, const String& message = "Settings saved!");
private:
void loop();

View File

@ -8,6 +8,7 @@ enum WebApiError {
GenericDataTooLarge,
GenericParseError,
GenericValueMissing,
GenericWriteFailed,
DtuBase = 2000,
DtuSerialZero,

View File

@ -26,6 +26,11 @@ bool ConfigurationClass::write()
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
if (doc.capacity() == 0) {
MessageOutput.println("Failed to allocate memory");
return false;
}
JsonObject cfg = doc.createNestedObject("cfg");
cfg["version"] = config.Cfg.Version;
cfg["save_count"] = config.Cfg.SaveCount;
@ -151,6 +156,12 @@ bool ConfigurationClass::read()
File f = LittleFS.open(CONFIG_FILENAME, "r", false);
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
if (doc.capacity() == 0) {
MessageOutput.println("Failed to allocate memory");
return false;
}
// Deserialize the JSON document
const DeserializationError error = deserializeJson(doc, f);
if (error) {
@ -311,6 +322,12 @@ void ConfigurationClass::migrate()
}
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
if (doc.capacity() == 0) {
MessageOutput.println("Failed to allocate memory");
return;
}
// Deserialize the JSON document
const DeserializationError error = deserializeJson(doc, f);
if (error) {

View File

@ -101,4 +101,16 @@ void WebApiClass::sendTooManyRequests(AsyncWebServerRequest* request)
request->send(response);
}
void WebApiClass::writeConfig(JsonObject& retMsg, const WebApiError code, const String& message)
{
if (!Configuration.write()) {
retMsg["message"] = "Write failed!";
retMsg["code"] = WebApiError::GenericWriteFailed;
} else {
retMsg["type"] = "success";
retMsg["message"] = message;
retMsg["code"] = code;
}
}
WebApiClass WebApi;

View File

@ -175,11 +175,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
Display.setLanguage(config.Display.Language);
Display.Diagram().updatePeriod();
Configuration.write();
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
WebApi.writeConfig(retMsg);
response->setLength();
request->send(response);

View File

@ -154,11 +154,8 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request)
config.Dtu.Nrf.PaLevel = root["nrf_palevel"].as<uint8_t>();
config.Dtu.Cmt.PaLevel = root["cmt_palevel"].as<int8_t>();
config.Dtu.Cmt.Frequency = root["cmt_frequency"].as<uint32_t>();
Configuration.write();
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
WebApi.writeConfig(retMsg);
response->setLength();
request->send(response);

View File

@ -167,11 +167,8 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request)
inverter->Serial = strtoll(root["serial"].as<String>().c_str(), NULL, 16);
strncpy(inverter->Name, root["name"].as<String>().c_str(), INV_MAX_NAME_STRLEN);
Configuration.write();
retMsg["type"] = "success";
retMsg["message"] = "Inverter created!";
retMsg["code"] = WebApiError::InverterAdded;
WebApi.writeConfig(retMsg, WebApiError::InverterAdded, "Inverter created!");
response->setLength();
request->send(response);
@ -294,11 +291,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request)
arrayCount++;
}
Configuration.write();
retMsg["type"] = "success";
retMsg["code"] = WebApiError::InverterChanged;
retMsg["message"] = "Inverter changed!";
WebApi.writeConfig(retMsg, WebApiError::InverterChanged, "Inverter changed!");
response->setLength();
request->send(response);
@ -395,11 +388,8 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request)
inverter.Serial = 0;
strncpy(inverter.Name, "", sizeof(inverter.Name));
Configuration.write();
retMsg["type"] = "success";
retMsg["message"] = "Inverter deleted!";
retMsg["code"] = WebApiError::InverterDeleted;
WebApi.writeConfig(retMsg, WebApiError::InverterDeleted, "Inverter deleted!");
response->setLength();
request->send(response);
@ -466,11 +456,7 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request)
order++;
}
Configuration.write();
retMsg["type"] = "success";
retMsg["message"] = "Inverter order saved!";
retMsg["code"] = WebApiError::InverterOrdered;
WebApi.writeConfig(retMsg, WebApiError::InverterOrdered, "Inverter order saved!");
response->setLength();
request->send(response);

View File

@ -334,11 +334,8 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
config.Mqtt.Hass.Retain = root["mqtt_hass_retain"].as<bool>();
config.Mqtt.Hass.IndividualPanels = root["mqtt_hass_individualpanels"].as<bool>();
strlcpy(config.Mqtt.Hass.Topic, root["mqtt_hass_topic"].as<String>().c_str(), sizeof(config.Mqtt.Hass.Topic));
Configuration.write();
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
WebApi.writeConfig(retMsg);
response->setLength();
request->send(response);

View File

@ -238,11 +238,8 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
}
config.WiFi.ApTimeout = root["aptimeout"].as<uint>();
config.Mdns.Enabled = root["mdnsenabled"].as<bool>();
Configuration.write();
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
WebApi.writeConfig(retMsg);
response->setLength();
request->send(response);

View File

@ -179,11 +179,8 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request)
config.Ntp.Latitude = root["latitude"].as<double>();
config.Ntp.Longitude = root["longitude"].as<double>();
config.Ntp.SunsetType = root["sunsettype"].as<uint8_t>();
Configuration.write();
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
WebApi.writeConfig(retMsg);
response->setLength();
request->send(response);

View File

@ -101,11 +101,8 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request)
CONFIG_T& config = Configuration.get();
strlcpy(config.Security.Password, root["password"].as<String>().c_str(), sizeof(config.Security.Password));
config.Security.AllowReadonly = root["allow_readonly"].as<bool>();
Configuration.write();
retMsg["type"] = "success";
retMsg["message"] = "Settings saved!";
retMsg["code"] = WebApiError::GenericSuccess;
WebApi.writeConfig(retMsg);
response->setLength();
request->send(response);

View File

@ -39,6 +39,7 @@
"1003": "Daten zu groß!",
"1004": "Fehler beim interpretieren der Daten!",
"1005": "Benötigte Werte fehlen!",
"1006": "Schreiben fehlgeschlagen!",
"2001": "Die Seriennummer darf nicht 0 sein!",
"2002": "Das Abfraginterval muss größer als 0 sein!",
"2003": "Ungültige Sendeleistung angegeben!",

View File

@ -39,6 +39,7 @@
"1003": "Data too large!",
"1004": "Failed to parse data!",
"1005": "Values are missing!",
"1006": "Write failed!",
"2001": "Serial cannot be zero!",
"2002": "Poll interval must be greater zero!",
"2003": "Invalid power level setting!",

View File

@ -39,6 +39,7 @@
"1003": "Données trop importantes !",
"1004": "Échec de l'analyse des données !",
"1005": "Certaines valeurs sont manquantes !",
"1006": "Write failed!",
"2001": "Le numéro de série ne peut pas être nul !",
"2002": "L'intervalle de sondage doit être supérieur à zéro !",
"2003": "Réglage du niveau de puissance invalide !",