feat: harden errors, recovery, and resource usage
This commit is contained in:
+23
-7
@@ -36,6 +36,7 @@ static const uint8_t kHttpMaxOpenSockets = 12U;
|
||||
|
||||
typedef struct { bool configured; bool connected; bool retry_scheduled; uint8_t reconnect_attempt; } wifi_state_t;
|
||||
static portMUX_TYPE s_wifi_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static portMUX_TYPE s_diagnostics_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static wifi_state_t s_wifi_state = {0};
|
||||
static bool s_littlefs_mounted;
|
||||
static httpd_handle_t s_server;
|
||||
@@ -51,6 +52,20 @@ static esp_timer_handle_t s_reconnect_timer;
|
||||
|
||||
static uint32_t platform_random(void *unused) { (void)unused; return esp_random(); }
|
||||
|
||||
static void record_rejected_input(void) {
|
||||
portENTER_CRITICAL(&s_diagnostics_lock);
|
||||
if (s_rejected_input < UINT16_MAX) ++s_rejected_input;
|
||||
portEXIT_CRITICAL(&s_diagnostics_lock);
|
||||
}
|
||||
|
||||
static uint16_t rejected_input_snapshot(void) {
|
||||
uint16_t rejected = 0;
|
||||
portENTER_CRITICAL(&s_diagnostics_lock);
|
||||
rejected = s_rejected_input;
|
||||
portEXIT_CRITICAL(&s_diagnostics_lock);
|
||||
return rejected;
|
||||
}
|
||||
|
||||
static wifi_state_t wifi_state_snapshot(void) {
|
||||
wifi_state_t snapshot;
|
||||
portENTER_CRITICAL(&s_wifi_lock);
|
||||
@@ -75,7 +90,8 @@ static void refresh_health(void) {
|
||||
.minimum_free_heap_bytes = esp_get_minimum_free_heap_size(),
|
||||
.largest_free_block_bytes = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT),
|
||||
.connected_clients = (uint8_t)clients,
|
||||
.rejected_input = s_rejected_input,
|
||||
.rejected_input = rejected_input_snapshot(),
|
||||
.reset_reason = (int8_t)esp_reset_reason(),
|
||||
.wifi_state = wifi_state_name(&wifi_state),
|
||||
});
|
||||
}
|
||||
@@ -108,7 +124,7 @@ static void sync_broadcast_work(void *unused) {
|
||||
}
|
||||
|
||||
static void queue_state_broadcast(void) {
|
||||
if (s_server != NULL && httpd_queue_work(s_server, sync_broadcast_work, NULL) != ESP_OK) ++s_rejected_input;
|
||||
if (s_server != NULL && httpd_queue_work(s_server, sync_broadcast_work, NULL) != ESP_OK) record_rejected_input();
|
||||
}
|
||||
|
||||
static bool schedule_bot_turn(void *unused, uint32_t delay_ms) {
|
||||
@@ -124,7 +140,7 @@ static void bot_turn_work(void *unused) {
|
||||
|
||||
static void bot_timer_callback(void *unused) {
|
||||
(void)unused;
|
||||
if (s_server != NULL && httpd_queue_work(s_server, bot_turn_work, NULL) != ESP_OK) ++s_rejected_input;
|
||||
if (s_server != NULL && httpd_queue_work(s_server, bot_turn_work, NULL) != ESP_OK) record_rejected_input();
|
||||
}
|
||||
|
||||
static void sync_expire_work(void *unused) {
|
||||
@@ -167,18 +183,18 @@ static esp_err_t api_handler(httpd_req_t *request) {
|
||||
const size_t maximum = route_body_limit(route);
|
||||
size_t body_length = 0U;
|
||||
if (request->method == HTTP_POST) {
|
||||
if ((size_t)request->content_len > maximum) { body_length = maximum + 1U; ++s_rejected_input; }
|
||||
if ((size_t)request->content_len > maximum) { body_length = maximum + 1U; record_rejected_input(); }
|
||||
else {
|
||||
while (body_length < (size_t)request->content_len) {
|
||||
const int received = httpd_req_recv(request, body + body_length, request->content_len - body_length);
|
||||
if (received <= 0) { ++s_rejected_input; body_length = maximum + 1U; break; }
|
||||
if (received <= 0) { record_rejected_input(); body_length = maximum + 1U; break; }
|
||||
body_length += (size_t)received;
|
||||
}
|
||||
body[body_length <= kRequestBodyCapacity ? body_length : 0U] = '\0';
|
||||
}
|
||||
}
|
||||
const bool target_too_large = request->method == HTTP_GET && httpd_req_get_url_query_len(request) > 128U;
|
||||
if (target_too_large) ++s_rejected_input;
|
||||
if (target_too_large) record_rejected_input();
|
||||
if (route == HTTP_API_ROUTE_STATE || route == HTTP_API_ROUTE_STATISTICS) {
|
||||
const size_t token_length = httpd_req_get_hdr_value_len(request, "X-Session-Token");
|
||||
if (token_length > 0U && token_length < sizeof(token) && httpd_req_get_hdr_value_str(request, "X-Session-Token", token, sizeof(token)) != ESP_OK) token[0] = '\0';
|
||||
@@ -205,7 +221,7 @@ static esp_err_t websocket_handler(httpd_req_t *request) {
|
||||
httpd_ws_frame_t frame = {0};
|
||||
if (httpd_ws_recv_frame(request, &frame, 0U) != ESP_OK || frame.type != HTTPD_WS_TYPE_TEXT ||
|
||||
frame.len > kWebSocketFrameCapacity) {
|
||||
++s_rejected_input;
|
||||
record_rejected_input();
|
||||
sync_service_close(&s_sync, client_id);
|
||||
httpd_sess_trigger_close(s_server, client_id);
|
||||
return ESP_OK;
|
||||
|
||||
Reference in New Issue
Block a user