|
|
|
@ -16,6 +16,7 @@ |
|
|
|
#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 <string.h> |
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
|
|
|
//#pragma comment(lib, "comctl32.lib")
|
|
|
|
//#pragma comment(lib, "comctl32.lib")
|
|
|
|
@ -23,7 +24,7 @@ |
|
|
|
//#pragma comment(lib, "gdi32.lib")
|
|
|
|
//#pragma comment(lib, "gdi32.lib")
|
|
|
|
|
|
|
|
|
|
|
|
#define WINDOW_WIDTH 900 |
|
|
|
#define WINDOW_WIDTH 900 |
|
|
|
#define WINDOW_HEIGHT 700 |
|
|
|
#define WINDOW_HEIGHT 900 |
|
|
|
#define UPDATE_INTERVAL 100 /* 100ms */ |
|
|
|
#define UPDATE_INTERVAL 100 /* 100ms */ |
|
|
|
|
|
|
|
|
|
|
|
/* Global app pointer for callbacks */ |
|
|
|
/* Global app pointer for callbacks */ |
|
|
|
@ -83,10 +84,25 @@ int etcpmon_gui_init(struct etcpmon_app* app, HINSTANCE hInstance) { |
|
|
|
wcex.lpszClassName = ETCPMON_WINDOW_CLASS; |
|
|
|
wcex.lpszClassName = ETCPMON_WINDOW_CLASS; |
|
|
|
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); |
|
|
|
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION); |
|
|
|
|
|
|
|
|
|
|
|
if (!RegisterClassExA(&wcex)) { |
|
|
|
if (!RegisterClassExA(&wcex)) { |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Register Graph window class */ |
|
|
|
|
|
|
|
WNDCLASSEXA wcexGraph; |
|
|
|
|
|
|
|
memset(&wcexGraph, 0, sizeof(wcexGraph)); |
|
|
|
|
|
|
|
wcexGraph.cbSize = sizeof(wcexGraph); |
|
|
|
|
|
|
|
wcexGraph.style = CS_HREDRAW | CS_VREDRAW; |
|
|
|
|
|
|
|
wcexGraph.lpfnWndProc = GraphWndProc; |
|
|
|
|
|
|
|
wcexGraph.hInstance = hInstance; |
|
|
|
|
|
|
|
wcexGraph.hIcon = NULL; |
|
|
|
|
|
|
|
wcexGraph.hCursor = LoadCursor(NULL, IDC_CROSS); |
|
|
|
|
|
|
|
wcexGraph.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); |
|
|
|
|
|
|
|
wcexGraph.lpszClassName = "ETCPMonGraph"; |
|
|
|
|
|
|
|
wcexGraph.hIconSm = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RegisterClassExA(&wcexGraph); |
|
|
|
|
|
|
|
|
|
|
|
/* Initialize Winsock */ |
|
|
|
/* Initialize Winsock */ |
|
|
|
WSADATA wsaData; |
|
|
|
WSADATA wsaData; |
|
|
|
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { |
|
|
|
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { |
|
|
|
@ -104,7 +120,7 @@ HWND etcpmon_gui_create_window(struct etcpmon_app* app) { |
|
|
|
0, |
|
|
|
0, |
|
|
|
ETCPMON_WINDOW_CLASS, |
|
|
|
ETCPMON_WINDOW_CLASS, |
|
|
|
"ETCP Monitor", |
|
|
|
"ETCP Monitor", |
|
|
|
WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX, |
|
|
|
WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME, |
|
|
|
CW_USEDEFAULT, CW_USEDEFAULT, |
|
|
|
CW_USEDEFAULT, CW_USEDEFAULT, |
|
|
|
WINDOW_WIDTH, WINDOW_HEIGHT, |
|
|
|
WINDOW_WIDTH, WINDOW_HEIGHT, |
|
|
|
NULL, NULL, app->hInstance, app |
|
|
|
NULL, NULL, app->hInstance, app |
|
|
|
@ -192,8 +208,55 @@ 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, |
|
|
|
x, y + 20, 300, 120, hWnd, (HMENU)IDC_LIST_CONNECTIONS, hInst, NULL); |
|
|
|
x, y + 20, 300, 120, hWnd, (HMENU)IDC_LIST_CONNECTIONS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Graph area - between Connections and ETCP Metrics */ |
|
|
|
|
|
|
|
y += 140; |
|
|
|
|
|
|
|
// app->hGraphWnd = CreateWindowA("STATIC", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,
|
|
|
|
|
|
|
|
// 10, y, GRAPH_WIDTH, GRAPH_HEIGHT, hWnd, (HMENU)IDC_GRAPH, hInst, app);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app->hGraphWnd = CreateWindowExA( |
|
|
|
|
|
|
|
WS_EX_CLIENTEDGE, |
|
|
|
|
|
|
|
"ETCPMonGraph", "", |
|
|
|
|
|
|
|
WS_CHILD | WS_VISIBLE | WS_BORDER, |
|
|
|
|
|
|
|
10, y, GRAPH_WIDTH, GRAPH_HEIGHT, |
|
|
|
|
|
|
|
hWnd, (HMENU)IDC_GRAPH, hInst, app); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Channel list - grid blocks below graph */ |
|
|
|
|
|
|
|
y += GRAPH_HEIGHT + 5; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char* channel_short_names[] = { |
|
|
|
|
|
|
|
"RTT-L", "RTT10", "RTT100", "Jitter", |
|
|
|
|
|
|
|
"Retrns", "ACKs", "Inflght", "Bytes/s" |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int block_w = 200; |
|
|
|
|
|
|
|
int block_h = 50; |
|
|
|
|
|
|
|
int cols = 4; |
|
|
|
|
|
|
|
int spacing = 5; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) { |
|
|
|
|
|
|
|
int col = i % cols; |
|
|
|
|
|
|
|
int row = i / cols; |
|
|
|
|
|
|
|
int bx = 10 + col * (block_w + spacing); |
|
|
|
|
|
|
|
int by = y + row * (block_h + spacing); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app->hChannelName[i] = CreateWindowExA(0, "STATIC", channel_short_names[i], |
|
|
|
|
|
|
|
WS_CHILD | WS_VISIBLE, |
|
|
|
|
|
|
|
bx, by, block_w, 16, hWnd, (HMENU)(UINT_PTR)(IDC_CH_NAME_0 + i), hInst, NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app->hChannelValue[i] = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY, |
|
|
|
|
|
|
|
bx, by + 16, block_w, 18, hWnd, (HMENU)(UINT_PTR)(IDC_CH_VALUE_0 + i), hInst, NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app->hChannelCheck[i] = CreateWindowExA(0, "BUTTON", "", |
|
|
|
|
|
|
|
WS_CHILD | WS_VISIBLE | BS_CHECKBOX | BST_CHECKED, |
|
|
|
|
|
|
|
bx, by + 34, 16, 14, hWnd, (HMENU)(UINT_PTR)(IDC_CH_CHECK_0 + i), hInst, NULL); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int channel_grid_h = ((GRAPH_METRICS_COUNT + cols - 1) / cols) * (block_h + spacing) - spacing; |
|
|
|
|
|
|
|
y += channel_grid_h; |
|
|
|
|
|
|
|
|
|
|
|
/* ETCP Metrics group */ |
|
|
|
/* ETCP Metrics group */ |
|
|
|
y += 150; |
|
|
|
y = 485; |
|
|
|
CreateWindowExA(0, "BUTTON", "ETCP Metrics", |
|
|
|
CreateWindowExA(0, "BUTTON", "ETCP Metrics", |
|
|
|
WS_CHILD | WS_VISIBLE | BS_GROUPBOX, |
|
|
|
WS_CHILD | WS_VISIBLE | BS_GROUPBOX, |
|
|
|
x, y, 430, 220, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
x, y, 430, 220, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
@ -265,8 +328,8 @@ static void CreateControls(struct etcpmon_app* app) { |
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY, |
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY, |
|
|
|
mx + 85, my, 100, 20, hWnd, (HMENU)IDC_EDIT_ETCP_LINKS, hInst, NULL); |
|
|
|
mx + 85, my, 100, 20, hWnd, (HMENU)IDC_EDIT_ETCP_LINKS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
|
|
/* TUN Metrics group */ |
|
|
|
/* TUN Metrics group - right of ETCP Metrics */ |
|
|
|
x = 460; y = 240; |
|
|
|
x = 460; y = 485; |
|
|
|
CreateWindowExA(0, "BUTTON", "TUN Metrics", |
|
|
|
CreateWindowExA(0, "BUTTON", "TUN Metrics", |
|
|
|
WS_CHILD | WS_VISIBLE | BS_GROUPBOX, |
|
|
|
WS_CHILD | WS_VISIBLE | BS_GROUPBOX, |
|
|
|
x, y, 430, 140, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
x, y, 430, 140, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
@ -312,14 +375,14 @@ static void CreateControls(struct etcpmon_app* app) { |
|
|
|
mx + 285, my, 100, 20, hWnd, (HMENU)IDC_EDIT_TUN_WRITE_ERRS, hInst, NULL); |
|
|
|
mx + 285, my, 100, 20, hWnd, (HMENU)IDC_EDIT_TUN_WRITE_ERRS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
|
|
/* Links list */ |
|
|
|
/* Links list */ |
|
|
|
y = 470; |
|
|
|
y = 715; |
|
|
|
CreateWindowExA(0, "STATIC", "Links:", |
|
|
|
CreateWindowExA(0, "STATIC", "Links:", |
|
|
|
WS_CHILD | WS_VISIBLE, |
|
|
|
WS_CHILD | WS_VISIBLE, |
|
|
|
10, y, 100, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
10, y, 100, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
|
|
|
|
|
|
|
app->hListLinks = CreateWindowExA(WS_EX_CLIENTEDGE, "LISTBOX", "", |
|
|
|
app->hListLinks = CreateWindowExA(WS_EX_CLIENTEDGE, "LISTBOX", "", |
|
|
|
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, |
|
|
|
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, |
|
|
|
10, y + 20, 880, 120, 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) { |
|
|
|
@ -476,6 +539,21 @@ 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) { |
|
|
|
|
|
|
|
if (!app || !metrics) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (app->hGraphWnd) { |
|
|
|
|
|
|
|
InvalidateRect(app->hGraphWnd, NULL, FALSE); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (app->client) { |
|
|
|
|
|
|
|
struct metrics_history* h = etcpmon_client_get_history(app->client); |
|
|
|
|
|
|
|
if (h && h->count > 0) { |
|
|
|
|
|
|
|
int last_idx = (h->head - 1 + GRAPH_HISTORY_SIZE) % GRAPH_HISTORY_SIZE; |
|
|
|
|
|
|
|
UpdateChannelValues(app, last_idx); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void on_disconnected(void* user_data) { |
|
|
|
static void on_disconnected(void* user_data) { |
|
|
|
@ -508,7 +586,10 @@ 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) { |
|
|
|
struct etcpmon_app* app = (struct etcpmon_app*)user_data; |
|
|
|
struct etcpmon_app* app = (struct etcpmon_app*)user_data; |
|
|
|
etcpmon_gui_update_metrics(app, metrics, links, links_count); |
|
|
|
if (app) { |
|
|
|
|
|
|
|
etcpmon_gui_update_metrics(app, metrics, links, links_count); |
|
|
|
|
|
|
|
etcpmon_client_add_to_history(app->client, metrics); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void on_error(const char* msg, void* user_data) { |
|
|
|
static void on_error(const char* msg, void* user_data) { |
|
|
|
@ -615,25 +696,32 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app, |
|
|
|
metrics->tun.write_errors); |
|
|
|
metrics->tun.write_errors); |
|
|
|
|
|
|
|
|
|
|
|
/* Update links list */ |
|
|
|
/* Update links list */ |
|
|
|
SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0); |
|
|
|
if (app->hListLinks) { |
|
|
|
for (uint8_t i = 0; i < links_count; i++) { |
|
|
|
SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0); |
|
|
|
char display[256]; |
|
|
|
for (uint8_t i = 0; i < links_count; i++) { |
|
|
|
snprintf(display, sizeof(display), |
|
|
|
char display[256]; |
|
|
|
"Link %u: Status=%s, EncErrors=%u, DecErrors=%u, " |
|
|
|
snprintf(display, sizeof(display), |
|
|
|
"SendErr=%u, RecvErr=%u, BytesEnc=%llu, BytesDec=%llu, " |
|
|
|
"Link %u: Status=%s, EncErrors=%u, DecErrors=%u, " |
|
|
|
"BW=%u Kbps, NATChg=%u", |
|
|
|
"SendErr=%u, RecvErr=%u, BytesEnc=%llu, BytesDec=%llu, " |
|
|
|
links[i].local_link_id, |
|
|
|
"BW=%u Kbps, NATChg=%u", |
|
|
|
links[i].status ? "UP" : "DOWN", |
|
|
|
links[i].local_link_id, |
|
|
|
links[i].encrypt_errors, |
|
|
|
links[i].status ? "UP" : "DOWN", |
|
|
|
links[i].decrypt_errors, |
|
|
|
links[i].encrypt_errors, |
|
|
|
links[i].send_errors, |
|
|
|
links[i].decrypt_errors, |
|
|
|
links[i].recv_errors, |
|
|
|
links[i].send_errors, |
|
|
|
(unsigned long long)links[i].total_encrypted, |
|
|
|
links[i].recv_errors, |
|
|
|
(unsigned long long)links[i].total_decrypted, |
|
|
|
(unsigned long long)links[i].total_encrypted, |
|
|
|
links[i].bandwidth, |
|
|
|
(unsigned long long)links[i].total_decrypted, |
|
|
|
links[i].nat_changes_count); |
|
|
|
links[i].bandwidth, |
|
|
|
|
|
|
|
links[i].nat_changes_count); |
|
|
|
SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)display); |
|
|
|
|
|
|
|
|
|
|
|
SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)display); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (app->hGraphWnd) { |
|
|
|
|
|
|
|
InvalidateRect(app->hGraphWnd, NULL, FALSE); |
|
|
|
|
|
|
|
UpdateWindow(app->hGraphWnd); // Force immediate paint
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -658,6 +746,9 @@ void etcpmon_gui_clear_metrics(struct etcpmon_app* app) { |
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_TUN_READ_ERRS, ""); |
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_TUN_READ_ERRS, ""); |
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_TUN_WRITE_ERRS, ""); |
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_TUN_WRITE_ERRS, ""); |
|
|
|
|
|
|
|
|
|
|
|
SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0); |
|
|
|
if (app->hListLinks) { |
|
|
|
|
|
|
|
SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
SendMessage(app->hListConnections, LB_RESETCONTENT, 0, 0); |
|
|
|
SendMessage(app->hListConnections, LB_RESETCONTENT, 0, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
|