GUI: поле действия и кнопка Send для отправки команд в utun

- Добавлен ETCPMON_CMD_ACTION в протокол (32 байта текст)
- В GUI добавлено поле ввода и кнопка Send правее блока Sockets
- Добавлен etcpmon_client_send_action для отправки команд
- Обработка action 'nat' в control_server: запускает NAT check для всех линков
- Сделана route_bgp_start_link_nat_check не-static
- Добавлена route_bgp_request_nat_check_all
- Исправлен баг route_ping.c (request_id -> nonce)
- Исправлена линковка tests/Makefile.am
This commit is contained in:
Evgeny committed 2026-04-22 20:52:30 +03:00
1 parent 5b0a743e02
commit 57dba26e7c
10 files changed
+125 -5

No files matched your search

+41
View File
@@ -355,6 +355,47 @@ int etcpmon_client_request_metrics(struct etcpmon_client* client) {
return 0;
}
int etcpmon_client_send_action(struct etcpmon_client* client, const char* action) {
if (!client || client->sock == INVALID_SOCKET || !action) return -1;
struct etcpmon_cmd_action cmd;
memset(&cmd, 0, sizeof(cmd));
strncpy(cmd.action, action, sizeof(cmd.action) - 1);
cmd.action[sizeof(cmd.action) - 1] = '\0';
struct etcpmon_msg_header hdr;
etcpmon_build_header(&hdr, sizeof(cmd), ETCPMON_CMD_ACTION, 0);
if (client->log_file) {
log_hex_data(client->log_file, "TX", (const uint8_t*)&hdr, sizeof(hdr));
fprintf(client->log_file, "%llu: [LOG] CMD_ACTION '%s'\n",
(unsigned long long)get_timestamp_ms(), cmd.action);
fflush(client->log_file);
}
int sent = send(client->sock, (const char*)&hdr, sizeof(hdr), 0);
if (sent != sizeof(hdr)) {
if (client->log_file) {
fprintf(client->log_file, "%llu: [ERROR] Failed to send CMD_ACTION header: %d\n",
(unsigned long long)get_timestamp_ms(), WSAGetLastError());
fflush(client->log_file);
}
return -1;
}
sent = send(client->sock, (const char*)&cmd, sizeof(cmd), 0);
if (sent != sizeof(cmd)) {
if (client->log_file) {
fprintf(client->log_file, "%llu: [ERROR] Failed to send CMD_ACTION payload: %d\n",
(unsigned long long)get_timestamp_ms(), WSAGetLastError());
fflush(client->log_file);
}
return -1;
}
return 0;
}
/* Send request with callback - queued version */
int etcpmon_client_send_request(struct etcpmon_client* client,
uint8_t type,
+3
View File
@@ -186,6 +186,9 @@ struct metrics_history* etcpmon_client_get_history(struct etcpmon_client* client
/* Add metrics to history */
void etcpmon_client_add_to_history(struct etcpmon_client* client, struct etcpmon_rsp_metrics* metrics);
/* Send action command to server */
int etcpmon_client_send_action(struct etcpmon_client* client, const char* action);
uint64_t get_timestamp_ms(void); // Add this declaration
#ifdef __cplusplus
+30
View File
@@ -30,6 +30,7 @@ static void CreateControls(struct etcpmon_app* app);
static void OnConnect(struct etcpmon_app* app);
static void OnDisconnect(struct etcpmon_app* app);
static void OnConnectionSelect(struct etcpmon_app* app);
static void OnAction(struct etcpmon_app* app);
static void OnTimer(struct etcpmon_app* app);
static void UpdateUIState(struct etcpmon_app* app);
static void AddTooltip(HWND hTip, HWND hCtrl, const char* text);
@@ -212,6 +213,19 @@ static void CreateControls(struct etcpmon_app* app) {
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT,
x + 310, y + 20, 300, 120, hWnd, (HMENU)IDC_LIST_SOCKETS, hInst, NULL);
/* Action input */
CreateWindowExA(0, "STATIC", "Action:",
WS_CHILD | WS_VISIBLE,
x + 620, y, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
app->hEditAction = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "",
WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,
x + 620, y + 20, 200, 22, hWnd, (HMENU)IDC_EDIT_ACTION, hInst, NULL);
app->hBtnAction = CreateWindowExA(0, "BUTTON", "Send",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
x + 830, y + 19, 60, 24, hWnd, (HMENU)IDC_BTN_ACTION, hInst, NULL);
/* Graph area */
y += 140;
app->hGraphWnd = CreateWindowExA(
@@ -940,6 +954,9 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l
OnConnectionSelect(app);
}
break;
case IDC_BTN_ACTION:
OnAction(app);
break;
}
}
break;
@@ -1019,6 +1036,19 @@ static void OnConnectionSelect(struct etcpmon_app* app) {
}
}
static void OnAction(struct etcpmon_app* app) {
if (!app || !app->client || !app->hEditAction) return;
char action[33];
GetWindowTextA(app->hEditAction, action, sizeof(action));
action[sizeof(action) - 1] = '\0';
if (strlen(action) > 0) {
etcpmon_client_send_action(app->client, action);
SetWindowTextA(app->hEditAction, "");
}
}
static void OnTimer(struct etcpmon_app* app) {
if (!app || !app->client) return;
+6
View File
@@ -41,6 +41,10 @@ extern "C" {
#define IDC_LIST_SOCKETS 106
#define IDC_TIMER_UPDATE 105
/* Action control IDs */
#define IDC_EDIT_ACTION 107
#define IDC_BTN_ACTION 108
/* ETCP Metrics control IDs */
#define IDC_EDIT_ETCP_NAME 200
#define IDC_EDIT_ETCP_RTT_LAST 201
@@ -197,6 +201,8 @@ struct etcpmon_app {
HWND hBtnDisconnect;
HWND hListConnections;
HWND hListSockets;
HWND hEditAction;
HWND hBtnAction;
/* ETCP metrics controls */
HWND hEditEtcpName;
+6
View File
@@ -49,6 +49,7 @@ extern "C" {
#define ETCPMON_CMD_GET_METRICS 0x03 /* Request metrics for selected */
#define ETCPMON_CMD_DISCONNECT 0x04 /* Disconnect from monitoring */
#define ETCPMON_CMD_LIST_SOCKETS 0x05 /* Request local socket list */
#define ETCPMON_CMD_ACTION 0x06 /* Execute action (text command) */
/* Server -> Client responses */
#define ETCPMON_RSP_CONN_LIST 0x81 /* Connection list response */
@@ -86,6 +87,11 @@ struct etcpmon_cmd_select {
uint64_t peer_node_id; /* peer_node_id of connection to monitor */
};
/* CMD_ACTION: Execute action command */
struct etcpmon_cmd_action {
char action[32]; /* Null-terminated action string */
};
/* CMD_GET_METRICS: No payload required (uses previously selected connection) */
/* CMD_DISCONNECT: No payload required */