Files
HaloKeymind/examples/simple_room_server/main.cpp
T
João Brázio 95214e8c40 Ensure command buffers stay NUL-terminated to prevent overflow
The serial command buffers must stay NUL-terminated within their
bounds: if they ever aren't, strlen() can return >= sizeof(command)
and the read loop would index past the buffer. Additionally, a full
buffer now becomes a completed line (end-of-line marker placed
inside the buffer, NUL terminator kept) instead of overwriting the
terminator and silently corrupting the buffer for the next pass.

Applies to the serial CLI readers of the repeater, room server,
sensor and secure chat examples, and to the CLI rescue reader of
the companion example.
2026-09-04 20:01:39 +01:00

169 lines
4.1 KiB
C++

#include <Arduino.h> // needed for PlatformIO
#include <Mesh.h>
#include "MyMesh.h"
#ifdef ETHERNET_ENABLED
#define ETHERNET_CLI_BANNER "MeshCore Room Server CLI"
#include <helpers/nrf52/EthernetCLI.h>
#endif
#ifdef DISPLAY_CLASS
#include "UITask.h"
static UITask ui_task(display);
#endif
StdRNG fast_rng;
SimpleMeshTables tables;
MyMesh the_mesh(board, radio_driver, *new ArduinoMillis(), fast_rng, rtc_clock, tables);
void halt() {
while (1) ;
}
static char command[MAX_POST_TEXT_LEN+1];
#ifdef ETHERNET_ENABLED
static char ethernet_command[MAX_POST_TEXT_LEN+1];
#endif
void setup() {
Serial.begin(115200);
delay(1000);
board.begin();
#ifdef HAS_EXTERNAL_WATCHDOG
external_watchdog.begin();
#endif
#ifdef DISPLAY_CLASS
if (display.begin()) {
display.startFrame();
display.setCursor(0, 0);
display.print("Please wait...");
display.endFrame();
}
#endif
if (!radio_init()) { halt(); }
fast_rng.begin(radio_driver.getRngSeed());
FILESYSTEM* fs;
#if defined(NRF52_PLATFORM)
InternalFS.begin();
fs = &InternalFS;
IdentityStore store(InternalFS, "");
#elif defined(RP2040_PLATFORM)
LittleFS.begin();
fs = &LittleFS;
IdentityStore store(LittleFS, "/identity");
store.begin();
#elif defined(ESP32)
SPIFFS.begin(true);
fs = &SPIFFS;
IdentityStore store(SPIFFS, "/identity");
#else
#error "need to define filesystem"
#endif
if (!store.load("_main", the_mesh.self_id)) {
the_mesh.self_id = radio_new_identity(); // create new random identity
int count = 0;
while (count < 10 && (the_mesh.self_id.pub_key[0] == 0x00 || the_mesh.self_id.pub_key[0] == 0xFF)) { // reserved id hashes
the_mesh.self_id = radio_new_identity(); count++;
}
store.save("_main", the_mesh.self_id);
}
Serial.print("Room ID: ");
mesh::Utils::printHex(Serial, the_mesh.self_id.pub_key, PUB_KEY_SIZE); Serial.println();
command[0] = 0;
#ifdef ETHERNET_ENABLED
ethernet_command[0] = 0;
#endif
sensors.begin();
the_mesh.begin(fs);
#ifdef DISPLAY_CLASS
ui_task.begin(the_mesh.getNodePrefs(), FIRMWARE_BUILD_DATE, FIRMWARE_VERSION);
#endif
#ifdef ETHERNET_ENABLED
ethernet_start_task();
#endif
// send out initial zero hop Advertisement to the mesh
#if ENABLE_ADVERT_ON_BOOT == 1
the_mesh.sendSelfAdvertisement(16000, false);
#endif
board.onBootComplete();
}
void loop() {
int len = strlen(command);
// `command` must stay NUL-terminated within its bounds. If it ever isn't,
// strlen() above can return >= sizeof(command) and the loop below would then
// index past the buffer, so clamp defensively.
if (len >= (int)sizeof(command)) {
command[0] = 0;
len = 0;
}
while (Serial.available() && len < sizeof(command)-1) {
char c = Serial.read();
if (c != '\n') {
command[len++] = c;
command[len] = 0;
}
Serial.print(c);
}
if (len == sizeof(command)-1) { // buffer full: treat as a completed line
command[sizeof(command)-2] = '\r'; // place end-of-line marker inside the buffer
command[sizeof(command)-1] = 0; // keep the buffer NUL-terminated
}
if (len > 0 && command[len - 1] == '\r') { // received complete line
command[len - 1] = 0; // replace newline with C string null terminator
char reply[160];
reply[0] = 0;
#ifdef ETHERNET_ENABLED
if (!ethernet_handle_command(command, reply)) {
the_mesh.handleCommand(0, command, reply);
}
#else
the_mesh.handleCommand(0, command, reply); // NOTE: there is no sender_timestamp via serial!
#endif
if (reply[0]) {
Serial.print(" -> "); Serial.println(reply);
}
command[0] = 0; // reset command buffer
}
#ifdef ETHERNET_ENABLED
ethernet_loop_maintain();
if (ethernet_read_line(ethernet_command, sizeof(ethernet_command))) {
char reply[160];
reply[0] = 0;
if (!ethernet_handle_command(ethernet_command, reply)) {
the_mesh.handleCommand(0, ethernet_command, reply);
}
ethernet_send_reply(reply);
ethernet_command[0] = 0;
}
#endif
the_mesh.loop();
sensors.loop();
#ifdef DISPLAY_CLASS
ui_task.loop();
#endif
rtc_clock.tick();
#ifdef HAS_EXTERNAL_WATCHDOG
external_watchdog.loop();
#endif
}