653 lines
30 KiB
C
653 lines
30 KiB
C
//
|
||
// Created by HuangXin on 2023/4/26.
|
||
//
|
||
#include <ctype.h>
|
||
#include "main.h"
|
||
#include "misc.h"
|
||
#include "zlog_module.h"
|
||
#include "dhcp_network.h"
|
||
#include "sds/sds.h"
|
||
#include "dhcp_options.h"
|
||
#include "user_errno.h"
|
||
|
||
typedef struct {
|
||
U8 op_code;
|
||
U8 op_size;
|
||
U8 op_value[256];
|
||
} STR_OPT;
|
||
|
||
static GtkWidget *g_detailWnd = NULL;
|
||
static GtkWidget *g_statusBar = NULL;
|
||
static GtkTextBuffer *g_pTxtBuf[4];
|
||
static GtkWidget *g_ptvDHcp[4];
|
||
static GtkWidget *g_pSelVal[4];
|
||
static PBUF_INFO g_HexBuf[4];
|
||
static PDHCP_INFO g_preInfo = NULL;
|
||
static U32 g_curPage = 0;
|
||
static const char *g_mess_info[] = {"NONE", "DISCOVER", "OFFER", "REQUEST", "DECLINE",
|
||
"ACK", "NAK", "RELEASE", "INFORM"};
|
||
|
||
static gboolean delete_event(GtkWidget *widget, GdkEventAny *UNUSED(event)) {
|
||
/* 如果你的 "delete_event" 信号处理函数返回 FALSE,GTK 会发出 "destroy" 信号。
|
||
* 返回 TRUE,你不希望关闭窗口。
|
||
* 当你想弹出“你确定要退出吗?”对话框时它很有用。*/
|
||
//gtk_widget_hide_all(window_test);
|
||
gtk_widget_hide(widget);
|
||
return TRUE; //注意必须为TRUE,否则子窗口点击关闭按钮后,就摧毁了,而不是隐藏了。
|
||
}
|
||
|
||
static void add_dhcp_tree_colums(GtkWidget *treeView) {
|
||
GList *cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(treeView));
|
||
|
||
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) \
|
||
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 { \
|
||
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 *pIps = (U32 *)(val); \
|
||
gtk_tree_store_append(store, &iterOpt, &iterSub); \
|
||
s = sdsempty(); \
|
||
sprintf(s, "%s", u32_to_str_ip(*pIps)); \
|
||
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(U8 *pkg, U32 nBytes, GtkWidget *treeView) {
|
||
PVLAN_HDR pvLan;
|
||
PVLAN_HDR2 pvLan2;
|
||
// 填充右上侧 TreeView 协议数据
|
||
sds s;
|
||
GtkTreeIter iter, iterSub, iterOpt;
|
||
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));
|
||
struct ethhdr *pEth = (struct ethhdr *)pkg;
|
||
struct iphdr *pIp = NULL;
|
||
struct udphdr *pUdp = NULL;
|
||
PDHCP_PROTO pDhcp = NULL;
|
||
|
||
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(pEth->h_dest, s);
|
||
ADD_SUB_STRING("Destination", s);
|
||
sdsfree(s);
|
||
|
||
s = sdsempty();
|
||
MAC_TO_STR(pEth->h_source, s);
|
||
ADD_SUB_STRING("Source", s);
|
||
sdsfree(s);
|
||
|
||
switch (get_package_vlan_type(pkg)) {
|
||
default:
|
||
pIp = (struct iphdr *)(pkg + IP_HDR_OFFSET);
|
||
pUdp = (struct udphdr *)(UDP_HDR_OFFSET);
|
||
pDhcp = (PDHCP_PROTO)((U8 *)pkg + DHCP_OFFSET);
|
||
break;
|
||
case VLAN_LEVEL1:
|
||
pvLan = (PVLAN_HDR)(pkg + sizeof(struct ethhdr));
|
||
pIp = (struct iphdr *)(pkg + IP_HDR_OFFSET + sizeof(VLAN_HDR));
|
||
pUdp = (struct udphdr *)(pkg + UDP_HDR_OFFSET + sizeof(VLAN_HDR));
|
||
pDhcp = (PDHCP_PROTO)((U8 *)pkg + DHCP_OFFSET + sizeof(VLAN_HDR));
|
||
// 添加 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(pvLan->id));
|
||
ADD_SUB_INT("Type", "0x%04X", ntohs(pvLan->type));
|
||
break;
|
||
case VLAN_LEVEL2:
|
||
pvLan2 = (PVLAN_HDR2)(pkg + sizeof(struct ethhdr));
|
||
pIp = (struct iphdr *)(pkg + IP_HDR_OFFSET + sizeof(VLAN_HDR2));
|
||
pUdp = (struct udphdr *)(pkg + UDP_HDR_OFFSET + sizeof(VLAN_HDR2));
|
||
pDhcp = (PDHCP_PROTO)((U8 *)pkg + DHCP_OFFSET + sizeof(VLAN_HDR2));
|
||
gtk_tree_store_append(store, &iter, NULL);
|
||
gtk_tree_store_set(store, &iter, 0, itemTitle[1], 1, "", -1);
|
||
ADD_SUB_INT("ID Low", "%u", VLAN_VNI_ID(pvLan2->id1));
|
||
ADD_SUB_INT("Type", "0x%04X", ntohs(pvLan2->h_type));
|
||
ADD_SUB_INT("ID Hight", "%u", VLAN_VNI_ID(pvLan2->id2));
|
||
ADD_SUB_INT("Type", "0x%04X", ntohs(pvLan2->type));
|
||
break;
|
||
}
|
||
|
||
// 添加 IP 头
|
||
gtk_tree_store_append(store, &iter, NULL);
|
||
gtk_tree_store_set(store, &iter, 0, itemTitle[2], 1, "", -1);
|
||
ADD_SUB_INT("Version", "%u", pIp->version);
|
||
|
||
s = sdsempty();
|
||
sprintf(s, "%u %s (%u)", pIp->ihl * 4, "bytes", pIp->ihl);
|
||
ADD_SUB_STRING("Header Length", s);
|
||
sdsfree(s);
|
||
|
||
ADD_SUB_INT("Differentiated Services Field", "0x%02X", pIp->tos);
|
||
ADD_SUB_INT("Total Length", "%u", ntohs(pIp->tot_len));
|
||
ADD_SUB_INT("Identification", "0x%04X", ntohs(pIp->id));
|
||
ADD_SUB_INT("Flags", "0x%04X", ntohs(pIp->frag_off));
|
||
ADD_SUB_INT("Time to live", "%u", pIp->ttl);
|
||
ADD_SUB_STRING("Protocol", "UDP");
|
||
ADD_SUB_INT("Header Checksum", "0x%04X", ntohs(pIp->check));
|
||
ADD_SUB_STRING("Source", inet_ntoa(*(struct in_addr *)&pIp->saddr));
|
||
ADD_SUB_STRING("Destination", inet_ntoa(*(struct in_addr *)&pIp->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(pUdp->source));
|
||
ADD_SUB_INT("Destination Port", "%u", ntohs(pUdp->dest));
|
||
ADD_SUB_INT("Length", "%u", ntohs(pUdp->len));
|
||
ADD_SUB_INT("Checksum", "0x%04X", ntohs(pUdp->check));
|
||
|
||
// 添加 DHCP 内容
|
||
gtk_tree_store_append(store, &iter, NULL);
|
||
gtk_tree_store_set(store, &iter, 0, itemTitle[4], 1, "", -1);
|
||
switch (pDhcp->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 (pDhcp->htype) {
|
||
case 1:
|
||
ADD_SUB_STRING("Hardware Type", "Ethernet");
|
||
break;
|
||
default:
|
||
ADD_SUB_STRING("Hardware Type", "Unknown");
|
||
}
|
||
ADD_SUB_INT("Hardware address length", "%u", pDhcp->hlen);
|
||
ADD_SUB_INT("Hops", "%u", pDhcp->hops);
|
||
ADD_SUB_INT("Transaction ID", "0x%08X", pDhcp->xid);
|
||
ADD_SUB_INT("Seconds elapsed", "%u", pDhcp->secs);
|
||
ADD_SUB_INT("Bootp flags", "0x%04X", pDhcp->flags);
|
||
ADD_SUB_STRING("Client IP address", inet_ntoa(*(struct in_addr *)&pDhcp->ciaddr));
|
||
ADD_SUB_STRING("Your(client) IP address", inet_ntoa(*(struct in_addr *)&pDhcp->yiaddr));
|
||
ADD_SUB_STRING("Next server IP address", inet_ntoa(*(struct in_addr *)&pDhcp->siaddr));
|
||
ADD_SUB_STRING("Relay agent IP address", inet_ntoa(*(struct in_addr *)&pDhcp->giaddr));
|
||
s = sdsempty();
|
||
MAC_TO_STR(pDhcp->chaddr, s);
|
||
ADD_SUB_STRING("Client MAC address", s);
|
||
sdsfree(s);
|
||
|
||
if (strlen((char *)pDhcp->sname) > 0) {
|
||
ADD_SUB_STRING("Server host name", pDhcp->sname);
|
||
} else {
|
||
ADD_SUB_STRING("Server host name", "not given");
|
||
}
|
||
|
||
if (strlen((char *)pDhcp->file) > 0) {
|
||
ADD_SUB_STRING("Boot file name", pDhcp->file);
|
||
} else {
|
||
ADD_SUB_STRING("Boot file name", "not given");
|
||
}
|
||
|
||
ADD_SUB_STRING("Magic cookie", "DHCP");
|
||
|
||
U8 *opPointer, *optEnd = (U8 *)pkg + nBytes;
|
||
opPointer = pDhcp->options;
|
||
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));
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|
||
static gboolean upgrade_statusbar_proc(gpointer user_data) {
|
||
PDHCP_INFO pInfo = (PDHCP_INFO)user_data;
|
||
int ret;
|
||
DHCP_OPT opt;
|
||
char buf[1024] = {0};
|
||
S32 tmOffer = 0, tmAck = 0;
|
||
const char *pIp = NULL, *pNetmask = NULL, *pGw = NULL, *pDns1 = NULL, *pDns2 = NULL;
|
||
|
||
if (pInfo) {
|
||
tmOffer = MAX(0,
|
||
(pInfo->pOfferBuf.tm.tv_sec * 1000000 + pInfo->pOfferBuf.tm.tv_usec) -
|
||
(pInfo->pDiscBuf.tm.tv_sec * 1000000 + pInfo->pDiscBuf.tm.tv_usec));
|
||
tmAck = MAX(0,
|
||
(pInfo->pAckBuf.tm.tv_sec * 1000000 + pInfo->pAckBuf.tm.tv_usec) -
|
||
(pInfo->pReqBuf.tm.tv_sec * 1000000 + pInfo->pReqBuf.tm.tv_usec));
|
||
|
||
if (pInfo->pAckBuf.p) {
|
||
U32 optSize = 0;
|
||
PDHCP_PROTO pDhcp = get_dhcp_date(pInfo->pAckBuf.p, &optSize, pInfo->pAckBuf.buf_size);
|
||
pIp = u32_to_str_ip_safe(pDhcp->yiaddr);
|
||
|
||
ret = dhcp_get_option(OPT_NETMASK, pDhcp->options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
|
||
pNetmask = u32_to_str_ip_safe(*((U32 *)opt.pValue));
|
||
}
|
||
|
||
ret = dhcp_get_option(OPT_ROUTER, pDhcp->options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS && opt.len == sizeof(U32)) {
|
||
pGw = u32_to_str_ip_safe(*((U32 *)opt.pValue));
|
||
}
|
||
|
||
ret = dhcp_get_option(OPT_DNS, pDhcp->options, optSize, &opt);
|
||
if (ret == ERR_SUCCESS && opt.len >= sizeof(U32)) {
|
||
U32 *pVal = (U32 *)opt.pValue;
|
||
pDns1 = u32_to_str_ip_safe(*pVal);
|
||
|
||
if (opt.len > sizeof(U32)) {
|
||
pVal++;
|
||
pDns2 = u32_to_str_ip_safe(*pVal);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
sprintf(buf, "Offer %d.%03ds | ACK %d.%03ds | ip: %s | netmask: %s | gateway: %s | dns1: %s | dns2: %s |",
|
||
tmOffer / 1000000, (tmOffer % 1000000) / 1000, tmAck / 1000000, (tmAck % 1000000) / 1000,
|
||
SAFETY_STR_STRING(pIp, ""), SAFETY_STR_STRING(pNetmask, ""), SAFETY_STR_STRING(pGw, ""),
|
||
SAFETY_STR_STRING(pDns1, ""), SAFETY_STR_STRING(pDns2, ""));
|
||
|
||
gtk_statusbar_pop(GTK_STATUSBAR(g_statusBar), 0);
|
||
gtk_statusbar_push(GTK_STATUSBAR(g_statusBar), 0, buf);
|
||
|
||
if (pIp) {
|
||
free((void *)pIp);
|
||
}
|
||
|
||
if (pDns1) {
|
||
free((void *)pDns1);
|
||
}
|
||
|
||
if (pDns2) {
|
||
free((void *)pDns2);
|
||
}
|
||
|
||
if (pGw) {
|
||
free((void *)pGw);
|
||
}
|
||
|
||
if (pNetmask) {
|
||
free((void *)pNetmask);
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
void details_wnd_show(PDHCP_INFO pInfo) {
|
||
int i;
|
||
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);
|
||
}
|
||
}
|
||
|
||
g_HexBuf[0] = &pInfo->pDiscBuf;
|
||
g_HexBuf[1] = &pInfo->pOfferBuf;
|
||
g_HexBuf[2] = &pInfo->pReqBuf;
|
||
g_HexBuf[3] = &pInfo->pAckBuf;
|
||
// 填充HEX 窗口数据
|
||
for (i = 0; i < 4; i++) {
|
||
char buf[128] = {0};
|
||
U32 offset = 0;
|
||
|
||
if (g_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 = g_HexBuf[i]->buf_size / 16 + ((g_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 ", g_HexBuf[i]->p[k * 16 + m]);
|
||
strcat(buf, bufStr);
|
||
if (m == 7 || m == 15) {
|
||
strcat(buf, " ");
|
||
}
|
||
}
|
||
|
||
gtk_text_buffer_insert(g_pTxtBuf[i], &iter, buf, -1);
|
||
memset(buf, 0, 128);
|
||
|
||
for (int m = 0; m < 16; m++) {
|
||
if (isprint(g_HexBuf[i]->p[k * 16 + m])) {
|
||
char bufStr[2] = {0};
|
||
bufStr[0] = (char)g_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(g_HexBuf[i]->p, g_HexBuf[i]->buf_size, g_ptvDHcp[i]);
|
||
}
|
||
|
||
upgrade_statusbar_proc(pInfo);
|
||
}
|
||
|
||
gtk_widget_show_all(g_detailWnd);
|
||
}
|
||
|
||
static gboolean button_release_event(GtkWidget *self, GdkEventButton UNUSED(event), gpointer UNUSED(user_data)) {
|
||
int row, col;
|
||
GtkTextIter iter;
|
||
GtkTreeIter it;
|
||
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(g_pSelVal[g_curPage]));
|
||
GtkListStore *store = GTK_LIST_STORE(model);
|
||
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));
|
||
row = gtk_text_iter_get_line(&iter);
|
||
col = gtk_text_iter_get_line_offset(&iter);
|
||
|
||
if (gtk_tree_model_get_iter_first(model, &it)) {
|
||
gtk_list_store_clear(store);
|
||
}
|
||
|
||
if (col >= 11 && col < 59 && row > 0) {
|
||
int k;
|
||
int id;
|
||
U8 valBuf[8] = {0};
|
||
sds s = sdsempty();
|
||
const char *binTbl[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
|
||
"1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
|
||
const char *itemTitle[] = {"Binary", "unsigne char", "unsigne short", "unsigne int", "unsigne long long",
|
||
"char", "short", "int", "long long"};
|
||
if (col >= 35) {
|
||
k = col - 12;
|
||
} else {
|
||
k = col - 11;
|
||
}
|
||
id = (row - 1) * 16 + (k + 1) / 3;
|
||
|
||
//printf("Select at(%d, %d), %d, %d, %d of %d\n", row, col, k, (k + 1) / 3, id, g_curPage);
|
||
memcpy(valBuf, &g_HexBuf[g_curPage]->p[id], MIN(8, g_HexBuf[g_curPage]->buf_size - id));
|
||
// printf("%d, %d, %s, %s\n", valBuf[0] >> 4, valBuf[0] & 0x0F, binTbl[(valBuf[0] >> 4) & 0xF],
|
||
// binTbl[valBuf[0] & 0x0F]);
|
||
|
||
sprintf(s, "%s%s", binTbl[(valBuf[0] >> 4) & 0xF], binTbl[valBuf[0] & 0x0F]);
|
||
gtk_list_store_append(store, &it);
|
||
gtk_list_store_set(store, &it, 0, itemTitle[0], 1, s, -1);
|
||
|
||
sdsclear(s);
|
||
sprintf(s, "%u", valBuf[0]);
|
||
gtk_list_store_append(store, &it);
|
||
gtk_list_store_set(store, &it, 0, itemTitle[1], 1, s, -1);
|
||
|
||
sdsclear(s);
|
||
sprintf(s, "%u", *(unsigned short *)valBuf);
|
||
gtk_list_store_append(store, &it);
|
||
gtk_list_store_set(store, &it, 0, itemTitle[2], 1, s, -1);
|
||
|
||
sdsclear(s);
|
||
sprintf(s, "%u", *(unsigned int *)valBuf);
|
||
gtk_list_store_append(store, &it);
|
||
gtk_list_store_set(store, &it, 0, itemTitle[3], 1, s, -1);
|
||
|
||
sdsclear(s);
|
||
sprintf(s, "%llu", *(unsigned long long *)valBuf);
|
||
gtk_list_store_append(store, &it);
|
||
gtk_list_store_set(store, &it, 0, itemTitle[4], 1, s, -1);
|
||
|
||
sdsclear(s);
|
||
sprintf(s, "%d", valBuf[0]);
|
||
gtk_list_store_append(store, &it);
|
||
gtk_list_store_set(store, &it, 0, itemTitle[5], 1, s, -1);
|
||
|
||
sdsclear(s);
|
||
sprintf(s, "%d", *(short *)valBuf);
|
||
gtk_list_store_append(store, &it);
|
||
gtk_list_store_set(store, &it, 0, itemTitle[6], 1, s, -1);
|
||
|
||
sdsclear(s);
|
||
sprintf(s, "%d", *(int *)valBuf);
|
||
gtk_list_store_append(store, &it);
|
||
gtk_list_store_set(store, &it, 0, itemTitle[7], 1, s, -1);
|
||
|
||
sdsclear(s);
|
||
sprintf(s, "%lld", *(long long *)valBuf);
|
||
gtk_list_store_append(store, &it);
|
||
gtk_list_store_set(store, &it, 0, itemTitle[8], 1, s, -1);
|
||
|
||
sdsfree(s);
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
void switch_page(GtkNotebook *UNUSED(self), GtkWidget *UNUSED(page), guint(page_num), gpointer UNUSED(user_data)) {
|
||
if (g_preInfo) {
|
||
details_wnd_show(g_preInfo);
|
||
upgrade_statusbar_proc(g_preInfo);
|
||
}
|
||
g_curPage = page_num;
|
||
}
|
||
|
||
void details_wnd_create(GtkBuilder *builder) {
|
||
// 创建主窗口
|
||
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||
//设置窗口大小
|
||
gtk_widget_set_size_request(window, 900, 600);
|
||
GtkWidget *vBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
|
||
// 笔记本放进窗口
|
||
gtk_container_add(GTK_CONTAINER(window), vBox);
|
||
|
||
// 创建笔记本控件
|
||
GtkWidget *notebook = gtk_notebook_new();
|
||
// 笔记本放进 VBox
|
||
//gtk_container_add(GTK_CONTAINER(vBox), notebook);
|
||
gtk_box_pack_start(GTK_BOX(vBox), notebook, TRUE, TRUE, 0);
|
||
|
||
// 页标签的位置,可以有四种位置:上、下、左或右。
|
||
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
|
||
g_signal_connect(notebook, "switch-page", G_CALLBACK(switch_page), NULL);
|
||
gtk_widget_set_name(notebook, "nbDhcpInfo");
|
||
|
||
for (int i = 0; i < 4; i++) {
|
||
const char *pTabName[] = {"Discover", "Offer", "Request", "ACK/NACK"};
|
||
// 第一个页面
|
||
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);
|
||
|
||
// 上半部分控件
|
||
GtkWidget *tvDhcp = gtk_tree_view_new();
|
||
gtk_tree_view_set_grid_lines(GTK_TREE_VIEW(tvDhcp), GTK_TREE_VIEW_GRID_LINES_BOTH);
|
||
gtk_container_add(GTK_CONTAINER(scMsg), tvDhcp);
|
||
|
||
gtk_paned_pack1(GTK_PANED(vpaned), scMsg, 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);
|
||
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), vpaned, 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_pSelVal[i] = tvHex;
|
||
}
|
||
|
||
g_statusBar = gtk_statusbar_new();
|
||
gtk_box_pack_start(GTK_BOX(vBox), g_statusBar, FALSE, FALSE, 0);
|
||
//gtk_widget_set_size_request(vBox, -1, 16);
|
||
|
||
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), builder);
|
||
|
||
g_detailWnd = window;
|
||
} |