Browse Source

gr restore v2

nodeinfo-routing-update
jeka 1 month ago
parent
commit
1947810cb0
  1. 4
      src/control_server.c
  2. 51
      tools/etcpmon/Makefile
  3. 41
      tools/etcpmon/etcpmon_graph.c
  4. 55
      tools/etcpmon/etcpmon_gui.c

4
src/control_server.c

@ -419,6 +419,10 @@ static void client_read_callback(socket_t fd, void* arg) {
if (received == SOCKET_ERROR) { if (received == SOCKET_ERROR) {
int err = WSAGetLastError(); int err = WSAGetLastError();
if (err != WSAEWOULDBLOCK) { if (err != WSAEWOULDBLOCK) {
if (err == 10054) {
client->connected = 0;
return;
}
if (server && server->log_file) { if (server && server->log_file) {
fprintf(server->log_file, "%llu: [ERROR] Client recv error: %d\n", fprintf(server->log_file, "%llu: [ERROR] Client recv error: %d\n",
(unsigned long long)get_timestamp_ms(), err); (unsigned long long)get_timestamp_ms(), err);

51
tools/etcpmon/Makefile

@ -1,40 +1,35 @@
# ETCP Monitor Makefile for MinGW # ETCP Monitor Makefile
# Usage: make [CC=gcc] [CFLAGS=...] [LDFLAGS=...] # Usage: make [target]
#
# Targets:
# all - Build the application (default)
# clean - Remove object files and executable
# rebuild - Clean and rebuild
CC = gcc
CFLAGS = -Wall -O2 -DWIN32_LEAN_AND_MEAN
CFLAGS += -I. -I../../src
LDFLAGS = -mwindows
LIBS = -lws2_32 -lcomctl32 -luser32 -lgdi32
# Compiler
CC ?= gcc
# Target
TARGET = etcpmon.exe TARGET = etcpmon.exe
SRCS = etcpmon_main.c etcpmon_gui.c etcpmon_client.c etcpmon_graph.c
# Source files
SRCS = etcpmon_main.c \
etcpmon_gui.c \
etcpmon_client.c \
etcpmon_graph.c
# Object files
OBJS = $(SRCS:.c=.o) OBJS = $(SRCS:.c=.o)
# Windows-specific libraries .PHONY: all clean rebuild
LIBS = -lws2_32 -lgdi32 -lcomdlg32 -lkernel32 -luser32 -lcomctl32
# Compiler flags
CFLAGS += -Wall -Wextra
CFLAGS += -O2
CFLAGS += -D_WIN32_WINNT=0x0601
CFLAGS += -DUNICODE -D_UNICODE
CFLAGS += -I.
# Build rule
.PHONY: all clean
all: $(TARGET) all: $(TARGET)
$(TARGET): $(OBJS) $(TARGET): $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS) @echo Linking $@
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
%.o: %.c %.o: %.c
$(CC) $(CFLAGS) -c $< -o $@ @echo Compiling $<
$(CC) $(CFLAGS) -c -o $@ $<
clean: clean:
rm -f $(OBJS) $(TARGET) *.o @echo Cleaning...
rm -f $(OBJS) $(TARGET)
rebuild: clean $(TARGET)

41
tools/etcpmon/etcpmon_graph.c

@ -6,49 +6,40 @@
* - Строка с значениями под курсором ("RTT-L: 45.2 ...") полностью убрана * - Строка с значениями под курсором ("RTT-L: 45.2 ...") полностью убрана
* - Значения в блоках под графиком всегда живые (обновляются в on_metrics) * - Значения в блоках под графиком всегда живые (обновляются в on_metrics)
*/ */
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include "etcpmon_graph.h" #include "etcpmon_graph.h"
#include "etcpmon_client.h" #include "etcpmon_client.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "etcpmon_gui.h" #include "etcpmon_gui.h"
const COLORREF graph_colors[GRAPH_METRICS_COUNT] = { const COLORREF graph_colors[GRAPH_METRICS_COUNT] = {
RGB(255,0,0), RGB(0,255,0), RGB(0,0,255), RGB(255,255,0), RGB(255,0,0), RGB(0,255,0), RGB(0,0,255), RGB(255,255,0),
RGB(255,0,255), RGB(0,255,255), RGB(255,128,0), RGB(128,0,255) RGB(255,0,255), RGB(0,255,255), RGB(255,128,0), RGB(128,0,255)
}; };
const char* graph_metric_names[GRAPH_METRICS_COUNT] = { const char* graph_metric_names[GRAPH_METRICS_COUNT] = {
"RTT Last","RTT Avg10","RTT Avg100","Jitter", "RTT Last","RTT Avg10","RTT Avg100","Jitter",
"Retrns","ACKs","Inflght","Bytes/s" "Retrns","ACKs","Inflght","Bytes/s"
}; };
static void RecalculateMinMax(struct metrics_history* hist, int vis, int oldest) static void RecalculateMinMax(struct metrics_history* hist, int vis, int oldest)
{ {
for (int m = 0; m < GRAPH_METRICS_COUNT; m++) { for (int m = 0; m < GRAPH_METRICS_COUNT; m++) {
float mn = 1e9f; float mn = 1e9f;
float mx = -1e9f; float mx = -1e9f;
for (int i = 0; i < vis; i++) { for (int i = 0; i < vis; i++) {
float v = hist->values[m][(oldest + i) % GRAPH_HISTORY_SIZE]; float v = hist->values[m][(oldest + i) % GRAPH_HISTORY_SIZE];
if (v < mn) mn = v; if (v < mn) mn = v;
if (v > mx) mx = v; if (v > mx) mx = v;
} }
if (mx - mn < 0.001f) { if (mx - mn < 0.001f) {
if (mn > 0.0f) { mn *= 0.9f; mx *= 1.1f; } if (mn > 0.0f) { mn *= 0.9f; mx *= 1.1f; }
else { mx = 1.0f; } else { mx = 1.0f; }
} }
hist->min_val[m] = mn; hist->min_val[m] = mn;
hist->max_val[m] = mx; hist->max_val[m] = mx;
} }
} }
void GetSelectedChannels(struct etcpmon_app* app, int* selected, int* count) { void GetSelectedChannels(struct etcpmon_app* app, int* selected, int* count) {
*count = 0; *count = 0;
if (!app) return; if (!app) return;
@ -62,26 +53,20 @@ void GetSelectedChannels(struct etcpmon_app* app, int* selected, int* count) {
for (int i = 0; i < 4 && i < GRAPH_METRICS_COUNT; i++) for (int i = 0; i < 4 && i < GRAPH_METRICS_COUNT; i++)
selected[(*count)++] = i; selected[(*count)++] = i;
} }
void DrawGraph(HDC hdc, RECT* rc, struct etcpmon_app* app) void DrawGraph(HDC hdc, RECT* rc, struct etcpmon_app* app)
{ {
if (!app || !rc) return; if (!app || !rc) return;
int w = rc->right - rc->left; int w = rc->right - rc->left;
int h = rc->bottom - rc->top; int h = rc->bottom - rc->top;
/* Off-screen буфер */ /* Off-screen буфер */
HDC memDC = CreateCompatibleDC(hdc); HDC memDC = CreateCompatibleDC(hdc);
HBITMAP bmp = CreateCompatibleBitmap(hdc, w, h); HBITMAP bmp = CreateCompatibleBitmap(hdc, w, h);
HBITMAP oldBmp = (HBITMAP)SelectObject(memDC, bmp); HBITMAP oldBmp = (HBITMAP)SelectObject(memDC, bmp);
SetBkMode(memDC, TRANSPARENT); SetBkMode(memDC, TRANSPARENT);
/* Фон */ /* Фон */
HBRUSH bg = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); HBRUSH bg = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
FillRect(memDC, rc, bg); FillRect(memDC, rc, bg);
DeleteObject(bg); DeleteObject(bg);
/* Нет данных */ /* Нет данных */
if (!app->client || !etcpmon_client_get_history(app->client) || if (!app->client || !etcpmon_client_get_history(app->client) ||
etcpmon_client_get_history(app->client)->count < 2) etcpmon_client_get_history(app->client)->count < 2)
@ -90,21 +75,17 @@ void DrawGraph(HDC hdc, RECT* rc, struct etcpmon_app* app)
DrawTextA(memDC, "Waiting for data...", -1, rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE); DrawTextA(memDC, "Waiting for data...", -1, rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
goto end; goto end;
} }
struct metrics_history* hist = etcpmon_client_get_history(app->client); struct metrics_history* hist = etcpmon_client_get_history(app->client);
/* Выбранные каналы */ /* Выбранные каналы */
int sel[GRAPH_METRICS_COUNT]; int sel[GRAPH_METRICS_COUNT];
int sc = 0; int sc = 0;
GetSelectedChannels(app, sel, &sc); GetSelectedChannels(app, sel, &sc);
int pad = 5; int pad = 5;
int gl = pad + 45; /* левая граница графика */ int gl = pad + 45; /* левая граница графика */
int gr = w - pad; /* правая граница */ int gr = w - pad; /* правая граница */
int gt = pad; /* верх */ int gt = pad; /* верх */
int gb = h - 25; /* низ */ int gb = h - 25; /* низ */
int gh = gb - gt; int gh = gb - gt;
/* === Сетка === */ /* === Сетка === */
HPEN grid = CreatePen(PS_DOT, 1, GetSysColor(COLOR_BTNSHADOW)); HPEN grid = CreatePen(PS_DOT, 1, GetSysColor(COLOR_BTNSHADOW));
HPEN old = (HPEN)SelectObject(memDC, grid); HPEN old = (HPEN)SelectObject(memDC, grid);
@ -115,7 +96,6 @@ void DrawGraph(HDC hdc, RECT* rc, struct etcpmon_app* app)
} }
SelectObject(memDC, old); SelectObject(memDC, old);
DeleteObject(grid); DeleteObject(grid);
/* === Оси === */ /* === Оси === */
HPEN axis = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWTEXT)); HPEN axis = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWTEXT));
old = (HPEN)SelectObject(memDC, axis); old = (HPEN)SelectObject(memDC, axis);
@ -123,30 +103,24 @@ void DrawGraph(HDC hdc, RECT* rc, struct etcpmon_app* app)
MoveToEx(memDC, gl, gb, NULL); LineTo(memDC, gr, gb); MoveToEx(memDC, gl, gb, NULL); LineTo(memDC, gr, gb);
SelectObject(memDC, old); SelectObject(memDC, old);
DeleteObject(axis); DeleteObject(axis);
/* Сколько точек видно */ /* Сколько точек видно */
int vis = (hist->count < gr - gl) ? hist->count : (gr - gl); int vis = (hist->count < gr - gl) ? hist->count : (gr - gl);
int oldest = (hist->head - vis + GRAPH_HISTORY_SIZE) % GRAPH_HISTORY_SIZE; int oldest = (hist->head - vis + GRAPH_HISTORY_SIZE) % GRAPH_HISTORY_SIZE;
int startx = gr - vis; int startx = gr - vis;
/* Пересчёт min/max 5 раз в секунду */ /* Пересчёт min/max 5 раз в секунду */
DWORD now = GetTickCount(); DWORD now = GetTickCount();
if (now - hist->last_minmax_update >= 200) { if (now - hist->last_minmax_update >= 200) {
RecalculateMinMax(hist, vis, oldest); RecalculateMinMax(hist, vis, oldest);
hist->last_minmax_update = now; hist->last_minmax_update = now;
} }
/* Буфер точек */ /* Буфер точек */
POINT* points = (POINT*)malloc((vis + 1) * sizeof(POINT)); POINT* points = (POINT*)malloc((vis + 1) * sizeof(POINT));
/* Рисуем графики */ /* Рисуем графики */
for (int ch = 0; ch < sc; ch++) { for (int ch = 0; ch < sc; ch++) {
int m = sel[ch]; int m = sel[ch];
float mn = hist->min_val[m]; float mn = hist->min_val[m];
float mx = hist->max_val[m]; float mx = hist->max_val[m];
SelectObject(memDC, app->hGraphPens[m]); SelectObject(memDC, app->hGraphPens[m]);
for (int i = 0; i < vis; i++) { for (int i = 0; i < vis; i++) {
float v = hist->values[m][(oldest + i) % GRAPH_HISTORY_SIZE]; float v = hist->values[m][(oldest + i) % GRAPH_HISTORY_SIZE];
int x = startx + i; int x = startx + i;
@ -158,9 +132,7 @@ void DrawGraph(HDC hdc, RECT* rc, struct etcpmon_app* app)
} }
Polyline(memDC, points, vis); Polyline(memDC, points, vis);
} }
free(points); free(points);
/* === ВЕРТИКАЛЬНАЯ ЛИНИЯ КУРСОРА (только линия, без текста) === */ /* === ВЕРТИКАЛЬНАЯ ЛИНИЯ КУРСОРА (только линия, без текста) === */
if (app->graph_cursor_active) { if (app->graph_cursor_active) {
HPEN cp = CreatePen(PS_SOLID, 1, RGB(80, 80, 80)); HPEN cp = CreatePen(PS_SOLID, 1, RGB(80, 80, 80));
@ -170,20 +142,16 @@ void DrawGraph(HDC hdc, RECT* rc, struct etcpmon_app* app)
SelectObject(memDC, old); SelectObject(memDC, old);
DeleteObject(cp); DeleteObject(cp);
} }
end: end:
/* Копируем на экран */ /* Копируем на экран */
BitBlt(hdc, 0, 0, w, h, memDC, 0, 0, SRCCOPY); BitBlt(hdc, 0, 0, w, h, memDC, 0, 0, SRCCOPY);
SelectObject(memDC, oldBmp); SelectObject(memDC, oldBmp);
DeleteObject(bmp); DeleteObject(bmp);
DeleteDC(memDC); DeleteDC(memDC);
} }
void UpdateChannelValues(struct etcpmon_app* app, int history_idx) void UpdateChannelValues(struct etcpmon_app* app, int history_idx)
{ {
if (!app || !app->client) return; if (!app || !app->client) return;
struct metrics_history* h = etcpmon_client_get_history(app->client); struct metrics_history* h = etcpmon_client_get_history(app->client);
if (!h || history_idx < 0 || history_idx >= GRAPH_HISTORY_SIZE) { if (!h || history_idx < 0 || history_idx >= GRAPH_HISTORY_SIZE) {
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) { for (int i = 0; i < GRAPH_METRICS_COUNT; i++) {
@ -192,15 +160,11 @@ void UpdateChannelValues(struct etcpmon_app* app, int history_idx)
} }
return; return;
} }
static char last_text[GRAPH_METRICS_COUNT][32] = {0}; static char last_text[GRAPH_METRICS_COUNT][32] = {0};
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) { for (int i = 0; i < GRAPH_METRICS_COUNT; i++) {
if (!app->hChannelValue[i]) continue; if (!app->hChannelValue[i]) continue;
float val = h->values[i][history_idx]; float val = h->values[i][history_idx];
char buf[32] = {0}; char buf[32] = {0};
if (i == GRAPH_METRIC_BYTES_SENT) { if (i == GRAPH_METRIC_BYTES_SENT) {
if (val >= 1024*1024) snprintf(buf, sizeof(buf), "%.1f MB/s", val/(1024.*1024.)); if (val >= 1024*1024) snprintf(buf, sizeof(buf), "%.1f MB/s", val/(1024.*1024.));
else if (val >= 1024) snprintf(buf, sizeof(buf), "%.1f KB/s", val/1024.); else if (val >= 1024) snprintf(buf, sizeof(buf), "%.1f KB/s", val/1024.);
@ -213,22 +177,17 @@ void UpdateChannelValues(struct etcpmon_app* app, int history_idx)
} else { } else {
snprintf(buf, sizeof(buf), "%.1f ms", val); snprintf(buf, sizeof(buf), "%.1f ms", val);
} }
if (strcmp(buf, last_text[i]) == 0) if (strcmp(buf, last_text[i]) == 0)
continue; continue;
strcpy(last_text[i], buf); strcpy(last_text[i], buf);
SendMessageA(app->hChannelValue[i], WM_SETREDRAW, FALSE, 0); SendMessageA(app->hChannelValue[i], WM_SETREDRAW, FALSE, 0);
SetWindowTextA(app->hChannelValue[i], buf); SetWindowTextA(app->hChannelValue[i], buf);
SendMessageA(app->hChannelValue[i], WM_SETREDRAW, TRUE, 0); SendMessageA(app->hChannelValue[i], WM_SETREDRAW, TRUE, 0);
InvalidateRect(app->hChannelValue[i], NULL, FALSE); InvalidateRect(app->hChannelValue[i], NULL, FALSE);
} }
} }
LRESULT CALLBACK GraphWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT CALLBACK GraphWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
struct etcpmon_app* app = (struct etcpmon_app*)GetWindowLongPtrA(hWnd, GWLP_USERDATA); struct etcpmon_app* app = (struct etcpmon_app*)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
switch (message) { switch (message) {
case WM_CREATE: { case WM_CREATE: {
CREATESTRUCTA* cs = (CREATESTRUCTA*)lParam; CREATESTRUCTA* cs = (CREATESTRUCTA*)lParam;

55
tools/etcpmon/etcpmon_gui.c

@ -1,35 +1,28 @@
/* /*
* etcpmon_gui.c - ETCP Monitor GUI Implementation * etcpmon_gui.c - ETCP Monitor GUI Implementation
*/ */
/* Must define this before any windows headers to exclude winsock.h */ /* Must define this before any windows headers to exclude winsock.h */
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
/* Must include winsock2.h before windows.h */ /* Must include winsock2.h before windows.h */
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
#include <commctrl.h> #include <commctrl.h>
#include "etcpmon_gui.h" #include "etcpmon_gui.h"
#include "etcpmon_client.h" #include "etcpmon_client.h"
#include "etcpmon_protocol.h" #include "etcpmon_protocol.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
//#pragma comment(lib, "comctl32.lib") //#pragma comment(lib, "comctl32.lib")
//#pragma comment(lib, "user32.lib") //#pragma comment(lib, "user32.lib")
//#pragma comment(lib, "gdi32.lib") //#pragma comment(lib, "gdi32.lib")
#define WINDOW_WIDTH 900 #define WINDOW_WIDTH 900
#define WINDOW_HEIGHT 900 #define WINDOW_HEIGHT 900
#define UPDATE_INTERVAL 10 /* 50ms → 20 samples per second */ #define UPDATE_INTERVAL 10 /* 50ms → 20 samples per second */
/* Global app pointer for callbacks */ /* Global app pointer for callbacks */
static struct etcpmon_app* g_app = NULL; static struct etcpmon_app* g_app = NULL;
/* Forward declarations */ /* Forward declarations */
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static void CreateControls(struct etcpmon_app* app); static void CreateControls(struct etcpmon_app* app);
@ -38,7 +31,6 @@ static void OnDisconnect(struct etcpmon_app* app);
static void OnConnectionSelect(struct etcpmon_app* app); static void OnConnectionSelect(struct etcpmon_app* app);
static void OnTimer(struct etcpmon_app* app); static void OnTimer(struct etcpmon_app* app);
static void UpdateUIState(struct etcpmon_app* app); static void UpdateUIState(struct etcpmon_app* app);
/* Callback functions for client events */ /* Callback functions for client events */
static void on_connected(void* user_data); static void on_connected(void* user_data);
static void on_disconnected(void* user_data); static void on_disconnected(void* user_data);
@ -47,7 +39,6 @@ static void on_metrics(struct etcpmon_rsp_metrics* metrics,
struct etcpmon_link_metrics* links, struct etcpmon_link_metrics* links,
uint8_t links_count, void* user_data); uint8_t links_count, void* user_data);
static void on_error(const char* msg, void* user_data); static void on_error(const char* msg, void* user_data);
/* Helper functions */ /* Helper functions */
static void SetDlgItemTextFmt(HWND hDlg, int nIDDlgItem, const char* fmt, ...) { static void SetDlgItemTextFmt(HWND hDlg, int nIDDlgItem, const char* fmt, ...) {
char buf[256]; char buf[256];
@ -57,7 +48,6 @@ static void SetDlgItemTextFmt(HWND hDlg, int nIDDlgItem, const char* fmt, ...) {
va_end(args); va_end(args);
SetDlgItemTextA(hDlg, nIDDlgItem, buf); SetDlgItemTextA(hDlg, nIDDlgItem, buf);
} }
int etcpmon_gui_init(struct etcpmon_app* app, HINSTANCE hInstance) { int etcpmon_gui_init(struct etcpmon_app* app, HINSTANCE hInstance) {
if (!app) return -1; if (!app) return -1;
@ -111,7 +101,6 @@ int etcpmon_gui_init(struct etcpmon_app* app, HINSTANCE hInstance) {
return 0; return 0;
} }
HWND etcpmon_gui_create_window(struct etcpmon_app* app) { HWND etcpmon_gui_create_window(struct etcpmon_app* app) {
if (!app) return NULL; if (!app) return NULL;
@ -141,7 +130,6 @@ HWND etcpmon_gui_create_window(struct etcpmon_app* app) {
/* Create all controls */ /* Create all controls */
CreateControls(app); CreateControls(app);
SetTimer(app->hWndMain, IDC_TIMER_UPDATE, UPDATE_INTERVAL, NULL); SetTimer(app->hWndMain, IDC_TIMER_UPDATE, UPDATE_INTERVAL, NULL);
/* Set default values */ /* Set default values */
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ADDR, "127.0.0.1"); SetDlgItemTextA(app->hWndMain, IDC_EDIT_ADDR, "127.0.0.1");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_PORT, "9090"); SetDlgItemTextA(app->hWndMain, IDC_EDIT_PORT, "9090");
@ -159,12 +147,10 @@ HWND etcpmon_gui_create_window(struct etcpmon_app* app) {
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) { for (int i = 0; i < GRAPH_METRICS_COUNT; i++) {
app->hGraphPens[i] = CreatePen(PS_SOLID, 2, graph_colors[i]); app->hGraphPens[i] = CreatePen(PS_SOLID, 2, graph_colors[i]);
} }
UpdateUIState(app); UpdateUIState(app);
return app->hWndMain; return app->hWndMain;
} }
static void CreateControls(struct etcpmon_app* app) { static void CreateControls(struct etcpmon_app* app) {
HWND hWnd = app->hWndMain; HWND hWnd = app->hWndMain;
HINSTANCE hInst = app->hInstance; HINSTANCE hInst = app->hInstance;
@ -215,7 +201,6 @@ static void CreateControls(struct etcpmon_app* app) {
/* Graph area */ /* Graph area */
y += 140; y += 140;
app->hGraphWnd = CreateWindowExA( app->hGraphWnd = CreateWindowExA(
WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE,
"ETCPMonGraph", "", "ETCPMonGraph", "",
@ -393,7 +378,6 @@ static void CreateControls(struct etcpmon_app* app) {
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT,
10, y + 20, 880, 100, hWnd, (HMENU)IDC_LIST_LINKS, hInst, NULL); 10, y + 20, 880, 100, hWnd, (HMENU)IDC_LIST_LINKS, hInst, NULL);
} }
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
struct etcpmon_app* app = NULL; struct etcpmon_app* app = NULL;
@ -429,7 +413,6 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l
SendMessage(app->hWndStatus, WM_SIZE, 0, 0); SendMessage(app->hWndStatus, WM_SIZE, 0, 0);
} }
break; break;
case WM_TIMER: case WM_TIMER:
if (wParam == IDC_TIMER_UPDATE && app) { if (wParam == IDC_TIMER_UPDATE && app) {
OnTimer(app); OnTimer(app);
@ -447,7 +430,6 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l
return 0; return 0;
} }
static void OnConnect(struct etcpmon_app* app) { static void OnConnect(struct etcpmon_app* app) {
if (!app || !app->client) return; if (!app || !app->client) return;
@ -470,7 +452,6 @@ static void OnConnect(struct etcpmon_app* app) {
etcpmon_gui_set_status(app, "Connection failed"); etcpmon_gui_set_status(app, "Connection failed");
} }
} }
static void OnDisconnect(struct etcpmon_app* app) { static void OnDisconnect(struct etcpmon_app* app) {
if (!app || !app->client) return; if (!app || !app->client) return;
@ -480,7 +461,6 @@ static void OnDisconnect(struct etcpmon_app* app) {
etcpmon_gui_clear_metrics(app); etcpmon_gui_clear_metrics(app);
etcpmon_gui_set_status(app, "Disconnected"); etcpmon_gui_set_status(app, "Disconnected");
} }
static void OnConnectionSelect(struct etcpmon_app* app) { static void OnConnectionSelect(struct etcpmon_app* app) {
if (!app || !app->client) return; if (!app || !app->client) return;
@ -493,32 +473,26 @@ static void OnConnectionSelect(struct etcpmon_app* app) {
/* Request metrics for this connection */ /* Request metrics for this connection */
etcpmon_client_select_connection(app->client, peer_id); etcpmon_client_select_connection(app->client, peer_id);
} }
static void OnTimer(struct etcpmon_app* app) { static void OnTimer(struct etcpmon_app* app) {
if (!app || !app->client) return; if (!app || !app->client) return;
/* 1. Сеть */ /* 1. Сеть */
etcpmon_client_process(app->client); etcpmon_client_process(app->client);
/* 2. Первый запрос списка после подключения */ /* 2. Первый запрос списка после подключения */
static int first_connect = 1; static int first_connect = 1;
if (first_connect && app->isConnected) { if (first_connect && app->isConnected) {
etcpmon_client_request_list(app->client); etcpmon_client_request_list(app->client);
first_connect = 0; first_connect = 0;
} }
/* 3. Запрос метрик */ /* 3. Запрос метрик */
if (app->client->selected_peer_id != 0) { if (app->client->selected_peer_id != 0) {
etcpmon_client_request_metrics(app->client); etcpmon_client_request_metrics(app->client);
} }
/* 4. График — 20 раз в секунду */ /* 4. График — 20 раз в секунду */
if (app->hGraphWnd) { if (app->hGraphWnd) {
InvalidateRect(app->hGraphWnd, NULL, FALSE); InvalidateRect(app->hGraphWnd, NULL, FALSE);
UpdateWindow(app->hGraphWnd); /* форсируем немедленную перерисовку */ UpdateWindow(app->hGraphWnd); /* форсируем немедленную перерисовку */
} }
} }
static void UpdateUIState(struct etcpmon_app* app) { static void UpdateUIState(struct etcpmon_app* app) {
if (!app) return; if (!app) return;
@ -527,7 +501,6 @@ static void UpdateUIState(struct etcpmon_app* app) {
EnableWindow(app->hBtnConnect, !app->isConnected); EnableWindow(app->hBtnConnect, !app->isConnected);
EnableWindow(app->hBtnDisconnect, app->isConnected); EnableWindow(app->hBtnDisconnect, app->isConnected);
} }
/* Client callbacks */ /* Client callbacks */
static void on_connected(void* user_data) { static void on_connected(void* user_data) {
struct etcpmon_app* app = (struct etcpmon_app*)user_data; struct etcpmon_app* app = (struct etcpmon_app*)user_data;
@ -540,7 +513,6 @@ static void on_connected(void* user_data) {
} }
etcpmon_client_request_list(app->client); etcpmon_client_request_list(app->client);
} }
void etcpmon_gui_update_graph(struct etcpmon_app* app, struct etcpmon_rsp_metrics* metrics) { void etcpmon_gui_update_graph(struct etcpmon_app* app, struct etcpmon_rsp_metrics* metrics) {
if (!app || !metrics) return; if (!app || !metrics) return;
@ -556,26 +528,22 @@ void etcpmon_gui_update_graph(struct etcpmon_app* app, struct etcpmon_rsp_metric
} }
} }
} }
static void on_disconnected(void* user_data) { static void on_disconnected(void* user_data) {
struct etcpmon_app* app = (struct etcpmon_app*)user_data; struct etcpmon_app* app = (struct etcpmon_app*)user_data;
app->isConnected = 0; app->isConnected = 0;
UpdateUIState(app); UpdateUIState(app);
etcpmon_gui_set_status(app, "Disconnected"); etcpmon_gui_set_status(app, "Disconnected");
} }
static void on_conn_list(struct etcpmon_conn_info* list, uint8_t count, void* user_data) { static void on_conn_list(struct etcpmon_conn_info* list, uint8_t count, void* user_data) {
struct etcpmon_app* app = (struct etcpmon_app*)user_data; struct etcpmon_app* app = (struct etcpmon_app*)user_data;
etcpmon_gui_update_conn_list(app, list, count); etcpmon_gui_update_conn_list(app, list, count);
etcpmon_gui_set_status(app, "Connection list updated"); etcpmon_gui_set_status(app, "Connection list updated");
/* Automatically select the first connection if available */ /* Automatically select the first connection if available */
if (count > 0 && app->hListConnections) { if (count > 0 && app->hListConnections) {
SendMessage(app->hListConnections, LB_SETCURSEL, 0, 0); SendMessage(app->hListConnections, LB_SETCURSEL, 0, 0);
OnConnectionSelect(app); OnConnectionSelect(app);
} }
} }
static void on_metrics(struct etcpmon_rsp_metrics* metrics, static void on_metrics(struct etcpmon_rsp_metrics* metrics,
struct etcpmon_link_metrics* links, struct etcpmon_link_metrics* links,
uint8_t links_count, void* user_data) { uint8_t links_count, void* user_data) {
@ -583,7 +551,6 @@ static void on_metrics(struct etcpmon_rsp_metrics* metrics,
if (app) { if (app) {
etcpmon_gui_update_metrics(app, metrics, links, links_count); etcpmon_gui_update_metrics(app, metrics, links, links_count);
etcpmon_client_add_to_history(app->client, metrics); etcpmon_client_add_to_history(app->client, metrics);
struct metrics_history* h = etcpmon_client_get_history(app->client); struct metrics_history* h = etcpmon_client_get_history(app->client);
if (h && h->count > 0) { if (h && h->count > 0) {
int last_idx = (h->head - 1 + GRAPH_HISTORY_SIZE) % GRAPH_HISTORY_SIZE; int last_idx = (h->head - 1 + GRAPH_HISTORY_SIZE) % GRAPH_HISTORY_SIZE;
@ -591,18 +558,14 @@ static void on_metrics(struct etcpmon_rsp_metrics* metrics,
} }
} }
} }
static void on_error(const char* msg, void* user_data) { static void on_error(const char* msg, void* user_data) {
struct etcpmon_app* app = (struct etcpmon_app*)user_data; struct etcpmon_app* app = (struct etcpmon_app*)user_data;
etcpmon_gui_set_status(app, msg); etcpmon_gui_set_status(app, msg);
} }
int etcpmon_gui_run(struct etcpmon_app* app) { int etcpmon_gui_run(struct etcpmon_app* app) {
if (!app || !app->hWndMain) return -1; if (!app || !app->hWndMain) return -1;
ShowWindow(app->hWndMain, SW_SHOW); ShowWindow(app->hWndMain, SW_SHOW);
UpdateWindow(app->hWndMain); UpdateWindow(app->hWndMain);
MSG msg; MSG msg;
while (GetMessageA(&msg, NULL, 0, 0)) { while (GetMessageA(&msg, NULL, 0, 0)) {
TranslateMessage(&msg); TranslateMessage(&msg);
@ -610,29 +573,24 @@ int etcpmon_gui_run(struct etcpmon_app* app) {
} }
return (int)msg.wParam; return (int)msg.wParam;
} }
void etcpmon_gui_cleanup(struct etcpmon_app* app) { void etcpmon_gui_cleanup(struct etcpmon_app* app) {
if (!app) return; if (!app) return;
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) { for (int i = 0; i < GRAPH_METRICS_COUNT; i++) {
if (app->hGraphPens[i]) DeleteObject(app->hGraphPens[i]); if (app->hGraphPens[i]) DeleteObject(app->hGraphPens[i]);
} }
if (app->client) { if (app->client) {
etcpmon_client_cleanup(app->client); etcpmon_client_cleanup(app->client);
free(app->client); free(app->client);
app->client = NULL; app->client = NULL;
} }
WSACleanup(); WSACleanup();
g_app = NULL; g_app = NULL;
} }
void etcpmon_gui_set_status(struct etcpmon_app* app, const char* text) { void etcpmon_gui_set_status(struct etcpmon_app* app, const char* text) {
if (!app || !app->hWndStatus) return; if (!app || !app->hWndStatus) return;
SendMessageA(app->hWndStatus, SB_SETTEXTA, 0, (LPARAM)text); SendMessageA(app->hWndStatus, SB_SETTEXTA, 0, (LPARAM)text);
} }
void etcpmon_gui_update_conn_list(struct etcpmon_app* app, void etcpmon_gui_update_conn_list(struct etcpmon_app* app,
struct etcpmon_conn_info* list, struct etcpmon_conn_info* list,
uint8_t count) { uint8_t count) {
@ -653,7 +611,6 @@ void etcpmon_gui_update_conn_list(struct etcpmon_app* app,
} }
} }
} }
/* Обновляет EDIT только если текст действительно изменился → убирает моргание */ /* Обновляет EDIT только если текст действительно изменился → убирает моргание */
static BOOL UpdateEditIfChanged(HWND hDlg, int nIDDlgItem, const char* fmt, ...) static BOOL UpdateEditIfChanged(HWND hDlg, int nIDDlgItem, const char* fmt, ...)
{ {
@ -662,27 +619,21 @@ static BOOL UpdateEditIfChanged(HWND hDlg, int nIDDlgItem, const char* fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vsnprintf(new_text, sizeof(new_text), fmt, args); vsnprintf(new_text, sizeof(new_text), fmt, args);
va_end(args); va_end(args);
char old_text[128] = {0}; char old_text[128] = {0};
GetDlgItemTextA(hDlg, nIDDlgItem, old_text, sizeof(old_text)); GetDlgItemTextA(hDlg, nIDDlgItem, old_text, sizeof(old_text));
if (strcmp(old_text, new_text) == 0) if (strcmp(old_text, new_text) == 0)
return FALSE; return FALSE;
SetDlgItemTextA(hDlg, nIDDlgItem, new_text); SetDlgItemTextA(hDlg, nIDDlgItem, new_text);
InvalidateRect(GetDlgItem(hDlg, nIDDlgItem), NULL, FALSE); InvalidateRect(GetDlgItem(hDlg, nIDDlgItem), NULL, FALSE);
return TRUE; return TRUE;
} }
void etcpmon_gui_update_metrics(struct etcpmon_app* app, void etcpmon_gui_update_metrics(struct etcpmon_app* app,
struct etcpmon_rsp_metrics* metrics, struct etcpmon_rsp_metrics* metrics,
struct etcpmon_link_metrics* links, struct etcpmon_link_metrics* links,
uint8_t links_count) uint8_t links_count)
{ {
if (!app || !metrics) return; if (!app || !metrics) return;
HWND hMain = app->hWndMain; HWND hMain = app->hWndMain;
/* ETCP Metrics — обновляем ТОЛЬКО при изменении */ /* ETCP Metrics — обновляем ТОЛЬКО при изменении */
UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_LAST, "%u us", metrics->etcp.rtt_last * 100); UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_LAST, "%u us", metrics->etcp.rtt_last * 100);
UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_AVG10, "%u us", metrics->etcp.rtt_avg_10 * 100); UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_RTT_AVG10, "%u us", metrics->etcp.rtt_avg_10 * 100);
@ -693,7 +644,6 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app,
UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_ACKS, "%u", metrics->etcp.ack_count); UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_ACKS, "%u", metrics->etcp.ack_count);
UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_INFLIGHT, "%u bytes", metrics->etcp.unacked_bytes); UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_INFLIGHT, "%u bytes", metrics->etcp.unacked_bytes);
UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_LINKS, "%u", metrics->etcp.links_count); UpdateEditIfChanged(hMain, IDC_EDIT_ETCP_LINKS, "%u", metrics->etcp.links_count);
/* TUN Metrics */ /* TUN Metrics */
UpdateEditIfChanged(hMain, IDC_EDIT_TUN_READ_BYTES, "%llu", (unsigned long long)metrics->tun.bytes_read); UpdateEditIfChanged(hMain, IDC_EDIT_TUN_READ_BYTES, "%llu", (unsigned long long)metrics->tun.bytes_read);
UpdateEditIfChanged(hMain, IDC_EDIT_TUN_WRITE_BYTES, "%llu", (unsigned long long)metrics->tun.bytes_written); UpdateEditIfChanged(hMain, IDC_EDIT_TUN_WRITE_BYTES, "%llu", (unsigned long long)metrics->tun.bytes_written);
@ -701,7 +651,6 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app,
UpdateEditIfChanged(hMain, IDC_EDIT_TUN_WRITE_PKTS, "%u", metrics->tun.packets_written); UpdateEditIfChanged(hMain, IDC_EDIT_TUN_WRITE_PKTS, "%u", metrics->tun.packets_written);
UpdateEditIfChanged(hMain, IDC_EDIT_TUN_READ_ERRS, "%u", metrics->tun.read_errors); UpdateEditIfChanged(hMain, IDC_EDIT_TUN_READ_ERRS, "%u", metrics->tun.read_errors);
UpdateEditIfChanged(hMain, IDC_EDIT_TUN_WRITE_ERRS, "%u", metrics->tun.write_errors); UpdateEditIfChanged(hMain, IDC_EDIT_TUN_WRITE_ERRS, "%u", metrics->tun.write_errors);
/* Links list */ /* Links list */
if (app->hListLinks) { if (app->hListLinks) {
SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0); SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0);
@ -721,21 +670,17 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app,
(unsigned long long)links[i].total_decrypted, (unsigned long long)links[i].total_decrypted,
links[i].bandwidth, links[i].bandwidth,
links[i].nat_changes_count); links[i].nat_changes_count);
SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)display); SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)display);
} }
InvalidateRect(app->hListLinks, NULL, FALSE); InvalidateRect(app->hListLinks, NULL, FALSE);
} }
/* График */ /* График */
if (app->hGraphWnd) { if (app->hGraphWnd) {
InvalidateRect(app->hGraphWnd, NULL, FALSE); InvalidateRect(app->hGraphWnd, NULL, FALSE);
} }
} }
void etcpmon_gui_clear_metrics(struct etcpmon_app* app) { void etcpmon_gui_clear_metrics(struct etcpmon_app* app) {
if (!app) return; if (!app) return;
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ETCP_NAME, ""); SetDlgItemTextA(app->hWndMain, IDC_EDIT_ETCP_NAME, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ETCP_RTT_LAST, ""); SetDlgItemTextA(app->hWndMain, IDC_EDIT_ETCP_RTT_LAST, "");
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ETCP_RTT_AVG10, ""); SetDlgItemTextA(app->hWndMain, IDC_EDIT_ETCP_RTT_AVG10, "");

Loading…
Cancel
Save