|
|
|
|
@ -19,7 +19,7 @@
|
|
|
|
|
//#pragma comment(lib, "user32.lib")
|
|
|
|
|
//#pragma comment(lib, "gdi32.lib")
|
|
|
|
|
#define WINDOW_WIDTH 900 |
|
|
|
|
#define WINDOW_HEIGHT 900 |
|
|
|
|
#define WINDOW_HEIGHT 1080 |
|
|
|
|
#define UPDATE_INTERVAL 10 /* 50ms → 20 samples per second */ |
|
|
|
|
/* Global app pointer for callbacks */ |
|
|
|
|
static struct etcpmon_app* g_app = NULL; |
|
|
|
|
@ -379,6 +379,115 @@ static void CreateControls(struct etcpmon_app* app) {
|
|
|
|
|
app->hListLinks = CreateWindowExA(WS_EX_CLIENTEDGE, "LISTBOX", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, |
|
|
|
|
10, y + 20, 880, 100, hWnd, (HMENU)IDC_LIST_LINKS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
/* Queues & Errors group - below Links */ |
|
|
|
|
y = 845; |
|
|
|
|
CreateWindowExA(0, "BUTTON", "Queues & Errors", |
|
|
|
|
WS_CHILD | WS_VISIBLE | BS_GROUPBOX, |
|
|
|
|
10, y, 880, 165, hWnd, (HMENU)IDC_STATIC_QUEUES, hInst, NULL); |
|
|
|
|
|
|
|
|
|
int qy = y + 22; |
|
|
|
|
int q_col1 = 20; |
|
|
|
|
int q_col2 = 300; |
|
|
|
|
int q_col3 = 580; |
|
|
|
|
|
|
|
|
|
/* Queue metrics - row 1 */ |
|
|
|
|
CreateWindowExA(0, "STATIC", "InQ:", |
|
|
|
|
WS_CHILD | WS_VISIBLE, q_col1, qy, 50, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
app->hEditQInQBytes = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 55, qy - 2, 60, 18, hWnd, (HMENU)IDC_EDIT_Q_IN_Q_BYTES, hInst, NULL); |
|
|
|
|
app->hEditQInQPkts = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 120, qy - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_Q_IN_Q_PKTS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
CreateWindowExA(0, "STATIC", "InSend:", |
|
|
|
|
WS_CHILD | WS_VISIBLE, q_col2, qy, 60, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
app->hEditQInSendBytes = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col2 + 65, qy - 2, 60, 18, hWnd, (HMENU)IDC_EDIT_Q_IN_SEND_BYTES, hInst, NULL); |
|
|
|
|
app->hEditQInSendPkts = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col2 + 130, qy - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_Q_IN_SEND_PKTS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
CreateWindowExA(0, "STATIC", "WaitAck:", |
|
|
|
|
WS_CHILD | WS_VISIBLE, q_col3, qy, 65, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
app->hEditQWaitAckBytes = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col3 + 70, qy - 2, 60, 18, hWnd, (HMENU)IDC_EDIT_Q_WAIT_ACK_BYTES, hInst, NULL); |
|
|
|
|
app->hEditQWaitAckPkts = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col3 + 135, qy - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_Q_WAIT_ACK_PKTS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
/* Queue metrics - row 2 */ |
|
|
|
|
qy += 28; |
|
|
|
|
CreateWindowExA(0, "STATIC", "AckQ:", |
|
|
|
|
WS_CHILD | WS_VISIBLE, q_col1, qy, 50, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
app->hEditQAckBytes = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 55, qy - 2, 60, 18, hWnd, (HMENU)IDC_EDIT_Q_ACK_BYTES, hInst, NULL); |
|
|
|
|
app->hEditQAckPkts = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 120, qy - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_Q_ACK_PKTS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
CreateWindowExA(0, "STATIC", "RecvQ:", |
|
|
|
|
WS_CHILD | WS_VISIBLE, q_col2, qy, 60, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
app->hEditQRecvBytes = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col2 + 65, qy - 2, 60, 18, hWnd, (HMENU)IDC_EDIT_Q_RECV_BYTES, hInst, NULL); |
|
|
|
|
app->hEditQRecvPkts = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col2 + 130, qy - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_Q_RECV_PKTS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
CreateWindowExA(0, "STATIC", "OutQ:", |
|
|
|
|
WS_CHILD | WS_VISIBLE, q_col3, qy, 50, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
app->hEditQOutBytes = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col3 + 55, qy - 2, 60, 18, hWnd, (HMENU)IDC_EDIT_Q_OUT_BYTES, hInst, NULL); |
|
|
|
|
app->hEditQOutPkts = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col3 + 120, qy - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_Q_OUT_PKTS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
/* Error counters - row 3 */ |
|
|
|
|
qy += 30; |
|
|
|
|
CreateWindowExA(0, "STATIC", "Errors:", |
|
|
|
|
WS_CHILD | WS_VISIBLE, q_col1, qy, 50, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
app->hEditErrReinit = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 55, qy - 2, 55, 18, hWnd, (HMENU)IDC_EDIT_ERR_REINIT, hInst, NULL); |
|
|
|
|
app->hEditErrReset = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 115, qy - 2, 55, 18, hWnd, (HMENU)IDC_EDIT_ERR_RESET, hInst, NULL); |
|
|
|
|
app->hEditErrPktFmt = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 175, qy - 2, 55, 18, hWnd, (HMENU)IDC_EDIT_ERR_PKT_FMT, hInst, NULL); |
|
|
|
|
|
|
|
|
|
/* Timer flags - same row, to the right */ |
|
|
|
|
CreateWindowExA(0, "STATIC", "Timers:", |
|
|
|
|
WS_CHILD | WS_VISIBLE, q_col2, qy, 50, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
app->hEditTimerRetrans = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col2 + 55, qy - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_TIMER_RETRANS, hInst, NULL); |
|
|
|
|
app->hEditTimerAckResp = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col2 + 110, qy - 2, 50, 18, hWnd, (HMENU)IDC_EDIT_TIMER_ACK_RESP, hInst, NULL); |
|
|
|
|
|
|
|
|
|
/* ID metrics - row 4 */ |
|
|
|
|
qy += 30; |
|
|
|
|
CreateWindowExA(0, "STATIC", "IDs:", |
|
|
|
|
WS_CHILD | WS_VISIBLE, q_col1, qy, 30, 16, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
app->hEditIdNextTx = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 35, qy - 2, 65, 18, hWnd, (HMENU)IDC_EDIT_ID_NEXT_TX, hInst, NULL); |
|
|
|
|
app->hEditIdLastRx = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 105, qy - 2, 65, 18, hWnd, (HMENU)IDC_EDIT_ID_LAST_RX, hInst, NULL); |
|
|
|
|
app->hEditIdLastDel = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 175, qy - 2, 65, 18, hWnd, (HMENU)IDC_EDIT_ID_LAST_DEL, hInst, NULL); |
|
|
|
|
app->hEditIdRxAckTill = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", |
|
|
|
|
WS_CHILD | WS_VISIBLE | ES_READONLY | ES_CENTER, |
|
|
|
|
q_col1 + 245, qy - 2, 65, 18, hWnd, (HMENU)IDC_EDIT_ID_RX_ACK_TILL, hInst, NULL); |
|
|
|
|
} |
|
|
|
|
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { |
|
|
|
|
struct etcpmon_app* app = NULL; |
|
|
|
|
@ -655,15 +764,47 @@ 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_READ_ERRS, "%u", metrics->tun.read_errors); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_TUN_WRITE_ERRS, "%u", metrics->tun.write_errors); |
|
|
|
|
|
|
|
|
|
/* Queue Metrics */ |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_IN_Q_BYTES, "%u", metrics->etcp.input_queue_bytes); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_IN_Q_PKTS, "%u", metrics->etcp.input_queue_packets); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_IN_SEND_BYTES, "%u", metrics->etcp.input_send_q_bytes); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_IN_SEND_PKTS, "%u", metrics->etcp.input_send_q_packets); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_WAIT_ACK_BYTES, "%u", metrics->etcp.input_wait_ack_bytes); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_WAIT_ACK_PKTS, "%u", metrics->etcp.input_wait_ack_packets); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_ACK_BYTES, "%u", metrics->etcp.ack_q_bytes); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_ACK_PKTS, "%u", metrics->etcp.ack_q_packets); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_RECV_BYTES, "%u", metrics->etcp.recv_q_bytes); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_RECV_PKTS, "%u", metrics->etcp.recv_q_packets); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_OUT_BYTES, "%u", metrics->etcp.output_queue_bytes); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_Q_OUT_PKTS, "%u", metrics->etcp.output_queue_packets); |
|
|
|
|
|
|
|
|
|
/* Error Counters */ |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_ERR_REINIT, "%u", metrics->etcp.reinit_count); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_ERR_RESET, "%u", metrics->etcp.reset_count); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_ERR_PKT_FMT, "%u", metrics->etcp.pkt_format_errors); |
|
|
|
|
|
|
|
|
|
/* Timer Flags */ |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_TIMER_RETRANS, "%s", metrics->etcp.retrans_timer_active ? "ON" : "OFF"); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_TIMER_ACK_RESP, "%s", metrics->etcp.ack_resp_timer_active ? "ON" : "OFF"); |
|
|
|
|
|
|
|
|
|
/* ID Metrics */ |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_ID_NEXT_TX, "%u", metrics->etcp.next_tx_id); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_ID_LAST_RX, "%u", metrics->etcp.last_rx_id); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_ID_LAST_DEL, "%u", metrics->etcp.last_delivered_id); |
|
|
|
|
UpdateEditIfChanged(hMain, IDC_EDIT_ID_RX_ACK_TILL, "%u", metrics->etcp.rx_ack_till); |
|
|
|
|
|
|
|
|
|
/* Links list */ |
|
|
|
|
if (app->hListLinks) { |
|
|
|
|
SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0); |
|
|
|
|
for (uint8_t i = 0; i < links_count; i++) { |
|
|
|
|
char display[256]; |
|
|
|
|
char display[380]; |
|
|
|
|
snprintf(display, sizeof(display), |
|
|
|
|
"Link %u: Status=%s, EncErrors=%u, DecErrors=%u, " |
|
|
|
|
"SendErr=%u, RecvErr=%u, BytesEnc=%llu, BytesDec=%llu, " |
|
|
|
|
"BW=%u Kbps, NATChg=%u, RTT=%u us, TT=%u us", |
|
|
|
|
"Link %u: Status=%s, EncErr=%u, DecErr=%u, " |
|
|
|
|
"SndErr=%u, RcvErr=%u, Enc=%llu, Dec=%llu, " |
|
|
|
|
"BW=%u Kbps, NAT=%u, RTT=%u us, TT=%u us, " |
|
|
|
|
"Timers: Init=%s, KA=%s, Shaper=%s, " |
|
|
|
|
"KAsent=%u, KArecv=%u", |
|
|
|
|
links[i].local_link_id, |
|
|
|
|
links[i].status ? "UP" : "DOWN", |
|
|
|
|
links[i].encrypt_errors, |
|
|
|
|
@ -675,7 +816,12 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app,
|
|
|
|
|
links[i].bandwidth, |
|
|
|
|
links[i].nat_changes_count, |
|
|
|
|
links[i].rtt_last * 100, |
|
|
|
|
links[i].tt_last * 100); |
|
|
|
|
links[i].tt_last * 100, |
|
|
|
|
links[i].init_timer_active ? "ON" : "OFF", |
|
|
|
|
links[i].keepalive_timer_active ? "ON" : "OFF", |
|
|
|
|
links[i].shaper_timer_active ? "ON" : "OFF", |
|
|
|
|
links[i].keepalive_sent, |
|
|
|
|
links[i].keepalive_recv); |
|
|
|
|
SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)display); |
|
|
|
|
} |
|
|
|
|
InvalidateRect(app->hListLinks, NULL, FALSE); |
|
|
|
|
@ -705,6 +851,31 @@ void etcpmon_gui_clear_metrics(struct etcpmon_app* app) {
|
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_TUN_READ_ERRS, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_TUN_WRITE_ERRS, ""); |
|
|
|
|
|
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_IN_Q_BYTES, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_IN_Q_PKTS, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_IN_SEND_BYTES, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_IN_SEND_PKTS, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_WAIT_ACK_BYTES, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_WAIT_ACK_PKTS, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_ACK_BYTES, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_ACK_PKTS, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_RECV_BYTES, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_RECV_PKTS, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_OUT_BYTES, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_Q_OUT_PKTS, ""); |
|
|
|
|
|
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ERR_REINIT, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ERR_RESET, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ERR_PKT_FMT, ""); |
|
|
|
|
|
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_TIMER_RETRANS, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_TIMER_ACK_RESP, ""); |
|
|
|
|
|
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ID_NEXT_TX, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ID_LAST_RX, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ID_LAST_DEL, ""); |
|
|
|
|
SetDlgItemTextA(app->hWndMain, IDC_EDIT_ID_RX_ACK_TILL, ""); |
|
|
|
|
|
|
|
|
|
if (app->hListLinks) { |
|
|
|
|
SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0); |
|
|
|
|
} |
|
|
|
|
|