vcpe/dhcp_tools/detail_wnd.c

490 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Created by HuangXin on 2023/4/26.
//
#include <ctype.h>
#include "main.h"
#include "zlog_module.h"
#include "dhcp_network.h"
#include "sds/sds.h"
#include "dhcp_options.h"
static GtkWidget *g_detailWnd = NULL;
#if 0
static void dhcp_details_store_create(GtkBuilder *builder) {
int i, j;
PDHCP_INFO pInfo, pTemp;
GtkTreeIter iter, iter_child;
GtkWidget *view = GTK_WIDGET(gtk_builder_get_object(builder, "tvDiscDhcp"));
GtkTreeStore *store = GTK_TREE_STORE(gtk_builder_get_object(builder, "lsDhcpInfo"));
gtk_tree_view_set_model(GTK_TREE_VIEW(view), NULL);
gtk_tree_store_clear(store);
// 创建根节点
gtk_tree_store_append(store, &iter, NULL);
// clang-format off
gtk_tree_store_set(store,
&iter,
COL_DHCP_ITEM, "name",
COL_DHCP_VALUE, "",
COL_ITEM_ATTR_VISIABLE, TRUE,
COL_VALUE_ATTR_VISIABLE, FALSE,
-1);
// clang-format on
gtk_tree_store_append(store, &iter_child, &iter);
// clang-format off
// 创建子节点
gtk_tree_store_set(store,
&iter_child,
COL_DHCP_VALUE, "",
COL_ITEM_ATTR_VISIABLE, FALSE,
COL_VALUE_ATTR_VISIABLE, TRUE,
-1);
// clang-format on
gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
}
void details_wnd_create(void *b) {
GtkBuilder *builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "./res/detail.glade", NULL);
GtkWidget *deatilWnd = GTK_WIDGET(gtk_builder_get_object(builder, "wndDetails"));
GtkWidget *panDisc = GTK_WIDGET(gtk_builder_get_object(builder, "hbDisc"));
GtkWidget *tab = GTK_WIDGET(gtk_builder_get_object(builder, "nbDetails"));
GtkWidget *labDisc = GTK_WIDGET(gtk_builder_get_object(builder, "labDiscover"));
GtkWidget *labAck = GTK_WIDGET(gtk_builder_get_object(builder, "labAck"));
GtkWidget *scAck = GTK_WIDGET(gtk_builder_get_object(builder, "scAck"));
gtk_container_add(GTK_CONTAINER(deatilWnd), tab); // 笔记本放进窗口
gtk_notebook_append_page(GTK_NOTEBOOK(tab), panDisc, labDisc);
gtk_notebook_append_page(GTK_NOTEBOOK(tab), scAck, labAck);
g_signal_connect(G_OBJECT(deatilWnd), "delete_event", G_CALLBACK(delete_event), builder);
g_signal_connect(G_OBJECT(deatilWnd), "show", G_CALLBACK(show), builder);
gtk_builder_connect_signals(builder, NULL);
//gtk_widget_show(deatilWnd);
}
#endif
typedef struct {
U8 op_code;
U8 op_size;
U8 op_value[256];
} STR_OPT;
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 gboolean delete_event(GtkWidget *widget, GdkEventAny *event) {
/* 如果你的 "delete_event" 信号处理函数返回 FALSEGTK 会发出 "destroy" 信号。
* 返回 TRUE你不希望关闭窗口。
* 当你想弹出“你确定要退出吗?”对话框时它很有用。*/
//gtk_widget_hide_all(window_test);
gtk_widget_hide(widget);
return TRUE; //注意必须为TRUE否则子窗口点击关闭按钮后就摧毁了而不是隐藏了。
}
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);
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) \
do { \
gtk_tree_store_append(store, &iterSub, &iter); \
gtk_tree_store_set(store, &iterSub, 0, (name), 1, (s), -1); \
} while (0)
#define ADD_SUB_INT(name, fmt, v) \
do { \
gtk_tree_store_append(store, &iterSub, &iter); \
s = sdsempty(); \
sprintf(s, (fmt), (v)); \
gtk_tree_store_set(store, &iterSub, 0, (name), 1, s, -1); \
sdsfree(s); \
} while (0)
#define ADD_SUB_OPTION(code, len, val) \
do { \
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: \
do { \
gtk_tree_store_append(store, &iterOpt, &iterSub); \
s = sdsempty(); \
t = sdsempty(); \
sprintf(s, "(%u) %s", (val)[count_flag], dhcp_get_opName((val)[count_flag])); \
sprintf(t, "%s Item", dhcp_get_opName(code)); \
gtk_tree_store_set(store, &iterOpt, 0, t, 1, s, -1);\
sdsfree(s); \
sdsfree(t); \
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);\
} \
} while (0)
static void create_dhcp_tree_mode(PDHCP_PACKAGE p, GtkWidget *treeView) {
// 填充右上侧 TreeView 协议数据
sds s, t;
GtkTreeIter iter, iterSub, iterOpt;
GtkTreeStore *store = 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"};
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->vlan_hdr.eth.h_dest, s);
ADD_SUB_STRING("Destination", s);
sdsfree(s);
s = sdsempty();
MAC_TO_STR(p->vlan_hdr.eth.h_source, s);
ADD_SUB_STRING("Source", s);
sdsfree(s);
// 添加 VLan 头相关内容
gtk_tree_store_append(store, &iter, NULL);
gtk_tree_store_set(store, &iter, 0, itemTitle[1], 1, "", -1);
ADD_SUB_INT("ID", "%u", VLAN_VNI_ID(p->vlan_hdr.vlan.id));
ADD_SUB_INT("Type", "0x%04X", ntohs(p->vlan_hdr.vlan.type));
// 添加 IP 头
gtk_tree_store_append(store, &iter, NULL);
gtk_tree_store_set(store, &iter, 0, itemTitle[2], 1, "", -1);
ADD_SUB_INT("Version", "%u", p->vlan_hdr.ip.version);
s = sdsempty();
sprintf(s, "%u %s (%u)", p->vlan_hdr.ip.ihl*4, "bytes", p->vlan_hdr.ip.ihl);
ADD_SUB_STRING("Header Length", s);
sdsfree(s);
ADD_SUB_INT("Differentiated Services Field", "0x%02X", p->vlan_hdr.ip.tos);
ADD_SUB_INT("Total Length", "%u", ntohs(p->vlan_hdr.ip.tot_len));
ADD_SUB_INT("Identification", "0x%04X", ntohs(p->vlan_hdr.ip.id));
ADD_SUB_INT("Flags", "0x%04X", ntohs(p->vlan_hdr.ip.frag_off));
ADD_SUB_INT("Time to live", "%u", p->vlan_hdr.ip.ttl);
ADD_SUB_STRING("Protocol", "UDP");
ADD_SUB_INT("Header Checksum", "0x%04X", ntohs(p->vlan_hdr.ip.check));
ADD_SUB_STRING("Source", inet_ntoa(*(struct in_addr*)&p->vlan_hdr.ip.saddr));
ADD_SUB_STRING("Destination", inet_ntoa(*(struct in_addr*)&p->vlan_hdr.ip.daddr));
// 添加 UDP 头
gtk_tree_store_append(store, &iter, NULL);
gtk_tree_store_set(store, &iter, 0, itemTitle[3], 1, "", -1);
ADD_SUB_INT("Source Port", "%u", ntohs(p->vlan_hdr.udp.source));
ADD_SUB_INT("Destination Port", "%u", ntohs(p->vlan_hdr.udp.dest));
ADD_SUB_INT("Length", "%u", ntohs(p->vlan_hdr.udp.len));
ADD_SUB_INT("Checksum", "0x%04X", ntohs(p->vlan_hdr.udp.check));
// 添加 DHCP 内容
gtk_tree_store_append(store, &iter, NULL);
gtk_tree_store_set(store, &iter, 0, itemTitle[4], 1, "", -1);
switch(p->dhcp.op) {
case 1:
ADD_SUB_STRING("Message Type", "Boot Request");
break;
case 2:
ADD_SUB_STRING("Message Type", "Boot Reply");
break;
default:
ADD_SUB_STRING("Message Type", "Unknown");
}
switch(p->dhcp.htype) {
case 1:
ADD_SUB_STRING("Hardware Type", "Ethernet");
break;
default:
ADD_SUB_STRING("Hardware Type", "Unknown");
}
ADD_SUB_INT("Hardware address length", "%u", p->dhcp.hlen);
ADD_SUB_INT("Hops", "%u", p->dhcp.hops);
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));
s = sdsempty();
MAC_TO_STR(p->dhcp.chaddr, s);
ADD_SUB_STRING("Client MAC address", s);
sdsfree(s);
if(p->dhcp.sname[0] != '\0')
ADD_SUB_STRING("Server host name", p->dhcp.sname);
else
ADD_SUB_STRING("Server host name", "not given");
if(p->dhcp.file[0] != '\0')
ADD_SUB_STRING("Boot file name", p->dhcp.file);
else
ADD_SUB_STRING("Boot file name", "not given");
ADD_SUB_STRING("Magic cookie", "DHCP");
U8 *opPointer;
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;
s = sdsempty();
sprintf(s, "(%u) %s", opTmp.op_code, dhcp_get_opName(opTmp.op_code));
ADD_SUB_STRING("Option", s);
sdsfree(s);
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));
}
void details_wnd_show(PDHCP_INFO pInfo) {
PBUF_INFO hexBuf[4];
if (pInfo) {
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;
if (hexBuf[i]->buf_size == 0) {
continue;
}
gtk_text_buffer_get_start_iter(g_pTxtBuf[i], &iter);
gtk_text_buffer_get_end_iter(g_pTxtBuf[i], &iter1);
if (strlen(gtk_text_buffer_get_text(g_pTxtBuf[i], &iter, &iter1, TRUE)) > 0) {
continue;
}
gtk_text_buffer_get_iter_at_offset(g_pTxtBuf[i], &iter, 0);
sprintf(buf, " Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII Tables\n");
gtk_text_buffer_insert_with_tags_by_name(g_pTxtBuf[i], &iter, buf, -1, "hex_head", NULL);
int row = hexBuf[i]->buf_size / 16 + ((hexBuf[i]->buf_size % 16) > 0 ? 1 : 0);
for (int k = 0; k < row; k++) {
char bufOffset[24] = {0};
memset(buf, 0, 128);
sprintf(bufOffset, " %08X ", offset);
gtk_text_buffer_insert_with_tags_by_name(g_pTxtBuf[i], &iter, bufOffset, -1, "hex_offset", NULL);
for (int m = 0; m < 16; m++) {
char bufStr[4] = {0};
sprintf(bufStr, "%02X ", hexBuf[i]->p[k * 16 + m]);
strcat(buf, bufStr);
if (m == 7 || m == 15) {
strcat(buf, " ");
}
}
for (int m = 0; m < 16; m++) {
if (isprint(hexBuf[i]->p[k * 16 + m])) {
char bufStr[2] = {0};
bufStr[0] = (char)hexBuf[i]->p[k * 16 + m];
strcat(buf, bufStr);
} else {
strcat(buf, ".");
}
}
strcat(buf, "\n");
gtk_text_buffer_insert_with_tags_by_name(g_pTxtBuf[i], &iter, buf, -1, "bold", NULL);
offset += 16;
}
// 填充 TreeView
add_dhcp_tree_colums(g_ptvDHcp[i]);
create_dhcp_tree_mode((PDHCP_PACKAGE)hexBuf[i]->p, g_ptvDHcp[i]);
}
}
gtk_widget_show_all(g_detailWnd);
}
static gboolean button_release_event(GtkWidget *self, GdkEventButton event, gpointer user_data) {
GtkTextIter iter, start_sel, end_sel;
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(self));
gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer));
int row = gtk_text_iter_get_line(&iter);
int col = gtk_text_iter_get_line_offset(&iter);
if (col <= 57 && col >= 11) {
if ((col <= 35 && ((col - 11) % 3) == 0) || (col > 35 && (col - 12) % 3 == 0)) {
GtkTextMark *mark = gtk_text_buffer_get_insert(buffer);
gtk_text_buffer_get_iter_at_mark(buffer, &start_sel, mark);
gtk_text_buffer_get_iter_at_line_offset(buffer, &end_sel, row, 59);
char *text = (char *)gtk_text_buffer_get_text(buffer, &iter, &end_sel, FALSE);
//printf("Select %s(%d, %d)\n", text, row, col);
}
}
return FALSE;
}
void details_wnd_create(GtkBuilder *builder) {
// 创建主窗口
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//设置窗口大小
gtk_widget_set_size_request(window, 900, 600);
// 创建笔记本控件
GtkWidget *notebook = gtk_notebook_new();
// 笔记本放进窗口
gtk_container_add(GTK_CONTAINER(window), notebook);
// 页标签的位置,可以有四种位置:上、下、左或右。
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
for (int i = 0; i < 4; i++) {
GtkTreeIter iter;
const char *pTabName[] = {"Discover", "Offer", "Request", "Ack"};
// 第一个页面
GtkWidget *label = gtk_label_new(pTabName[i]);
// 水平分割面板
GtkWidget *boxTab = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3);
// 左侧 Hex 窗口
GtkWidget *scHex = gtk_scrolled_window_new(NULL, NULL);
GtkWidget *scText = gtk_text_view_new();
gtk_container_add(GTK_CONTAINER(scHex), scText);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scHex), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
// 分隔条
GtkWidget *vSepar = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
// 右侧 详细信息窗口
GtkWidget *scMsg = gtk_scrolled_window_new(NULL, NULL);
// 上下分割面板
GtkWidget *vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
gtk_container_add(GTK_CONTAINER(scMsg), vpaned);
// 上半部分控件
GtkWidget *tvDhcp = gtk_tree_view_new();
gtk_tree_view_set_grid_lines(GTK_TREE_VIEW(tvDhcp), GTK_TREE_VIEW_GRID_LINES_BOTH);
gtk_paned_pack1(GTK_PANED(vpaned), tvDhcp, TRUE, FALSE);
gtk_widget_set_size_request(tvDhcp, -1, 300);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scMsg), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
// 下半部分控件
GtkWidget *tvHex = gtk_tree_view_new();
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(tvHex), column);
g_object_set(column, "min-width", 120, NULL);
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(tvHex), column);
GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
const char *itemTitle[] = {"Binary", "unsigne char", "unsigne short", "unsigne int", "unsigne char long long",
"char", "short", "int", "long long"};
for (int k = 0; k < ARRAY_SIZE(itemTitle); k++) {
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, itemTitle[k], 1, "", -1);
}
gtk_tree_view_set_model(GTK_TREE_VIEW(tvHex), GTK_TREE_MODEL(store));
gtk_tree_view_set_grid_lines(GTK_TREE_VIEW(tvHex), GTK_TREE_VIEW_GRID_LINES_BOTH);
gtk_paned_pack2(GTK_PANED(vpaned), tvHex, FALSE, FALSE);
// 控件布局
gtk_box_pack_start(GTK_BOX(boxTab), scHex, TRUE, TRUE, 1);
gtk_box_pack_start(GTK_BOX(boxTab), vSepar, FALSE, FALSE, 1);
gtk_box_pack_start(GTK_BOX(boxTab), scMsg, TRUE, TRUE, 1);
gtk_widget_set_size_request(scHex, 580, -1);
gtk_widget_set_size_request(tvDhcp, 300, -1);
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), boxTab, label);
g_pTxtBuf[i] = gtk_text_view_get_buffer(GTK_TEXT_VIEW(scText));
gtk_text_view_set_editable(GTK_TEXT_VIEW(scText), FALSE);
gtk_text_view_set_monospace(GTK_TEXT_VIEW(scText), TRUE);
gtk_text_buffer_create_tag(g_pTxtBuf[i], "blue_foreground", "foreground", "blue", NULL);
gtk_text_buffer_create_tag(g_pTxtBuf[i], "hex_head", "foreground", "red", "pixels_below_lines", 5, NULL);
gtk_text_buffer_create_tag(g_pTxtBuf[i], "hex_offset", "foreground", "red", NULL);
gtk_text_buffer_create_tag(g_pTxtBuf[i], "bold", "weight", PANGO_WEIGHT_BOLD, NULL);
g_signal_connect(G_OBJECT(scText), "button_release_event", G_CALLBACK(button_release_event), builder);
g_ptvDHcp[i] = tvDhcp;
g_ptvHex[i] = tvHex;
}
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), builder);
//g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), builder);
g_detailWnd = window;
}