Clarify control Action replies and graph display contracts
This commit is contained in:
1 parent
4daa0e7f6b
commit
89c27b8fca
3 files changed
+63
-34
No files matched your search
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user