OCT 1. 修正DHCP Tools切换数据包窗口时异常问题

2. DHCP Tools 数据包窗口Tab切换时自动更新页面
3. 增加数据包超时重传
4. 增加数据包发送、接收时间戳
This commit is contained in:
黄昕 2023-05-05 15:25:25 +08:00
parent d91e80acb3
commit 99e1ec5cf9
6 changed files with 199 additions and 123 deletions

View File

@ -3,6 +3,7 @@
//
#include <ctype.h>
#include "main.h"
#include "misc.h"
#include "zlog_module.h"
#include "dhcp_network.h"
#include "sds/sds.h"
@ -76,11 +77,11 @@ typedef struct {
U8 op_value[256];
} STR_OPT;
static char* g_mess_info[] = { "NONE", "DISCOVER", "OFFER", "REQUEST", "DECLINE", "ACK", "NAK", "RELEASE", "INFORM"};
static char *g_mess_info[] = {"NONE", "DISCOVER", "OFFER", "REQUEST", "DECLINE", "ACK", "NAK", "RELEASE", "INFORM"};
static GtkTextBuffer *g_pTxtBuf[4];
static GtkWidget *g_ptvDHcp[4];
static GtkWidget *g_ptvHex[4];
static GtkTextBuffer *g_pTxtBuf[4];
static GtkWidget *g_ptvDHcp[4];
static GtkWidget *g_ptvHex[4];
static gboolean delete_event(GtkWidget *widget, GdkEventAny *event) {
/* 如果你的 "delete_event" 信号处理函数返回 FALSEGTK 会发出 "destroy" 信号。
@ -92,13 +93,17 @@ static gboolean delete_event(GtkWidget *widget, GdkEventAny *event) {
}
static void add_dhcp_tree_colums(GtkWidget *treeView) {
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes("协议", renderer, "text", 0, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column);
GList *cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(treeView));
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 1, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column);
if (g_list_length(cols) == 0) {
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes("协议", renderer, "text", 0, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column);
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 1, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), column);
}
}
#define ADD_SUB_STRING(name, s) \
@ -116,76 +121,93 @@ static void add_dhcp_tree_colums(GtkWidget *treeView) {
sdsfree(s); \
} while (0)
#define ADD_SUB_OPTION(code, len, val) \
do { \
int count_flag = 0; \
char *p; \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
s = sdsempty(); \
sprintf(s, "%u", (len)); \
gtk_tree_store_set(store, &iterOpt, 0, "Length", 1, s, -1); \
sdsfree(s); \
\
switch(dhcp_get_opType(code)) { \
case 1: \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, (val), -1);\
break; \
case 2: \
do { \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
s = sdsempty(); \
sprintf(s, "(%u) %s", (val)[count_flag], dhcp_get_opName((val)[count_flag]));\
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, s, -1);\
sdsfree(s); \
count_flag++; \
} while(count_flag != (len)); \
break; \
case 3: \
do { \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
s = sdsempty(); \
sprintf(s, "%u.%u.%u.%u", (val)[count_flag], (val)[count_flag+1], (val)[count_flag+2], (val)[count_flag+3]);\
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, s, -1); \
sdsfree(s); \
count_flag += 4; \
} while(count_flag != (len)); \
break; \
case 4: \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
for(int i = 0; i<(len); i++) \
count_flag = count_flag*256 + (val)[i]; \
s = sdsempty(); \
sprintf(s, "%d(s)", count_flag); \
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, s, -1); \
sdsfree(s); \
break; \
case 6: \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
s = sdsempty(); \
if((code) == OPT_MESSAGETYPE) { \
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, g_mess_info[(val)[0]], -1);\
} \
sdsfree(s); \
break; \
default: \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, "", -1);\
} \
#define ADD_SUB_OPTION(code, len, val) \
do { \
U8 *pVal; \
int count_flag = 0; \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
s = sdsempty(); \
sprintf(s, "%u", (len)); \
gtk_tree_store_set(store, &iterOpt, 0, "Length", 1, s, -1); \
sdsfree(s); \
\
switch (dhcp_get_opType(code)) { \
case 1: \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, (val), -1); \
break; \
case 2: \
pVal = val; \
do { \
sds sv = sdsempty(); \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
s = sdsempty(); \
sprintf(s, "%s", dhcp_get_opName(*pVal)); \
sprintf(sv, "Request (%03d)", *pVal); \
gtk_tree_store_set(store, &iterOpt, 0, sv, 1, s, -1); \
sdsfree(s); \
sdsfree(sv); \
count_flag++; \
pVal++; \
} while (count_flag != (len)); \
break; \
case 3: \
do { \
U32 *pIp = (U32 *)(val); \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
s = sdsempty(); \
sprintf(s, "%s", u32_to_str_ip(*pIp)); \
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, s, -1); \
sdsfree(s); \
count_flag += 4; \
} while (count_flag != (len)); \
break; \
case 4: \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
for (int i = 0; i < (len); i++) \
count_flag = count_flag * 256 + (val)[i]; \
s = sdsempty(); \
sprintf(s, "%d(s)", count_flag); \
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, s, -1); \
sdsfree(s); \
break; \
case 6: \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
s = sdsempty(); \
if ((code) == OPT_MESSAGETYPE) { \
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, g_mess_info[(val)[0]], -1); \
} \
sdsfree(s); \
break; \
default: \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
gtk_tree_store_set(store, &iterOpt, 0, dhcp_get_opName(code), 1, "", -1); \
} \
} while (0)
static void create_dhcp_tree_mode(PDHCP_PACKAGE p, GtkWidget *treeView) {
static void create_dhcp_tree_mode(PDHCP_PACKAGE p, U32 nBytes, GtkWidget *treeView) {
// 填充右上侧 TreeView 协议数据
sds s;
GtkTreeIter iter, iterSub, iterOpt;
GtkTreeStore *store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
GtkTreeStore *store = NULL; //gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
const char *itemTitle[] = {"Ethernet II", "802.1Q Virtual LAN", "IP Version 4", "UDP", "DHCP"};
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeView));
//GtkTreeStore *store = GTK_TREE_STORE();
if (model) {
store = GTK_TREE_STORE(model);
if (gtk_tree_model_get_iter_first(model, &iter)) {
gtk_tree_store_clear(store);
}
} else {
store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
gtk_tree_view_set_model(GTK_TREE_VIEW(treeView), GTK_TREE_MODEL(store));
}
gtk_tree_store_append(store, &iter, NULL);
gtk_tree_store_set(store, &iter, 0, itemTitle[0], 1, "", -1);
// 添加 Ethernet II 头相关内容
s = sdsempty();
MAC_TO_STR(p->hdr.eth.h_dest, s);
ADD_SUB_STRING("Destination", s);
@ -210,7 +232,7 @@ static void create_dhcp_tree_mode(PDHCP_PACKAGE p, GtkWidget *treeView) {
ADD_SUB_INT("Version", "%u", p->hdr.ip.version);
s = sdsempty();
sprintf(s, "%u %s (%u)", p->hdr.ip.ihl*4, "bytes", p->hdr.ip.ihl);
sprintf(s, "%u %s (%u)", p->hdr.ip.ihl * 4, "bytes", p->hdr.ip.ihl);
ADD_SUB_STRING("Header Length", s);
sdsfree(s);
@ -221,8 +243,8 @@ static void create_dhcp_tree_mode(PDHCP_PACKAGE p, GtkWidget *treeView) {
ADD_SUB_INT("Time to live", "%u", p->hdr.ip.ttl);
ADD_SUB_STRING("Protocol", "UDP");
ADD_SUB_INT("Header Checksum", "0x%04X", ntohs(p->hdr.ip.check));
ADD_SUB_STRING("Source", inet_ntoa(*(struct in_addr*)&p->hdr.ip.saddr));
ADD_SUB_STRING("Destination", inet_ntoa(*(struct in_addr*)&p->hdr.ip.daddr));
ADD_SUB_STRING("Source", inet_ntoa(*(struct in_addr *)&p->hdr.ip.saddr));
ADD_SUB_STRING("Destination", inet_ntoa(*(struct in_addr *)&p->hdr.ip.daddr));
// 添加 UDP 头
gtk_tree_store_append(store, &iter, NULL);
@ -235,7 +257,7 @@ static void create_dhcp_tree_mode(PDHCP_PACKAGE p, GtkWidget *treeView) {
// 添加 DHCP 内容
gtk_tree_store_append(store, &iter, NULL);
gtk_tree_store_set(store, &iter, 0, itemTitle[4], 1, "", -1);
switch(p->dhcp.op) {
switch (p->dhcp.op) {
case 1:
ADD_SUB_STRING("Message Type", "Boot Request");
break;
@ -245,7 +267,7 @@ static void create_dhcp_tree_mode(PDHCP_PACKAGE p, GtkWidget *treeView) {
default:
ADD_SUB_STRING("Message Type", "Unknown");
}
switch(p->dhcp.htype) {
switch (p->dhcp.htype) {
case 1:
ADD_SUB_STRING("Hardware Type", "Ethernet");
break;
@ -257,67 +279,84 @@ static void create_dhcp_tree_mode(PDHCP_PACKAGE p, GtkWidget *treeView) {
ADD_SUB_INT("Transaction ID", "0x%08X", p->dhcp.xid);
ADD_SUB_INT("Seconds elapsed", "%u", p->dhcp.secs);
ADD_SUB_INT("Bootp flags", "0x%04X", p->dhcp.flags);
ADD_SUB_STRING("Client IP address", inet_ntoa(*(struct in_addr*)&p->dhcp.ciaddr));
ADD_SUB_STRING("Your(client) IP address", inet_ntoa(*(struct in_addr*)&p->dhcp.yiaddr));
ADD_SUB_STRING("Next server IP address", inet_ntoa(*(struct in_addr*)&p->dhcp.siaddr));
ADD_SUB_STRING("Relay agent IP address", inet_ntoa(*(struct in_addr*)&p->dhcp.giaddr));
ADD_SUB_STRING("Client IP address", inet_ntoa(*(struct in_addr *)&p->dhcp.ciaddr));
ADD_SUB_STRING("Your(client) IP address", inet_ntoa(*(struct in_addr *)&p->dhcp.yiaddr));
ADD_SUB_STRING("Next server IP address", inet_ntoa(*(struct in_addr *)&p->dhcp.siaddr));
ADD_SUB_STRING("Relay agent IP address", inet_ntoa(*(struct in_addr *)&p->dhcp.giaddr));
s = sdsempty();
MAC_TO_STR(p->dhcp.chaddr, s);
ADD_SUB_STRING("Destination", s);
sdsfree(s);
if(strlen(p->dhcp.sname) != 0)
if (strlen((char *)p->dhcp.sname) != 0) {
ADD_SUB_STRING("Server host name", p->dhcp.sname);
else
} else {
ADD_SUB_STRING("Server host name", "not given");
}
if(strlen(p->dhcp.file) != 0)
if (strlen((char *)p->dhcp.file) != 0) {
ADD_SUB_STRING("Boot file name", p->dhcp.file);
else
} else {
ADD_SUB_STRING("Boot file name", "not given");
}
ADD_SUB_STRING("Magic cookie", "DHCP");
U8 *opPointer;
U8 *opPointer, *optEnd = (U8 *)p + nBytes;
opPointer = p->dhcp.options;
while (*opPointer && *opPointer != OPT_END) {
STR_OPT opTmp;
opTmp.op_code = *opPointer;
opPointer++;
opTmp.op_size = *opPointer;
opPointer++;
memcpy(opTmp.op_value, opPointer, opTmp.op_size);
opPointer += opTmp.op_size;
while (*opPointer && opPointer < optEnd) {
if (*opPointer == OPT_END) {
ADD_SUB_STRING("Option(255)", "End");
opPointer++;
} else {
STR_OPT opTmp;
sds st = sdsempty();
opTmp.op_code = *opPointer;
opPointer++;
opTmp.op_size = *opPointer;
opPointer++;
memcpy(opTmp.op_value, opPointer, opTmp.op_size);
opPointer += opTmp.op_size;
s = sdsempty();
sprintf(s, "(%u) %s", opTmp.op_code, dhcp_get_opName(opTmp.op_code));
ADD_SUB_STRING("Option", s);
sdsfree(s);
s = sdsempty();
//sprintf(s, "(%u) %s", opTmp.op_code, dhcp_get_opName(opTmp.op_code));
sprintf(st, "Option(%u)", opTmp.op_code);
ADD_SUB_STRING(st, dhcp_get_opName(opTmp.op_code));
sdsfree(s);
sdsfree(st);
ADD_SUB_OPTION(opTmp.op_code, opTmp.op_size, opTmp.op_value);
ADD_SUB_OPTION(opTmp.op_code, opTmp.op_size, opTmp.op_value);
}
}
if(*opPointer == OPT_END) {
ADD_SUB_STRING("Option", "(255) End");
}
gtk_tree_view_set_model(GTK_TREE_VIEW(treeView), GTK_TREE_MODEL(store));
g_object_unref(GTK_TREE_MODEL(store));
}
static PDHCP_INFO g_preInfo = NULL;
void details_wnd_show(PDHCP_INFO pInfo) {
PBUF_INFO hexBuf[4];
int i;
PBUF_INFO hexBuf[4];
GtkTextIter iter, iter1;
if (pInfo) {
if (pInfo != g_preInfo) {
g_preInfo = pInfo;
for (i = 0; i < 4; i++) {
gtk_text_buffer_get_start_iter(g_pTxtBuf[i], &iter);
gtk_text_buffer_get_end_iter(g_pTxtBuf[i], &iter1);
gtk_text_buffer_delete(g_pTxtBuf[i], &iter, &iter1);
}
}
hexBuf[0] = &pInfo->pDiscBuf;
hexBuf[1] = &pInfo->pOfferBuf;
hexBuf[2] = &pInfo->pReqBuf;
hexBuf[3] = &pInfo->pAckBuf;
// 填充HEX 窗口数据
for (int i = 0; i < 4; i++) {
char buf[128] = {0};
U32 offset = 0;
GtkTextIter iter, iter1;
for (i = 0; i < 4; i++) {
char buf[128] = {0};
U32 offset = 0;
if (hexBuf[i]->buf_size == 0) {
continue;
@ -367,7 +406,7 @@ void details_wnd_show(PDHCP_INFO pInfo) {
// 填充 TreeView
add_dhcp_tree_colums(g_ptvDHcp[i]);
create_dhcp_tree_mode((PDHCP_PACKAGE)hexBuf[i]->p, g_ptvDHcp[i]);
create_dhcp_tree_mode((PDHCP_PACKAGE)hexBuf[i]->p, hexBuf[i]->buf_size, g_ptvDHcp[i]);
}
}
@ -394,6 +433,15 @@ static gboolean button_release_event(GtkWidget *self, GdkEventButton event, gpoi
return FALSE;
}
void switch_page(GtkNotebook *UNUSED(self),
GtkWidget *UNUSED(page),
guint UNUSED(page_num),
gpointer UNUSED(user_data)) {
if (g_preInfo) {
details_wnd_show(g_preInfo);
}
}
void details_wnd_create(GtkBuilder *builder) {
// 创建主窗口
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@ -407,6 +455,7 @@ void details_wnd_create(GtkBuilder *builder) {
// 页标签的位置,可以有四种位置:上、下、左或右。
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
g_signal_connect(notebook, "switch-page", G_CALLBACK(switch_page), NULL);
for (int i = 0; i < 4; i++) {
GtkTreeIter iter;

View File

@ -51,9 +51,10 @@ typedef enum {
} DHCP_STATUS;
typedef struct {
U8 *p;
int buf_size;
unsigned int tm;
U8 *p;
int buf_size;
struct timeval tm;
U32 snd;
} BUF_INFO, *PBUF_INFO;
typedef struct {

View File

@ -2,6 +2,7 @@
// Created by xajhuang on 2023/4/12.
//
#include <zlog.h>
#include <sys/time.h>
#include "main.h"
#include "misc.h"
#include "task_manager.h"
@ -9,10 +10,12 @@
#include "zlog_module.h"
#include "dhcp_network.h"
#define MAIN_WND_WIDTH (1024)
#define MAIN_WND_HEIGHT (768)
#define DHCP_STEP_TIMEOUT (30)
#define ZLOG_CFG_PATH "./config/zlog.conf"
#define MAIN_WND_WIDTH (1024)
#define MAIN_WND_HEIGHT (768)
#define ZLOG_CFG_PATH "./config/zlog.conf"
static GtkBuilder *g_mainBuilder = NULL;
static PDHCP_INFO g_pDhcpInfo = NULL;
@ -342,9 +345,10 @@ int cacheDhcpAckBuffer(PDHCP_INFO pInfo, U8 *pBuf, int size) {
}
_Noreturn static void *dhcpThreadCb(void *UNUSED(pData)) {
U8 *pkg;
int size = 0;
PDHCP_INFO pInfo, pTemp;
U8 *pkg;
int size = 0;
PDHCP_INFO pInfo, pTemp;
struct timeval now;
while (TRUE) {
if (!g_runTask) {
@ -361,7 +365,6 @@ _Noreturn static void *dhcpThreadCb(void *UNUSED(pData)) {
pInfo->pDiscBuf.buf_size = size;
pInfo->step = STEP_DISCOVER;
pInfo->status = STA_WAIT_START;
pInfo->pDiscBuf.tm = time(NULL);
g_idle_add(tree_view_data_store_upgade, pInfo);
}
break;
@ -374,9 +377,19 @@ _Noreturn static void *dhcpThreadCb(void *UNUSED(pData)) {
if (pkg_mmap_tx((U8 *)pkg, pInfo->pDiscBuf.buf_size) == pInfo->pDiscBuf.buf_size) {
pInfo->status = STA_SEND_REQ;
gettimeofday(&pInfo->pDiscBuf.tm, NULL);
pInfo->pDiscBuf.snd += 1;
g_idle_add(tree_view_data_store_upgade, pInfo);
}
}
} else if (pInfo->status == STA_SEND_REQ) {
// 处理超时
gettimeofday(&now, NULL);
if (now.tv_sec - pInfo->pDiscBuf.tm.tv_sec > DHCP_STEP_TIMEOUT) {
// 超时重传
pInfo->status = STA_WAIT_START;
}
}
break;
case STEP_OFFER:
@ -387,7 +400,6 @@ _Noreturn static void *dhcpThreadCb(void *UNUSED(pData)) {
pInfo->pReqBuf.buf_size = size;
pInfo->step = STEP_REQUEST;
pInfo->status = STA_WAIT_START;
pInfo->pReqBuf.tm = time(NULL);
g_idle_add(tree_view_data_store_upgade, pInfo);
}
}
@ -401,9 +413,19 @@ _Noreturn static void *dhcpThreadCb(void *UNUSED(pData)) {
if (pkg_mmap_tx((U8 *)pkg, pInfo->pReqBuf.buf_size) == pInfo->pReqBuf.buf_size) {
pInfo->status = STA_SEND_REQ;
gettimeofday(&pInfo->pReqBuf.tm, NULL);
pInfo->pReqBuf.snd = 1;
g_idle_add(tree_view_data_store_upgade, pInfo);
}
}
} else if (pInfo->status == STA_SEND_REQ) {
// 处理超时
gettimeofday(&now, NULL);
if (now.tv_sec - pInfo->pReqBuf.tm.tv_sec > DHCP_STEP_TIMEOUT) {
// 超时重传
pInfo->status = STA_WAIT_START;
}
}
break;
case STEP_ACK:

View File

@ -3,6 +3,7 @@
//
#include <uv.h>
#include <string.h>
#include <sys/time.h>
#include "user_errno.h"
#include "dhcp_network.h"
#include "dhcp_options.h"
@ -236,7 +237,8 @@ static void on_dhcp_recv(uv_work_t *req) {
cacheDhcpOfferBuffer(pInfo, pWork->pPkgBase, pWork->nSize);
memcpy(&pInfo->offerRsp, &rspDhcp, sizeof(DHCP_RSP));
pInfo->pOfferBuf.tm = time(NULL);
gettimeofday(&pInfo->pOfferBuf.tm, NULL);
break;
case DHCP_MSG_ACK:
pInfo->step = STEP_ACK;
@ -244,7 +246,7 @@ static void on_dhcp_recv(uv_work_t *req) {
cacheDhcpAckBuffer(pInfo, pWork->pPkgBase, pWork->nSize);
memcpy(&pInfo->ackRsp, &rspDhcp, sizeof(DHCP_RSP));
pInfo->pAckBuf.tm = time(NULL);
gettimeofday(&pInfo->pAckBuf.tm, NULL);
break;
case DHCP_MSG_NAK:
break;

View File

@ -208,7 +208,7 @@ const char* dhcp_get_opName(int opt) {
return g_opCfg[i].opName;
}
return NULL;
return "Unknown";
}
int dhcp_get_opType(int opt) {

View File

@ -4,6 +4,7 @@
#include <time.h>
#include "lease.h"
#include "misc.h"
#include "user_errno.h"
#include "zlog_module.h"
#include "dhcp_network.h"
@ -33,6 +34,7 @@ int usr_lease_lock_ip(PDHCP_USER pUser, U32 ip) {
memset(pLock, 0, sizeof(LOCK_IP));
pLock->ip = ip;
HASH_ADD_INT(pUser->plockIp, ip, pLock);
LOG_MOD(trace, ZM_DHCP_LEASE, "User %u lock ip %s\n", pUser->uid, u32_to_str_ip(ip));
return ERR_SUCCESS;
}