Qt: Refactor ConversationDialog for endpoints.
Create a TrafficTableDialog (for lack of a better name) parent class from the general parts of ConversationDialog. Use it to create EndpointsDialog. Move the contents of conversation_tree_widget.{cpp,h} to conversation_dialog.{cpp,h} to match endpoint_dialog and traffic_table_dialog. Fill in GeoIP columns dynamically instead of using a hard-coded limit. Use "endp_" and "ENDP_" prefixes for a lot of endpoint variables and defines. Try to make geoip_db_lookup_ipv4 and geoip_db_lookup_ipv6 more robust. Clean up some includes. Fix a shadowed variable. Change-Id: I23054816ac7f8c6edb3b1f01c8536db37ba4122d Reviewed-on: https://code.wireshark.org/review/3462 Petri-Dish: Gerald Combs <gerald@wireshark.org> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Gerald Combs <gerald@wireshark.org>
This commit is contained in:
parent
382815d6bd
commit
30f3d52441
|
@ -144,7 +144,7 @@ typedef struct _hostlist_talker_t {
|
|||
|
||||
} hostlist_talker_t;
|
||||
|
||||
/** Register the conversation table for the multiple conversation window.
|
||||
/** Register the conversation table for the conversation and endpoint windows.
|
||||
*
|
||||
* @param proto_id is the protocol with conversation
|
||||
* @param hide_ports hide the port columns
|
||||
|
|
|
@ -282,24 +282,27 @@ geoip_db_lookup_latlon4(guint32 addr, float *lat, float *lon) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
#define VAL_STR_LEN 100
|
||||
|
||||
/*
|
||||
* GeoIP 1.4.3 and later provide GeoIP_set_charset(), but in versions
|
||||
* 1.4.3 to 1.4.6 that only applies to the City databases. I.e., it's
|
||||
* possible to produce invalid UTF-8 sequences even if GeoIP_set_charset()
|
||||
* is used.
|
||||
*/
|
||||
static void
|
||||
iso_8859_1_to_utf_8(char *val) {
|
||||
char *utf8_val;
|
||||
|
||||
utf8_val = g_convert(val, VAL_STR_LEN, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
|
||||
if (utf8_val) {
|
||||
g_strlcpy(val, utf8_val, VAL_STR_LEN);
|
||||
g_free(utf8_val);
|
||||
/* Ensure that a given db value is UTF-8 */
|
||||
static const char *
|
||||
db_val_to_utf_8(const char *val, GeoIP *gi) {
|
||||
|
||||
if (GeoIP_charset(gi) == GEOIP_CHARSET_ISO_8859_1) {
|
||||
char *utf8_val;
|
||||
utf8_val = g_convert(val, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
|
||||
if (utf8_val) {
|
||||
char *ret_val = ep_strdup(utf8_val);
|
||||
g_free(utf8_val);
|
||||
return ret_val;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
const char *
|
||||
|
@ -307,7 +310,7 @@ geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
|
|||
GeoIP *gi;
|
||||
GeoIPRecord *gir;
|
||||
const char *raw_val, *ret = not_found;
|
||||
static char val[VAL_STR_LEN];
|
||||
char *val;
|
||||
|
||||
gi = g_array_index(geoip_dat_arr, GeoIP *, dbnum);
|
||||
if (gi) {
|
||||
|
@ -315,9 +318,7 @@ geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
|
|||
case GEOIP_COUNTRY_EDITION:
|
||||
raw_val = GeoIP_country_name_by_ipnum(gi, addr);
|
||||
if (raw_val) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%s", raw_val);
|
||||
iso_8859_1_to_utf_8(val);
|
||||
ret = val;
|
||||
ret = db_val_to_utf_8(raw_val, gi);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -325,13 +326,10 @@ geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
|
|||
case GEOIP_CITY_EDITION_REV1:
|
||||
gir = GeoIP_record_by_ipnum(gi, addr);
|
||||
if (gir && gir->city && gir->region) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%s, %s", gir->city, gir->region);
|
||||
iso_8859_1_to_utf_8(val);
|
||||
ret = val;
|
||||
val = ep_strdup_printf("%s, %s", gir->city, gir->region);
|
||||
ret = db_val_to_utf_8(val, gi);
|
||||
} else if (gir && gir->city) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%s", gir->city);
|
||||
iso_8859_1_to_utf_8(val);
|
||||
ret = val;
|
||||
ret = db_val_to_utf_8(gir->city, gi);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -340,9 +338,7 @@ geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
|
|||
case GEOIP_ASNUM_EDITION:
|
||||
raw_val = GeoIP_name_by_ipnum(gi, addr);
|
||||
if (raw_val) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%s", raw_val);
|
||||
iso_8859_1_to_utf_8(val);
|
||||
ret = val;
|
||||
ret = db_val_to_utf_8(raw_val, gi);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -352,7 +348,7 @@ geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
|
|||
float lon;
|
||||
char *c;
|
||||
if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%f", lat);
|
||||
val = ep_strdup_printf("%f", lat);
|
||||
c = strchr(val, ',');
|
||||
if (c != NULL) *c = '.';
|
||||
ret = val;
|
||||
|
@ -366,7 +362,7 @@ geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found) {
|
|||
float lon;
|
||||
char *c;
|
||||
if(geoip_db_lookup_latlon4(addr, &lat, &lon) == 0) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%f", lon);
|
||||
val = ep_strdup_printf("%f", lat);
|
||||
c = strchr(val, ',');
|
||||
if (c != NULL) *c = '.';
|
||||
ret = val;
|
||||
|
@ -423,7 +419,7 @@ geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found)
|
|||
GeoIP *gi;
|
||||
geoipv6_t gaddr;
|
||||
const char *raw_val, *ret = not_found;
|
||||
static char val[VAL_STR_LEN];
|
||||
char *val;
|
||||
#if NUM_DB_TYPES > 31
|
||||
GeoIPRecord *gir;
|
||||
#endif
|
||||
|
@ -436,9 +432,7 @@ geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found)
|
|||
case GEOIP_COUNTRY_EDITION_V6:
|
||||
raw_val = GeoIP_country_name_by_ipnum_v6(gi, gaddr);
|
||||
if (raw_val) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%s", raw_val);
|
||||
iso_8859_1_to_utf_8(val);
|
||||
ret = val;
|
||||
ret = db_val_to_utf_8(raw_val, gi);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -447,13 +441,10 @@ geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found)
|
|||
case GEOIP_CITY_EDITION_REV1_V6:
|
||||
gir = GeoIP_record_by_ipnum_v6(gi, gaddr);
|
||||
if (gir && gir->city && gir->region) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%s, %s", gir->city, gir->region);
|
||||
iso_8859_1_to_utf_8(val);
|
||||
ret = val;
|
||||
val = ep_strdup_printf("%s, %s", gir->city, gir->region);
|
||||
ret = db_val_to_utf_8(val, gi);
|
||||
} else if (gir && gir->city) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%s", gir->city);
|
||||
iso_8859_1_to_utf_8(val);
|
||||
ret = val;
|
||||
ret = db_val_to_utf_8(gir->city, gi);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -462,9 +453,7 @@ geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found)
|
|||
case GEOIP_ASNUM_EDITION_V6:
|
||||
raw_val = GeoIP_name_by_ipnum_v6(gi, gaddr);
|
||||
if (raw_val) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%s", raw_val);
|
||||
iso_8859_1_to_utf_8(val);
|
||||
ret = val;
|
||||
ret = db_val_to_utf_8(raw_val, gi);
|
||||
}
|
||||
break;
|
||||
#endif /* NUM_DB_TYPES */
|
||||
|
@ -475,7 +464,7 @@ geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found)
|
|||
float lon;
|
||||
char *c;
|
||||
if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%f", lat);
|
||||
val = ep_strdup_printf("%f", lat);
|
||||
c = strchr(val, ',');
|
||||
if (c != NULL) *c = '.';
|
||||
ret = val;
|
||||
|
@ -489,7 +478,7 @@ geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found)
|
|||
float lon;
|
||||
char *c;
|
||||
if(geoip_db_lookup_latlon6(gaddr, &lat, &lon) == 0) {
|
||||
g_snprintf(val, VAL_STR_LEN, "%f", lon);
|
||||
val = ep_strdup_printf("%f", lat);
|
||||
c = strchr(val, ',');
|
||||
if (c != NULL) *c = '.';
|
||||
ret = val;
|
||||
|
|
|
@ -73,7 +73,8 @@ WS_DLL_PUBLIC int geoip_db_type(guint dbnum);
|
|||
* @param dbnum Database index
|
||||
* @param addr IPv4 address to look up
|
||||
* @param not_found The string to return if the lookup fails. May be NULL.
|
||||
* @return The database entry if found, else not_found
|
||||
*
|
||||
* @return The database entry if found, else not_found. Return value must not be freed.
|
||||
*/
|
||||
WS_DLL_PUBLIC const char *geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const char *not_found);
|
||||
|
||||
|
@ -83,7 +84,8 @@ WS_DLL_PUBLIC const char *geoip_db_lookup_ipv4(guint dbnum, guint32 addr, const
|
|||
* @param dbnum Database index
|
||||
* @param addr IPv6 address to look up
|
||||
* @param not_found The string to return if the lookup fails. May be NULL.
|
||||
* @return The database entry if found, else not_found
|
||||
*
|
||||
* @return The database entry if found, else not_found. Return value must not be freed.
|
||||
*/
|
||||
WS_DLL_PUBLIC const char *geoip_db_lookup_ipv6(guint dbnum, struct e_in6_addr addr, const char *not_found);
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ set(COMMON_UI_SRC
|
|||
alert_box.c
|
||||
capture.c
|
||||
capture_ui_utils.c
|
||||
conversation_ui.c
|
||||
decode_as_utils.c
|
||||
export_object.c
|
||||
export_object_dicom.c
|
||||
|
@ -52,6 +51,7 @@ set(COMMON_UI_SRC
|
|||
tap-tcp-stream.c
|
||||
text_import.c
|
||||
time_shift.c
|
||||
traffic_table_ui.c
|
||||
util.c
|
||||
)
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@ WIRESHARK_UI_SRC = \
|
|||
alert_box.c \
|
||||
capture.c \
|
||||
capture_ui_utils.c \
|
||||
conversation_ui.c \
|
||||
decode_as_utils.c \
|
||||
export_object.c \
|
||||
export_object_dicom.c \
|
||||
|
@ -73,6 +72,7 @@ WIRESHARK_UI_SRC = \
|
|||
tap-tcp-stream.c \
|
||||
text_import.c \
|
||||
time_shift.c \
|
||||
traffic_table_ui.c \
|
||||
util.c
|
||||
|
||||
noinst_HEADERS = \
|
||||
|
@ -80,7 +80,6 @@ noinst_HEADERS = \
|
|||
capture.h \
|
||||
capture_globals.h \
|
||||
capture_ui_utils.h \
|
||||
conversation_ui.h \
|
||||
decode_as_utils.h \
|
||||
export_object.h \
|
||||
last_open_dir.h \
|
||||
|
@ -113,6 +112,7 @@ noinst_HEADERS = \
|
|||
text_import.h \
|
||||
text_import_scanner.h \
|
||||
time_shift.h \
|
||||
traffic_table_ui.h \
|
||||
ui_util.h \
|
||||
utf8_entities.h \
|
||||
util.h
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <epan/tap.h>
|
||||
#include <epan/timestamp.h>
|
||||
#include <epan/stat_cmd_args.h>
|
||||
#include <ui/conversation_ui.h>
|
||||
#include <ui/traffic_table_ui.h>
|
||||
#include <epan/conversation_table.h>
|
||||
#include <ui/cli/tshark-tap.h>
|
||||
|
||||
|
|
|
@ -1926,12 +1926,12 @@ init_ct_table_page(conversations_table *conversations, GtkWidget *vbox, gboolean
|
|||
conversations->fixed_col = FALSE;
|
||||
|
||||
for (i = 0; i < CONV_NUM_COLUMNS; i++) {
|
||||
conversations->default_titles[i] = column_titles[i];
|
||||
conversations->default_titles[i] = conv_column_titles[i];
|
||||
}
|
||||
|
||||
if (strcmp(table_name, "NCP")==0) {
|
||||
conversations->default_titles[CONV_COLUMN_SRC_PORT] = conn_a_title;
|
||||
conversations->default_titles[CONV_COLUMN_DST_PORT] = conn_b_title;
|
||||
conversations->default_titles[CONV_COLUMN_SRC_PORT] = conv_conn_a_title;
|
||||
conversations->default_titles[CONV_COLUMN_DST_PORT] = conv_conn_b_title;
|
||||
}
|
||||
|
||||
g_snprintf(title, sizeof(title), "%s Conversations", table_name);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include <epan/conv_id.h>
|
||||
#include <epan/conversation_table.h>
|
||||
#include <ui/conversation_ui.h>
|
||||
#include <ui/traffic_table_ui.h>
|
||||
|
||||
/** @file
|
||||
* Conversation definitions.
|
||||
|
|
|
@ -167,8 +167,8 @@ hostlist_sort_column(GtkTreeModel *model,
|
|||
hostlist_talker_t *host1 = NULL;
|
||||
hostlist_talker_t *host2 = NULL;
|
||||
|
||||
gtk_tree_model_get(model, a, HOST_INDEX_COLUMN, &idx1, -1);
|
||||
gtk_tree_model_get(model, b, HOST_INDEX_COLUMN, &idx2, -1);
|
||||
gtk_tree_model_get(model, a, ENDP_INDEX_COLUMN, &idx1, -1);
|
||||
gtk_tree_model_get(model, b, ENDP_INDEX_COLUMN, &idx2, -1);
|
||||
|
||||
if (!hl || idx1 >= hl->hash.conv_array->len || idx2 >= hl->hash.conv_array->len)
|
||||
return 0;
|
||||
|
@ -177,9 +177,9 @@ hostlist_sort_column(GtkTreeModel *model,
|
|||
host2 = &g_array_index(hl->hash.conv_array, hostlist_talker_t, idx2);
|
||||
|
||||
switch(data_column){
|
||||
case HOST_ADR_COLUMN: /* Address */
|
||||
case ENDP_COLUMN_ADDR: /* Address */
|
||||
return(CMP_ADDRESS(&host1->myaddress, &host2->myaddress));
|
||||
case HOST_PORT_COLUMN: /* (Port) */
|
||||
case ENDP_COLUMN_PORT: /* (Port) */
|
||||
CMP_INT(host1->port, host2->port);
|
||||
#ifdef HAVE_GEOIP
|
||||
default:
|
||||
|
@ -224,7 +224,7 @@ hostlist_select_filter_cb(GtkWidget *widget _U_, gpointer callback_data, guint c
|
|||
return;
|
||||
|
||||
gtk_tree_model_get (model, &iter,
|
||||
HOST_INDEX_COLUMN, &idx,
|
||||
ENDP_INDEX_COLUMN, &idx,
|
||||
-1);
|
||||
|
||||
if(idx>= hl->hash.conv_array->len){
|
||||
|
@ -486,12 +486,12 @@ draw_hostlist_table_addresses(hostlist_table *hl)
|
|||
while (iter_valid) {
|
||||
hostlist_talker_t *host;
|
||||
|
||||
gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, HOST_INDEX_COLUMN, &idx, -1);
|
||||
gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, ENDP_INDEX_COLUMN, &idx, -1);
|
||||
host = &g_array_index(hl->hash.conv_array, hostlist_talker_t, idx);
|
||||
|
||||
gtk_list_store_set (store, &iter,
|
||||
HOST_ADR_COLUMN, get_conversation_address(&host->myaddress, hl->resolve_names),
|
||||
HOST_PORT_COLUMN, get_conversation_port(host->port, host->ptype, hl->resolve_names),
|
||||
ENDP_COLUMN_ADDR, get_conversation_address(&host->myaddress, hl->resolve_names),
|
||||
ENDP_COLUMN_PORT, get_conversation_port(host->port, host->ptype, hl->resolve_names),
|
||||
-1);
|
||||
|
||||
iter_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
|
||||
|
@ -536,7 +536,7 @@ draw_hostlist_table_data(hostlist_table *hl)
|
|||
hostlist_talker_t *host;
|
||||
|
||||
if (iter_valid) {
|
||||
gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, HOST_INDEX_COLUMN, &idx, -1);
|
||||
gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, ENDP_INDEX_COLUMN, &idx, -1);
|
||||
} else {
|
||||
idx = new_idx;
|
||||
new_idx++;
|
||||
|
@ -557,7 +557,7 @@ draw_hostlist_table_data(hostlist_table *hl)
|
|||
host->modified = FALSE;
|
||||
if (!iter_valid) {
|
||||
#ifdef HAVE_GEOIP
|
||||
char *geoip[NUM_GEOIP_COLS];
|
||||
char *geoip[ENDP_NUM_GEOIP_COLUMNS];
|
||||
guint j;
|
||||
|
||||
if ((host->myaddress.type == AT_IPv4 || host->myaddress.type == AT_IPv6) && !hl->geoip_visible) {
|
||||
|
@ -572,7 +572,7 @@ draw_hostlist_table_data(hostlist_table *hl)
|
|||
column = (GtkTreeViewColumn *)columns->data;
|
||||
title_p = gtk_tree_view_column_get_title(column);
|
||||
id = gtk_tree_view_column_get_sort_column_id(column);
|
||||
if (title_p[0] != 0 && id >= HOST_GEOIP1_COLUMN) {
|
||||
if (title_p[0] != 0 && id >= ENDP_COLUMN_GEOIP1) {
|
||||
gtk_tree_view_column_set_visible(column, TRUE);
|
||||
}
|
||||
columns = g_list_next(columns);
|
||||
|
@ -582,7 +582,7 @@ draw_hostlist_table_data(hostlist_table *hl)
|
|||
}
|
||||
|
||||
/* Filled in from the GeoIP config, if any */
|
||||
for (j = 0; j < NUM_GEOIP_COLS; j++) {
|
||||
for (j = 0; j < ENDP_NUM_GEOIP_COLUMNS; j++) {
|
||||
if (host->myaddress.type == AT_IPv4 && j < geoip_db_num_dbs()) {
|
||||
const guchar *name = geoip_db_lookup_ipv4(j, pntoh32(host->myaddress.data), "-");
|
||||
geoip[j] = g_strdup(name);
|
||||
|
@ -599,45 +599,45 @@ draw_hostlist_table_data(hostlist_table *hl)
|
|||
#endif /* HAVE_GEOIP */
|
||||
|
||||
gtk_list_store_insert_with_values( store, &iter, G_MAXINT,
|
||||
HOST_ADR_COLUMN, get_conversation_address(&host->myaddress, hl->resolve_names),
|
||||
HOST_PORT_COLUMN, get_conversation_port(host->port, host->ptype, hl->resolve_names),
|
||||
HOST_PACKETS_COLUMN, host->tx_frames+host->rx_frames,
|
||||
HOST_BYTES_COLUMN, host->tx_bytes+host->rx_bytes,
|
||||
HOST_PKT_AB_COLUMN, host->tx_frames,
|
||||
HOST_BYTES_AB_COLUMN, host->tx_bytes,
|
||||
HOST_PKT_BA_COLUMN, host->rx_frames,
|
||||
HOST_BYTES_BA_COLUMN, host->rx_bytes,
|
||||
ENDP_COLUMN_ADDR, get_conversation_address(&host->myaddress, hl->resolve_names),
|
||||
ENDP_COLUMN_PORT, get_conversation_port(host->port, host->ptype, hl->resolve_names),
|
||||
ENDP_COLUMN_PACKETS, host->tx_frames+host->rx_frames,
|
||||
ENDP_COLUMN_BYTES, host->tx_bytes+host->rx_bytes,
|
||||
ENDP_COLUMN_PKT_AB, host->tx_frames,
|
||||
ENDP_COLUMN_BYTES_AB, host->tx_bytes,
|
||||
ENDP_COLUMN_PKT_BA, host->rx_frames,
|
||||
ENDP_COLUMN_BYTES_BA, host->rx_bytes,
|
||||
#ifdef HAVE_GEOIP
|
||||
HOST_GEOIP1_COLUMN, geoip[0],
|
||||
HOST_GEOIP2_COLUMN, geoip[1],
|
||||
HOST_GEOIP3_COLUMN, geoip[2],
|
||||
HOST_GEOIP4_COLUMN, geoip[3],
|
||||
HOST_GEOIP5_COLUMN, geoip[4],
|
||||
HOST_GEOIP6_COLUMN, geoip[5],
|
||||
HOST_GEOIP7_COLUMN, geoip[6],
|
||||
HOST_GEOIP8_COLUMN, geoip[7],
|
||||
HOST_GEOIP9_COLUMN, geoip[8],
|
||||
HOST_GEOIP10_COLUMN, geoip[9],
|
||||
HOST_GEOIP11_COLUMN, geoip[10],
|
||||
HOST_GEOIP12_COLUMN, geoip[11],
|
||||
HOST_GEOIP13_COLUMN, geoip[12],
|
||||
ENDP_COLUMN_GEOIP1, geoip[0],
|
||||
ENDP_COLUMN_GEOIP2, geoip[1],
|
||||
ENDP_COLUMN_GEOIP3, geoip[2],
|
||||
ENDP_COLUMN_GEOIP4, geoip[3],
|
||||
ENDP_COLUMN_GEOIP5, geoip[4],
|
||||
ENDP_COLUMN_GEOIP6, geoip[5],
|
||||
ENDP_COLUMN_GEOIP7, geoip[6],
|
||||
ENDP_COLUMN_GEOIP8, geoip[7],
|
||||
ENDP_COLUMN_GEOIP9, geoip[8],
|
||||
ENDP_COLUMN_GEOIP10, geoip[9],
|
||||
ENDP_COLUMN_GEOIP11, geoip[10],
|
||||
ENDP_COLUMN_GEOIP12, geoip[11],
|
||||
ENDP_COLUMN_GEOIP13, geoip[12],
|
||||
#endif
|
||||
HOST_INDEX_COLUMN, idx,
|
||||
ENDP_INDEX_COLUMN, idx,
|
||||
-1);
|
||||
|
||||
#ifdef HAVE_GEOIP
|
||||
for (j = 0; j < NUM_GEOIP_COLS; j++)
|
||||
for (j = 0; j < ENDP_NUM_GEOIP_COLUMNS; j++)
|
||||
g_free(geoip[j]);
|
||||
#endif /* HAVE_GEOIP */
|
||||
}
|
||||
else {
|
||||
gtk_list_store_set (store, &iter,
|
||||
HOST_PACKETS_COLUMN, host->tx_frames+host->rx_frames,
|
||||
HOST_BYTES_COLUMN, host->tx_bytes+host->rx_bytes,
|
||||
HOST_PKT_AB_COLUMN, host->tx_frames,
|
||||
HOST_BYTES_AB_COLUMN, host->tx_bytes,
|
||||
HOST_PKT_BA_COLUMN, host->rx_frames,
|
||||
HOST_BYTES_BA_COLUMN, host->rx_bytes,
|
||||
ENDP_COLUMN_PACKETS, host->tx_frames+host->rx_frames,
|
||||
ENDP_COLUMN_BYTES, host->tx_bytes+host->rx_bytes,
|
||||
ENDP_COLUMN_PKT_AB, host->tx_frames,
|
||||
ENDP_COLUMN_BYTES_AB, host->tx_bytes,
|
||||
ENDP_COLUMN_PKT_BA, host->rx_frames,
|
||||
ENDP_COLUMN_BYTES_BA, host->rx_bytes,
|
||||
-1);
|
||||
}
|
||||
|
||||
|
@ -668,7 +668,7 @@ draw_hostlist_table_data_cb(void *arg)
|
|||
|
||||
typedef struct {
|
||||
int nb_cols;
|
||||
gint columns_order[HOST_NUM_COLUMNS];
|
||||
gint columns_order[ENDP_NUM_COLUMNS+ENDP_NUM_GEOIP_COLUMNS];
|
||||
GString *CSV_str;
|
||||
hostlist_table *talkers;
|
||||
} csv_t;
|
||||
|
@ -684,27 +684,27 @@ csv_handle(GtkTreeModel *model, GtkTreePath *path _U_, GtkTreeIter *iter,
|
|||
guint idx;
|
||||
guint64 value;
|
||||
|
||||
gtk_tree_model_get(model, iter, HOST_INDEX_COLUMN, &idx, -1);
|
||||
gtk_tree_model_get(model, iter, ENDP_INDEX_COLUMN, &idx, -1);
|
||||
|
||||
for (i=0; i< csv->nb_cols; i++) {
|
||||
if (i)
|
||||
g_string_append(csv->CSV_str, ",");
|
||||
|
||||
switch(csv->columns_order[i]) {
|
||||
case HOST_ADR_COLUMN:
|
||||
case HOST_PORT_COLUMN:
|
||||
case ENDP_COLUMN_ADDR:
|
||||
case ENDP_COLUMN_PORT:
|
||||
gtk_tree_model_get(model, iter, csv->columns_order[i], &table_text, -1);
|
||||
if (table_text) {
|
||||
g_string_append_printf(csv->CSV_str, "\"%s\"", table_text);
|
||||
g_free(table_text);
|
||||
}
|
||||
break;
|
||||
case HOST_PACKETS_COLUMN:
|
||||
case HOST_BYTES_COLUMN:
|
||||
case HOST_PKT_AB_COLUMN:
|
||||
case HOST_BYTES_AB_COLUMN:
|
||||
case HOST_PKT_BA_COLUMN:
|
||||
case HOST_BYTES_BA_COLUMN:
|
||||
case ENDP_COLUMN_PACKETS:
|
||||
case ENDP_COLUMN_BYTES:
|
||||
case ENDP_COLUMN_PKT_AB:
|
||||
case ENDP_COLUMN_BYTES_AB:
|
||||
case ENDP_COLUMN_PKT_BA:
|
||||
case ENDP_COLUMN_BYTES_BA:
|
||||
gtk_tree_model_get(model, iter, csv->columns_order[i], &value, -1);
|
||||
g_string_append_printf(csv->CSV_str, "\"%" G_GINT64_MODIFIER "u\"", value);
|
||||
break;
|
||||
|
@ -1023,34 +1023,34 @@ open_as_map_cb(GtkWindow *copy_bt, gpointer data _U_)
|
|||
}
|
||||
#endif /* HAVE_GEOIP */
|
||||
|
||||
static gint default_col_size[HOST_NUM_COLUMNS];
|
||||
static gint default_col_size[ENDP_NUM_COLUMNS+ENDP_NUM_GEOIP_COLUMNS];
|
||||
|
||||
static void
|
||||
init_default_col_size(GtkWidget *view)
|
||||
{
|
||||
|
||||
default_col_size[HOST_ADR_COLUMN] = get_default_col_size(view, "00000000.000000000000");
|
||||
default_col_size[HOST_PORT_COLUMN] = get_default_col_size(view, "000000");
|
||||
default_col_size[HOST_PACKETS_COLUMN] = get_default_col_size(view, "00 000 000");
|
||||
default_col_size[HOST_BYTES_COLUMN] = get_default_col_size(view, "0 000 000 000");
|
||||
default_col_size[HOST_PKT_AB_COLUMN] = default_col_size[HOST_PACKETS_COLUMN];
|
||||
default_col_size[HOST_PKT_BA_COLUMN] = default_col_size[HOST_PACKETS_COLUMN];
|
||||
default_col_size[HOST_BYTES_AB_COLUMN] = default_col_size[HOST_BYTES_COLUMN];
|
||||
default_col_size[HOST_BYTES_BA_COLUMN] = default_col_size[HOST_BYTES_COLUMN];
|
||||
default_col_size[ENDP_COLUMN_ADDR] = get_default_col_size(view, "00000000.000000000000");
|
||||
default_col_size[ENDP_COLUMN_PORT] = get_default_col_size(view, "000000");
|
||||
default_col_size[ENDP_COLUMN_PACKETS] = get_default_col_size(view, "00 000 000");
|
||||
default_col_size[ENDP_COLUMN_BYTES] = get_default_col_size(view, "0 000 000 000");
|
||||
default_col_size[ENDP_COLUMN_PKT_AB] = default_col_size[ENDP_COLUMN_PACKETS];
|
||||
default_col_size[ENDP_COLUMN_PKT_BA] = default_col_size[ENDP_COLUMN_PACKETS];
|
||||
default_col_size[ENDP_COLUMN_BYTES_AB] = default_col_size[ENDP_COLUMN_BYTES];
|
||||
default_col_size[ENDP_COLUMN_BYTES_BA] = default_col_size[ENDP_COLUMN_BYTES];
|
||||
#ifdef HAVE_GEOIP
|
||||
default_col_size[HOST_GEOIP1_COLUMN] = default_col_size[HOST_ADR_COLUMN];
|
||||
default_col_size[HOST_GEOIP2_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP3_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP4_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP5_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP6_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP7_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP8_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP9_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP10_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP11_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP12_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[HOST_GEOIP13_COLUMN] = default_col_size[HOST_GEOIP1_COLUMN];
|
||||
default_col_size[ENDP_COLUMN_GEOIP1] = default_col_size[ENDP_COLUMN_ADDR];
|
||||
default_col_size[ENDP_COLUMN_GEOIP2] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP3] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP4] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP5] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP6] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP7] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP8] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP9] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP10] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP11] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP12] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
default_col_size[ENDP_COLUMN_GEOIP13] = default_col_size[ENDP_COLUMN_GEOIP1];
|
||||
|
||||
#endif
|
||||
}
|
||||
|
@ -1080,17 +1080,17 @@ init_hostlist_table_page(hostlist_table *hosttable, GtkWidget *vbox, gboolean hi
|
|||
hosttable->default_titles[7] = "Rx Bytes";
|
||||
|
||||
#ifdef HAVE_GEOIP
|
||||
for (i = 0; i < NUM_GEOIP_COLS; i++) {
|
||||
for (i = 0; i < ENDP_NUM_GEOIP_COLUMNS; i++) {
|
||||
if (i < geoip_db_num_dbs()) {
|
||||
hosttable->default_titles[NUM_BUILTIN_COLS + i] = geoip_db_name(i);
|
||||
hosttable->default_titles[ENDP_NUM_COLUMNS + i] = geoip_db_name(i);
|
||||
} else {
|
||||
hosttable->default_titles[NUM_BUILTIN_COLS + i] = "";
|
||||
hosttable->default_titles[ENDP_NUM_COLUMNS + i] = "";
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_GEOIP */
|
||||
|
||||
if (strcmp(table_name, "NCP")==0) {
|
||||
hosttable->default_titles[1] = "Connection";
|
||||
hosttable->default_titles[1] = endp_conn_title;
|
||||
}
|
||||
|
||||
hosttable->has_ports=!hide_ports;
|
||||
|
@ -1104,7 +1104,8 @@ init_hostlist_table_page(hostlist_table *hosttable, GtkWidget *vbox, gboolean hi
|
|||
gtk_box_pack_start(GTK_BOX(vbox), hosttable->name_lb, FALSE, FALSE, 0);
|
||||
|
||||
/* Create the store */
|
||||
store = gtk_list_store_new (HOST_NUM_COLUMNS + 1, /* Total number of columns */
|
||||
|
||||
store = gtk_list_store_new (ENDP_INDEX_COLUMN + 1, /* Total number of columns */
|
||||
G_TYPE_STRING, /* Address */
|
||||
G_TYPE_STRING, /* Port */
|
||||
G_TYPE_UINT64, /* Packets */
|
||||
|
@ -1146,26 +1147,26 @@ init_hostlist_table_page(hostlist_table *hosttable, GtkWidget *vbox, gboolean hi
|
|||
g_object_set_data(G_OBJECT(store), HOST_PTR_KEY, hosttable);
|
||||
g_object_set_data(G_OBJECT(hosttable->table), HOST_PTR_KEY, hosttable);
|
||||
|
||||
for (i = 0; i < HOST_NUM_COLUMNS; i++) {
|
||||
for (i = 0; i < ENDP_NUM_COLUMNS+ENDP_NUM_GEOIP_COLUMNS; i++) {
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
g_object_set(renderer, "ypad", 0, NULL);
|
||||
switch(i) {
|
||||
case HOST_ADR_COLUMN: /* address and port */
|
||||
case HOST_PORT_COLUMN:
|
||||
case ENDP_COLUMN_ADDR: /* address and port */
|
||||
case ENDP_COLUMN_PORT:
|
||||
column = gtk_tree_view_column_new_with_attributes (hosttable->default_titles[i], renderer, "text",
|
||||
i, NULL);
|
||||
if(hide_ports && i == HOST_PORT_COLUMN){
|
||||
if(hide_ports && i == ENDP_COLUMN_PORT){
|
||||
/* hide srcport and dstport if we don't use ports */
|
||||
gtk_tree_view_column_set_visible(column, FALSE);
|
||||
}
|
||||
gtk_tree_sortable_set_sort_func(sortable, i, hostlist_sort_column, GINT_TO_POINTER(i), NULL);
|
||||
break;
|
||||
case HOST_PACKETS_COLUMN: /* counts */
|
||||
case HOST_BYTES_COLUMN:
|
||||
case HOST_PKT_AB_COLUMN:
|
||||
case HOST_BYTES_AB_COLUMN:
|
||||
case HOST_PKT_BA_COLUMN:
|
||||
case HOST_BYTES_BA_COLUMN: /* right align numbers */
|
||||
case ENDP_COLUMN_PACKETS: /* counts */
|
||||
case ENDP_COLUMN_BYTES:
|
||||
case ENDP_COLUMN_PKT_AB:
|
||||
case ENDP_COLUMN_BYTES_AB:
|
||||
case ENDP_COLUMN_PKT_BA:
|
||||
case ENDP_COLUMN_BYTES_BA: /* right align numbers */
|
||||
g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
|
||||
column = gtk_tree_view_column_new_with_attributes (hosttable->default_titles[i], renderer, NULL);
|
||||
gtk_tree_view_column_set_cell_data_func(column, renderer, u64_data_func, GINT_TO_POINTER(i), NULL);
|
||||
|
@ -1175,8 +1176,8 @@ init_hostlist_table_page(hostlist_table *hosttable, GtkWidget *vbox, gboolean hi
|
|||
i, NULL);
|
||||
gtk_tree_view_column_set_visible(column, FALSE);
|
||||
#ifdef HAVE_GEOIP
|
||||
if (i >= NUM_BUILTIN_COLS && i - NUM_BUILTIN_COLS < geoip_db_num_dbs()) {
|
||||
int goip_type = geoip_db_type(i - NUM_BUILTIN_COLS);
|
||||
if (i >= ENDP_NUM_COLUMNS && i - ENDP_NUM_COLUMNS < geoip_db_num_dbs()) {
|
||||
int goip_type = geoip_db_type(i - ENDP_NUM_COLUMNS);
|
||||
if (goip_type == WS_LON_FAKE_EDITION || goip_type == WS_LAT_FAKE_EDITION) {
|
||||
g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
|
||||
gtk_tree_sortable_set_sort_func(sortable, i, hostlist_sort_column, GINT_TO_POINTER(i), NULL);
|
||||
|
|
|
@ -25,49 +25,33 @@
|
|||
#define __HOSTLIST_TABLE_H__
|
||||
|
||||
#include <epan/conversation_table.h>
|
||||
#include <ui/traffic_table_ui.h>
|
||||
|
||||
/** @file
|
||||
* Hostlist definitions.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
HOST_ADR_COLUMN,
|
||||
HOST_PORT_COLUMN,
|
||||
HOST_PACKETS_COLUMN,
|
||||
HOST_BYTES_COLUMN,
|
||||
HOST_PKT_AB_COLUMN,
|
||||
HOST_BYTES_AB_COLUMN,
|
||||
HOST_PKT_BA_COLUMN,
|
||||
HOST_BYTES_BA_COLUMN,
|
||||
#ifdef HAVE_GEOIP
|
||||
HOST_GEOIP1_COLUMN,
|
||||
HOST_GEOIP2_COLUMN,
|
||||
HOST_GEOIP3_COLUMN,
|
||||
HOST_GEOIP4_COLUMN,
|
||||
HOST_GEOIP5_COLUMN,
|
||||
HOST_GEOIP6_COLUMN,
|
||||
HOST_GEOIP7_COLUMN,
|
||||
HOST_GEOIP8_COLUMN,
|
||||
HOST_GEOIP9_COLUMN,
|
||||
HOST_GEOIP10_COLUMN,
|
||||
HOST_GEOIP11_COLUMN,
|
||||
HOST_GEOIP12_COLUMN,
|
||||
HOST_GEOIP13_COLUMN,
|
||||
#endif
|
||||
HOST_NUM_COLUMNS,
|
||||
HOST_INDEX_COLUMN = HOST_NUM_COLUMNS
|
||||
} hostlist_column_type_e;
|
||||
|
||||
|
||||
|
||||
#define NUM_BUILTIN_COLS 8
|
||||
#ifdef HAVE_GEOIP
|
||||
# define NUM_GEOIP_COLS 13
|
||||
typedef enum {
|
||||
ENDP_COLUMN_GEOIP1 = ENDP_NUM_COLUMNS,
|
||||
ENDP_COLUMN_GEOIP2,
|
||||
ENDP_COLUMN_GEOIP3,
|
||||
ENDP_COLUMN_GEOIP4,
|
||||
ENDP_COLUMN_GEOIP5,
|
||||
ENDP_COLUMN_GEOIP6,
|
||||
ENDP_COLUMN_GEOIP7,
|
||||
ENDP_COLUMN_GEOIP8,
|
||||
ENDP_COLUMN_GEOIP9,
|
||||
ENDP_COLUMN_GEOIP10,
|
||||
ENDP_COLUMN_GEOIP11,
|
||||
ENDP_COLUMN_GEOIP12,
|
||||
ENDP_COLUMN_GEOIP13,
|
||||
} geoip_column_type_e;
|
||||
#define ENDP_NUM_GEOIP_COLUMNS 13
|
||||
#else
|
||||
# define NUM_GEOIP_COLS 0
|
||||
#define ENDP_NUM_GEOIP_COLUMNS 0
|
||||
#endif
|
||||
#define NUM_HOSTLIST_COLS (NUM_BUILTIN_COLS + NUM_GEOIP_COLS)
|
||||
#define ENDP_INDEX_COLUMN (ENDP_NUM_COLUMNS+ENDP_NUM_GEOIP_COLUMNS)
|
||||
|
||||
/** Hostlist widget */
|
||||
typedef struct _hostlist_table {
|
||||
|
@ -79,7 +63,7 @@ typedef struct _hostlist_table {
|
|||
GtkWidget *name_lb; /**< name label */
|
||||
GtkWidget *scrolled_window; /**< the scrolled window */
|
||||
GtkTreeView *table; /**< the GTK table */
|
||||
const char *default_titles[NUM_HOSTLIST_COLS]; /**< Column headers */
|
||||
const char *default_titles[ENDP_NUM_COLUMNS+ENDP_NUM_GEOIP_COLUMNS]; /**< Column headers */
|
||||
GtkWidget *menu; /**< context menu */
|
||||
gboolean has_ports; /**< table has ports */
|
||||
conv_hash_t hash; /**< hostlist hash table */
|
||||
|
|
|
@ -38,11 +38,11 @@ set(WIRESHARK_QT_HEADERS
|
|||
column_preferences_frame.h
|
||||
compiled_filter_output.h
|
||||
conversation_dialog.h
|
||||
conversation_tree_widget.h
|
||||
decode_as_dialog.h
|
||||
display_filter_combo.h
|
||||
display_filter_edit.h
|
||||
elided_label.h
|
||||
endpoint_dialog.h
|
||||
export_dissection_dialog.h
|
||||
export_object_dialog.h
|
||||
export_pdu_dialog.h
|
||||
|
@ -97,6 +97,7 @@ set(WIRESHARK_QT_HEADERS
|
|||
syntax_line_edit.h
|
||||
tcp_stream_dialog.h
|
||||
time_shift_dialog.h
|
||||
traffic_table_dialog.h
|
||||
uat_dialog.h
|
||||
wireshark_application.h
|
||||
)
|
||||
|
@ -124,7 +125,6 @@ set(WIRESHARK_QT_SRC
|
|||
capture_preferences_frame.cpp
|
||||
column_preferences_frame.cpp
|
||||
compiled_filter_output.cpp
|
||||
conversation_tree_widget.cpp
|
||||
decode_as_dialog.cpp
|
||||
display_filter_combo.cpp
|
||||
display_filter_edit.cpp
|
||||
|
@ -186,12 +186,14 @@ set(WIRESHARK_QT_SRC
|
|||
syntax_line_edit.cpp
|
||||
tcp_stream_dialog.cpp
|
||||
time_shift_dialog.cpp
|
||||
traffic_table_dialog.cpp
|
||||
uat_dialog.cpp
|
||||
wireshark_application.cpp
|
||||
)
|
||||
|
||||
set(WIRESHARK_QT_TAP_SRC
|
||||
conversation_dialog.cpp
|
||||
endpoint_dialog.cpp
|
||||
io_graph_dialog.cpp
|
||||
stats_tree_dialog.cpp
|
||||
)
|
||||
|
@ -211,7 +213,6 @@ set(WIRESHARK_QT_UI
|
|||
capture_interfaces_dialog.ui
|
||||
column_preferences_frame.ui
|
||||
compiled_filter_output.ui
|
||||
conversation_dialog.ui
|
||||
decode_as_dialog.ui
|
||||
export_object_dialog.ui
|
||||
export_pdu_dialog.ui
|
||||
|
@ -252,6 +253,7 @@ set(WIRESHARK_QT_UI
|
|||
summary_dialog.ui
|
||||
tcp_stream_dialog.ui
|
||||
time_shift_dialog.ui
|
||||
traffic_table_dialog.ui
|
||||
uat_dialog.ui
|
||||
)
|
||||
|
||||
|
|
|
@ -130,8 +130,6 @@ column_preferences_frame.cpp column_preferences_frame.h: ui_column_preferences_f
|
|||
|
||||
compiled_filter_output.cpp compiled_filter_output.h: ui_compiled_filter_output.h
|
||||
|
||||
conversation_dialog.cpp conversation_dialog.h: ui_conversation_dialog.h
|
||||
|
||||
decode_as_dialog.cpp decode_as_dialog.h: ui_decode_as_dialog.h
|
||||
|
||||
export_object_dialog.cpp export_object_dialog.h: ui_export_object_dialog.h
|
||||
|
@ -212,6 +210,8 @@ tcp_stream_dialog.cpp: ui_tcp_stream_dialog.h
|
|||
|
||||
time_shift_dialog.cpp time_shift_dialog.h: ui_time_shift_dialog.h
|
||||
|
||||
traffic_table_dialog.cpp traffic_table_dialog.h: ui_traffic_table_dialog.h
|
||||
|
||||
uat_dialog.cpp uat_dialog.h: ui_uat_dialog.h
|
||||
|
||||
doxygen:
|
||||
|
|
|
@ -34,7 +34,6 @@ NODIST_GENERATED_HEADER_FILES = \
|
|||
ui_capture_preferences_frame.h \
|
||||
ui_column_preferences_frame.h \
|
||||
ui_compiled_filter_output.h \
|
||||
ui_conversation_dialog.h \
|
||||
ui_decode_as_dialog.h \
|
||||
ui_export_object_dialog.h \
|
||||
ui_export_pdu_dialog.h \
|
||||
|
@ -75,6 +74,7 @@ NODIST_GENERATED_HEADER_FILES = \
|
|||
ui_summary_dialog.h \
|
||||
ui_tcp_stream_dialog.h \
|
||||
ui_time_shift_dialog.h \
|
||||
ui_traffic_table_dialog.h \
|
||||
ui_uat_dialog.h
|
||||
|
||||
# Generated C source files that we want in the distribution.
|
||||
|
@ -121,17 +121,17 @@ MOC_HDRS = \
|
|||
capture_filter_syntax_worker.h \
|
||||
capture_info_dialog.h \
|
||||
capture_interfaces_dialog.h \
|
||||
capture_preferences_frame.h \
|
||||
color_dialog.h \
|
||||
color_utils.h \
|
||||
capture_preferences_frame.h \
|
||||
column_preferences_frame.h \
|
||||
compiled_filter_output.h \
|
||||
conversation_dialog.h \
|
||||
conversation_tree_widget.h \
|
||||
decode_as_dialog.h \
|
||||
display_filter_combo.h \
|
||||
display_filter_edit.h \
|
||||
elided_label.h \
|
||||
endpoint_dialog.h \
|
||||
export_dissection_dialog.h \
|
||||
export_object_dialog.h \
|
||||
export_pdu_dialog.h \
|
||||
|
@ -188,6 +188,7 @@ MOC_HDRS = \
|
|||
syntax_line_edit.h \
|
||||
tcp_stream_dialog.h \
|
||||
time_shift_dialog.h \
|
||||
traffic_table_dialog.h \
|
||||
uat_dialog.h \
|
||||
wireshark_application.h
|
||||
|
||||
|
@ -201,7 +202,6 @@ UI_FILES = \
|
|||
capture_preferences_frame.ui \
|
||||
column_preferences_frame.ui \
|
||||
compiled_filter_output.ui \
|
||||
conversation_dialog.ui \
|
||||
decode_as_dialog.ui \
|
||||
export_object_dialog.ui \
|
||||
export_pdu_dialog.ui \
|
||||
|
@ -242,6 +242,7 @@ UI_FILES = \
|
|||
summary_dialog.ui \
|
||||
tcp_stream_dialog.ui \
|
||||
time_shift_dialog.ui \
|
||||
traffic_table_dialog.ui \
|
||||
uat_dialog.ui
|
||||
|
||||
#
|
||||
|
@ -308,17 +309,17 @@ WIRESHARK_QT_SRC = \
|
|||
capture_filter_syntax_worker.cpp \
|
||||
capture_info_dialog.cpp \
|
||||
capture_interfaces_dialog.cpp \
|
||||
capture_preferences_frame.cpp \
|
||||
color_dialog.cpp \
|
||||
color_utils.cpp \
|
||||
capture_preferences_frame.cpp \
|
||||
column_preferences_frame.cpp \
|
||||
compiled_filter_output.cpp \
|
||||
conversation_dialog.cpp \
|
||||
conversation_tree_widget.cpp \
|
||||
decode_as_dialog.cpp \
|
||||
display_filter_combo.cpp \
|
||||
display_filter_edit.cpp \
|
||||
elided_label.cpp \
|
||||
endpoint_dialog.cpp \
|
||||
export_dissection_dialog.cpp \
|
||||
export_object_dialog.cpp \
|
||||
export_pdu_dialog.cpp \
|
||||
|
@ -379,6 +380,7 @@ WIRESHARK_QT_SRC = \
|
|||
syntax_line_edit.cpp \
|
||||
tcp_stream_dialog.cpp \
|
||||
time_shift_dialog.cpp \
|
||||
traffic_table_dialog.cpp \
|
||||
uat_dialog.cpp \
|
||||
wireshark_application.cpp
|
||||
|
||||
|
|
|
@ -210,7 +210,6 @@ FORMS += \
|
|||
capture_interfaces_dialog.ui \
|
||||
column_preferences_frame.ui \
|
||||
compiled_filter_output.ui \
|
||||
conversation_dialog.ui \
|
||||
decode_as_dialog.ui \
|
||||
export_object_dialog.ui \
|
||||
export_pdu_dialog.ui \
|
||||
|
@ -251,6 +250,7 @@ FORMS += \
|
|||
summary_dialog.ui \
|
||||
tcp_stream_dialog.ui \
|
||||
time_shift_dialog.ui \
|
||||
traffic_table_dialog.ui \
|
||||
uat_dialog.ui
|
||||
|
||||
|
||||
|
@ -262,9 +262,9 @@ HEADERS += $$HEADERS_WS_C \
|
|||
column_preferences_frame.h \
|
||||
compiled_filter_output.h \
|
||||
conversation_dialog.h \
|
||||
conversation_tree_widget.h \
|
||||
decode_as_dialog.h \
|
||||
elided_label.h \
|
||||
endpoint_dialog.h \
|
||||
export_dissection_dialog.h \
|
||||
export_object_dialog.h \
|
||||
export_pdu_dialog.h \
|
||||
|
@ -300,6 +300,7 @@ HEADERS += $$HEADERS_WS_C \
|
|||
summary_dialog.h \
|
||||
tango_colors.h \
|
||||
tcp_stream_dialog.h \
|
||||
traffic_table_dialog.h \
|
||||
uat_dialog.h
|
||||
|
||||
win32 {
|
||||
|
@ -595,11 +596,11 @@ SOURCES += \
|
|||
column_preferences_frame.cpp \
|
||||
compiled_filter_output.cpp \
|
||||
conversation_dialog.cpp \
|
||||
conversation_tree_widget.cpp \
|
||||
decode_as_dialog.cpp \
|
||||
display_filter_combo.cpp \
|
||||
display_filter_edit.cpp \
|
||||
elided_label.cpp \
|
||||
endpoint_dialog.cpp \
|
||||
export_dissection_dialog.cpp \
|
||||
export_object_dialog.cpp \
|
||||
export_pdu_dialog.cpp \
|
||||
|
@ -660,5 +661,6 @@ SOURCES += \
|
|||
syntax_line_edit.cpp \
|
||||
tcp_stream_dialog.cpp \
|
||||
time_shift_dialog.cpp \
|
||||
traffic_table_dialog.cpp \
|
||||
uat_dialog.cpp \
|
||||
wireshark_application.cpp
|
||||
|
|
|
@ -20,30 +20,21 @@
|
|||
*/
|
||||
|
||||
#include "conversation_dialog.h"
|
||||
#include "ui_conversation_dialog.h"
|
||||
|
||||
#include <epan/addr_resolv.h>
|
||||
#include <epan/prefs.h>
|
||||
#include <epan/stat_cmd_args.h>
|
||||
|
||||
#include <epan/dissectors/packet-tcp.h>
|
||||
|
||||
#include "ui/recent.h"
|
||||
#include "ui/tap-tcp-stream.h"
|
||||
#include "ui/traffic_table_ui.h"
|
||||
|
||||
#include "wsutil/str_util.h"
|
||||
|
||||
#include "qt_ui_utils.h"
|
||||
|
||||
#include "wireshark_application.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QCheckBox>
|
||||
#include <QClipboard>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTabWidget>
|
||||
#include <QTextStream>
|
||||
#include <QToolButton>
|
||||
|
||||
// To do:
|
||||
// - https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6727
|
||||
|
@ -65,36 +56,15 @@
|
|||
// - Friendly unit displays https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9231
|
||||
// - Misleading bps calculation https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8703
|
||||
|
||||
ConversationDialog::ConversationDialog(QWidget *parent, capture_file *cf, int proto_id, const char *filter) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::ConversationDialog),
|
||||
cap_file_(cf),
|
||||
filter_(filter)
|
||||
const QString table_name_ = QObject::tr("Conversation");
|
||||
ConversationDialog::ConversationDialog(QWidget *parent, capture_file *cf, int cli_proto_id, const char *filter) :
|
||||
TrafficTableDialog(parent, cf, filter, table_name_)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
// XXX Use recent settings instead
|
||||
if (parent) {
|
||||
resize(parent->width(), parent->height() * 3 / 4);
|
||||
}
|
||||
|
||||
QMenu *copy_menu = new QMenu();
|
||||
QAction *ca;
|
||||
copy_bt_ = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
|
||||
ca = copy_menu->addAction(tr("as CSV"));
|
||||
ca->setToolTip(tr("Copy all values of this page to the clipboard in CSV (Comma Separated Values) format."));
|
||||
connect(ca, SIGNAL(triggered()), this, SLOT(copyAsCsv()));
|
||||
ca = copy_menu->addAction(tr("as YAML"));
|
||||
ca->setToolTip(tr("Copy all values of this page to the clipboard in the YAML data serialization format."));
|
||||
connect(ca, SIGNAL(triggered()), this, SLOT(copyAsYaml()));
|
||||
copy_bt_->setMenu(copy_menu);
|
||||
|
||||
follow_bt_ = ui->buttonBox->addButton(tr("Follow Stream..."), QDialogButtonBox::ActionRole);
|
||||
follow_bt_ = buttonBox()->addButton(tr("Follow Stream..."), QDialogButtonBox::ActionRole);
|
||||
follow_bt_->setToolTip(tr("Follow a TCP or UDP stream."));
|
||||
connect(follow_bt_, SIGNAL(clicked()), this, SLOT(followStream()));
|
||||
|
||||
graph_bt_ = ui->buttonBox->addButton(tr("Graph..."), QDialogButtonBox::ActionRole);
|
||||
graph_bt_ = buttonBox()->addButton(tr("Graph..."), QDialogButtonBox::ActionRole);
|
||||
graph_bt_->setToolTip(tr("Graph a TCP conversation."));
|
||||
connect(graph_bt_, SIGNAL(clicked()), this, SLOT(graphTcp()));
|
||||
|
||||
|
@ -106,51 +76,26 @@ ConversationDialog::ConversationDialog(QWidget *parent, capture_file *cf, int pr
|
|||
}
|
||||
}
|
||||
|
||||
// Reasonable defaults?
|
||||
if (conv_protos.isEmpty()) {
|
||||
conv_protos << proto_get_id_by_filter_name( "tcp" ) << proto_get_id_by_filter_name( "eth" )
|
||||
<< proto_get_id_by_filter_name( "ip" ) << proto_get_id_by_filter_name( "ipv6" )
|
||||
<< proto_get_id_by_filter_name( "udp" );
|
||||
conv_protos = defaultProtos();
|
||||
}
|
||||
|
||||
// Bring the command-line specified type to the front.
|
||||
if (get_conversation_by_proto_id(proto_id)) {
|
||||
conv_protos.removeAll(proto_id);
|
||||
conv_protos.prepend(proto_id);
|
||||
if (get_conversation_by_proto_id(cli_proto_id)) {
|
||||
conv_protos.removeAll(cli_proto_id);
|
||||
conv_protos.prepend(cli_proto_id);
|
||||
}
|
||||
|
||||
// QTabWidget selects the first item by default.
|
||||
foreach (int conv_proto, conv_protos) {
|
||||
addConversationTable(get_conversation_by_proto_id(conv_proto));
|
||||
addTrafficTable(get_conversation_by_proto_id(conv_proto));
|
||||
}
|
||||
|
||||
for (guint i = 0; i < conversation_table_get_num(); i++) {
|
||||
int proto_id = get_conversation_proto_id(get_conversation_table_by_num(i));
|
||||
if (proto_id < 0) {
|
||||
continue;
|
||||
}
|
||||
QString title = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
|
||||
|
||||
QAction *conv_action = new QAction(title, this);
|
||||
conv_action->setData(qVariantFromValue(proto_id));
|
||||
conv_action->setCheckable(true);
|
||||
conv_action->setChecked(conv_protos.contains(proto_id));
|
||||
connect(conv_action, SIGNAL(triggered()), this, SLOT(toggleConversation()));
|
||||
conv_type_menu_.addAction(conv_action);
|
||||
}
|
||||
|
||||
ui->conversationTypePushButton->setMenu(&conv_type_menu_);
|
||||
fillTypeMenu(conv_protos);
|
||||
|
||||
updateWidgets();
|
||||
itemSelectionChanged();
|
||||
|
||||
ui->nameResolutionCheckBox->setChecked(gbl_resolv_flags.network_name);
|
||||
|
||||
ui->conversationTabWidget->currentWidget()->setFocus();
|
||||
|
||||
connect(ui->conversationTabWidget, SIGNAL(currentChanged(int)),
|
||||
this, SLOT(itemSelectionChanged()));
|
||||
|
||||
if (cap_file_) {
|
||||
cf_retap_packets(cap_file_);
|
||||
}
|
||||
|
@ -161,8 +106,8 @@ ConversationDialog::~ConversationDialog()
|
|||
prefs_clear_string_list(recent.conversation_tabs);
|
||||
recent.conversation_tabs = NULL;
|
||||
|
||||
ConversationTreeWidget *cur_tree = qobject_cast<ConversationTreeWidget *>(ui->conversationTabWidget->currentWidget());
|
||||
foreach (QAction *ca, conv_type_menu_.actions()) {
|
||||
ConversationTreeWidget *cur_tree = qobject_cast<ConversationTreeWidget *>(trafficTableTabWidget()->currentWidget());
|
||||
foreach (QAction *ca, traffic_type_menu_.actions()) {
|
||||
int proto_id = ca->data().value<int>();
|
||||
if (proto_id_to_tree_.contains(proto_id) && ca->isChecked()) {
|
||||
char *title = g_strdup(proto_get_protocol_short_name(find_protocol_by_id(proto_id)));
|
||||
|
@ -173,23 +118,26 @@ ConversationDialog::~ConversationDialog()
|
|||
}
|
||||
}
|
||||
}
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConversationDialog::setCaptureFile(capture_file *cf)
|
||||
{
|
||||
if (!cf) { // We only want to know when the file closes.
|
||||
cap_file_ = NULL;
|
||||
for (int i = 0; i < ui->conversationTabWidget->count(); i++) {
|
||||
ConversationTreeWidget *cur_tree = qobject_cast<ConversationTreeWidget *>(ui->conversationTabWidget->widget(i));
|
||||
remove_tap_listener(cur_tree->conversationHash());
|
||||
for (int i = 0; i < trafficTableTabWidget()->count(); i++) {
|
||||
ConversationTreeWidget *cur_tree = qobject_cast<ConversationTreeWidget *>(trafficTableTabWidget()->widget(i));
|
||||
remove_tap_listener(cur_tree->trafficTreeHash());
|
||||
disconnect(cur_tree, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
|
||||
this, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
|
||||
}
|
||||
ui->displayFilterCheckBox->setEnabled(false);
|
||||
ui->conversationTypePushButton->setEnabled(false);
|
||||
displayFilterCheckBox()->setEnabled(false);
|
||||
enabledTypesPushButton()->setEnabled(false);
|
||||
follow_bt_->setEnabled(false);
|
||||
graph_bt_->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool ConversationDialog::addConversationTable(register_ct_t* table)
|
||||
bool ConversationDialog::addTrafficTable(register_ct_t* table)
|
||||
{
|
||||
int proto_id = get_conversation_proto_id(table);
|
||||
|
||||
|
@ -202,28 +150,28 @@ bool ConversationDialog::addConversationTable(register_ct_t* table)
|
|||
proto_id_to_tree_[proto_id] = conv_tree;
|
||||
const char* table_name = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
|
||||
|
||||
ui->conversationTabWidget->addTab(conv_tree, table_name);
|
||||
trafficTableTabWidget()->addTab(conv_tree, table_name);
|
||||
|
||||
connect(conv_tree, SIGNAL(itemSelectionChanged()),
|
||||
this, SLOT(itemSelectionChanged()));
|
||||
connect(conv_tree, SIGNAL(titleChanged(QWidget*,QString)),
|
||||
this, SLOT(setTabText(QWidget*,QString)));
|
||||
connect(conv_tree, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
|
||||
this, SLOT(chainFilterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
|
||||
connect(ui->nameResolutionCheckBox, SIGNAL(toggled(bool)),
|
||||
this, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
|
||||
connect(nameResolutionCheckBox(), SIGNAL(toggled(bool)),
|
||||
conv_tree, SLOT(setNameResolutionEnabled(bool)));
|
||||
|
||||
// XXX Move to ConversationTreeWidget ctor?
|
||||
const char *filter = NULL;
|
||||
if (ui->displayFilterCheckBox->isChecked()) {
|
||||
if (displayFilterCheckBox()->isChecked()) {
|
||||
filter = cap_file_->dfilter;
|
||||
} else if (!filter_.isEmpty()) {
|
||||
filter = filter_.toUtf8().constData();
|
||||
}
|
||||
|
||||
conv_tree->conversationHash()->user_data = conv_tree;
|
||||
conv_tree->trafficTreeHash()->user_data = conv_tree;
|
||||
|
||||
GString *error_string = register_tap_listener(proto_get_protocol_filter_name(proto_id), conv_tree->conversationHash(), filter, 0,
|
||||
GString *error_string = register_tap_listener(proto_get_protocol_filter_name(proto_id), conv_tree->trafficTreeHash(), filter, 0,
|
||||
ConversationTreeWidget::tapReset,
|
||||
get_conversation_packet_func(table),
|
||||
ConversationTreeWidget::tapDraw);
|
||||
|
@ -239,7 +187,7 @@ bool ConversationDialog::addConversationTable(register_ct_t* table)
|
|||
|
||||
conv_item_t *ConversationDialog::currentConversation()
|
||||
{
|
||||
ConversationTreeWidget *cur_tree = qobject_cast<ConversationTreeWidget *>(ui->conversationTabWidget->currentWidget());
|
||||
ConversationTreeWidget *cur_tree = qobject_cast<ConversationTreeWidget *>(trafficTableTabWidget()->currentWidget());
|
||||
|
||||
if (!cur_tree || cur_tree->selectedItems().count() < 1) {
|
||||
return NULL;
|
||||
|
@ -250,6 +198,10 @@ conv_item_t *ConversationDialog::currentConversation()
|
|||
|
||||
void ConversationDialog::followStream()
|
||||
{
|
||||
if (!cap_file_) {
|
||||
return;
|
||||
}
|
||||
|
||||
conv_item_t *conv_item = currentConversation();
|
||||
if (!conv_item) {
|
||||
return;
|
||||
|
@ -273,56 +225,16 @@ void ConversationDialog::followStream()
|
|||
return;
|
||||
}
|
||||
|
||||
chainFilterAction(filter, FilterAction::ActionApply, FilterAction::ActionTypePlain);
|
||||
emit filterAction(filter, FilterAction::ActionApply, FilterAction::ActionTypePlain);
|
||||
openFollowStreamDialog(ftype);
|
||||
}
|
||||
|
||||
void ConversationDialog::copyAsCsv()
|
||||
{
|
||||
ConversationTreeWidget *cur_tree = qobject_cast<ConversationTreeWidget *>(ui->conversationTabWidget->currentWidget());
|
||||
if (!cur_tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString csv;
|
||||
QTextStream stream(&csv, QIODevice::Text);
|
||||
for (int row = -1; row < cur_tree->topLevelItemCount(); row ++) {
|
||||
QStringList rdsl;
|
||||
foreach (QVariant v, cur_tree->rowData(row)) {
|
||||
if (!v.isValid()) {
|
||||
rdsl << "\"\"";
|
||||
} else if ((int) v.type() == (int) QMetaType::QString) {
|
||||
rdsl << QString("\"%1\"").arg(v.toString());
|
||||
} else {
|
||||
rdsl << v.toString();
|
||||
}
|
||||
}
|
||||
stream << rdsl.join(",") << endl;
|
||||
}
|
||||
wsApp->clipboard()->setText(stream.readAll());
|
||||
}
|
||||
|
||||
void ConversationDialog::copyAsYaml()
|
||||
{
|
||||
ConversationTreeWidget *cur_tree = qobject_cast<ConversationTreeWidget *>(ui->conversationTabWidget->currentWidget());
|
||||
if (!cur_tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString yaml;
|
||||
QTextStream stream(&yaml, QIODevice::Text);
|
||||
stream << "---" << endl;
|
||||
for (int row = -1; row < cur_tree->topLevelItemCount(); row ++) {
|
||||
stream << "-" << endl;
|
||||
foreach (QVariant v, cur_tree->rowData(row)) {
|
||||
stream << " - " << v.toString() << endl;
|
||||
}
|
||||
}
|
||||
wsApp->clipboard()->setText(stream.readAll());
|
||||
}
|
||||
|
||||
void ConversationDialog::graphTcp()
|
||||
{
|
||||
if (!cap_file_) {
|
||||
return;
|
||||
}
|
||||
|
||||
conv_item_t *conv_item = currentConversation();
|
||||
if (!conv_item) {
|
||||
return;
|
||||
|
@ -337,54 +249,13 @@ void ConversationDialog::graphTcp()
|
|||
return;
|
||||
}
|
||||
|
||||
chainFilterAction(filter, FilterAction::ActionApply, FilterAction::ActionTypePlain);
|
||||
emit filterAction(filter, FilterAction::ActionApply, FilterAction::ActionTypePlain);
|
||||
openTcpStreamGraph(GRAPH_TSEQ_TCPTRACE);
|
||||
}
|
||||
|
||||
void ConversationDialog::updateWidgets()
|
||||
{
|
||||
QWidget *cur_w = ui->conversationTabWidget->currentWidget();
|
||||
ui->conversationTabWidget->setUpdatesEnabled(false);
|
||||
ui->conversationTabWidget->clear();
|
||||
foreach (QAction *ca, conv_type_menu_.actions()) {
|
||||
int proto_id = ca->data().value<int>();
|
||||
if (proto_id_to_tree_.contains(proto_id) && ca->isChecked()) {
|
||||
ui->conversationTabWidget->addTab(proto_id_to_tree_[proto_id],
|
||||
proto_id_to_tree_[proto_id]->conversationTitle());
|
||||
proto_id_to_tree_[proto_id]->setNameResolutionEnabled(ui->nameResolutionCheckBox->isChecked());
|
||||
}
|
||||
}
|
||||
ui->conversationTabWidget->setCurrentWidget(cur_w);
|
||||
ui->conversationTabWidget->setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
void ConversationDialog::toggleConversation()
|
||||
{
|
||||
QAction *ca = qobject_cast<QAction *>(QObject::sender());
|
||||
if (!ca) {
|
||||
return;
|
||||
}
|
||||
|
||||
int proto_id = ca->data().value<int>();
|
||||
register_ct_t* table = get_conversation_by_proto_id(proto_id);
|
||||
|
||||
bool new_conv = addConversationTable(table);
|
||||
updateWidgets();
|
||||
|
||||
if (ca->isChecked()) {
|
||||
ui->conversationTabWidget->setCurrentWidget(proto_id_to_tree_[proto_id]);
|
||||
}
|
||||
|
||||
if (new_conv) {
|
||||
if (cap_file_) {
|
||||
cf_retap_packets(cap_file_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationDialog::itemSelectionChanged()
|
||||
{
|
||||
bool copy_enable = ui->conversationTabWidget->currentWidget() ? true : false;
|
||||
bool copy_enable = trafficTableTabWidget()->currentWidget() ? true : false;
|
||||
bool follow_enable = false, graph_enable = false;
|
||||
conv_item_t *conv_item = currentConversation();
|
||||
|
||||
|
@ -425,29 +296,13 @@ void ConversationDialog::on_displayFilterCheckBox_toggled(bool checked)
|
|||
filter = filter_.toUtf8().constData();
|
||||
}
|
||||
|
||||
for (int i = 0; i < ui->conversationTabWidget->count(); i++) {
|
||||
set_tap_dfilter(ui->conversationTabWidget->widget(i), filter);
|
||||
for (int i = 0; i < trafficTableTabWidget()->count(); i++) {
|
||||
set_tap_dfilter(trafficTableTabWidget()->widget(i), filter);
|
||||
}
|
||||
|
||||
cf_retap_packets(cap_file_);
|
||||
}
|
||||
|
||||
void ConversationDialog::setTabText(QWidget *tree, const QString &text)
|
||||
{
|
||||
// Could use QObject::sender as well
|
||||
int index = ui->conversationTabWidget->indexOf(tree);
|
||||
if (index >= 0) {
|
||||
ui->conversationTabWidget->setTabText(index, text);
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationDialog::chainFilterAction(QString &filter, FilterAction::Action action, FilterAction::ActionType type)
|
||||
{
|
||||
if (cap_file_) { // We probably shouldn't fail silently
|
||||
emit filterAction(filter, action, type);
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationDialog::on_buttonBox_helpRequested()
|
||||
{
|
||||
wsApp->helpTopicAction(HELP_STATS_CONVERSATIONS_DIALOG);
|
||||
|
@ -456,7 +311,381 @@ void ConversationDialog::on_buttonBox_helpRequested()
|
|||
void init_conversation_table(struct register_ct* ct, const char *filter)
|
||||
{
|
||||
Q_UNUSED(ct)
|
||||
wsApp->emitStatCommandSignal("Conversation", filter, GINT_TO_POINTER(get_conversation_proto_id(ct)));
|
||||
wsApp->emitStatCommandSignal("Conversations", filter, GINT_TO_POINTER(get_conversation_proto_id(ct)));
|
||||
}
|
||||
|
||||
|
||||
// ConversationTreeWidgetItem
|
||||
// TrafficTableTreeWidgetItem / QTreeWidgetItem subclass that allows sorting
|
||||
|
||||
// Minimum bandwidth calculation duration
|
||||
// https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8703
|
||||
const double min_bw_calc_duration_ = 5 / 1000.0; // seconds
|
||||
const QString bps_na_ = QObject::tr("N/A");
|
||||
|
||||
const int ci_col_ = 0;
|
||||
const int pkts_col_ = 1;
|
||||
class ConversationTreeWidgetItem : public TrafficTableTreeWidgetItem
|
||||
{
|
||||
public:
|
||||
ConversationTreeWidgetItem(QTreeWidget *tree) : TrafficTableTreeWidgetItem(tree) {}
|
||||
ConversationTreeWidgetItem(QTreeWidget *parent, const QStringList &strings)
|
||||
: TrafficTableTreeWidgetItem (parent, strings) {}
|
||||
|
||||
// Set column text to its cooked representation.
|
||||
void update(gboolean resolve_names) {
|
||||
conv_item_t *conv_item = data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
bool ok;
|
||||
quint64 cur_packets = data(pkts_col_, Qt::UserRole).toULongLong(&ok);
|
||||
|
||||
if (!conv_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
quint64 packets = conv_item->tx_frames + conv_item->rx_frames;
|
||||
if (ok && cur_packets == packets) {
|
||||
return;
|
||||
}
|
||||
|
||||
setText(CONV_COLUMN_SRC_ADDR, get_conversation_address(&conv_item->src_address, resolve_names));
|
||||
setText(CONV_COLUMN_SRC_PORT, get_conversation_port(conv_item->src_port, conv_item->ptype, resolve_names));
|
||||
setText(CONV_COLUMN_DST_ADDR, get_conversation_address(&conv_item->dst_address, resolve_names));
|
||||
setText(CONV_COLUMN_DST_PORT, get_conversation_port(conv_item->dst_port, conv_item->ptype, resolve_names));
|
||||
|
||||
double duration = nstime_to_sec(&conv_item->stop_time) - nstime_to_sec(&conv_item->start_time);
|
||||
QString col_str, bps_ab = bps_na_, bps_ba = bps_na_;
|
||||
|
||||
col_str = QString("%L1").arg(packets);
|
||||
setText(CONV_COLUMN_PACKETS, col_str);
|
||||
col_str = gchar_free_to_qstring(format_size(conv_item->tx_bytes + conv_item->rx_bytes, format_size_unit_none|format_size_prefix_si));
|
||||
setText(CONV_COLUMN_BYTES, col_str);
|
||||
col_str = QString("%L1").arg(conv_item->tx_frames);
|
||||
setText(CONV_COLUMN_PKT_AB, QString::number(conv_item->tx_frames));
|
||||
col_str = gchar_free_to_qstring(format_size(conv_item->tx_bytes, format_size_unit_none|format_size_prefix_si));
|
||||
setText(CONV_COLUMN_BYTES_AB, col_str);
|
||||
col_str = QString("%L1").arg(conv_item->rx_frames);
|
||||
setText(CONV_COLUMN_PKT_BA, QString::number(conv_item->rx_frames));
|
||||
col_str = gchar_free_to_qstring(format_size(conv_item->rx_bytes, format_size_unit_none|format_size_prefix_si));
|
||||
setText(CONV_COLUMN_BYTES_BA, col_str);
|
||||
setText(CONV_COLUMN_START, QString::number(nstime_to_sec(&conv_item->start_time), 'f', 9));
|
||||
setText(CONV_COLUMN_DURATION, QString::number(duration, 'f', 6));
|
||||
if (duration > min_bw_calc_duration_) {
|
||||
bps_ab = gchar_free_to_qstring(format_size((gint64) conv_item->tx_bytes * 8 / duration, format_size_unit_none|format_size_prefix_si));
|
||||
bps_ba = gchar_free_to_qstring(format_size((gint64) conv_item->rx_bytes * 8 / duration, format_size_unit_none|format_size_prefix_si));
|
||||
}
|
||||
setText(CONV_COLUMN_BPS_AB, bps_ab);
|
||||
setText(CONV_COLUMN_BPS_BA, bps_ba);
|
||||
setData(pkts_col_, Qt::UserRole, qVariantFromValue(packets));
|
||||
}
|
||||
|
||||
// Return a string, qulonglong, double, or invalid QVariant representing the raw column data.
|
||||
QVariant colData(int col, bool resolve_names) const {
|
||||
conv_item_t *conv_item = data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
|
||||
if (!conv_item) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
double duration = nstime_to_sec(&conv_item->stop_time) - nstime_to_sec(&conv_item->start_time);
|
||||
double bps_ab = 0, bps_ba = 0;
|
||||
if (duration > min_bw_calc_duration_) {
|
||||
bps_ab = conv_item->tx_bytes * 8 / duration;
|
||||
bps_ba = conv_item->rx_bytes * 8 / duration;
|
||||
}
|
||||
|
||||
switch (col) {
|
||||
case CONV_COLUMN_SRC_ADDR:
|
||||
return get_conversation_address(&conv_item->src_address, resolve_names);
|
||||
case CONV_COLUMN_SRC_PORT:
|
||||
if (resolve_names) {
|
||||
return get_conversation_port(conv_item->src_port, conv_item->ptype, resolve_names);
|
||||
} else {
|
||||
return quint32(conv_item->src_port);
|
||||
}
|
||||
case CONV_COLUMN_DST_ADDR:
|
||||
return get_conversation_address(&conv_item->dst_address, resolve_names);
|
||||
case CONV_COLUMN_DST_PORT:
|
||||
if (resolve_names) {
|
||||
return get_conversation_port(conv_item->dst_port, conv_item->ptype, resolve_names);
|
||||
} else {
|
||||
return quint32(conv_item->dst_port);
|
||||
}
|
||||
case CONV_COLUMN_PACKETS:
|
||||
return quint64(conv_item->tx_frames + conv_item->rx_frames);
|
||||
case CONV_COLUMN_BYTES:
|
||||
return quint64(conv_item->tx_bytes + conv_item->rx_bytes);
|
||||
case CONV_COLUMN_PKT_AB:
|
||||
return quint64(conv_item->tx_frames);
|
||||
case CONV_COLUMN_BYTES_AB:
|
||||
return quint64(conv_item->tx_bytes);
|
||||
case CONV_COLUMN_PKT_BA:
|
||||
return quint64(conv_item->rx_frames);
|
||||
case CONV_COLUMN_BYTES_BA:
|
||||
return quint64(conv_item->rx_bytes);
|
||||
case CONV_COLUMN_START:
|
||||
return nstime_to_sec(&conv_item->start_time);
|
||||
case CONV_COLUMN_DURATION:
|
||||
return duration;
|
||||
case CONV_COLUMN_BPS_AB:
|
||||
return bps_ab;
|
||||
case CONV_COLUMN_BPS_BA:
|
||||
return bps_ba;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator< (const QTreeWidgetItem &other) const
|
||||
{
|
||||
conv_item_t *conv_item = data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
conv_item_t *other_item = other.data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
|
||||
if (!conv_item || !other_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sort_col = treeWidget()->sortColumn();
|
||||
double conv_duration = nstime_to_sec(&conv_item->stop_time) - nstime_to_sec(&conv_item->start_time);
|
||||
double other_duration = nstime_to_sec(&other_item->stop_time) - nstime_to_sec(&other_item->start_time);
|
||||
|
||||
switch(sort_col) {
|
||||
case CONV_COLUMN_SRC_ADDR:
|
||||
return cmp_address(&conv_item->src_address, &other_item->src_address) < 0 ? true : false;
|
||||
case CONV_COLUMN_SRC_PORT:
|
||||
return conv_item->src_port < other_item->src_port;
|
||||
case CONV_COLUMN_DST_ADDR:
|
||||
return cmp_address(&conv_item->dst_address, &other_item->dst_address) < 0 ? true : false;
|
||||
case CONV_COLUMN_DST_PORT:
|
||||
return conv_item->dst_port < other_item->dst_port;
|
||||
case CONV_COLUMN_PACKETS:
|
||||
return (conv_item->tx_frames + conv_item->rx_frames) < (other_item->tx_frames + other_item->rx_frames);
|
||||
case CONV_COLUMN_BYTES:
|
||||
return (conv_item->tx_bytes + conv_item->rx_bytes) < (other_item->tx_bytes + other_item->rx_bytes);
|
||||
case CONV_COLUMN_PKT_AB:
|
||||
return conv_item->tx_frames < other_item->tx_frames;
|
||||
case CONV_COLUMN_BYTES_AB:
|
||||
return conv_item->tx_bytes < other_item->tx_bytes;
|
||||
case CONV_COLUMN_PKT_BA:
|
||||
return conv_item->rx_frames < other_item->rx_frames;
|
||||
case CONV_COLUMN_BYTES_BA:
|
||||
return conv_item->rx_bytes < other_item->rx_bytes;
|
||||
case CONV_COLUMN_START:
|
||||
return nstime_to_sec(&conv_item->start_time) < nstime_to_sec(&other_item->start_time);
|
||||
case CONV_COLUMN_DURATION:
|
||||
return conv_duration < other_duration;
|
||||
case CONV_COLUMN_BPS_AB:
|
||||
return conv_item->tx_bytes / conv_duration < other_item->tx_bytes / other_duration;
|
||||
case CONV_COLUMN_BPS_BA:
|
||||
return conv_item->rx_bytes / conv_duration < other_item->rx_bytes / other_duration;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// ConversationTreeWidget
|
||||
// TrafficTableTreeWidget / QTreeWidget subclass that allows tapping
|
||||
|
||||
ConversationTreeWidget::ConversationTreeWidget(QWidget *parent, register_ct_t* table) :
|
||||
TrafficTableTreeWidget(parent, table)
|
||||
{
|
||||
setColumnCount(CONV_NUM_COLUMNS);
|
||||
|
||||
for (int i = 0; i < CONV_NUM_COLUMNS; i++) {
|
||||
headerItem()->setText(i, conv_column_titles[i]);
|
||||
}
|
||||
|
||||
if (get_conversation_hide_ports(table_)) {
|
||||
hideColumn(CONV_COLUMN_SRC_PORT);
|
||||
hideColumn(CONV_COLUMN_DST_PORT);
|
||||
} else if (!strcmp(proto_get_protocol_filter_name(get_conversation_proto_id(table_)), "ncp")) {
|
||||
headerItem()->setText(CONV_COLUMN_SRC_PORT, conv_conn_a_title);
|
||||
headerItem()->setText(CONV_COLUMN_DST_PORT, conv_conn_b_title);
|
||||
}
|
||||
|
||||
int one_en = fontMetrics().height() / 2;
|
||||
for (int i = 0; i < CONV_NUM_COLUMNS; i++) {
|
||||
switch (i) {
|
||||
case CONV_COLUMN_SRC_ADDR:
|
||||
case CONV_COLUMN_DST_ADDR:
|
||||
setColumnWidth(i, one_en * strlen("000.000.000.000"));
|
||||
break;
|
||||
case CONV_COLUMN_SRC_PORT:
|
||||
case CONV_COLUMN_DST_PORT:
|
||||
setColumnWidth(i, one_en * strlen("000000"));
|
||||
break;
|
||||
case CONV_COLUMN_PACKETS:
|
||||
case CONV_COLUMN_PKT_AB:
|
||||
case CONV_COLUMN_PKT_BA:
|
||||
setColumnWidth(i, one_en * strlen("00,000"));
|
||||
break;
|
||||
case CONV_COLUMN_BYTES:
|
||||
case CONV_COLUMN_BYTES_AB:
|
||||
case CONV_COLUMN_BYTES_BA:
|
||||
setColumnWidth(i, one_en * strlen("000,000"));
|
||||
break;
|
||||
case CONV_COLUMN_START:
|
||||
setColumnWidth(i, one_en * strlen("00.000"));
|
||||
break;
|
||||
case CONV_COLUMN_DURATION:
|
||||
setColumnWidth(i, one_en * strlen("00.000000"));
|
||||
break;
|
||||
case CONV_COLUMN_BPS_AB:
|
||||
case CONV_COLUMN_BPS_BA:
|
||||
setColumnWidth(i, one_en * strlen("000 k"));
|
||||
break;
|
||||
default:
|
||||
setColumnWidth(i, one_en * 5);
|
||||
}
|
||||
}
|
||||
|
||||
QMenu *submenu;
|
||||
|
||||
initDirectionMap();
|
||||
|
||||
FilterAction::Action cur_action = FilterAction::ActionApply;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
||||
QMenu *subsubmenu = submenu->addMenu(FilterAction::actionTypeName(at));
|
||||
foreach (FilterAction::ActionDirection ad, FilterAction::actionDirections()) {
|
||||
FilterAction *fa = new FilterAction(subsubmenu, cur_action, at, ad);
|
||||
subsubmenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
}
|
||||
|
||||
cur_action = FilterAction::ActionPrepare;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
||||
QMenu *subsubmenu = submenu->addMenu(FilterAction::actionTypeName(at));
|
||||
foreach (FilterAction::ActionDirection ad, FilterAction::actionDirections()) {
|
||||
FilterAction *fa = new FilterAction(subsubmenu, cur_action, at, ad);
|
||||
subsubmenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
}
|
||||
|
||||
cur_action = FilterAction::ActionFind;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionDirection ad, FilterAction::actionDirections()) {
|
||||
FilterAction *fa = new FilterAction(submenu, cur_action, FilterAction::ActionTypePlain, ad);
|
||||
submenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
|
||||
cur_action = FilterAction::ActionColorize;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionDirection ad, FilterAction::actionDirections()) {
|
||||
FilterAction *fa = new FilterAction(submenu, cur_action, FilterAction::ActionTypePlain, ad);
|
||||
submenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
|
||||
updateItems();
|
||||
}
|
||||
|
||||
ConversationTreeWidget::~ConversationTreeWidget() {
|
||||
reset_conversation_table_data(&hash_);
|
||||
}
|
||||
|
||||
// Callbacks for register_tap_listener
|
||||
void ConversationTreeWidget::tapReset(void *conv_hash_ptr)
|
||||
{
|
||||
conv_hash_t *hash = (conv_hash_t*)conv_hash_ptr;
|
||||
ConversationTreeWidget *conv_tree = static_cast<ConversationTreeWidget *>(hash->user_data);
|
||||
if (!conv_tree) return;
|
||||
|
||||
conv_tree->clear();
|
||||
reset_conversation_table_data(&conv_tree->hash_);
|
||||
}
|
||||
|
||||
void ConversationTreeWidget::tapDraw(void *conv_hash_ptr)
|
||||
{
|
||||
conv_hash_t *hash = (conv_hash_t*)conv_hash_ptr;
|
||||
ConversationTreeWidget *conv_tree = static_cast<ConversationTreeWidget *>(hash->user_data);
|
||||
if (!conv_tree) return;
|
||||
|
||||
conv_tree->updateItems();
|
||||
}
|
||||
|
||||
QMap<FilterAction::ActionDirection, conv_direction_e> fad_to_cd_;
|
||||
|
||||
void ConversationTreeWidget::initDirectionMap()
|
||||
{
|
||||
if (fad_to_cd_.size() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
fad_to_cd_[FilterAction::ActionDirectionAToFromB] = CONV_DIR_A_TO_FROM_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAToB] = CONV_DIR_A_TO_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAFromB] = CONV_DIR_A_FROM_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAToFromAny] = CONV_DIR_A_TO_FROM_ANY;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAToAny] = CONV_DIR_A_TO_ANY;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAFromAny] = CONV_DIR_A_FROM_ANY;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAnyToFromB] = CONV_DIR_ANY_TO_FROM_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAnyToB] = CONV_DIR_ANY_TO_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAnyFromB] = CONV_DIR_ANY_FROM_B;
|
||||
}
|
||||
|
||||
void ConversationTreeWidget::updateItems() {
|
||||
title_ = proto_get_protocol_short_name(find_protocol_by_id(get_conversation_proto_id(table_)));
|
||||
|
||||
if (hash_.conv_array && hash_.conv_array->len > 0) {
|
||||
title_.append(QString(" %1 %2").arg(UTF8_MIDDLE_DOT).arg(hash_.conv_array->len));
|
||||
}
|
||||
emit titleChanged(this, title_);
|
||||
|
||||
if (!hash_.conv_array) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSortingEnabled(false);
|
||||
for (int i = topLevelItemCount(); i < (int) hash_.conv_array->len; i++) {
|
||||
ConversationTreeWidgetItem *ctwi = new ConversationTreeWidgetItem(this);
|
||||
conv_item_t *conv_item = &g_array_index(hash_.conv_array, conv_item_t, i);
|
||||
ctwi->setData(ci_col_, Qt::UserRole, qVariantFromValue(conv_item));
|
||||
addTopLevelItem(ctwi);
|
||||
|
||||
for (int col = 0; col < columnCount(); col++) {
|
||||
switch (col) {
|
||||
case CONV_COLUMN_SRC_ADDR:
|
||||
case CONV_COLUMN_DST_ADDR:
|
||||
break;
|
||||
default:
|
||||
ctwi->setTextAlignment(col, Qt::AlignRight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
QTreeWidgetItemIterator iter(this);
|
||||
while (*iter) {
|
||||
ConversationTreeWidgetItem *ci = static_cast<ConversationTreeWidgetItem *>(*iter);
|
||||
ci->update(resolve_names_);
|
||||
++iter;
|
||||
}
|
||||
setSortingEnabled(true);
|
||||
|
||||
for (int col = 0; col < columnCount(); col++) {
|
||||
resizeColumnToContents(col);
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationTreeWidget::filterActionTriggered()
|
||||
{
|
||||
ConversationTreeWidgetItem *ctwi = static_cast<ConversationTreeWidgetItem *>(currentItem());
|
||||
FilterAction *fa = qobject_cast<FilterAction *>(QObject::sender());
|
||||
|
||||
if (!fa || !ctwi) {
|
||||
return;
|
||||
}
|
||||
|
||||
conv_item_t *conv_item = ctwi->data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
if (!conv_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString filter = get_conversation_filter(conv_item, fad_to_cd_[fa->actionDirection()]);
|
||||
emit filterAction(filter, fa->action(), fa->actionType());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -22,23 +22,29 @@
|
|||
#ifndef CONVERSATION_DIALOG_H
|
||||
#define CONVERSATION_DIALOG_H
|
||||
|
||||
#include <conversation_tree_widget.h>
|
||||
#include "traffic_table_dialog.h"
|
||||
|
||||
#include <file.h>
|
||||
Q_DECLARE_METATYPE(conv_item_t *)
|
||||
|
||||
#include "ui/follow.h"
|
||||
#include "epan/conversation_table.h"
|
||||
class ConversationTreeWidget : public TrafficTableTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ConversationTreeWidget(QWidget *parent, register_ct_t* table);
|
||||
~ConversationTreeWidget();
|
||||
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
static void tapReset(void *conv_hash_ptr);
|
||||
static void tapDraw(void *conv_hash_ptr);
|
||||
|
||||
#include <QDialog>
|
||||
private:
|
||||
void initDirectionMap();
|
||||
|
||||
namespace Ui {
|
||||
class ConversationDialog;
|
||||
}
|
||||
private slots:
|
||||
void updateItems();
|
||||
void filterActionTriggered();
|
||||
};
|
||||
|
||||
class ConversationDialog : public QDialog
|
||||
class ConversationDialog : public TrafficTableDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -50,7 +56,7 @@ public:
|
|||
* @param proto_id If valid, add this protocol and bring it to the front.
|
||||
* @param filter Display filter to apply.
|
||||
*/
|
||||
explicit ConversationDialog(QWidget *parent = 0, capture_file *cf = NULL, int proto_id = -1, const char *filter = NULL);
|
||||
explicit ConversationDialog(QWidget *parent = 0, capture_file *cf = NULL, int cli_proto_id = -1, const char *filter = NULL);
|
||||
~ConversationDialog();
|
||||
|
||||
public slots:
|
||||
|
@ -62,32 +68,18 @@ signals:
|
|||
void openTcpStreamGraph(int graph_type);
|
||||
|
||||
private:
|
||||
Ui::ConversationDialog *ui;
|
||||
|
||||
capture_file *cap_file_;
|
||||
QString filter_;
|
||||
QMenu conv_type_menu_;
|
||||
QMap<int, ConversationTreeWidget *> proto_id_to_tree_;
|
||||
QList<QAction> conv_actions_;
|
||||
QPushButton *copy_bt_;
|
||||
QPushButton *follow_bt_;
|
||||
QPushButton *graph_bt_;
|
||||
|
||||
// Adds a conversation tree. Returns true if the tree was freshly created, false if it was cached.
|
||||
bool addConversationTable(register_ct_t* table);
|
||||
bool addTrafficTable(register_ct_t* table);
|
||||
conv_item_t *currentConversation();
|
||||
|
||||
private slots:
|
||||
void updateWidgets();
|
||||
void toggleConversation();
|
||||
void itemSelectionChanged();
|
||||
void on_nameResolutionCheckBox_toggled(bool checked);
|
||||
void on_displayFilterCheckBox_toggled(bool checked);
|
||||
void setTabText(QWidget *tree, const QString &text);
|
||||
void chainFilterAction(QString& filter, FilterAction::Action action, FilterAction::ActionType type);
|
||||
void followStream();
|
||||
void copyAsCsv();
|
||||
void copyAsYaml();
|
||||
void graphTcp();
|
||||
void on_buttonBox_helpRequested();
|
||||
};
|
||||
|
|
|
@ -1,487 +0,0 @@
|
|||
/* conversation_tree_widget.cpp
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "conversation_tree_widget.h"
|
||||
|
||||
#include <epan/addr_resolv.h>
|
||||
#include <epan/to_str.h>
|
||||
|
||||
#include <epan/dissectors/packet-eth.h>
|
||||
#include <epan/dissectors/packet-fc.h>
|
||||
#include <epan/dissectors/packet-fddi.h>
|
||||
#include <epan/dissectors/packet-ip.h>
|
||||
#include <epan/dissectors/packet-ipv6.h>
|
||||
#include <epan/dissectors/packet-ipx.h>
|
||||
#include <epan/dissectors/packet-jxta.h>
|
||||
#include <epan/dissectors/packet-ncp-int.h>
|
||||
#include <epan/dissectors/packet-rsvp.h>
|
||||
#include <epan/dissectors/packet-sctp.h>
|
||||
#include <epan/dissectors/packet-tcp.h>
|
||||
#include <epan/dissectors/packet-tr.h>
|
||||
#include <epan/dissectors/packet-udp.h>
|
||||
#include <epan/dissectors/packet-ieee80211.h>
|
||||
|
||||
#include <ui/utf8_entities.h>
|
||||
|
||||
#include <wsutil/str_util.h>
|
||||
|
||||
#include "wireshark_application.h"
|
||||
|
||||
#include "qt_ui_utils.h"
|
||||
|
||||
#include <QContextMenuEvent>
|
||||
#include <QTreeWidgetItemIterator>
|
||||
|
||||
// QTreeWidget subclass that allows tapping
|
||||
|
||||
// Minimum bandwidth calculation duration
|
||||
// https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8703
|
||||
const double min_bw_calc_duration_ = 5 / 1000.0; // seconds
|
||||
const QString bps_na_ = QObject::tr("N/A");
|
||||
|
||||
QMap<FilterAction::ActionDirection, conv_direction_e> fad_to_cd_;
|
||||
|
||||
// QTreeWidgetItem subclass that allows sorting
|
||||
const int ci_col_ = 0;
|
||||
const int pkts_col_ = 1;
|
||||
class ConversationTreeWidgetItem : public QTreeWidgetItem
|
||||
{
|
||||
public:
|
||||
ConversationTreeWidgetItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
|
||||
ConversationTreeWidgetItem(QTreeWidget * parent, const QStringList & strings)
|
||||
: QTreeWidgetItem (parent,strings) {}
|
||||
|
||||
// Set column text to its cooked representation.
|
||||
void update(gboolean resolve_names) {
|
||||
conv_item_t *conv_item = data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
bool ok;
|
||||
quint64 cur_packets = data(pkts_col_, Qt::UserRole).toULongLong(&ok);
|
||||
|
||||
if (!conv_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
quint64 packets = conv_item->tx_frames + conv_item->rx_frames;
|
||||
if (ok && cur_packets == packets) {
|
||||
return;
|
||||
}
|
||||
|
||||
setText(CONV_COLUMN_SRC_ADDR, get_conversation_address(&conv_item->src_address, resolve_names));
|
||||
setText(CONV_COLUMN_SRC_PORT, get_conversation_port(conv_item->src_port, conv_item->ptype, resolve_names));
|
||||
setText(CONV_COLUMN_DST_ADDR, get_conversation_address(&conv_item->dst_address, resolve_names));
|
||||
setText(CONV_COLUMN_DST_PORT, get_conversation_port(conv_item->dst_port, conv_item->ptype, resolve_names));
|
||||
|
||||
double duration = nstime_to_sec(&conv_item->stop_time) - nstime_to_sec(&conv_item->start_time);
|
||||
QString col_str, bps_ab = bps_na_, bps_ba = bps_na_;
|
||||
|
||||
col_str = QString("%L1").arg(packets);
|
||||
setText(CONV_COLUMN_PACKETS, col_str);
|
||||
col_str = gchar_free_to_qstring(format_size(conv_item->tx_bytes + conv_item->rx_bytes, format_size_unit_none|format_size_prefix_si));
|
||||
setText(CONV_COLUMN_BYTES, col_str);
|
||||
col_str = QString("%L1").arg(conv_item->tx_frames);
|
||||
setText(CONV_COLUMN_PKT_AB, QString::number(conv_item->tx_frames));
|
||||
col_str = gchar_free_to_qstring(format_size(conv_item->tx_bytes, format_size_unit_none|format_size_prefix_si));
|
||||
setText(CONV_COLUMN_BYTES_AB, col_str);
|
||||
col_str = QString("%L1").arg(conv_item->rx_frames);
|
||||
setText(CONV_COLUMN_PKT_BA, QString::number(conv_item->rx_frames));
|
||||
col_str = gchar_free_to_qstring(format_size(conv_item->rx_bytes, format_size_unit_none|format_size_prefix_si));
|
||||
setText(CONV_COLUMN_BYTES_BA, col_str);
|
||||
setText(CONV_COLUMN_START, QString::number(nstime_to_sec(&conv_item->start_time), 'f', 9));
|
||||
setText(CONV_COLUMN_DURATION, QString::number(duration, 'f', 6));
|
||||
if (duration > min_bw_calc_duration_) {
|
||||
bps_ab = gchar_free_to_qstring(format_size((gint64) conv_item->tx_bytes * 8 / duration, format_size_unit_none|format_size_prefix_si));
|
||||
bps_ba = gchar_free_to_qstring(format_size((gint64) conv_item->rx_bytes * 8 / duration, format_size_unit_none|format_size_prefix_si));
|
||||
}
|
||||
setText(CONV_COLUMN_BPS_AB, bps_ab);
|
||||
setText(CONV_COLUMN_BPS_BA, bps_ba);
|
||||
setData(pkts_col_, Qt::UserRole, qVariantFromValue(packets));
|
||||
}
|
||||
|
||||
// Return a string, qulonglong, double, or invalid QVariant representing the raw column data.
|
||||
QVariant colData(int col, bool resolve_names) {
|
||||
conv_item_t *conv_item = data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
|
||||
if (!conv_item) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
double duration = nstime_to_sec(&conv_item->stop_time) - nstime_to_sec(&conv_item->start_time);
|
||||
double bps_ab = 0, bps_ba = 0;
|
||||
if (duration > min_bw_calc_duration_) {
|
||||
bps_ab = conv_item->tx_bytes * 8 / duration;
|
||||
bps_ba = conv_item->rx_bytes * 8 / duration;
|
||||
}
|
||||
|
||||
switch (col) {
|
||||
case CONV_COLUMN_SRC_ADDR:
|
||||
return get_conversation_address(&conv_item->src_address, resolve_names);
|
||||
case CONV_COLUMN_SRC_PORT:
|
||||
if (resolve_names) {
|
||||
return get_conversation_port(conv_item->src_port, conv_item->ptype, resolve_names);
|
||||
} else {
|
||||
return quint32(conv_item->src_port);
|
||||
}
|
||||
case CONV_COLUMN_DST_ADDR:
|
||||
return get_conversation_address(&conv_item->dst_address, resolve_names);
|
||||
case CONV_COLUMN_DST_PORT:
|
||||
if (resolve_names) {
|
||||
return get_conversation_port(conv_item->dst_port, conv_item->ptype, resolve_names);
|
||||
} else {
|
||||
return quint32(conv_item->dst_port);
|
||||
}
|
||||
case CONV_COLUMN_PACKETS:
|
||||
return quint64(conv_item->tx_frames + conv_item->rx_frames);
|
||||
case CONV_COLUMN_BYTES:
|
||||
return quint64(conv_item->tx_bytes + conv_item->rx_bytes);
|
||||
case CONV_COLUMN_PKT_AB:
|
||||
return quint64(conv_item->tx_frames);
|
||||
case CONV_COLUMN_BYTES_AB:
|
||||
return quint64(conv_item->tx_bytes);
|
||||
case CONV_COLUMN_PKT_BA:
|
||||
return quint64(conv_item->rx_frames);
|
||||
case CONV_COLUMN_BYTES_BA:
|
||||
return quint64(conv_item->rx_bytes);
|
||||
case CONV_COLUMN_START:
|
||||
return nstime_to_sec(&conv_item->start_time);
|
||||
case CONV_COLUMN_DURATION:
|
||||
return duration;
|
||||
case CONV_COLUMN_BPS_AB:
|
||||
return bps_ab;
|
||||
case CONV_COLUMN_BPS_BA:
|
||||
return bps_ba;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
bool operator< (const QTreeWidgetItem &other) const
|
||||
{
|
||||
conv_item_t *conv_item = data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
conv_item_t *other_item = other.data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
|
||||
if (!conv_item || !other_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sort_col = treeWidget()->sortColumn();
|
||||
double conv_duration = nstime_to_sec(&conv_item->stop_time) - nstime_to_sec(&conv_item->start_time);
|
||||
double other_duration = nstime_to_sec(&other_item->stop_time) - nstime_to_sec(&other_item->start_time);
|
||||
|
||||
switch(sort_col) {
|
||||
case CONV_COLUMN_SRC_ADDR:
|
||||
return cmp_address(&conv_item->src_address, &other_item->src_address) < 0 ? true : false;
|
||||
case CONV_COLUMN_SRC_PORT:
|
||||
return conv_item->src_port < other_item->src_port;
|
||||
case CONV_COLUMN_DST_ADDR:
|
||||
return cmp_address(&conv_item->dst_address, &other_item->dst_address) < 0 ? true : false;
|
||||
case CONV_COLUMN_DST_PORT:
|
||||
return conv_item->dst_port < other_item->dst_port;
|
||||
case CONV_COLUMN_PACKETS:
|
||||
return (conv_item->tx_frames + conv_item->rx_frames) < (other_item->tx_frames + other_item->rx_frames);
|
||||
case CONV_COLUMN_BYTES:
|
||||
return (conv_item->tx_bytes + conv_item->rx_bytes) < (other_item->tx_bytes + other_item->rx_bytes);
|
||||
case CONV_COLUMN_PKT_AB:
|
||||
return conv_item->tx_frames < other_item->tx_frames;
|
||||
case CONV_COLUMN_BYTES_AB:
|
||||
return conv_item->tx_bytes < other_item->tx_bytes;
|
||||
case CONV_COLUMN_PKT_BA:
|
||||
return conv_item->rx_frames < other_item->rx_frames;
|
||||
case CONV_COLUMN_BYTES_BA:
|
||||
return conv_item->rx_bytes < other_item->rx_bytes;
|
||||
case CONV_COLUMN_START:
|
||||
return nstime_to_sec(&conv_item->start_time) < nstime_to_sec(&other_item->start_time);
|
||||
case CONV_COLUMN_DURATION:
|
||||
return conv_duration < other_duration;
|
||||
case CONV_COLUMN_BPS_AB:
|
||||
return conv_item->tx_bytes / conv_duration < other_item->tx_bytes / other_duration;
|
||||
case CONV_COLUMN_BPS_BA:
|
||||
return conv_item->rx_bytes / conv_duration < other_item->rx_bytes / other_duration;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
ConversationTreeWidget::ConversationTreeWidget(QWidget *parent, register_ct_t* table) :
|
||||
QTreeWidget(parent),
|
||||
table_(table),
|
||||
hash_(),
|
||||
resolve_names_(false)
|
||||
{
|
||||
setRootIsDecorated(false);
|
||||
sortByColumn(0, Qt::AscendingOrder);
|
||||
|
||||
setColumnCount(CONV_NUM_COLUMNS);
|
||||
|
||||
for (int i = 0; i < CONV_NUM_COLUMNS; i++) {
|
||||
headerItem()->setText(i, column_titles[i]);
|
||||
}
|
||||
|
||||
if (get_conversation_hide_ports(table_)) {
|
||||
hideColumn(CONV_COLUMN_SRC_PORT);
|
||||
hideColumn(CONV_COLUMN_DST_PORT);
|
||||
} else if (!strcmp(proto_get_protocol_filter_name(get_conversation_proto_id(table_)), "ncp")) {
|
||||
headerItem()->setText(CONV_COLUMN_SRC_PORT, conn_a_title);
|
||||
headerItem()->setText(CONV_COLUMN_DST_PORT, conn_b_title);
|
||||
}
|
||||
|
||||
int one_en = fontMetrics().height() / 2;
|
||||
for (int i = 0; i < CONV_NUM_COLUMNS; i++) {
|
||||
switch (i) {
|
||||
case CONV_COLUMN_SRC_ADDR:
|
||||
case CONV_COLUMN_DST_ADDR:
|
||||
setColumnWidth(i, one_en * strlen("000.000.000.000"));
|
||||
break;
|
||||
case CONV_COLUMN_SRC_PORT:
|
||||
case CONV_COLUMN_DST_PORT:
|
||||
setColumnWidth(i, one_en * strlen("000000"));
|
||||
break;
|
||||
case CONV_COLUMN_PACKETS:
|
||||
case CONV_COLUMN_PKT_AB:
|
||||
case CONV_COLUMN_PKT_BA:
|
||||
setColumnWidth(i, one_en * strlen("00,000"));
|
||||
break;
|
||||
case CONV_COLUMN_BYTES:
|
||||
case CONV_COLUMN_BYTES_AB:
|
||||
case CONV_COLUMN_BYTES_BA:
|
||||
setColumnWidth(i, one_en * strlen("000,000"));
|
||||
break;
|
||||
case CONV_COLUMN_START:
|
||||
setColumnWidth(i, one_en * strlen("00.000"));
|
||||
break;
|
||||
case CONV_COLUMN_DURATION:
|
||||
setColumnWidth(i, one_en * strlen("00.000000"));
|
||||
break;
|
||||
case CONV_COLUMN_BPS_AB:
|
||||
case CONV_COLUMN_BPS_BA:
|
||||
setColumnWidth(i, one_en * strlen("000 k"));
|
||||
break;
|
||||
default:
|
||||
setColumnWidth(i, one_en * 5);
|
||||
}
|
||||
}
|
||||
|
||||
QMenu *submenu;
|
||||
|
||||
initDirectionMap();
|
||||
|
||||
FilterAction::Action cur_action = FilterAction::ActionApply;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
||||
QMenu *subsubmenu = submenu->addMenu(FilterAction::actionTypeName(at));
|
||||
foreach (FilterAction::ActionDirection ad, FilterAction::actionDirections()) {
|
||||
FilterAction *fa = new FilterAction(subsubmenu, cur_action, at, ad);
|
||||
subsubmenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
}
|
||||
|
||||
cur_action = FilterAction::ActionPrepare;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
||||
QMenu *subsubmenu = submenu->addMenu(FilterAction::actionTypeName(at));
|
||||
foreach (FilterAction::ActionDirection ad, FilterAction::actionDirections()) {
|
||||
FilterAction *fa = new FilterAction(subsubmenu, cur_action, at, ad);
|
||||
subsubmenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
}
|
||||
|
||||
cur_action = FilterAction::ActionFind;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionDirection ad, FilterAction::actionDirections()) {
|
||||
FilterAction *fa = new FilterAction(submenu, cur_action, FilterAction::ActionTypePlain, ad);
|
||||
submenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
|
||||
cur_action = FilterAction::ActionColorize;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionDirection ad, FilterAction::actionDirections()) {
|
||||
FilterAction *fa = new FilterAction(submenu, cur_action, FilterAction::ActionTypePlain, ad);
|
||||
submenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
|
||||
updateItems();
|
||||
|
||||
connect(wsApp, SIGNAL(addressResolutionChanged()), this, SLOT(updateItems()));
|
||||
}
|
||||
|
||||
ConversationTreeWidget::~ConversationTreeWidget() {
|
||||
remove_tap_listener(&hash_);
|
||||
reset_conversation_table_data(&hash_);
|
||||
}
|
||||
|
||||
// Callbacks for register_tap_listener
|
||||
void ConversationTreeWidget::tapReset(void *conv_tree_ptr)
|
||||
{
|
||||
conv_hash_t *hash = (conv_hash_t*)conv_tree_ptr;
|
||||
ConversationTreeWidget *conv_tree = static_cast<ConversationTreeWidget *>(hash->user_data);
|
||||
if (!conv_tree) return;
|
||||
|
||||
conv_tree->clear();
|
||||
reset_conversation_table_data(&conv_tree->hash_);
|
||||
}
|
||||
|
||||
void ConversationTreeWidget::tapDraw(void *conv_tree_ptr)
|
||||
{
|
||||
conv_hash_t *hash = (conv_hash_t*)conv_tree_ptr;
|
||||
ConversationTreeWidget *conv_tree = static_cast<ConversationTreeWidget *>(hash->user_data);
|
||||
if (!conv_tree) return;
|
||||
|
||||
conv_tree->updateItems();
|
||||
}
|
||||
|
||||
QList<QVariant> ConversationTreeWidget::rowData(int row)
|
||||
{
|
||||
QList<QVariant> row_data;
|
||||
|
||||
for (int col = 0; col < columnCount(); col++) {
|
||||
if (isColumnHidden(col) || row >= topLevelItemCount()) {
|
||||
continue;
|
||||
}
|
||||
if (row < 0) {
|
||||
row_data << headerItem()->text(col);
|
||||
} else {
|
||||
ConversationTreeWidgetItem *ci = static_cast<ConversationTreeWidgetItem *>(topLevelItem(row));
|
||||
if (ci) {
|
||||
row_data << ci->colData(col, resolve_names_);
|
||||
}
|
||||
}
|
||||
}
|
||||
return row_data;
|
||||
}
|
||||
|
||||
void ConversationTreeWidget::setNameResolutionEnabled(bool enable)
|
||||
{
|
||||
if (resolve_names_ != enable) {
|
||||
resolve_names_ = enable;
|
||||
updateItems();
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationTreeWidget::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
bool enable = selectedItems().count() > 0 ? true : false;
|
||||
|
||||
foreach (QMenu *submenu, ctx_menu_.findChildren<QMenu*>()) {
|
||||
submenu->setEnabled(enable);
|
||||
}
|
||||
|
||||
ctx_menu_.exec(event->globalPos());
|
||||
}
|
||||
|
||||
void ConversationTreeWidget::initDirectionMap()
|
||||
{
|
||||
if (fad_to_cd_.size() > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
fad_to_cd_[FilterAction::ActionDirectionAToFromB] = CONV_DIR_A_TO_FROM_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAToB] = CONV_DIR_A_TO_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAFromB] = CONV_DIR_A_FROM_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAToFromAny] = CONV_DIR_A_TO_FROM_ANY;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAToAny] = CONV_DIR_A_TO_ANY;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAFromAny] = CONV_DIR_A_FROM_ANY;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAnyToFromB] = CONV_DIR_ANY_TO_FROM_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAnyToB] = CONV_DIR_ANY_TO_B;
|
||||
fad_to_cd_[FilterAction::ActionDirectionAnyFromB] = CONV_DIR_ANY_FROM_B;
|
||||
}
|
||||
|
||||
void ConversationTreeWidget::updateItems() {
|
||||
title_ = proto_get_protocol_short_name(find_protocol_by_id(get_conversation_proto_id(table_)));
|
||||
|
||||
if (hash_.conv_array && hash_.conv_array->len > 0) {
|
||||
title_.append(QString(" %1 %2").arg(UTF8_MIDDLE_DOT).arg(hash_.conv_array->len));
|
||||
}
|
||||
emit titleChanged(this, title_);
|
||||
|
||||
if (!hash_.conv_array) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSortingEnabled(false);
|
||||
for (int i = topLevelItemCount(); i < (int) hash_.conv_array->len; i++) {
|
||||
ConversationTreeWidgetItem *ctwi = new ConversationTreeWidgetItem(this);
|
||||
conv_item_t *conv_item = &g_array_index(hash_.conv_array, conv_item_t, i);
|
||||
ctwi->setData(ci_col_, Qt::UserRole, qVariantFromValue(conv_item));
|
||||
addTopLevelItem(ctwi);
|
||||
|
||||
for (int col = 0; col < columnCount(); col++) {
|
||||
switch (col) {
|
||||
case CONV_COLUMN_SRC_ADDR:
|
||||
case CONV_COLUMN_DST_ADDR:
|
||||
break;
|
||||
default:
|
||||
ctwi->setTextAlignment(col, Qt::AlignRight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
QTreeWidgetItemIterator iter(this);
|
||||
while (*iter) {
|
||||
ConversationTreeWidgetItem *ci = static_cast<ConversationTreeWidgetItem *>(*iter);
|
||||
ci->update(resolve_names_);
|
||||
++iter;
|
||||
}
|
||||
setSortingEnabled(true);
|
||||
|
||||
for (int col = 0; col < columnCount(); col++) {
|
||||
resizeColumnToContents(col);
|
||||
}
|
||||
}
|
||||
|
||||
void ConversationTreeWidget::filterActionTriggered()
|
||||
{
|
||||
if (selectedItems().count() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
FilterAction *fa = qobject_cast<FilterAction *>(QObject::sender());
|
||||
ConversationTreeWidgetItem *ctwi = static_cast<ConversationTreeWidgetItem *>(selectedItems()[0]);
|
||||
if (!fa || !ctwi) {
|
||||
return;
|
||||
}
|
||||
|
||||
conv_item_t *conv_item = ctwi->data(ci_col_, Qt::UserRole).value<conv_item_t *>();
|
||||
if (!conv_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString filter = get_conversation_filter(conv_item, fad_to_cd_[fa->actionDirection()]);
|
||||
emit filterAction(filter, fa->action(), fa->actionType());
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
* Local Variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* ex: set shiftwidth=4 tabstop=8 expandtab:
|
||||
* :indentSize=4:tabSize=8:noTabs=true:
|
||||
*/
|
|
@ -1,112 +0,0 @@
|
|||
/* conversation_tree_widget.h
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef CONVERSATION_TREE_WIDGET_H
|
||||
#define CONVERSATION_TREE_WIDGET_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <epan/packet.h>
|
||||
#include <epan/tap.h>
|
||||
#include "epan/conversation_table.h"
|
||||
|
||||
#include "ui/conversation_ui.h"
|
||||
|
||||
#include "filter_action.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QTreeWidget>
|
||||
|
||||
Q_DECLARE_METATYPE(conv_item_t *)
|
||||
|
||||
class ConversationTreeWidget : public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ConversationTreeWidget(QWidget *parent, register_ct_t* table);
|
||||
~ConversationTreeWidget();
|
||||
|
||||
static void tapReset(void *conv_tree_ptr);
|
||||
static void tapDraw(void *conv_tree_ptr);
|
||||
|
||||
// String, int, or double data for each column in a row.
|
||||
// Passing -1 returns titles.
|
||||
QList<QVariant> rowData(int row);
|
||||
|
||||
// Title string plus optional count
|
||||
const QString &conversationTitle() { return title_; }
|
||||
conv_hash_t* conversationHash() {return &hash_;}
|
||||
|
||||
signals:
|
||||
void titleChanged(QWidget *tree, const QString &text);
|
||||
void filterAction(QString& filter, FilterAction::Action action, FilterAction::ActionType type);
|
||||
|
||||
public slots:
|
||||
void setNameResolutionEnabled(bool enable);
|
||||
|
||||
protected:
|
||||
void contextMenuEvent(QContextMenuEvent *event);
|
||||
|
||||
private:
|
||||
register_ct_t* table_;
|
||||
QString title_;
|
||||
conv_hash_t hash_;
|
||||
bool resolve_names_;
|
||||
QMenu ctx_menu_;
|
||||
|
||||
void initDirectionMap();
|
||||
int tapEthernetPacket(packet_info *pinfo, const void *vip);
|
||||
int tapFibreChannelPacket(packet_info *pinfo, const void *vip);
|
||||
int tapFddiPacket(packet_info *pinfo, const void *vip);
|
||||
int tapIPv4Packet(packet_info *pinfo, const void *vip);
|
||||
int tapIPv6Packet(packet_info *pinfo, const void *vip);
|
||||
int tapIpxPacket(packet_info *pinfo, const void *vip);
|
||||
int tapJxtaPacket(packet_info *pinfo, const void *vip);
|
||||
int tapNcpPacket(packet_info *pinfo, const void *vip);
|
||||
int tapRsvpPacket(packet_info *pinfo, const void *vip);
|
||||
int tapSctpPacket(packet_info *pinfo, const void *vip);
|
||||
int tapTcpPacket(packet_info *pinfo, const void *vip);
|
||||
int tapTokenRingPacket(packet_info *pinfo, const void *vip);
|
||||
int tapUdpPacket(packet_info *pinfo, const void *vip);
|
||||
int tapUsbPacket(packet_info *pinfo, const void *vip);
|
||||
int tapWlanPacket(packet_info *pinfo, const void *vip);
|
||||
|
||||
private slots:
|
||||
void updateItems();
|
||||
void filterActionTriggered();
|
||||
};
|
||||
|
||||
#endif // CONVERSATION_TREE_WIDGET_H
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
* Local Variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* ex: set shiftwidth=4 tabstop=8 expandtab:
|
||||
* :indentSize=4:tabSize=8:noTabs=true:
|
||||
*/
|
|
@ -0,0 +1,545 @@
|
|||
/* endpoint_dialog.cpp
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "endpoint_dialog.h"
|
||||
|
||||
#ifdef HAVE_GEOIP
|
||||
#include <GeoIP.h>
|
||||
#include <epan/geoip_db.h>
|
||||
#include <wsutil/pint.h>
|
||||
#endif
|
||||
|
||||
#include "ui/recent.h"
|
||||
#include "ui/traffic_table_ui.h"
|
||||
|
||||
#include "wsutil/str_util.h"
|
||||
|
||||
#include "qt_ui_utils.h"
|
||||
|
||||
#include "wireshark_application.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
|
||||
const QString table_name_ = QObject::tr("Endpoint");
|
||||
EndpointDialog::EndpointDialog(QWidget *parent, capture_file *cf, int cli_proto_id, const char *filter) :
|
||||
TrafficTableDialog(parent, cf, filter, table_name_)
|
||||
{
|
||||
QList<int> endp_protos;
|
||||
for (GList *endp_tab = recent.endpoint_tabs; endp_tab; endp_tab = endp_tab->next) {
|
||||
int proto_id = proto_get_id_by_short_name((const char *)endp_tab->data);
|
||||
if (proto_id > -1 && !endp_protos.contains(proto_id)) {
|
||||
endp_protos.append(proto_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (endp_protos.isEmpty()) {
|
||||
endp_protos = defaultProtos();
|
||||
}
|
||||
|
||||
// Bring the command-line specified type to the front.
|
||||
if (get_conversation_by_proto_id(cli_proto_id)) {
|
||||
endp_protos.removeAll(cli_proto_id);
|
||||
endp_protos.prepend(cli_proto_id);
|
||||
}
|
||||
|
||||
// QTabWidget selects the first item by default.
|
||||
foreach (int endp_proto, endp_protos) {
|
||||
addTrafficTable(get_conversation_by_proto_id(endp_proto));
|
||||
}
|
||||
|
||||
fillTypeMenu(endp_protos);
|
||||
|
||||
updateWidgets();
|
||||
itemSelectionChanged();
|
||||
|
||||
if (cap_file_) {
|
||||
cf_retap_packets(cap_file_);
|
||||
}
|
||||
}
|
||||
|
||||
EndpointDialog::~EndpointDialog()
|
||||
{
|
||||
prefs_clear_string_list(recent.endpoint_tabs);
|
||||
recent.endpoint_tabs = NULL;
|
||||
|
||||
EndpointTreeWidget *cur_tree = qobject_cast<EndpointTreeWidget *>(trafficTableTabWidget()->currentWidget());
|
||||
foreach (QAction *ea, traffic_type_menu_.actions()) {
|
||||
int proto_id = ea->data().value<int>();
|
||||
if (proto_id_to_tree_.contains(proto_id) && ea->isChecked()) {
|
||||
char *title = g_strdup(proto_get_protocol_short_name(find_protocol_by_id(proto_id)));
|
||||
if (proto_id_to_tree_[proto_id] == cur_tree) {
|
||||
recent.endpoint_tabs = g_list_prepend(recent.endpoint_tabs, title);
|
||||
} else {
|
||||
recent.endpoint_tabs = g_list_append(recent.endpoint_tabs, title);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EndpointDialog::setCaptureFile(capture_file *cf)
|
||||
{
|
||||
if (!cf) { // We only want to know when the file closes.
|
||||
cap_file_ = NULL;
|
||||
for (int i = 0; i < trafficTableTabWidget()->count(); i++) {
|
||||
EndpointTreeWidget *cur_tree = qobject_cast<EndpointTreeWidget *>(trafficTableTabWidget()->widget(i));
|
||||
remove_tap_listener(cur_tree->trafficTreeHash());
|
||||
disconnect(cur_tree, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
|
||||
this, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
|
||||
}
|
||||
displayFilterCheckBox()->setEnabled(false);
|
||||
enabledTypesPushButton()->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool EndpointDialog::addTrafficTable(register_ct_t *table)
|
||||
{
|
||||
int proto_id = get_conversation_proto_id(table);
|
||||
|
||||
if (!table || proto_id_to_tree_.contains(proto_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EndpointTreeWidget *endp_tree = new EndpointTreeWidget(this, table);
|
||||
|
||||
proto_id_to_tree_[proto_id] = endp_tree;
|
||||
const char* table_name = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
|
||||
|
||||
trafficTableTabWidget()->addTab(endp_tree, table_name);
|
||||
|
||||
connect(endp_tree, SIGNAL(itemSelectionChanged()),
|
||||
this, SLOT(itemSelectionChanged()));
|
||||
connect(endp_tree, SIGNAL(titleChanged(QWidget*,QString)),
|
||||
this, SLOT(setTabText(QWidget*,QString)));
|
||||
connect(endp_tree, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
|
||||
this, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
|
||||
connect(nameResolutionCheckBox(), SIGNAL(toggled(bool)),
|
||||
endp_tree, SLOT(setNameResolutionEnabled(bool)));
|
||||
|
||||
// XXX Move to ConversationTreeWidget ctor?
|
||||
const char *filter = NULL;
|
||||
if (displayFilterCheckBox()->isChecked()) {
|
||||
filter = cap_file_->dfilter;
|
||||
} else if (!filter_.isEmpty()) {
|
||||
filter = filter_.toUtf8().constData();
|
||||
}
|
||||
|
||||
endp_tree->trafficTreeHash()->user_data = endp_tree;
|
||||
|
||||
GString *error_string = register_tap_listener(proto_get_protocol_filter_name(proto_id), endp_tree->trafficTreeHash(), filter, 0,
|
||||
EndpointTreeWidget::tapReset,
|
||||
get_hostlist_packet_func(table),
|
||||
EndpointTreeWidget::tapDraw);
|
||||
|
||||
if (error_string) {
|
||||
QMessageBox::warning(this, tr("Endpoint %1 failed to register tap listener").arg(table_name),
|
||||
error_string->str);
|
||||
g_string_free(error_string, TRUE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EndpointDialog::on_buttonBox_helpRequested()
|
||||
{
|
||||
wsApp->helpTopicAction(HELP_STATS_ENDPOINTS_DIALOG);
|
||||
}
|
||||
|
||||
void init_endpoint_table(struct register_ct* ct, const char *filter)
|
||||
{
|
||||
Q_UNUSED(ct)
|
||||
wsApp->emitStatCommandSignal("Endpoints", filter, GINT_TO_POINTER(get_conversation_proto_id(ct)));
|
||||
}
|
||||
|
||||
// EndpointTreeWidgetItem
|
||||
// TrafficTableTreeWidgetItem / QTreeWidgetItem subclass that allows sorting
|
||||
|
||||
const int ei_col_ = 0;
|
||||
const int pkts_col_ = 1;
|
||||
|
||||
const char *geoip_none_ = "-";
|
||||
|
||||
class EndpointTreeWidgetItem : public TrafficTableTreeWidgetItem
|
||||
{
|
||||
public:
|
||||
EndpointTreeWidgetItem(QTreeWidget *tree) : TrafficTableTreeWidgetItem(tree) {}
|
||||
EndpointTreeWidgetItem(QTreeWidget *parent, const QStringList &strings)
|
||||
: TrafficTableTreeWidgetItem (parent, strings) {}
|
||||
|
||||
// Set column text to its cooked representation.
|
||||
void update(gboolean resolve_names) {
|
||||
hostlist_talker_t *endp_item = data(ei_col_, Qt::UserRole).value<hostlist_talker_t *>();
|
||||
bool ok;
|
||||
quint64 cur_packets = data(pkts_col_, Qt::UserRole).toULongLong(&ok);
|
||||
|
||||
if (!endp_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
quint64 packets = endp_item->tx_frames + endp_item->rx_frames;
|
||||
if (ok && cur_packets == packets) {
|
||||
return;
|
||||
}
|
||||
|
||||
setText(ENDP_COLUMN_ADDR, get_conversation_address(&endp_item->myaddress, resolve_names));
|
||||
setText(ENDP_COLUMN_PORT, get_conversation_port(endp_item->port, endp_item->ptype, resolve_names));
|
||||
|
||||
QString col_str;
|
||||
|
||||
col_str = QString("%L1").arg(packets);
|
||||
setText(ENDP_COLUMN_PACKETS, col_str);
|
||||
col_str = gchar_free_to_qstring(format_size(endp_item->tx_bytes + endp_item->rx_bytes, format_size_unit_none|format_size_prefix_si));
|
||||
setText(ENDP_COLUMN_BYTES, col_str);
|
||||
col_str = QString("%L1").arg(endp_item->tx_frames);
|
||||
setText(ENDP_COLUMN_PKT_AB, QString::number(endp_item->tx_frames));
|
||||
col_str = gchar_free_to_qstring(format_size(endp_item->tx_bytes, format_size_unit_none|format_size_prefix_si));
|
||||
setText(ENDP_COLUMN_BYTES_AB, col_str);
|
||||
col_str = QString("%L1").arg(endp_item->rx_frames);
|
||||
setText(ENDP_COLUMN_PKT_BA, QString::number(endp_item->rx_frames));
|
||||
col_str = gchar_free_to_qstring(format_size(endp_item->rx_bytes, format_size_unit_none|format_size_prefix_si));
|
||||
setText(ENDP_COLUMN_BYTES_BA, col_str);
|
||||
setData(pkts_col_, Qt::UserRole, qVariantFromValue(packets));
|
||||
|
||||
#ifdef HAVE_GEOIP
|
||||
/* Filled in from the GeoIP config, if any */
|
||||
for (unsigned i = 0; i < geoip_db_num_dbs(); i++) {
|
||||
if (endp_item->myaddress.type == AT_IPv4) {
|
||||
setText(ENDP_NUM_COLUMNS+i, geoip_db_lookup_ipv4(i, pntoh32(endp_item->myaddress.data), geoip_none_));
|
||||
} else if (endp_item->myaddress.type == AT_IPv6) {
|
||||
const struct e_in6_addr *addr = (const struct e_in6_addr *) endp_item->myaddress.data;
|
||||
setText(ENDP_NUM_COLUMNS+i, geoip_db_lookup_ipv6(i, *addr, geoip_none_));
|
||||
} else {
|
||||
setText(ENDP_NUM_COLUMNS+i, geoip_none_);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Return a string, qulonglong, double, or invalid QVariant representing the raw column data.
|
||||
QVariant colData(int col, bool resolve_names) const {
|
||||
hostlist_talker_t *endp_item = data(ei_col_, Qt::UserRole).value<hostlist_talker_t *>();
|
||||
|
||||
if (!endp_item) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (col) {
|
||||
case ENDP_COLUMN_ADDR:
|
||||
return get_conversation_address(&endp_item->myaddress, resolve_names);
|
||||
case ENDP_COLUMN_PORT:
|
||||
if (resolve_names) {
|
||||
return get_conversation_port(endp_item->port, endp_item->ptype, resolve_names);
|
||||
} else {
|
||||
return quint32(endp_item->port);
|
||||
}
|
||||
case ENDP_COLUMN_PACKETS:
|
||||
return quint64(endp_item->tx_frames + endp_item->rx_frames);
|
||||
case ENDP_COLUMN_BYTES:
|
||||
return quint64(endp_item->tx_bytes + endp_item->rx_bytes);
|
||||
case ENDP_COLUMN_PKT_AB:
|
||||
return quint64(endp_item->tx_frames);
|
||||
case ENDP_COLUMN_BYTES_AB:
|
||||
return quint64(endp_item->tx_bytes);
|
||||
case ENDP_COLUMN_PKT_BA:
|
||||
return quint64(endp_item->rx_frames);
|
||||
case ENDP_COLUMN_BYTES_BA:
|
||||
return quint64(endp_item->rx_bytes);
|
||||
#ifdef HAVE_GEOIP
|
||||
default:
|
||||
{
|
||||
bool ok;
|
||||
|
||||
double dval = text(col).toDouble(&ok);
|
||||
if (ok) { // Assume lat / lon
|
||||
return dval;
|
||||
}
|
||||
|
||||
qulonglong ullval = text(col).toULongLong(&ok);
|
||||
if (ok) { // Assume lat / lon
|
||||
return ullval;
|
||||
}
|
||||
|
||||
qlonglong llval = text(col).toLongLong(&ok);
|
||||
if (ok) { // Assume lat / lon
|
||||
return llval;
|
||||
}
|
||||
|
||||
return text(col);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
default:
|
||||
return QVariant();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool operator< (const QTreeWidgetItem &other) const
|
||||
{
|
||||
hostlist_talker_t *endp_item = data(ei_col_, Qt::UserRole).value<hostlist_talker_t *>();
|
||||
hostlist_talker_t *other_item = other.data(ei_col_, Qt::UserRole).value<hostlist_talker_t *>();
|
||||
|
||||
if (!endp_item || !other_item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sort_col = treeWidget()->sortColumn();
|
||||
|
||||
switch(sort_col) {
|
||||
case ENDP_COLUMN_ADDR:
|
||||
return cmp_address(&endp_item->myaddress, &other_item->myaddress) < 0 ? true : false;
|
||||
case ENDP_COLUMN_PORT:
|
||||
return endp_item->port < other_item->port;
|
||||
case ENDP_COLUMN_PACKETS:
|
||||
return (endp_item->tx_frames + endp_item->rx_frames) < (other_item->tx_frames + other_item->rx_frames);
|
||||
case ENDP_COLUMN_BYTES:
|
||||
return (endp_item->tx_bytes + endp_item->rx_bytes) < (other_item->tx_bytes + other_item->rx_bytes);
|
||||
case ENDP_COLUMN_PKT_AB:
|
||||
return endp_item->tx_frames < other_item->tx_frames;
|
||||
case ENDP_COLUMN_BYTES_AB:
|
||||
return endp_item->tx_bytes < other_item->tx_bytes;
|
||||
case ENDP_COLUMN_PKT_BA:
|
||||
return endp_item->rx_frames < other_item->rx_frames;
|
||||
case ENDP_COLUMN_BYTES_BA:
|
||||
return endp_item->rx_bytes < other_item->rx_bytes;
|
||||
#ifdef HAVE_GEOIP
|
||||
default:
|
||||
{
|
||||
double ei_val, oi_val;
|
||||
bool ei_ok, oi_ok;
|
||||
ei_val = text(sort_col).toDouble(&ei_ok);
|
||||
oi_val = other.text(sort_col).toDouble(&oi_ok);
|
||||
|
||||
if (ei_ok && oi_ok) { // Assume lat / lon
|
||||
return ei_val < oi_val;
|
||||
} else {
|
||||
// XXX Fall back to string comparison. We might want to try sorting naturally
|
||||
// using QCollator instead.
|
||||
return text(sort_col) < other.text(sort_col);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#else
|
||||
default:
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
// EndpointTreeWidget
|
||||
// TrafficTableTreeWidget / QTreeWidget subclass that allows tapping
|
||||
//
|
||||
|
||||
EndpointTreeWidget::EndpointTreeWidget(QWidget *parent, register_ct_t *table) :
|
||||
TrafficTableTreeWidget(parent, table)
|
||||
{
|
||||
#ifdef HAVE_GEOIP
|
||||
setColumnCount(ENDP_NUM_COLUMNS + geoip_db_num_dbs());
|
||||
#else
|
||||
setColumnCount(ENDP_NUM_BUILTIN_COLUMNS);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < ENDP_NUM_COLUMNS; i++) {
|
||||
headerItem()->setText(i, endp_column_titles[i]);
|
||||
}
|
||||
|
||||
if (get_conversation_hide_ports(table_)) {
|
||||
hideColumn(ENDP_COLUMN_PORT);
|
||||
} else if (!strcmp(proto_get_protocol_filter_name(get_conversation_proto_id(table_)), "ncp")) {
|
||||
headerItem()->setText(ENDP_COLUMN_PORT, endp_conn_title);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GEOIP
|
||||
for (unsigned i = 0; i < geoip_db_num_dbs(); i++) {
|
||||
headerItem()->setText(ENDP_NUM_COLUMNS + i, geoip_db_name(i));
|
||||
hideColumn(ENDP_NUM_COLUMNS + i);
|
||||
}
|
||||
#endif
|
||||
|
||||
int one_en = fontMetrics().height() / 2;
|
||||
for (int i = 0; i < columnCount(); i++) {
|
||||
switch (i) {
|
||||
case ENDP_COLUMN_ADDR:
|
||||
setColumnWidth(i, one_en * strlen("000.000.000.000"));
|
||||
break;
|
||||
case ENDP_COLUMN_PORT:
|
||||
setColumnWidth(i, one_en * strlen("000000"));
|
||||
break;
|
||||
case ENDP_COLUMN_PACKETS:
|
||||
case ENDP_COLUMN_PKT_AB:
|
||||
case ENDP_COLUMN_PKT_BA:
|
||||
setColumnWidth(i, one_en * strlen("00,000"));
|
||||
break;
|
||||
case ENDP_COLUMN_BYTES:
|
||||
case ENDP_COLUMN_BYTES_AB:
|
||||
case ENDP_COLUMN_BYTES_BA:
|
||||
setColumnWidth(i, one_en * strlen("000,000"));
|
||||
break;
|
||||
default:
|
||||
setColumnWidth(i, one_en * strlen("-00.000000")); // GeoIP
|
||||
}
|
||||
}
|
||||
|
||||
QMenu *submenu;
|
||||
|
||||
FilterAction::Action cur_action = FilterAction::ActionApply;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
||||
FilterAction *fa = new FilterAction(submenu, cur_action, at);
|
||||
submenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
|
||||
cur_action = FilterAction::ActionPrepare;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
||||
FilterAction *fa = new FilterAction(submenu, cur_action, at);
|
||||
submenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
|
||||
cur_action = FilterAction::ActionFind;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
||||
FilterAction *fa = new FilterAction(submenu, cur_action, at);
|
||||
submenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
|
||||
cur_action = FilterAction::ActionColorize;
|
||||
submenu = ctx_menu_.addMenu(FilterAction::actionName(cur_action));
|
||||
foreach (FilterAction::ActionType at, FilterAction::actionTypes()) {
|
||||
FilterAction *fa = new FilterAction(submenu, cur_action, at);
|
||||
submenu->addAction(fa);
|
||||
connect(fa, SIGNAL(triggered()), this, SLOT(filterActionTriggered()));
|
||||
}
|
||||
|
||||
updateItems();
|
||||
|
||||
}
|
||||
|
||||
EndpointTreeWidget::~EndpointTreeWidget()
|
||||
{
|
||||
reset_hostlist_table_data(&hash_);
|
||||
}
|
||||
|
||||
void EndpointTreeWidget::tapReset(void *conv_hash_ptr)
|
||||
{
|
||||
conv_hash_t *hash = (conv_hash_t*)conv_hash_ptr;
|
||||
EndpointTreeWidget *endp_tree = static_cast<EndpointTreeWidget *>(hash->user_data);
|
||||
if (!endp_tree) return;
|
||||
|
||||
endp_tree->clear();
|
||||
reset_hostlist_table_data(&endp_tree->hash_);
|
||||
}
|
||||
|
||||
void EndpointTreeWidget::tapDraw(void *conv_hash_ptr)
|
||||
{
|
||||
conv_hash_t *hash = (conv_hash_t*)conv_hash_ptr;
|
||||
EndpointTreeWidget *endp_tree = static_cast<EndpointTreeWidget *>(hash->user_data);
|
||||
if (!endp_tree) return;
|
||||
|
||||
endp_tree->updateItems();
|
||||
}
|
||||
|
||||
void EndpointTreeWidget::updateItems()
|
||||
{
|
||||
title_ = proto_get_protocol_short_name(find_protocol_by_id(get_conversation_proto_id(table_)));
|
||||
|
||||
if (hash_.conv_array && hash_.conv_array->len > 0) {
|
||||
title_.append(QString(" %1 %2").arg(UTF8_MIDDLE_DOT).arg(hash_.conv_array->len));
|
||||
}
|
||||
emit titleChanged(this, title_);
|
||||
|
||||
if (!hash_.conv_array) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GEOIP
|
||||
if (topLevelItemCount() < 1 && hash_.conv_array->len > 0) {
|
||||
hostlist_talker_t *endp_item = &g_array_index(hash_.conv_array, hostlist_talker_t, 0);
|
||||
if (endp_item->myaddress.type == AT_IPv4 || endp_item->myaddress.type == AT_IPv6) {
|
||||
for (unsigned i = 0; i < geoip_db_num_dbs(); i++) {
|
||||
showColumn(ENDP_NUM_COLUMNS + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
setSortingEnabled(false);
|
||||
for (int i = topLevelItemCount(); i < (int) hash_.conv_array->len; i++) {
|
||||
EndpointTreeWidgetItem *etwi = new EndpointTreeWidgetItem(this);
|
||||
hostlist_talker_t *endp_item = &g_array_index(hash_.conv_array, hostlist_talker_t, i);
|
||||
etwi->setData(ei_col_, Qt::UserRole, qVariantFromValue(endp_item));
|
||||
addTopLevelItem(etwi);
|
||||
|
||||
for (int col = 0; col < columnCount(); col++) {
|
||||
if (col != ENDP_COLUMN_ADDR && col < ENDP_NUM_COLUMNS) {
|
||||
etwi->setTextAlignment(col, Qt::AlignRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
QTreeWidgetItemIterator iter(this);
|
||||
while (*iter) {
|
||||
EndpointTreeWidgetItem *ei = static_cast<EndpointTreeWidgetItem *>(*iter);
|
||||
ei->update(resolve_names_);
|
||||
++iter;
|
||||
}
|
||||
setSortingEnabled(true);
|
||||
|
||||
for (int col = 0; col < columnCount(); col++) {
|
||||
resizeColumnToContents(col);
|
||||
}
|
||||
}
|
||||
|
||||
void EndpointTreeWidget::filterActionTriggered()
|
||||
{
|
||||
EndpointTreeWidgetItem *etwi = static_cast<EndpointTreeWidgetItem *>(currentItem());
|
||||
FilterAction *fa = qobject_cast<FilterAction *>(QObject::sender());
|
||||
|
||||
if (!fa || !etwi) {
|
||||
return;
|
||||
}
|
||||
|
||||
hostlist_talker_t *endp_item = etwi->data(ei_col_, Qt::UserRole).value<hostlist_talker_t *>();
|
||||
if (!endp_item) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString filter = get_hostlist_filter(endp_item);
|
||||
emit filterAction(filter, fa->action(), fa->actionType());
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
* Local Variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* ex: set shiftwidth=4 tabstop=8 expandtab:
|
||||
* :indentSize=4:tabSize=8:noTabs=true:
|
||||
*/
|
|
@ -0,0 +1,88 @@
|
|||
/* endpoint_dialog.h
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef ENDPOINT_DIALOG_H
|
||||
#define ENDPOINT_DIALOG_H
|
||||
|
||||
#include "traffic_table_dialog.h"
|
||||
|
||||
Q_DECLARE_METATYPE(hostlist_talker_t *)
|
||||
|
||||
class EndpointTreeWidget : public TrafficTableTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit EndpointTreeWidget(QWidget *parent, register_ct_t* table);
|
||||
~EndpointTreeWidget();
|
||||
|
||||
static void tapReset(void *conv_hash_ptr);
|
||||
static void tapDraw(void *conv_hash_ptr);
|
||||
|
||||
private slots:
|
||||
void updateItems();
|
||||
void filterActionTriggered();
|
||||
|
||||
};
|
||||
|
||||
class EndpointDialog : public TrafficTableDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/** Create a new endpoint window.
|
||||
*
|
||||
* @param parent Parent widget.
|
||||
* @param cf Capture file. No statistics will be calculated if this is NULL.
|
||||
* @param proto_id If valid, add this protocol and bring it to the front.
|
||||
* @param filter Display filter to apply.
|
||||
*/
|
||||
explicit EndpointDialog(QWidget *parent = 0, capture_file *cf = NULL, int cli_proto_id = -1, const char *filter = NULL);
|
||||
~EndpointDialog();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void setCaptureFile(capture_file *cf);
|
||||
|
||||
private:
|
||||
QList<QAction> endp_actions_;
|
||||
|
||||
bool addTrafficTable(register_ct_t* table);
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_helpRequested();
|
||||
};
|
||||
|
||||
void init_endpoint_table(struct register_ct* ct, const char *filter);
|
||||
|
||||
#endif // ENDPOINT_DIALOG_H
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
* Local Variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* ex: set shiftwidth=4 tabstop=8 expandtab:
|
||||
* :indentSize=4:tabSize=8:noTabs=true:
|
||||
*/
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "filter_action.h"
|
||||
|
||||
FilterAction::FilterAction(QObject *parent, Action action, ActionType type, ActionDirection direction) :
|
||||
FilterAction::FilterAction(QObject *parent, FilterAction::Action action, FilterAction::ActionType type, FilterAction::ActionDirection direction) :
|
||||
QAction(parent),
|
||||
action_(action),
|
||||
type_(type),
|
||||
|
@ -30,6 +30,15 @@ FilterAction::FilterAction(QObject *parent, Action action, ActionType type, Acti
|
|||
setText(actionDirectionName(direction));
|
||||
}
|
||||
|
||||
FilterAction::FilterAction(QObject *parent, FilterAction::Action action, FilterAction::ActionType type) :
|
||||
QAction(parent),
|
||||
action_(action),
|
||||
type_(type),
|
||||
direction_(ActionDirectionAToAny)
|
||||
{
|
||||
setText(actionTypeName(type));
|
||||
}
|
||||
|
||||
|
||||
const QList<FilterAction::Action> FilterAction::actions() {
|
||||
static const QList<Action> actions_ = QList<Action>()
|
||||
|
|
|
@ -65,7 +65,8 @@ public:
|
|||
ActionDirectionAnyFromB
|
||||
};
|
||||
|
||||
explicit FilterAction(QObject *parent = 0, Action action = ActionApply, ActionType type = ActionTypePlain, ActionDirection direction = ActionDirectionAToFromB);
|
||||
explicit FilterAction(QObject *parent, Action action, ActionType type, ActionDirection direction);
|
||||
explicit FilterAction(QObject *parent, Action action, ActionType type);
|
||||
|
||||
Action action() { return action_; }
|
||||
static const QList<Action> actions();
|
||||
|
|
|
@ -143,6 +143,7 @@
|
|||
#include <qlocale.h>
|
||||
#include <qlibraryinfo.h>
|
||||
#include "conversation_dialog.h"
|
||||
#include "endpoint_dialog.h"
|
||||
|
||||
#ifdef HAVE_LIBPCAP
|
||||
capture_options global_capture_opts;
|
||||
|
@ -911,7 +912,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
register_all_tap_listeners();
|
||||
conversation_table_set_gui_info(init_conversation_table);
|
||||
hostlist_table_set_gui_info(NULL); /* XXX - TODO: Provide "GUI" function for Qt */
|
||||
hostlist_table_set_gui_info(init_endpoint_table);
|
||||
|
||||
if (ex_opt_count("read_format") > 0) {
|
||||
in_file_type = open_info_name_to_type(ex_opt_get_next("read_format"));
|
||||
|
|
|
@ -374,8 +374,10 @@ private slots:
|
|||
void on_actionStatisticsBACappObjectId_triggered();
|
||||
void on_actionStatisticsBACappService_triggered();
|
||||
void on_actionStatisticsCollectd_triggered();
|
||||
void statCommandConversation(const char *arg = NULL, void *userdata = NULL);
|
||||
void statCommandConversations(const char *arg = NULL, void *userdata = NULL);
|
||||
void on_actionStatisticsConversations_triggered();
|
||||
void statCommandEndpoints(const char *arg = NULL, void *userdata = NULL);
|
||||
void on_actionStatisticsEndpoints_triggered();
|
||||
void on_actionStatisticsHART_IP_triggered();
|
||||
void on_actionStatisticsHTTPPacketCounter_triggered();
|
||||
void on_actionStatisticsHTTPRequests_triggered();
|
||||
|
|
|
@ -109,7 +109,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>960</width>
|
||||
<height>21</height>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
|
@ -370,6 +370,7 @@
|
|||
<addaction name="actionSummary"/>
|
||||
<addaction name="actionProtocol_Hierarchy"/>
|
||||
<addaction name="actionStatisticsConversations"/>
|
||||
<addaction name="actionStatisticsEndpoints"/>
|
||||
<addaction name="actionStatisticsPacketLen"/>
|
||||
<addaction name="actionStatisticsIOGraph"/>
|
||||
<addaction name="separator"/>
|
||||
|
@ -1739,6 +1740,14 @@
|
|||
<string>Conversations at different protocol levels</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionStatisticsEndpoints">
|
||||
<property name="text">
|
||||
<string>Endpoints</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Endpoints at different protocol levels</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
#include "capture_file_dialog.h"
|
||||
#include "conversation_dialog.h"
|
||||
#include "decode_as_dialog.h"
|
||||
#include "endpoint_dialog.h"
|
||||
#include "export_object_dialog.h"
|
||||
#include "export_pdu_dialog.h"
|
||||
#include "io_graph_dialog.h"
|
||||
|
@ -2074,7 +2075,7 @@ void MainWindow::on_actionStatisticsCollectd_triggered()
|
|||
openStatisticsTreeDialog("collectd");
|
||||
}
|
||||
|
||||
void MainWindow::statCommandConversation(const char *arg, void *userdata)
|
||||
void MainWindow::statCommandConversations(const char *arg, void *userdata)
|
||||
{
|
||||
ConversationDialog *conv_dialog = new ConversationDialog(this, cap_file_, GPOINTER_TO_INT(userdata), arg);
|
||||
connect(conv_dialog, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
|
||||
|
@ -2090,7 +2091,26 @@ void MainWindow::statCommandConversation(const char *arg, void *userdata)
|
|||
|
||||
void MainWindow::on_actionStatisticsConversations_triggered()
|
||||
{
|
||||
statCommandConversation(NULL, NULL);
|
||||
statCommandConversations(NULL, NULL);
|
||||
}
|
||||
|
||||
void MainWindow::statCommandEndpoints(const char *arg, void *userdata)
|
||||
{
|
||||
EndpointDialog *endp_dialog = new EndpointDialog(this, cap_file_, GPOINTER_TO_INT(userdata), arg);
|
||||
connect(endp_dialog, SIGNAL(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)),
|
||||
this, SLOT(filterAction(QString&,FilterAction::Action,FilterAction::ActionType)));
|
||||
connect(endp_dialog, SIGNAL(openFollowStreamDialog(follow_type_t)),
|
||||
this, SLOT(openFollowStreamDialog(follow_type_t)));
|
||||
connect(endp_dialog, SIGNAL(openTcpStreamGraph(int)),
|
||||
this, SLOT(openTcpStreamDialog(int)));
|
||||
connect(this, SIGNAL(setCaptureFile(capture_file*)),
|
||||
endp_dialog, SLOT(setCaptureFile(capture_file*)));
|
||||
endp_dialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionStatisticsEndpoints_triggered()
|
||||
{
|
||||
statCommandEndpoints(NULL, NULL);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionStatisticsHART_IP_triggered()
|
||||
|
|
|
@ -0,0 +1,347 @@
|
|||
/* traffic_table_dialog.cpp
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "traffic_table_dialog.h"
|
||||
#include "ui_traffic_table_dialog.h"
|
||||
|
||||
#include <epan/addr_resolv.h>
|
||||
#include <epan/prefs.h>
|
||||
#include <epan/stat_cmd_args.h>
|
||||
|
||||
//#include <epan/dissectors/packet-tcp.h>
|
||||
|
||||
#include "ui/recent.h"
|
||||
//#include "ui/tap-tcp-stream.h"
|
||||
|
||||
#include "wireshark_application.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QClipboard>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTreeWidget>
|
||||
#include <QTextStream>
|
||||
#include <QToolButton>
|
||||
|
||||
// Bugs:
|
||||
// - Name resolution doesn't do anything if its preference is disabled.
|
||||
// - Columns don't resize correctly.
|
||||
// - Closing the capture file clears conversation data.
|
||||
|
||||
TrafficTableDialog::TrafficTableDialog(QWidget *parent, capture_file *cf, const char *filter, const QString &table_name) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::TrafficTableDialog),
|
||||
cap_file_(cf),
|
||||
filter_(filter)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
setWindowTitle(tr("Wireshark: %1s").arg(table_name));
|
||||
ui->enabledTypesPushButton->setText(tr("%1 Types").arg(table_name));
|
||||
|
||||
// XXX Use recent settings instead
|
||||
if (parent) {
|
||||
resize(parent->width(), parent->height() * 3 / 4);
|
||||
}
|
||||
|
||||
QMenu *copy_menu = new QMenu();
|
||||
QAction *ca;
|
||||
copy_bt_ = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ActionRole);
|
||||
ca = copy_menu->addAction(tr("as CSV"));
|
||||
ca->setToolTip(tr("Copy all values of this page to the clipboard in CSV (Comma Separated Values) format."));
|
||||
connect(ca, SIGNAL(triggered()), this, SLOT(copyAsCsv()));
|
||||
ca = copy_menu->addAction(tr("as YAML"));
|
||||
ca->setToolTip(tr("Copy all values of this page to the clipboard in the YAML data serialization format."));
|
||||
connect(ca, SIGNAL(triggered()), this, SLOT(copyAsYaml()));
|
||||
copy_bt_->setMenu(copy_menu);
|
||||
|
||||
ui->enabledTypesPushButton->setMenu(&traffic_type_menu_);
|
||||
ui->nameResolutionCheckBox->setChecked(gbl_resolv_flags.network_name);
|
||||
ui->trafficTableTabWidget->setFocus();
|
||||
|
||||
connect(ui->trafficTableTabWidget, SIGNAL(currentChanged(int)),
|
||||
this, SLOT(itemSelectionChanged()));
|
||||
|
||||
}
|
||||
|
||||
TrafficTableDialog::~TrafficTableDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
const QList<int> TrafficTableDialog::defaultProtos() const
|
||||
{
|
||||
// Reasonable defaults?
|
||||
return QList<int>() << proto_get_id_by_filter_name( "tcp" ) << proto_get_id_by_filter_name( "eth" )
|
||||
<< proto_get_id_by_filter_name( "ip" ) << proto_get_id_by_filter_name( "ipv6" )
|
||||
<< proto_get_id_by_filter_name( "udp" );
|
||||
}
|
||||
|
||||
void TrafficTableDialog::fillTypeMenu(QList<int> &enabled_protos)
|
||||
{
|
||||
for (guint i = 0; i < conversation_table_get_num(); i++) {
|
||||
int proto_id = get_conversation_proto_id(get_conversation_table_by_num(i));
|
||||
if (proto_id < 0) {
|
||||
continue;
|
||||
}
|
||||
QString title = proto_get_protocol_short_name(find_protocol_by_id(proto_id));
|
||||
|
||||
QAction *endp_action = new QAction(title, this);
|
||||
endp_action->setData(qVariantFromValue(proto_id));
|
||||
endp_action->setCheckable(true);
|
||||
endp_action->setChecked(enabled_protos.contains(proto_id));
|
||||
connect(endp_action, SIGNAL(triggered()), this, SLOT(toggleConversation()));
|
||||
traffic_type_menu_.addAction(endp_action);
|
||||
}
|
||||
}
|
||||
|
||||
QDialogButtonBox *TrafficTableDialog::buttonBox() const
|
||||
{
|
||||
return ui->buttonBox;
|
||||
}
|
||||
|
||||
QTabWidget *TrafficTableDialog::trafficTableTabWidget() const
|
||||
{
|
||||
return ui->trafficTableTabWidget;
|
||||
}
|
||||
|
||||
QCheckBox *TrafficTableDialog::displayFilterCheckBox() const
|
||||
{
|
||||
return ui->displayFilterCheckBox;
|
||||
}
|
||||
|
||||
QCheckBox *TrafficTableDialog::nameResolutionCheckBox() const
|
||||
{
|
||||
return ui->nameResolutionCheckBox;
|
||||
}
|
||||
|
||||
QPushButton *TrafficTableDialog::enabledTypesPushButton() const
|
||||
{
|
||||
return ui->enabledTypesPushButton;
|
||||
}
|
||||
|
||||
void TrafficTableDialog::on_nameResolutionCheckBox_toggled(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked);
|
||||
updateWidgets();
|
||||
}
|
||||
|
||||
void TrafficTableDialog::on_displayFilterCheckBox_toggled(bool checked)
|
||||
{
|
||||
if (!cap_file_) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *filter = NULL;
|
||||
if (checked) {
|
||||
filter = cap_file_->dfilter;
|
||||
} else if (!filter_.isEmpty()) {
|
||||
filter = filter_.toUtf8().constData();
|
||||
}
|
||||
|
||||
for (int i = 0; i < ui->trafficTableTabWidget->count(); i++) {
|
||||
set_tap_dfilter(ui->trafficTableTabWidget->widget(i), filter);
|
||||
}
|
||||
|
||||
cf_retap_packets(cap_file_);
|
||||
}
|
||||
|
||||
void TrafficTableDialog::setTabText(QWidget *tree, const QString &text)
|
||||
{
|
||||
// Could use QObject::sender as well
|
||||
int index = ui->trafficTableTabWidget->indexOf(tree);
|
||||
if (index >= 0) {
|
||||
ui->trafficTableTabWidget->setTabText(index, text);
|
||||
}
|
||||
}
|
||||
|
||||
void TrafficTableDialog::toggleConversation()
|
||||
{
|
||||
QAction *ca = qobject_cast<QAction *>(QObject::sender());
|
||||
if (!ca) {
|
||||
return;
|
||||
}
|
||||
|
||||
int proto_id = ca->data().value<int>();
|
||||
register_ct_t* table = get_conversation_by_proto_id(proto_id);
|
||||
|
||||
bool new_table = addTrafficTable(table);
|
||||
updateWidgets();
|
||||
|
||||
if (ca->isChecked()) {
|
||||
ui->trafficTableTabWidget->setCurrentWidget(proto_id_to_tree_[proto_id]);
|
||||
}
|
||||
|
||||
if (new_table) {
|
||||
if (cap_file_) {
|
||||
cf_retap_packets(cap_file_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrafficTableDialog::updateWidgets()
|
||||
{
|
||||
QWidget *cur_w = ui->trafficTableTabWidget->currentWidget();
|
||||
ui->trafficTableTabWidget->setUpdatesEnabled(false);
|
||||
ui->trafficTableTabWidget->clear();
|
||||
foreach (QAction *ca, traffic_type_menu_.actions()) {
|
||||
int proto_id = ca->data().value<int>();
|
||||
if (proto_id_to_tree_.contains(proto_id) && ca->isChecked()) {
|
||||
ui->trafficTableTabWidget->addTab(proto_id_to_tree_[proto_id],
|
||||
proto_id_to_tree_[proto_id]->trafficTreeTitle());
|
||||
proto_id_to_tree_[proto_id]->setNameResolutionEnabled(ui->nameResolutionCheckBox->isChecked());
|
||||
}
|
||||
}
|
||||
ui->trafficTableTabWidget->setCurrentWidget(cur_w);
|
||||
ui->trafficTableTabWidget->setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
QList<QVariant> TrafficTableDialog::curTreeRowData(int row) const
|
||||
{
|
||||
TrafficTableTreeWidget *cur_tree = qobject_cast<TrafficTableTreeWidget *>(ui->trafficTableTabWidget->currentWidget());
|
||||
if (!cur_tree) {
|
||||
return QList<QVariant>();
|
||||
}
|
||||
|
||||
return cur_tree->rowData(row);
|
||||
}
|
||||
|
||||
void TrafficTableDialog::copyAsCsv()
|
||||
{
|
||||
QTreeWidget *cur_tree = qobject_cast<QTreeWidget *>(ui->trafficTableTabWidget->currentWidget());
|
||||
if (!cur_tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString csv;
|
||||
QTextStream stream(&csv, QIODevice::Text);
|
||||
for (int row = -1; row < cur_tree->topLevelItemCount(); row ++) {
|
||||
QStringList rdsl;
|
||||
foreach (QVariant v, curTreeRowData(row)) {
|
||||
if (!v.isValid()) {
|
||||
rdsl << "\"\"";
|
||||
} else if ((int) v.type() == (int) QMetaType::QString) {
|
||||
rdsl << QString("\"%1\"").arg(v.toString());
|
||||
} else {
|
||||
rdsl << v.toString();
|
||||
}
|
||||
}
|
||||
stream << rdsl.join(",") << endl;
|
||||
}
|
||||
wsApp->clipboard()->setText(stream.readAll());
|
||||
}
|
||||
|
||||
void TrafficTableDialog::copyAsYaml()
|
||||
{
|
||||
QTreeWidget *cur_tree = qobject_cast<QTreeWidget *>(ui->trafficTableTabWidget->currentWidget());
|
||||
if (!cur_tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString yaml;
|
||||
QTextStream stream(&yaml, QIODevice::Text);
|
||||
stream << "---" << endl;
|
||||
for (int row = -1; row < cur_tree->topLevelItemCount(); row ++) {
|
||||
stream << "-" << endl;
|
||||
foreach (QVariant v, curTreeRowData(row)) {
|
||||
stream << " - " << v.toString() << endl;
|
||||
}
|
||||
}
|
||||
wsApp->clipboard()->setText(stream.readAll());
|
||||
}
|
||||
|
||||
|
||||
TrafficTableTreeWidget::TrafficTableTreeWidget(QWidget *parent, register_ct_t *table) :
|
||||
QTreeWidget(parent),
|
||||
table_(table),
|
||||
hash_(),
|
||||
resolve_names_(false)
|
||||
{
|
||||
setRootIsDecorated(false);
|
||||
sortByColumn(0, Qt::AscendingOrder);
|
||||
|
||||
connect(wsApp, SIGNAL(addressResolutionChanged()), this, SLOT(updateItems()));
|
||||
}
|
||||
|
||||
TrafficTableTreeWidget::~TrafficTableTreeWidget()
|
||||
{
|
||||
remove_tap_listener(&hash_);
|
||||
}
|
||||
|
||||
QList<QVariant> TrafficTableTreeWidget::rowData(int row) const
|
||||
{
|
||||
QList<QVariant> row_data;
|
||||
|
||||
if (row >= topLevelItemCount()) {
|
||||
return row_data;
|
||||
}
|
||||
|
||||
for (int col = 0; col < columnCount(); col++) {
|
||||
if (isColumnHidden(col)) {
|
||||
continue;
|
||||
}
|
||||
if (row < 0) {
|
||||
row_data << headerItem()->text(col);
|
||||
} else {
|
||||
TrafficTableTreeWidgetItem *ti = static_cast<TrafficTableTreeWidgetItem *>(topLevelItem(row));
|
||||
if (ti) {
|
||||
row_data << ti->colData(col, resolve_names_);
|
||||
}
|
||||
}
|
||||
}
|
||||
return row_data;
|
||||
}
|
||||
|
||||
void TrafficTableTreeWidget::setNameResolutionEnabled(bool enable)
|
||||
{
|
||||
if (resolve_names_ != enable) {
|
||||
resolve_names_ = enable;
|
||||
updateItems();
|
||||
}
|
||||
}
|
||||
|
||||
void TrafficTableTreeWidget::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
bool enable = currentItem() != NULL ? true : false;
|
||||
|
||||
foreach (QMenu *submenu, ctx_menu_.findChildren<QMenu*>()) {
|
||||
submenu->setEnabled(enable);
|
||||
}
|
||||
|
||||
ctx_menu_.exec(event->globalPos());
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
* Local Variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* ex: set shiftwidth=4 tabstop=8 expandtab:
|
||||
* :indentSize=4:tabSize=8:noTabs=true:
|
||||
*/
|
|
@ -0,0 +1,168 @@
|
|||
/* traffic_table_dialog.h
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
* Copyright 1998 Gerald Combs
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef TRAFFIC_TABLE_DIALOG_H
|
||||
#define TRAFFIC_TABLE_DIALOG_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "file.h"
|
||||
|
||||
#include "epan/conversation_table.h"
|
||||
|
||||
#include "ui/follow.h"
|
||||
|
||||
#include "filter_action.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QCheckBox>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QMenu>
|
||||
#include <QTabWidget>
|
||||
#include <QTreeWidget>
|
||||
|
||||
namespace Ui {
|
||||
class TrafficTableDialog;
|
||||
}
|
||||
|
||||
class TrafficTableTreeWidgetItem : public QTreeWidgetItem
|
||||
{
|
||||
public:
|
||||
TrafficTableTreeWidgetItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {}
|
||||
TrafficTableTreeWidgetItem(QTreeWidget *parent, const QStringList &strings)
|
||||
: QTreeWidgetItem (parent, strings) {}
|
||||
virtual QVariant colData(int col, bool resolve_names) const = 0;
|
||||
};
|
||||
|
||||
class TrafficTableTreeWidget : public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TrafficTableTreeWidget(QWidget *parent, register_ct_t* table);
|
||||
~TrafficTableTreeWidget();
|
||||
|
||||
// String, int, or double data for each column in a row.
|
||||
// Passing -1 returns titles.
|
||||
QList<QVariant> rowData(int row) const;
|
||||
|
||||
public slots:
|
||||
void setNameResolutionEnabled(bool enable);
|
||||
|
||||
// Title string plus optional count
|
||||
const QString &trafficTreeTitle() { return title_; }
|
||||
conv_hash_t* trafficTreeHash() {return &hash_;}
|
||||
|
||||
protected:
|
||||
register_ct_t* table_;
|
||||
QString title_;
|
||||
conv_hash_t hash_;
|
||||
bool resolve_names_;
|
||||
QMenu ctx_menu_;
|
||||
|
||||
void contextMenuEvent(QContextMenuEvent *event);
|
||||
|
||||
private:
|
||||
|
||||
private slots:
|
||||
virtual void updateItems() {}
|
||||
|
||||
signals:
|
||||
void titleChanged(QWidget *tree, const QString &text);
|
||||
void filterAction(QString& filter, FilterAction::Action action, FilterAction::ActionType type);
|
||||
};
|
||||
|
||||
class TrafficTableDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/** Create a new conversation window.
|
||||
*
|
||||
* @param parent Parent widget.
|
||||
* @param cf Capture file. No statistics will be calculated if this is NULL.
|
||||
* @param proto_id If valid, add this protocol and bring it to the front.
|
||||
* @param filter Display filter to apply.
|
||||
*/
|
||||
explicit TrafficTableDialog(QWidget *parent = 0, capture_file *cf = NULL, const char *filter = NULL, const QString &table_name = tr("Unknown"));
|
||||
~TrafficTableDialog();
|
||||
|
||||
public slots:
|
||||
virtual void setCaptureFile(capture_file *cf) { Q_UNUSED(cf) }
|
||||
|
||||
signals:
|
||||
void filterAction(QString& filter, FilterAction::Action action, FilterAction::ActionType type);
|
||||
void openFollowStreamDialog(follow_type_t type);
|
||||
void openTcpStreamGraph(int graph_type);
|
||||
|
||||
protected:
|
||||
Ui::TrafficTableDialog *ui;
|
||||
|
||||
capture_file *cap_file_;
|
||||
QString filter_;
|
||||
QMenu traffic_type_menu_;
|
||||
QPushButton *copy_bt_;
|
||||
QMap<int, TrafficTableTreeWidget *> proto_id_to_tree_;
|
||||
|
||||
const QList<int> defaultProtos() const;
|
||||
void fillTypeMenu(QList<int> &enabled_protos);
|
||||
// Adds a conversation tree. Returns true if the tree was freshly created, false if it was cached.
|
||||
virtual bool addTrafficTable(register_ct_t* table) { Q_UNUSED(table) return false; }
|
||||
|
||||
// UI getters
|
||||
QDialogButtonBox *buttonBox() const;
|
||||
QTabWidget *trafficTableTabWidget() const;
|
||||
QCheckBox *displayFilterCheckBox() const;
|
||||
QCheckBox *nameResolutionCheckBox() const;
|
||||
QPushButton *enabledTypesPushButton() const;
|
||||
|
||||
protected slots:
|
||||
virtual void itemSelectionChanged() {}
|
||||
void updateWidgets();
|
||||
|
||||
private:
|
||||
QList<QVariant> curTreeRowData(int row) const;
|
||||
|
||||
private slots:
|
||||
void on_nameResolutionCheckBox_toggled(bool checked);
|
||||
void on_displayFilterCheckBox_toggled(bool checked);
|
||||
void setTabText(QWidget *tree, const QString &text);
|
||||
void toggleConversation();
|
||||
|
||||
void copyAsCsv();
|
||||
void copyAsYaml();
|
||||
virtual void on_buttonBox_helpRequested() = 0;
|
||||
};
|
||||
|
||||
#endif // TRAFFIC_TABLE_DIALOG_H
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
* Local Variables:
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*
|
||||
* ex: set shiftwidth=4 tabstop=8 expandtab:
|
||||
* :indentSize=4:tabSize=8:noTabs=true:
|
||||
*/
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConversationDialog</class>
|
||||
<widget class="QDialog" name="ConversationDialog">
|
||||
<class>TrafficTableDialog</class>
|
||||
<widget class="QDialog" name="TrafficTableDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
|
@ -10,12 +10,9 @@
|
|||
<height>475</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Wireshark: Conversations</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="conversationTabWidget"/>
|
||||
<widget class="QTabWidget" name="trafficTableTabWidget"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,1,0">
|
||||
|
@ -66,13 +63,10 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="conversationTypePushButton">
|
||||
<widget class="QPushButton" name="enabledTypesPushButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Add and remove conversation types.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Conversation Types</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -94,7 +88,7 @@
|
|||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ConversationDialog</receiver>
|
||||
<receiver>TrafficTableDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
|
@ -110,7 +104,7 @@
|
|||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ConversationDialog</receiver>
|
||||
<receiver>TrafficTableDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
11
ui/recent.c
11
ui/recent.c
|
@ -74,7 +74,8 @@
|
|||
#define RECENT_GUI_GEOMETRY_WLAN_STATS_PANE "gui.geometry_status_wlan_stats_pane"
|
||||
#define RECENT_LAST_USED_PROFILE "gui.last_used_profile"
|
||||
#define RECENT_GUI_FILEOPEN_REMEMBERED_DIR "gui.fileopen_remembered_dir"
|
||||
#define RECENT_GUI_CONVERSATION_TABS "gui.conversation_tabs"
|
||||
#define RECENT_GUI_CONVERSATION_TABS "gui.conversation_tabs"
|
||||
#define RECENT_GUI_ENDPOINT_TABS "gui.endpoint_tabs"
|
||||
|
||||
#define RECENT_GUI_GEOMETRY "gui.geom."
|
||||
|
||||
|
@ -800,6 +801,12 @@ write_profile_recent(void)
|
|||
fprintf(rf, RECENT_GUI_CONVERSATION_TABS ": %s\n", string_list);
|
||||
g_free(string_list);
|
||||
|
||||
fprintf(rf, "\n# Open endpoint dialog tabs.\n");
|
||||
fprintf(rf, "# List of endpoint names, e.g. \"TCP\", \"IPv6\".\n");
|
||||
string_list = join_string_list(recent.endpoint_tabs);
|
||||
fprintf(rf, RECENT_GUI_ENDPOINT_TABS ": %s\n", string_list);
|
||||
g_free(string_list);
|
||||
|
||||
if (get_last_open_dir() != NULL) {
|
||||
fprintf(rf, "\n# Last directory navigated to in File Open dialog.\n");
|
||||
|
||||
|
@ -1036,6 +1043,8 @@ read_set_recent_pair_static(gchar *key, const gchar *value,
|
|||
recent.has_gui_geometry_main_lower_pane = TRUE;
|
||||
} else if (strcmp(key, RECENT_GUI_CONVERSATION_TABS) == 0) {
|
||||
recent.conversation_tabs = prefs_get_string_list(value);
|
||||
} else if (strcmp(key, RECENT_GUI_ENDPOINT_TABS) == 0) {
|
||||
recent.endpoint_tabs = prefs_get_string_list(value);
|
||||
} else if (strcmp(key, RECENT_KEY_COL_WIDTH) == 0) {
|
||||
col_l = prefs_get_string_list(value);
|
||||
if (col_l == NULL)
|
||||
|
|
|
@ -99,6 +99,7 @@ typedef struct recent_settings_tag {
|
|||
gboolean privs_warn_if_no_npf;
|
||||
GList *col_width_list; /* column widths */
|
||||
GList *conversation_tabs; /* enabled conversation dialog tabs */
|
||||
GList *endpoint_tabs; /* enabled endpoint dialog tabs */
|
||||
gchar *gui_fileopen_remembered_dir; /* folder of last capture loaded in File Open dialog */
|
||||
} recent_settings_t;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* conversation_ui.c
|
||||
/* traffic_table_ui.c
|
||||
* Copied from gtk/conversations_table.c 2003 Ronnie Sahlberg
|
||||
* Helper routines common to all conversations taps.
|
||||
*
|
||||
|
@ -22,10 +22,10 @@
|
|||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include "conversation_ui.h"
|
||||
#include "traffic_table_ui.h"
|
||||
#include "utf8_entities.h"
|
||||
|
||||
const char *column_titles[CONV_NUM_COLUMNS] = {
|
||||
const char *conv_column_titles[CONV_NUM_COLUMNS] = {
|
||||
"Address A",
|
||||
"Port A",
|
||||
"Address B",
|
||||
|
@ -42,10 +42,21 @@ const char *column_titles[CONV_NUM_COLUMNS] = {
|
|||
"bps B " UTF8_RIGHTWARDS_ARROW " A"
|
||||
};
|
||||
|
||||
const char *conn_a_title = "Connection A";
|
||||
const char *conn_b_title = "Connection B";
|
||||
const char *conv_conn_a_title = "Connection A";
|
||||
const char *conv_conn_b_title = "Connection B";
|
||||
|
||||
const char *endp_column_titles[ENDP_NUM_COLUMNS] = {
|
||||
"Address",
|
||||
"Port",
|
||||
"Packets",
|
||||
"Bytes",
|
||||
"Packets A " UTF8_RIGHTWARDS_ARROW " B",
|
||||
"Bytes A " UTF8_RIGHTWARDS_ARROW " B",
|
||||
"Packets B " UTF8_RIGHTWARDS_ARROW " A",
|
||||
"Bytes B " UTF8_RIGHTWARDS_ARROW " A"
|
||||
};
|
||||
|
||||
const char *endp_conn_title = "Connection";
|
||||
|
||||
/*
|
||||
* Editor modelines
|
|
@ -1,4 +1,4 @@
|
|||
/* conversation_ui.h
|
||||
/* traffic_table_ui.h
|
||||
* Copied from gtk/conversations_table.h 2003 Ronnie Sahlberg
|
||||
* Helper routines common to all conversations taps.
|
||||
*
|
||||
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
#endif /* __cplusplus */
|
||||
|
||||
/** @file
|
||||
* Conversation lists.
|
||||
* Conversation and endpoint lists.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
|
@ -51,10 +51,26 @@ typedef enum {
|
|||
CONV_INDEX_COLUMN = CONV_NUM_COLUMNS
|
||||
} conversation_column_type_e;
|
||||
|
||||
extern const char *conv_column_titles[CONV_NUM_COLUMNS];
|
||||
extern const char *conv_conn_a_title;
|
||||
extern const char *conv_conn_b_title;
|
||||
|
||||
extern const char *column_titles[CONV_NUM_COLUMNS];
|
||||
extern const char *conn_a_title;
|
||||
extern const char *conn_b_title;
|
||||
typedef enum
|
||||
{
|
||||
ENDP_COLUMN_ADDR,
|
||||
ENDP_COLUMN_PORT,
|
||||
ENDP_COLUMN_PACKETS,
|
||||
ENDP_COLUMN_BYTES,
|
||||
ENDP_COLUMN_PKT_AB,
|
||||
ENDP_COLUMN_BYTES_AB,
|
||||
ENDP_COLUMN_PKT_BA,
|
||||
ENDP_COLUMN_BYTES_BA,
|
||||
ENDP_NUM_COLUMNS,
|
||||
} endpoint_column_type_e;
|
||||
|
||||
extern const char *endp_column_titles[ENDP_NUM_COLUMNS];
|
||||
|
||||
extern const char *endp_conn_title;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
Loading…
Reference in New Issue