Clarify control Action replies and graph display contracts

This commit is contained in:
evgeny committed 2026-10-27 14:00:49 +01:00
1 parent 4daa0e7f6b
commit 89c27b8fca
3 files changed
+63 -34

No files matched your search

+13 -3
View File
@@ -1,5 +1,8 @@
/*
* etcpmon_graph.h - ETCP Monitor Graph Definitions
* Отрисовка восьми BBR-каналов из кольцевой истории etcpmon_client в GUI-потоке.
* GraphWndProc получает etcpmon_app через lpCreateParams при CreateWindowEx;
* история и GDI-перья принадлежат app/client, модуль их не освобождает.
* Один пиксель X соответствует сэмплу; временная шкала неравномерна при задержке ответов.
*/
#ifndef ETCPMON_GRAPH_H
@@ -27,14 +30,21 @@ extern "C" {
struct etcpmon_app;
struct metrics_history;
/* Graph colors for each metric */
/* Цвета/короткие имена в порядке GRAPH_METRIC_* из etcpmon_client.h. */
extern const COLORREF graph_colors[GRAPH_METRICS_COUNT];
extern const char* graph_metric_names[GRAPH_METRICS_COUNT];
/* Graph functions */
/* WinAPI wndproc: WM_PAINT рисует историю, движение мыши выбирает сэмпл, уход выключает курсор. */
LRESULT CALLBACK GraphWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
/* Нарисовать app в HDC hdc внутри client rect rc через временный off-screen bitmap.
* Менее двух сэмплов — Waiting for data; масштабы видимой части обновляются не чаще 200 мс. */
void DrawGraph(HDC hdc, RECT* rc, struct etcpmon_app* app);
/* Записать индексы отмеченных каналов в selected[GRAPH_METRICS_COUNT], их число — в *count.
* Если галочек нет, выбирает первые четыре канала; для NULL app число равно нулю. */
void GetSelectedChannels(struct etcpmon_app* app, int* selected, int* count);
/* Обновить поля значений app по физическому индексу cursor_sample в кольце; неверный индекс даёт "-".
* Типы/единицы описаны в metrics_history; байты форматируются в B/KiB/MiB, скорости — B/s/KiB/s/MiB/s.
* Сравнивает с текущим текстом контрола, не хранит отдельного кеша и не добавляет сэмплы. */
void UpdateChannelValues(struct etcpmon_app* app, int cursor_sample);
#ifdef __cplusplus
+29 -16
View File
@@ -1,5 +1,9 @@
/*
* etcpmon_gui.h - ETCP Monitor GUI Header
* WinAPI GUI etcpmon: init(app, instance) → create_window → run → cleanup.
* Caller владеет app; все вызовы, Winsock-клиент и callbacks работают в одном GUI-потоке.
* init регистрирует классы окон и запускает Winsock; create_window выделяет client, создаёт
* контролы/таймер 10 мс и сразу начинает connect к 192.168.40.1:9091. run показывает окно.
* GUI опрашивает списки раз в секунду; метрики автоматически запрашивает client раз в 100 мс.
*/
#ifndef ETCPMON_GUI_H
@@ -213,7 +217,8 @@ extern "C" {
#define IDC_CH_VALUE_7 527
#define IDC_CH_CHECK_7 537
/* Main application structure */
/* Состояние одного приложения; HWND контролов принадлежат окнам, перья и client — app.
* Порядок hChannel* совпадает с GRAPH_METRIC_*; интерфейс не предназначен для нескольких app одновременно. */
struct etcpmon_app {
HINSTANCE hInstance;
HWND hWndMain;
@@ -375,53 +380,61 @@ struct etcpmon_app {
HWND hDebugCatRadio[IDC_DEBUG_MAX_CAT][6]; /* [row][level] радио-кнопки */
int debug_cat_count;
/* Client state */
/* Выделенный create_window клиент; cleanup освобождает его и завершает Winsock. */
struct etcpmon_client* client;
int need_initial_request; /* 1 = нужно запросить список при первом таймере */
int need_initial_request; /* 1 = после готовности TCP запросить списки и debug config */
uint64_t last_selected_peer_id; /* чтобы не спамить SELECT_CONN каждый тик */
/* Timer */
UINT_PTR updateTimer;
DWORD last_poll_time;
int isConnected;
DWORD last_poll_time; /* GetTickCount последнего опроса списков; период 1000 мс */
int isConnected; /* Включает CONNECTING; блокирует редактирование адреса */
};
/* Initialize application */
/* Обнулить caller-owned app, зарегистрировать классы с hInstance, запустить Winsock.
* 0 = успех, -1 = ошибка; основное окно и TCP-клиент ещё не созданы. */
int etcpmon_gui_init(struct etcpmon_app* app, HINSTANCE hInstance);
/* Create main window */
/* Создать главное окно, контролы, client и таймер; начать connect к адресу по умолчанию.
* Возвращает HWND (также app->hWndMain) или NULL при ошибке создания окна. Показывает окно run. */
HWND etcpmon_gui_create_window(struct etcpmon_app* app);
/* Run message loop */
/* Показать app->hWndMain и обрабатывать сообщения/сеть до WM_QUIT.
* Возвращает wParam сообщения выхода, -1 для отсутствующего app/окна. */
int etcpmon_gui_run(struct etcpmon_app* app);
/* Cleanup */
/* После завершения run освободить tooltip, перья, client и Winsock; сам app не освобождает. */
void etcpmon_gui_cleanup(struct etcpmon_app* app);
/* Update connection status display */
/* Скопировать text в status bar app; состояние соединения не меняет. */
void etcpmon_gui_set_status(struct etcpmon_app* app, const char* text);
/* Update connection list */
/* Показать list[count], сохранить выбор по last_selected_peer_id или выбрать первую запись.
* list заимствован на время вызова, count=0 очищает список; SELECT здесь не отправляется. */
void etcpmon_gui_update_conn_list(struct etcpmon_app* app,
struct etcpmon_conn_info* list,
uint8_t count);
/* Update socket list */
/* Показать list[count] локальных сокетов; пустые name/ip пропускаются. Данные заимствованы на время вызова. */
void etcpmon_gui_update_socket_list(struct etcpmon_app* app,
struct etcpmon_socket_info* list,
uint8_t count);
/* Update metrics display */
/* Показать metrics и links[links_count], перерисовать график из уже обновлённой истории client.
* Входные снимки заимствованы на время вызова; новый сэмпл в историю не добавляет. */
void etcpmon_gui_update_metrics(struct etcpmon_app* app,
struct etcpmon_rsp_metrics* metrics,
struct etcpmon_link_metrics* links,
uint8_t links_count);
/* Clear metrics display */
/* Очистить поля/линки/график и освободить кеши метрик client, обнулить его историю.
* Транспорт, selected_peer_id и pending не меняет; не вызывать с используемыми далее указателями на кеш.
* Повторный вывод прежних величин после очистки обновляет сами контролы, отдельного кеша текста нет. */
void etcpmon_gui_clear_metrics(struct etcpmon_app* app);
/* Update graph with new metrics */
/* Запросить перерисовку графика app и обновить значения последнего сэмпла при неактивном курсоре.
* metrics служит проверкой ненулевого аргумента; данные берутся из истории client, сэмпл не добавляется. */
void etcpmon_gui_update_graph(struct etcpmon_app* app,
struct etcpmon_rsp_metrics* metrics);
+21 -15
View File
@@ -1,10 +1,14 @@
/*
* etcpmon_protocol.h - ETCP Monitor Protocol Definitions
*
* Binary protocol for monitoring ETCP connections
* Format: [2 bytes: msg_size] [1 byte: msg_type] [payload...]
*
* Period: 100ms (10 updates per second)
* Общий формат TCP control_server для etcpmon и других локальных клиентов управления.
* Кадр: [size:uint16][type:uint8][seq_id:uint8][payload]; size включает 4-байтовый заголовок,
* допустимо 4..32768 байт. Структуры packed(1), числа копируются в порядке байтов хоста
* без htons/ntohs; взаимодействующие сборки должны иметь одинаковый layout и endianness.
* VERSION — константа исходников, по сети не передаётся; согласования версии нет.
* TCP не сохраняет границы кадров. Метрики выдаются по запросу; 100 мс — интервал клиента.
* seq=0 не связывается с pending; ответ на запрос копирует его seq (кроме отдельных NODE_INFO).
* SELECT_CONN/SET_DEBUG_CONFIG/DISCONNECT не подтверждаются; ACTION даёт ACTION_RESULT либо ERROR.
* Подписка на узлы: NODE_INFO с seq=0, затем NODE_INFO_END с seq запроса; обновления также с seq=0.
* Встроенного шифрования/аутентификации нет; сервер допускает IPv4 по [control] allow.
*/
#ifndef ETCPMON_PROTOCOL_H
@@ -92,12 +96,12 @@ struct etcpmon_msg_header {
/* CMD_SELECT_CONN: Select connection to monitor */
struct etcpmon_cmd_select {
uint64_t peer_node_id; /* peer_node_id of connection to monitor */
uint64_t peer_node_id; /* ID выбранного соединения; 0 снимает выбор, SELECT не подтверждается */
};
/* CMD_ACTION: Execute action command */
struct etcpmon_cmd_action {
char action[32]; /* Null-terminated action string */
char action[32]; /* Ровно 32 байта с NUL; полное имя "nat"/"nodes", неизвестное имя даёт ERROR */
};
/* CMD_GET_METRICS: No payload required (uses previously selected connection) */
@@ -231,7 +235,7 @@ struct etcpmon_link_metrics {
uint32_t bandwidth; /* Configured bandwidth (Kbps) */
uint32_t nat_changes_count; /* NAT address changes */
uint32_t rtt_last; /* Last RTT (0.1ms units) */
uint32_t rtt_avg10; /* avg RTT (0.1ms units) */
uint32_t rtt_avg10; /* Сейчас BBR min_rtt_us / 100 (0.1 мс), 0 без BBR; не среднее 10 RTT */
uint32_t tt_last; /* Last transmit time (0.1ms units) */
/* Timer flags (1 = active, 0 = NULL) */
@@ -293,9 +297,9 @@ struct etcpmon_tun_metrics {
/* Router congestion metrics — aggregated over all router_conns */
struct etcpmon_router_metrics {
uint32_t total_conns;
uint32_t total_inflight;
uint32_t total_send_q;
uint32_t total_recv_q;
uint32_t total_inflight; /* Сумма числа записей inflight_q, не байтов */
uint32_t total_send_q; /* Сумма числа записей send_q */
uint32_t total_recv_q; /* Сумма числа записей recv_q */
uint32_t pkts_sent;
uint32_t pkts_send_err;
uint32_t pkts_rcvd;
@@ -322,7 +326,7 @@ struct etcpmon_rsp_metrics {
struct etcpmon_rsp_debug_config {
uint8_t global_level; /* Global debug level (0=NONE..5=TRACE) */
uint8_t category_count; /* Number of categories */
/* Followed by: char names_csv[]; null-terminated CSV: "UASYNC,LL_QUEUE,...\0" */
/* Followed by: char names_csv[]; NUL-terminated CSV категорий 1..N из debug_config */
/* Followed by: uint8_t levels[category_count]; per-category levels */
};
@@ -378,7 +382,8 @@ struct etcpmon_rsp_error {
* Utility Functions (optional, for both client and server)
* ============================================================================ */
/* Build message header */
/* Заполнить hdr из размера payload, типа и seq. Границы не проверяет:
* вызывающий код обязан обеспечить payload_size <= ETCPMON_MAX_MSG_SIZE - sizeof(*hdr). */
static inline void etcpmon_build_header(struct etcpmon_msg_header* hdr,
uint16_t payload_size,
uint8_t msg_type,
@@ -388,7 +393,8 @@ static inline void etcpmon_build_header(struct etcpmon_msg_header* hdr,
hdr->seq_id = seq_id;
}
/* Validate message header */
/* Проверить только диапазон hdr->size; 0 = допустим, -1 = ошибка.
* hdr должен указывать на полный заголовок; наличие payload/тип/seq эта функция не проверяет. */
static inline int etcpmon_validate_header(const struct etcpmon_msg_header* hdr) {
if (hdr->size < sizeof(struct etcpmon_msg_header) ||
hdr->size > ETCPMON_MAX_MSG_SIZE) {