From 1a4033b63b1efa75b3d914b9f4d280e8159f0d09 Mon Sep 17 00:00:00 2001 From: Gerald Combs Date: Thu, 24 Oct 2013 22:52:30 +0000 Subject: [PATCH] Initial and woefully incomplete flow graph support. Copy common code from ui/gtk/flow_graph.c and ui/gtk/graph_analysis.[ch] to ui/tap-sequence-analysis.[ch]. Start using the name "sequence" in places. svn path=/trunk/; revision=52824 --- ui/CMakeLists.txt | 1 + ui/Makefile.common | 2 + ui/gtk/flow_graph.c | 330 ++----------------- ui/gtk/graph_analysis.c | 417 +++--------------------- ui/gtk/graph_analysis.h | 34 +- ui/gtk/rtp_player.c | 4 +- ui/gtk/voip_calls.c | 52 +-- ui/gtk/voip_calls.h | 2 +- ui/gtk/voip_calls_dlg.c | 17 +- ui/qt/CMakeLists.txt | 5 + ui/qt/Makefile.common | 6 + ui/qt/QtShark.pro | 4 + ui/qt/main_window.h | 1 + ui/qt/main_window.ui | 9 + ui/qt/main_window_slots.cpp | 10 + ui/qt/sequence_diagram.cpp | 227 +++++++++++++ ui/qt/sequence_diagram.h | 107 +++++++ ui/qt/sequence_dialog.cpp | 147 +++++++++ ui/qt/sequence_dialog.h | 78 +++++ ui/qt/sequence_dialog.ui | 206 ++++++++++++ ui/qt/tcp_stream_dialog.cpp | 3 +- ui/tap-sequence-analysis.c | 620 ++++++++++++++++++++++++++++++++++++ ui/tap-sequence-analysis.h | 129 ++++++++ 23 files changed, 1650 insertions(+), 761 deletions(-) create mode 100644 ui/qt/sequence_diagram.cpp create mode 100644 ui/qt/sequence_diagram.h create mode 100644 ui/qt/sequence_dialog.cpp create mode 100644 ui/qt/sequence_dialog.h create mode 100644 ui/qt/sequence_dialog.ui create mode 100644 ui/tap-sequence-analysis.c create mode 100644 ui/tap-sequence-analysis.h diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 73375a3654..d7aad7d95b 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -39,6 +39,7 @@ set(COMMON_UI_SRC software_update.c tap-megaco-common.c tap-rtp-common.c + tap-sequence-analysis.c tap-tcp-stream.c text_import.c time_shift.c diff --git a/ui/Makefile.common b/ui/Makefile.common index fc4ceb8825..93eb221065 100644 --- a/ui/Makefile.common +++ b/ui/Makefile.common @@ -60,6 +60,7 @@ WIRESHARK_UI_SRC = \ ssl_key_export.c \ tap-megaco-common.c \ tap-rtp-common.c \ + tap-sequence-analysis.c \ tap-tcp-stream.c \ text_import.c \ time_shift.c \ @@ -86,6 +87,7 @@ noinst_HEADERS = \ ssl_key_export.h \ tap-megaco-common.h \ tap-rtp-common.h \ + tap-sequence-analysis.h \ tap-tcp-stream.h \ text_import.h \ text_import_scanner.h \ diff --git a/ui/gtk/flow_graph.c b/ui/gtk/flow_graph.c index 0c0337444f..b4842f98f2 100644 --- a/ui/gtk/flow_graph.c +++ b/ui/gtk/flow_graph.c @@ -34,8 +34,6 @@ #include #include #include -#include -#include #include #include "../stat_menu.h" @@ -49,26 +47,7 @@ #include "ui/gtk/main.h" #include "ui/gtk/old-gtk-compat.h" - -#define TYPE_OF_PACKETS_DISPLAYED 0 -#define TYPE_OF_PACKETS_ALL 1 - -#define TYPE_OF_FLOW_GENERAL 0 -#define TYPE_OF_FLOW_TCP 1 - -#define NODE_ADDR_TYPE_SRCDST 0 -#define NODE_ADDR_TYPE_NET_SRCDST 1 - -static int type_of_packets = TYPE_OF_PACKETS_DISPLAYED; -static int type_of_flow = TYPE_OF_FLOW_GENERAL; -static int node_addr_type = NODE_ADDR_TYPE_SRCDST; - -static int tap_identifier; - -static gboolean have_frame_tap_listener = FALSE; -static gboolean have_tcp_tap_listener = FALSE; - -static graph_analysis_info_t *graph_analysis = NULL; +static seq_analysis_info_t *graph_analysis = NULL; static graph_analysis_data_t *graph_analysis_data = NULL; static GtkWidget *flow_graph_dlg = NULL; @@ -80,51 +59,13 @@ static GtkWidget *select_tcp_rb; static GtkWidget *src_dst_rb; static GtkWidget *net_src_dst_rb; -/****************************************************************************/ -/* free up memory and initialize the pointers */ - -static void -flow_graph_reset(void *ptr _U_) -{ - graph_analysis_item_t *graph_item; - - GList *list; - - if (graph_analysis !=NULL){ - - /* free the graph data items */ - list = g_list_first(graph_analysis->list); - while (list) - { - graph_item = (graph_analysis_item_t *)list->data; - g_free(graph_item->frame_label); - g_free(graph_item->comment); - g_free(list->data); - list = g_list_next(list); - } - g_list_free(graph_analysis->list); - graph_analysis->nconv = 0; - graph_analysis->list = NULL; - } -} /****************************************************************************/ static void flow_graph_data_init(void) { - graph_analysis = (graph_analysis_info_t *)g_malloc(sizeof(graph_analysis_info_t)); - graph_analysis->nconv = 0; - graph_analysis->list = NULL; -} - - -/****************************************************************************/ -static void -remove_tap_listener_flow_graph(void) -{ - remove_tap_listener(&(tap_identifier)); - - have_frame_tap_listener=FALSE; - have_tcp_tap_listener=FALSE; + graph_analysis = (seq_analysis_info_t *)g_malloc0(sizeof(seq_analysis_info_t)); + graph_analysis->type = SEQ_ANALYSIS_ANY; + graph_analysis->all_packets = TRUE; } @@ -134,11 +75,8 @@ remove_tap_listener_flow_graph(void) static void flow_graph_on_destroy(GObject *object _U_, gpointer user_data _U_) { - /* remove_tap_listeners */ - remove_tap_listener_flow_graph(); - /* Clean up memory used by tap */ - flow_graph_reset(NULL); + sequence_analysis_list_free(graph_analysis); g_assert(graph_analysis != NULL); g_assert(graph_analysis_data != NULL); @@ -160,7 +98,7 @@ toggle_select_all(GtkWidget *widget _U_, gpointer user_data _U_) { /* is the button now active? */ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_all_rb))) { - type_of_packets = TYPE_OF_PACKETS_ALL; + graph_analysis->all_packets = TRUE; } } @@ -170,7 +108,7 @@ toggle_select_displayed(GtkWidget *widget _U_, gpointer user_data _U_) { /* is the button now active? */ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_displayed_rb))) { - type_of_packets = TYPE_OF_PACKETS_DISPLAYED; + graph_analysis->all_packets = FALSE; } } @@ -180,7 +118,7 @@ toggle_select_general(GtkWidget *widget _U_, gpointer user_data _U_) { /* is the button now active? */ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_general_rb))) { - type_of_flow = TYPE_OF_FLOW_GENERAL; + graph_analysis->type = SEQ_ANALYSIS_ANY; } } @@ -190,7 +128,7 @@ toggle_select_tcp(GtkWidget *widget _U_, gpointer user_data _U_) { /* is the button now active? */ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(select_tcp_rb))) { - type_of_flow = TYPE_OF_FLOW_TCP; + graph_analysis->type = SEQ_ANALYSIS_TCP; } } @@ -200,7 +138,7 @@ toggle_select_srcdst(GtkWidget *widget _U_, gpointer user_data _U_) { /* is the button now active? */ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(src_dst_rb))) { - node_addr_type = NODE_ADDR_TYPE_SRCDST; + graph_analysis->any_addr = FALSE; } } @@ -210,245 +148,18 @@ toggle_select_netsrcdst(GtkWidget *widget _U_, gpointer user_data _U_) { /* is the button now active? */ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(net_src_dst_rb))) { - node_addr_type = NODE_ADDR_TYPE_NET_SRCDST; + graph_analysis->any_addr = TRUE; } } -/****************************************************************************/ -/* Add a new frame into the graph */ -static int -flow_graph_frame_add_to_graph(packet_info *pinfo) -{ - graph_analysis_item_t *gai; - int i; - gchar *protocol; - gchar *colinfo; - - protocol=NULL; - colinfo=NULL; - - if (node_addr_type == NODE_ADDR_TYPE_NET_SRCDST) { - if (pinfo->net_src.type!=AT_NONE && pinfo->net_dst.type!=AT_NONE) { - gai = (graph_analysis_item_t *)g_malloc(sizeof(graph_analysis_item_t)); - COPY_ADDRESS(&(gai->src_addr),&(pinfo->net_src)); - COPY_ADDRESS(&(gai->dst_addr),&(pinfo->net_dst)); - } - else return 0; - - } else { - if (pinfo->src.type!=AT_NONE && pinfo->dst.type!=AT_NONE) { - gai = (graph_analysis_item_t *)g_malloc(sizeof(graph_analysis_item_t)); - COPY_ADDRESS(&(gai->src_addr),&(pinfo->src)); - COPY_ADDRESS(&(gai->dst_addr),&(pinfo->dst)); - } - else return 0; - } - - gai->fd = pinfo->fd; - - gai->port_src=pinfo->srcport; - gai->port_dst=pinfo->destport; - gai->comment=NULL; - gai->frame_label=NULL; - -#if 0 /* this code doesn't make sense. */ - g_free(gai->comment); - g_free(gai->frame_label); -#endif - - if(pinfo->cinfo) { - if (pinfo->cinfo->col_first[COL_INFO]>=0){ - - for (i = pinfo->cinfo->col_first[COL_INFO]; i <= pinfo->cinfo->col_last[COL_INFO]; i++) { - if (pinfo->cinfo->fmt_matx[i][COL_INFO]) { - colinfo = g_strdup(pinfo->cinfo->col_data[i]); - /* break; ? or g_free(colinfo); before g_strdup() */ - } - } - } - - if (pinfo->cinfo->col_first[COL_PROTOCOL]>=0){ - - for (i = pinfo->cinfo->col_first[COL_PROTOCOL]; i <= pinfo->cinfo->col_last[COL_PROTOCOL]; i++) { - if (pinfo->cinfo->fmt_matx[i][COL_PROTOCOL]) { - protocol = g_strdup(pinfo->cinfo->col_data[i]); - /* break; ? or g_free(protocol); before g_strdup() */ - } - } - } - } - - if (colinfo != NULL) { - if (protocol != NULL) { - gai->frame_label = g_strdup_printf("%.19s", colinfo); - gai->comment = g_strdup_printf("%s: %s", protocol, colinfo); - } else { - gai->frame_label = g_strdup_printf("%.19s", colinfo); - gai->comment = g_strdup_printf("%s", colinfo); - } - } else { - /* This will probably never happen...*/ - if (protocol != NULL) { - gai->frame_label = g_strdup_printf("%.19s", protocol); - gai->comment = g_strdup_printf("%s", protocol); - } - } - - g_free(protocol); - g_free(colinfo); - - gai->line_style=1; - gai->conv_num=0; - gai->display=TRUE; - - graph_analysis->list = g_list_append(graph_analysis->list, gai); - - return 1; -} - -/****************************************************************************/ -/* Add a new tcp frame into the graph */ -static int -flow_graph_tcp_add_to_graph(packet_info *pinfo, const struct tcpheader *tcph) -{ - graph_analysis_item_t *gai; - /* copied from packet-tcp */ - static const gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR" }; - guint i, bpos; - gboolean flags_found = FALSE; - gchar flags[64]; - - gai = (graph_analysis_item_t *)g_malloc(sizeof(graph_analysis_item_t)); - gai->fd = pinfo->fd; - if (node_addr_type == NODE_ADDR_TYPE_NET_SRCDST) { - COPY_ADDRESS(&(gai->src_addr),&(pinfo->net_src)); - COPY_ADDRESS(&(gai->dst_addr),&(pinfo->net_dst)); - } else { - COPY_ADDRESS(&(gai->src_addr),&(pinfo->src)); - COPY_ADDRESS(&(gai->dst_addr),&(pinfo->dst)); - } - gai->port_src=pinfo->srcport; - gai->port_dst=pinfo->destport; - - flags[0] = '\0'; - for (i = 0; i < 8; i++) { - bpos = 1 << i; - if (tcph->th_flags & bpos) { - if (flags_found) { - g_strlcat(flags, ", ", sizeof(flags)); - } - g_strlcat(flags, fstr[i], sizeof(flags)); - flags_found = TRUE; - } - } - if (flags[0] == '\0') { - g_snprintf (flags, sizeof(flags), ""); - } - - if ((tcph->th_have_seglen)&&(tcph->th_seglen!=0)){ - gai->frame_label = g_strdup_printf("%s - Len: %u",flags, tcph->th_seglen); - } - else{ - gai->frame_label = g_strdup(flags); - } - - if (tcph->th_flags & TH_ACK) - gai->comment = g_strdup_printf("Seq = %u Ack = %u",tcph->th_seq, tcph->th_ack); - else - gai->comment = g_strdup_printf("Seq = %u",tcph->th_seq); - - gai->line_style=1; - gai->conv_num=0; - gai->display=TRUE; - - graph_analysis->list = g_list_append(graph_analysis->list, gai); - - return 1; -} - - - -/****************************************************************************/ -/* whenever a frame packet is seen by the tap listener */ -static gboolean -flow_graph_frame_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *dummy _U_) -{ - if ((type_of_packets == TYPE_OF_PACKETS_ALL)||(pinfo->fd->flags.passed_dfilter==1)){ - flow_graph_frame_add_to_graph(pinfo); - } - - return TRUE; -} - -/****************************************************************************/ -/* whenever a TCP packet is seen by the tap listener */ -static gboolean -flow_graph_tcp_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *tcp_info) -{ - const struct tcpheader *tcph = (struct tcpheader *)tcp_info; - - if ((type_of_packets == TYPE_OF_PACKETS_ALL)||(pinfo->fd->flags.passed_dfilter==1)){ - flow_graph_tcp_add_to_graph(pinfo,tcph); - } - - return TRUE; -} - - -static void -flow_graph_packet_draw(void *prs _U_) -{ - return; -} - /****************************************************************************/ static void flow_graph_on_ok(GtkButton *button _U_, gpointer user_data) { - if ((have_frame_tap_listener==TRUE) - ||(have_tcp_tap_listener==TRUE)) - { - /* remove_tap_listeners */ - remove_tap_listener_flow_graph(); - } - /* Scan for displayed packets (retap all packets) */ - - if (type_of_flow == TYPE_OF_FLOW_GENERAL){ - /* Register the tap listener */ - - if(have_frame_tap_listener==FALSE) - { - /* don't register tap listener, if we have it already */ - register_tap_listener("frame", &tap_identifier, NULL, - TL_REQUIRES_COLUMNS, - flow_graph_reset, - flow_graph_frame_packet, - flow_graph_packet_draw - ); - have_frame_tap_listener=TRUE; - } - - cf_retap_packets(&cfile); - } - else if (type_of_flow == TYPE_OF_FLOW_TCP){ - /* Register the tap listener */ - - if(have_tcp_tap_listener==FALSE) - { - /* don't register tap listener, if we have it already */ - register_tap_listener("tcp", &tap_identifier, NULL, - 0, - flow_graph_reset, - flow_graph_tcp_packet, - flow_graph_packet_draw - ); - have_tcp_tap_listener=TRUE; - } - - cf_retap_packets(&cfile); - } + sequence_analysis_list_free(graph_analysis); + sequence_analysis_list_get(&cfile, graph_analysis); if (graph_analysis_data->dlg.window != NULL){ /* if we still have a window */ graph_analysis_update(graph_analysis_data); /* refresh it xxx */ @@ -524,7 +235,7 @@ flow_graph_dlg_create(void) gtk_widget_set_tooltip_text (select_all_rb, ("Process all packets")); g_signal_connect(select_all_rb, "toggled", G_CALLBACK(toggle_select_all), NULL); ws_gtk_grid_attach(GTK_GRID(range_grid), select_all_rb, 0, 0, 1, 1); - if (type_of_packets == TYPE_OF_PACKETS_ALL) { + if (graph_analysis->all_packets) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_all_rb),TRUE); } gtk_widget_show(select_all_rb); @@ -535,7 +246,7 @@ flow_graph_dlg_create(void) gtk_widget_set_tooltip_text (select_displayed_rb, ("Process displayed packets")); g_signal_connect(select_displayed_rb, "toggled", G_CALLBACK(toggle_select_displayed), NULL); ws_gtk_grid_attach(GTK_GRID(range_grid), select_displayed_rb, 0, 1, 1, 1); - if (type_of_packets == TYPE_OF_PACKETS_DISPLAYED) { + if (!graph_analysis->all_packets) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_displayed_rb),TRUE); } gtk_widget_show(select_displayed_rb); @@ -556,7 +267,7 @@ flow_graph_dlg_create(void) gtk_widget_set_tooltip_text (select_general_rb, ("Show all packets, with general information")); g_signal_connect(select_general_rb, "toggled", G_CALLBACK(toggle_select_general), NULL); ws_gtk_grid_attach(GTK_GRID(flow_type_grid), select_general_rb, 0, 0, 1, 1); - if (type_of_flow == TYPE_OF_FLOW_GENERAL) { + if (graph_analysis->type == SEQ_ANALYSIS_ANY) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_general_rb),TRUE); } gtk_widget_show(select_general_rb); @@ -567,7 +278,7 @@ flow_graph_dlg_create(void) gtk_widget_set_tooltip_text (select_tcp_rb, ("Show only TCP packets, with TCP specific information")); g_signal_connect(select_tcp_rb, "toggled", G_CALLBACK(toggle_select_tcp), NULL); ws_gtk_grid_attach(GTK_GRID(flow_type_grid), select_tcp_rb, 0, 1, 1, 1); - if (type_of_flow == TYPE_OF_FLOW_TCP) { + if (graph_analysis->type == SEQ_ANALYSIS_TCP) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(select_tcp_rb),TRUE); } gtk_widget_show(select_tcp_rb); @@ -589,7 +300,7 @@ flow_graph_dlg_create(void) ("Nodes in the diagram are identified with source and destination addresses")); g_signal_connect(src_dst_rb, "toggled", G_CALLBACK(toggle_select_srcdst), NULL); ws_gtk_grid_attach(GTK_GRID(node_addr_grid), src_dst_rb, 0, 0, 1, 1); - if (node_addr_type == NODE_ADDR_TYPE_SRCDST) { + if (!graph_analysis->any_addr) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(src_dst_rb),TRUE); } gtk_widget_show(src_dst_rb); @@ -601,7 +312,7 @@ flow_graph_dlg_create(void) ("Nodes in the diagram are identified with network source and destination addresses")); g_signal_connect(net_src_dst_rb, "toggled", G_CALLBACK(toggle_select_netsrcdst), NULL); ws_gtk_grid_attach(GTK_GRID(node_addr_grid), net_src_dst_rb, 0, 1, 1, 1); - if (node_addr_type == NODE_ADDR_TYPE_NET_SRCDST) { + if (graph_analysis->any_addr) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(net_src_dst_rb),TRUE); } gtk_widget_show(net_src_dst_rb); @@ -660,8 +371,7 @@ flow_graph_init_tap(const char *dummy _U_, void *userdata _U_) flow_graph_data_init(); /* init the Graph Analysis */ - graph_analysis_data = graph_analysis_init(); - graph_analysis_data->graph_info = graph_analysis; + graph_analysis_data = graph_analysis_init(graph_analysis); flow_graph_dlg_create(); } diff --git a/ui/gtk/graph_analysis.c b/ui/gtk/graph_analysis.c index cbaec02659..3856f71a40 100644 --- a/ui/gtk/graph_analysis.c +++ b/ui/gtk/graph_analysis.c @@ -52,13 +52,10 @@ #include "ui/util.h" -#include "ui/alert_box.h" #include "ui/last_open_dir.h" #include "ui/recent.h" #include "ui/simple_dialog.h" -#include - #include "ui/gtk/gtkglobals.h" #include "ui/gtk/file_dlg.h" #include "ui/gtk/gui_utils.h" @@ -81,27 +78,19 @@ #define COMMENT_WIDTH 400 #define TIME_WIDTH 150 -#define NODE_CHARS_WIDTH 20 -#define CONV_TIME_HEADER "Conv.| Time " -#define TIME_HEADER "|Time " -#define CONV_TIME_EMPTY_HEADER " | " -#define TIME_EMPTY_HEADER "| " -#define CONV_TIME_HEADER_LENGTH 16 -#define TIME_HEADER_LENGTH 10 - /****************************************************************************/ /* Reset the user_data structure */ static void graph_analysis_reset(graph_analysis_data_t *user_data) { int i; - user_data->num_nodes = 0; + user_data->graph_info->num_nodes = 0; user_data->num_items = 0; for (i=0; inodes[i].type = AT_NONE; - user_data->nodes[i].len = 0; - g_free((void *)user_data->nodes[i].data); - user_data->nodes[i].data = NULL; + user_data->graph_info->nodes[i].type = AT_NONE; + user_data->graph_info->nodes[i].len = 0; + g_free((void *)user_data->graph_info->nodes[i].data); + user_data->graph_info->nodes[i].data = NULL; } user_data->dlg.first_node = 0; @@ -116,14 +105,14 @@ static void graph_analysis_init_dlg(graph_analysis_data_t *user_data) { int i; - user_data->num_nodes = 0; + user_data->graph_info->num_nodes = 0; user_data->num_items = 0; user_data->on_destroy_user_data = NULL; user_data->data = NULL; for (i=0; inodes[i].type = AT_NONE; - user_data->nodes[i].len = 0; - user_data->nodes[i].data = NULL; + user_data->graph_info->nodes[i].type = AT_NONE; + user_data->graph_info->nodes[i].len = 0; + user_data->graph_info->nodes[i].data = NULL; } user_data->dlg.first_node = 0; @@ -169,10 +158,10 @@ static void on_destroy(GtkWidget *win _U_, graph_analysis_data_t *user_data) int i; for (i=0; inodes[i].type = AT_NONE; - user_data->nodes[i].len = 0; - g_free((void *)user_data->nodes[i].data); - user_data->nodes[i].data = NULL; + user_data->graph_info->nodes[i].type = AT_NONE; + user_data->graph_info->nodes[i].len = 0; + g_free((void *)user_data->graph_info->nodes[i].data); + user_data->graph_info->nodes[i].data = NULL; } user_data->dlg.window = NULL; g_free(user_data->dlg.title); @@ -241,281 +230,6 @@ static void draw_arrow(GdkDrawable *pixmap, GdkRGBA *color, gint x, gint y, gboo } #endif -/****************************************************************************/ -/* Adds trailing characters to complete the requested length. */ -/****************************************************************************/ - -static void enlarge_string(GString *gstr, guint32 length, char pad) { - - gsize i; - - for (i = gstr->len; i < length; i++) { - g_string_append_c(gstr, pad); - } -} - -/****************************************************************************/ -/* overwrites the characters in a string, between positions p1 and p2, with */ -/* the characters of text_to_insert */ -/* NB: it does not check that p1 and p2 fit into string */ -/****************************************************************************/ - -static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32 p2) { - - gsize len; - gsize pos; - - if (p1 == p2) - return; - - if (p1 > p2) { - pos = p2; - len = p1 - p2; - } - else{ - pos = p1; - len = p2 - p1; - } - - if (len > strlen(text_to_insert)) { - len = strlen(text_to_insert); - } - - if (pos > gstr->len) - pos = gstr->len; - - /* ouch this is ugly but gtk1 needs it */ - if ((pos + len) > gstr->len) - g_string_truncate(gstr, pos); - else - g_string_erase(gstr, pos, len); - - g_string_insert(gstr, pos, text_to_insert); -} - -/****************************************************************************/ -static gboolean -dialog_graph_dump_to_file(char *pathname, graph_analysis_data_t *user_data) -{ - guint32 i, first_node, display_items, display_nodes; - guint32 start_position, end_position, item_width, header_length; - graph_analysis_item_t *gai; - guint16 first_conv_num = 0; - gboolean several_convs = FALSE; - gboolean first_packet = TRUE; - - GString *label_string, *empty_line, *separator_line, *tmp_str, *tmp_str2; - const char *empty_header; - char src_port[8], dst_port[8]; - gchar *time_str; - GList *list; - - FILE *of; - - of = ws_fopen(pathname, "w"); - if (of==NULL) { - open_failure_alert_box(pathname, errno, TRUE); - return FALSE; - } - - time_str = (gchar *)g_malloc(COL_MAX_LEN); - label_string = g_string_new(""); - empty_line = g_string_new(""); - separator_line = g_string_new(""); - tmp_str = g_string_new(""); - tmp_str2 = g_string_new(""); - - display_items = 0; - list = g_list_first(user_data->graph_info->list); - while (list) - { - gai = (graph_analysis_item_t *)list->data; - list = g_list_next(list); - - if (!gai->display) - continue; - - display_items += 1; - if (first_packet) { - first_conv_num = gai->conv_num; - first_packet = FALSE; - } - else if (gai->conv_num != first_conv_num) { - several_convs = TRUE; - } - } - - /* if not items to display */ - if (display_items == 0) - goto exit; - - display_nodes = user_data->num_nodes; - - first_node = user_data->dlg.first_node; - - /* Write the conv. and time headers */ - if (several_convs) { - fprintf(of, CONV_TIME_HEADER); - empty_header = CONV_TIME_EMPTY_HEADER; - header_length = CONV_TIME_HEADER_LENGTH; - } - else{ - fprintf(of, TIME_HEADER); - empty_header = TIME_EMPTY_HEADER; - header_length = TIME_HEADER_LENGTH; - } - - /* Write the node names on top */ - for (i=0; inodes[i+first_node]))); - enlarge_string(label_string, NODE_CHARS_WIDTH*2, ' '); - fprintf(of, "%s", label_string->str); - g_string_printf(label_string, "| "); - enlarge_string(label_string, NODE_CHARS_WIDTH, ' '); - g_string_append(empty_line, label_string->str); - } - - fprintf(of, "|\n%s", empty_header); - g_string_printf(label_string, "| "); - enlarge_string(label_string, NODE_CHARS_WIDTH, ' '); - fprintf(of, "%s", label_string->str); - - /* Write the node names on top */ - for (i=1; inodes[i+first_node]))); - if (label_string->len < NODE_CHARS_WIDTH) - { - enlarge_string(label_string, NODE_CHARS_WIDTH, ' '); - g_string_append(label_string, "| "); - } - enlarge_string(label_string, NODE_CHARS_WIDTH*2, ' '); - fprintf(of, "%s", label_string->str); - g_string_printf(label_string, "| "); - enlarge_string(label_string, NODE_CHARS_WIDTH, ' '); - g_string_append(empty_line, label_string->str); - } - - fprintf(of, "\n"); - - g_string_append_c(empty_line, '|'); - - enlarge_string(separator_line, (guint32) empty_line->len + header_length, '-'); - - /* - * Draw the items - */ - - list = g_list_first(user_data->graph_info->list); - while (list) - { - gai = (graph_analysis_item_t *)list->data; - list = g_list_next(list); - - if (!gai->display) - continue; - - start_position = (gai->src_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2; - - end_position = (gai->dst_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2; - - if (start_position > end_position) { - item_width = start_position-end_position; - } - else if (start_position < end_position) { - item_width = end_position-start_position; - } - else{ /* same origin and destination address */ - end_position = start_position+NODE_CHARS_WIDTH; - item_width = NODE_CHARS_WIDTH; - } - - /* separator between conversations */ - if (gai->conv_num != first_conv_num) { - fprintf(of, "%s\n", separator_line->str); - first_conv_num = gai->conv_num; - } - - /* write the conversation number */ - if (several_convs) { - g_string_printf(label_string, "%i", gai->conv_num); - enlarge_string(label_string, 5, ' '); - fprintf(of, "%s", label_string->str); - } - -#if 0 - /* write the time */ - g_string_printf(label_string, "|%.3f", nstime_to_sec(&gai->fd->rel_ts)); -#endif - /* Write the time, using the same format as in the time col */ - set_fd_time(cfile.epan, gai->fd, time_str); - g_string_printf(label_string, "|%s", time_str); - enlarge_string(label_string, 10, ' '); - fprintf(of, "%s", label_string->str); - - /* write the frame label */ - - g_string_printf(tmp_str, "%s", empty_line->str); - overwrite(tmp_str, gai->frame_label, - start_position, - end_position - ); - fprintf(of, "%s", tmp_str->str); - - /* write the comments */ - fprintf(of, "%s\n", gai->comment); - - /* write the arrow and frame label*/ - fprintf(of, "%s", empty_header); - - g_string_printf(tmp_str, "%s", empty_line->str); - - g_string_truncate(tmp_str2, 0); - - if (start_position'); - } - else{ - g_string_printf(tmp_str2, "<"); - enlarge_string(tmp_str2, item_width-1, '-'); - } - - overwrite(tmp_str, tmp_str2->str, - start_position, - end_position - ); - - g_snprintf(src_port, sizeof(src_port), "(%i)", gai->port_src); - g_snprintf(dst_port, sizeof(dst_port), "(%i)", gai->port_dst); - - if (start_positionstr); - } - -exit: - g_string_free(label_string, TRUE); - g_string_free(empty_line, TRUE); - g_string_free(separator_line, TRUE); - g_string_free(tmp_str, TRUE); - g_string_free(tmp_str2, TRUE); - g_free(time_str); - fclose (of); - return TRUE; - -} - /****************************************************************************/ /* save in a file */ @@ -559,7 +273,7 @@ on_save_bt_clicked (GtkWidget *button _U_, /* User gave up. */ break; } - if (dialog_graph_dump_to_file(pathname, user_data)) { + if (sequence_analysis_dump_to_file(pathname, user_data->graph_info, &cfile, user_data->dlg.first_node)) { /* We succeeded. */ g_free(pathname); break; @@ -580,7 +294,7 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) guint32 right_x_border; guint32 top_y_border; guint32 bottom_y_border; - graph_analysis_item_t *gai; + seq_analysis_item_t *gai; PangoLayout *layout; PangoLayout *middle_layout; @@ -595,7 +309,6 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) char label_string[MAX_COMMENT]; GList *list; cairo_t *cr; - gchar *time_str; #if 0 GdkColor *color_p, *bg_color_p; @@ -657,7 +370,6 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) } bg_pixbuf = gdk_pixbuf_new_from_xpm_data(voip_bg_xpm); - time_str = (gchar *)g_malloc(COL_MAX_LEN); user_data->dlg.needs_redraw = FALSE; gtk_widget_get_allocation(user_data->dlg.draw_area_time, &draw_area_time_alloc); @@ -724,7 +436,7 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) i = 0; while (list) { - gai = (graph_analysis_item_t *)list->data; + gai = (seq_analysis_item_t *)list->data; if (gai->display) { if (current_item>=display_items) break; /* the item is outside the display */ if (i>=first_item) { @@ -738,6 +450,7 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) gai->frame_label[46] = '.'; } user_data->dlg.items[current_item].frame_label = gai->frame_label; + user_data->dlg.items[current_item].time_str = gai->time_str; user_data->dlg.items[current_item].comment = gai->comment; user_data->dlg.items[current_item].conv_num = gai->conv_num; @@ -764,21 +477,12 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) last_item = first_item+display_items-1; user_data->dlg.last_item = last_item; - /* if no items to display */ - if (display_items == 0) { - g_free(time_str); - return; - } - - /* Calculate the x borders */ /* We use time from the last display item to calcultate the x left border */ #if 0 g_snprintf(label_string, MAX_LABEL, "%.3f", nstime_to_sec(&user_data->dlg.items[display_items-1].fd->rel_ts)); #endif - /* Write the time, using the same format as in th etime col */ - set_fd_time(cfile.epan, user_data->dlg.items[display_items-1].fd, time_str); - g_snprintf(label_string, MAX_LABEL, "%s", time_str); + g_snprintf(label_string, MAX_LABEL, "%s", user_data->dlg.items[display_items-1].time_str); layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area_time, label_string); middle_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area_time, label_string); small_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area_time, label_string); @@ -923,10 +627,10 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) #endif } /* Draw the node names on top and the division lines */ - for (i=0; inum_nodes; i++) { + for (i=0; igraph_info->num_nodes; i++) { /* print the node identifiers */ /* XXX we assign 5 pixels per character in the node identity */ - g_strlcpy(label_string, get_addr_name(&(user_data->nodes[i])), NODE_WIDTH/5); + g_strlcpy(label_string, get_addr_name(&(user_data->graph_info->nodes[i])), NODE_WIDTH/5); pango_layout_set_text(layout, label_string, -1); pango_layout_get_pixel_size(layout, &label_width, &label_height); #if GTK_CHECK_VERSION(2,22,0) @@ -978,8 +682,7 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) g_snprintf(label_string, MAX_LABEL, "%.3f", nstime_to_sec(&user_data->dlg.items[current_item].fd->rel_ts)); #endif /* Draw the time */ - set_fd_time(cfile.epan, user_data->dlg.items[current_item].fd, time_str); - g_snprintf(label_string, MAX_LABEL, "%s", time_str); + g_snprintf(label_string, MAX_LABEL, "%s", user_data->dlg.items[current_item].time_str); pango_layout_set_text(layout, label_string, -1); pango_layout_get_pixel_size(layout, &label_width, &label_height); #if GTK_CHECK_VERSION(2,22,0) @@ -1186,7 +889,7 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) #endif /* draw the div line of the selected item with soft gray*/ if ( current_item+first_item == user_data->dlg.selected_item ) - for (i=0; inum_nodes; i++) { + for (i=0; igraph_info->num_nodes; i++) { #if GTK_CHECK_VERSION(2,22,0) cr = cairo_create (user_data->dlg.surface_main); gdk_cairo_set_source_rgba (cr, &grey_color1); @@ -1214,7 +917,6 @@ static void dialog_graph_draw(graph_analysis_data_t *user_data) } g_object_unref(G_OBJECT(layout)); - g_free(time_str); /* refresh the draw areas */ if (gtk_widget_is_drawable(user_data->dlg.draw_area_time) ) { @@ -1851,11 +1553,11 @@ static void create_draw_area(graph_analysis_data_t *user_data, GtkWidget *box) /* create main Graph draw area */ user_data->dlg.draw_area = gtk_drawing_area_new(); /* allow a little extra space (2*NODE_WIDTH) for wide labels */ - user_data->dlg.surface_width = user_data->num_nodes * NODE_WIDTH + 2*NODE_WIDTH; + user_data->dlg.surface_width = user_data->graph_info->num_nodes * NODE_WIDTH + 2*NODE_WIDTH; gtk_widget_set_size_request(user_data->dlg.draw_area, user_data->dlg.surface_width, user_data->dlg.surface_height); user_data->dlg.scroll_window = gtk_scrolled_window_new(NULL, NULL); - if ( user_data->num_nodes < 6) - gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.surface_height); + if ( user_data->graph_info->num_nodes < 6) + gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*user_data->graph_info->num_nodes, user_data->dlg.surface_height); else gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.surface_height); @@ -2036,60 +1738,13 @@ static void dialog_graph_create_window(graph_analysis_data_t *user_data) g_free(win_name); } -/* Return the index array if the node is in the array. Return -1 if there is room in the array - * and Return -2 if the array is full - */ /****************************************************************************/ -static gint add_or_get_node(graph_analysis_data_t *user_data, address *node) { - guint i; - - if (node->type == AT_NONE) return NODE_OVERFLOW; - - for (i=0; inum_nodes ; i++) { - if ( CMP_ADDRESS(&(user_data->nodes[i]), node) == 0 ) return i; /* it is in the array */ - } - - if (i == MAX_NUM_NODES) { - return NODE_OVERFLOW; - } else { - user_data->num_nodes++; - COPY_ADDRESS(&(user_data->nodes[i]), node); - return i; - } -} - -/* Get the nodes from the list */ -/****************************************************************************/ -static void get_nodes(graph_analysis_data_t *user_data) -{ - GList *list; - graph_analysis_item_t *gai; - - /* fill the node array */ - list = g_list_first(user_data->graph_info->list); - while (list) - { - gai = (graph_analysis_item_t *)list->data; - if (gai->display) { - user_data->num_items++; - if (!user_data->dlg.inverse) { - gai->src_node = (guint16)add_or_get_node(user_data, &(gai->src_addr)); - gai->dst_node = (guint16)add_or_get_node(user_data, &(gai->dst_addr)); - } else { - gai->dst_node = (guint16)add_or_get_node(user_data, &(gai->src_addr)); - gai->src_node = (guint16)add_or_get_node(user_data, &(gai->dst_addr)); - } - } - list = g_list_next(list); - } -} - -/****************************************************************************/ -graph_analysis_data_t *graph_analysis_init(void) +graph_analysis_data_t *graph_analysis_init(seq_analysis_info_t *sainfo) { graph_analysis_data_t *user_data; /* init */ user_data = g_new(graph_analysis_data_t,1); + user_data->graph_info = sainfo; /* init user_data */ graph_analysis_init_dlg(user_data); @@ -2107,7 +1762,7 @@ void graph_analysis_create(graph_analysis_data_t *user_data) graph_analysis_reset(user_data); /* get nodes (each node is an address) */ - get_nodes(user_data); + user_data->num_items = sequence_analysis_get_nodes(user_data->graph_info); /* create the graph windows */ dialog_graph_create_window(user_data); @@ -2125,12 +1780,12 @@ void graph_analysis_update(graph_analysis_data_t *user_data) graph_analysis_reset(user_data); /* get nodes (each node is an address) */ - get_nodes(user_data); + user_data->num_items = sequence_analysis_get_nodes(user_data->graph_info); - user_data->dlg.surface_width = user_data->num_nodes * NODE_WIDTH; + user_data->dlg.surface_width = user_data->graph_info->num_nodes * NODE_WIDTH; gtk_widget_set_size_request(user_data->dlg.draw_area, user_data->dlg.surface_width, user_data->dlg.surface_height); - if (user_data->num_nodes < 6) - gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.surface_height); + if (user_data->graph_info->num_nodes < 6) + gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*user_data->graph_info->num_nodes, user_data->dlg.surface_height); else gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.surface_height); @@ -2146,12 +1801,12 @@ void graph_analysis_update(graph_analysis_data_t *user_data) void graph_analysis_redraw(graph_analysis_data_t *user_data) { /* get nodes (each node is an address) */ - get_nodes(user_data); + user_data->num_items = sequence_analysis_get_nodes(user_data->graph_info); - user_data->dlg.surface_width = user_data->num_nodes * NODE_WIDTH; + user_data->dlg.surface_width = user_data->graph_info->num_nodes * NODE_WIDTH; gtk_widget_set_size_request(user_data->dlg.draw_area, user_data->dlg.surface_width, user_data->dlg.surface_height); - if (user_data->num_nodes < 6) - gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*user_data->num_nodes, user_data->dlg.surface_height); + if (user_data->graph_info->num_nodes < 6) + gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*user_data->graph_info->num_nodes, user_data->dlg.surface_height); else gtk_widget_set_size_request(user_data->dlg.scroll_window, NODE_WIDTH*5, user_data->dlg.surface_height); diff --git a/ui/gtk/graph_analysis.h b/ui/gtk/graph_analysis.h index a34c5fa5c4..c734ae32d5 100644 --- a/ui/gtk/graph_analysis.h +++ b/ui/gtk/graph_analysis.h @@ -34,35 +34,10 @@ #include #include #include - -#define MAX_NUM_NODES 40 - -/** defines an entry for the graph analysis */ -typedef struct _graph_analysis_item { - frame_data *fd; /**< Holds the frame number and time information */ - address src_addr; - guint16 port_src; - address dst_addr; - guint16 port_dst; - gchar *frame_label; /**< the label on top of the arrow */ - gchar *comment; /**< a comment that appears at the left of the graph */ - guint16 conv_num; /**< the conversation number, each conversation will be colored */ - gboolean display; /**< indicate if the packet is displayed or not in the graph */ - guint16 src_node; /**< this is used by graph_analysis.c to identify the node */ - guint16 dst_node; /**< a node is an IP address that will be displayed in columns */ - guint16 line_style; /**< the arrow line width in pixels*/ -} graph_analysis_item_t; - -/** defines the graph analysis structure */ -typedef struct _graph_analysis_info { - int nconv; /**< number of conversations in the list */ - GList* list; /**< list with the graph analysis items */ - GHashTable *ht; /**< hash table for retrieving graph analysis items */ -} graph_analysis_info_t; +#include /** max number of nodes to display, each node will be an IP address */ #define MAX_NUM_COL_CONV 10 -#define NODE_OVERFLOW MAX_NUM_NODES+1 #define NUM_DISPLAY_ITEMS 1000 typedef struct _display_items { @@ -70,6 +45,7 @@ typedef struct _display_items { guint16 port_src; guint16 port_dst; gchar *frame_label; /**< the label on top of the arrow */ + gchar *time_str; /**< timestamp */ gchar *comment; /**< a comment that appears at the left of the graph */ guint16 conv_num; /**< the conversation number, each conversation will be colored */ guint16 src_node; /**< this is used by graph_analysis.c to identify the node */ @@ -119,18 +95,16 @@ typedef void (*destroy_user_data_cb)(void *data); /** structure that holds general information and the dialog */ typedef struct _graph_analysis_data_t { /**> graphic data */ - graph_analysis_info_t *graph_info; + seq_analysis_info_t *graph_info; /**> dialog associated data */ graph_analysis_dialog_data_t dlg; - address nodes[MAX_NUM_NODES]; - guint32 num_nodes; guint32 num_items; destroy_user_data_cb on_destroy_user_data; /**< callback info for destroy */ void *data; /**< data to be passes when on destroy */ } graph_analysis_data_t; -graph_analysis_data_t* graph_analysis_init(void); +graph_analysis_data_t* graph_analysis_init(seq_analysis_info_t *sainfo); void graph_analysis_create(graph_analysis_data_t* user_data); void graph_analysis_update(graph_analysis_data_t* user_data); void graph_analysis_redraw(graph_analysis_data_t* user_data); diff --git a/ui/gtk/rtp_player.c b/ui/gtk/rtp_player.c index 541a7f614a..82f833ccf1 100644 --- a/ui/gtk/rtp_player.c +++ b/ui/gtk/rtp_player.c @@ -427,7 +427,7 @@ static void mark_rtp_stream_to_play(gchar *key _U_ , rtp_stream_info_t *rsi, gpointer ptr _U_) { GList* graph_list; - graph_analysis_item_t *graph_item; + seq_analysis_item_t *graph_item; GList* voip_calls_list; voip_calls_info_t *tmp_voip_call; @@ -440,7 +440,7 @@ mark_rtp_stream_to_play(gchar *key _U_ , rtp_stream_info_t *rsi, gpointer ptr _U graph_list = g_list_first(voip_calls->graph_analysis->list); while (graph_list) { - graph_item = (graph_analysis_item_t *)graph_list->data; + graph_item = (seq_analysis_item_t *)graph_list->data; if (rsi->first_frame_number == graph_item->fd->num) { rsi->call_num = graph_item->conv_num; /* if it is in the graph list, then check if the voip_call is selected */ diff --git a/ui/gtk/voip_calls.c b/ui/gtk/voip_calls.c index 8d7e06a23c..6fc1706a70 100644 --- a/ui/gtk/voip_calls.c +++ b/ui/gtk/voip_calls.c @@ -160,7 +160,7 @@ void voip_calls_reset(voip_calls_tapinfo_t *tapinfo) voip_calls_info_t *callsinfo; voip_rtp_tapinfo_t *rtp_tapinfo = &the_tapinfo_rtp_struct; voip_rtp_stream_info_t *strinfo; - graph_analysis_item_t *graph_item; + seq_analysis_item_t *graph_item; GList *list; #ifdef HAVE_LIBPORTAUDIO @@ -204,7 +204,7 @@ void voip_calls_reset(voip_calls_tapinfo_t *tapinfo) list = g_list_first(tapinfo->graph_analysis->list); while (list) { - graph_item = (graph_analysis_item_t *)list->data; + graph_item = (seq_analysis_item_t *)list->data; g_free(graph_item->frame_label); g_free(graph_item->comment); g_free((void *)graph_item->src_addr.data); @@ -234,7 +234,7 @@ void voip_calls_reset(voip_calls_tapinfo_t *tapinfo) /****************************************************************************/ void graph_analysis_data_init(void) { - the_tapinfo_struct.graph_analysis = (graph_analysis_info_t *)g_malloc(sizeof(graph_analysis_info_t)); + the_tapinfo_struct.graph_analysis = (seq_analysis_info_t *)g_malloc(sizeof(seq_analysis_info_t)); the_tapinfo_struct.graph_analysis->nconv = 0; the_tapinfo_struct.graph_analysis->list = NULL; the_tapinfo_struct.graph_analysis->ht= g_hash_table_new(g_int_hash, g_int_equal); @@ -244,9 +244,9 @@ void graph_analysis_data_init(void) { /* Add a new item into the graph */ static void add_to_graph(voip_calls_tapinfo_t *tapinfo _U_, packet_info *pinfo, const gchar *frame_label, const gchar *comment, guint16 call_num, address *src_addr, address *dst_addr, guint16 line_style) { - graph_analysis_item_t *gai; + seq_analysis_item_t *gai; - gai = (graph_analysis_item_t *)g_malloc(sizeof(graph_analysis_item_t)); + gai = (seq_analysis_item_t *)g_malloc(sizeof(seq_analysis_item_t)); gai->fd = pinfo->fd; COPY_ADDRESS(&(gai->src_addr),src_addr); COPY_ADDRESS(&(gai->dst_addr),dst_addr); @@ -276,12 +276,12 @@ static void add_to_graph(voip_calls_tapinfo_t *tapinfo _U_, packet_info *pinfo, /* return 0 if the frame_num is not in the graph list */ static int append_to_frame_graph(voip_calls_tapinfo_t *tapinfo _U_, guint32 frame_num, const gchar *new_frame_label, const gchar *new_comment) { - graph_analysis_item_t *gai=NULL; + seq_analysis_item_t *gai=NULL; gchar *frame_label = NULL; gchar *comment = NULL; if(NULL!=tapinfo->graph_analysis->ht) - gai=(graph_analysis_item_t *)g_hash_table_lookup(tapinfo->graph_analysis->ht, &frame_num); + gai=(seq_analysis_item_t *)g_hash_table_lookup(tapinfo->graph_analysis->ht, &frame_num); if(gai) { frame_label = gai->frame_label; comment = gai->comment; @@ -305,12 +305,12 @@ static int append_to_frame_graph(voip_calls_tapinfo_t *tapinfo _U_, guint32 fram /* return 0 if the frame_num is not in the graph list */ static int change_frame_graph(voip_calls_tapinfo_t *tapinfo _U_, guint32 frame_num, const gchar *new_frame_label, const gchar *new_comment) { - graph_analysis_item_t *gai=NULL; + seq_analysis_item_t *gai=NULL; gchar *frame_label = NULL; gchar *comment = NULL; if(NULL!=tapinfo->graph_analysis->ht) - gai=(graph_analysis_item_t *)g_hash_table_lookup(tapinfo->graph_analysis->ht, &frame_num); + gai=(seq_analysis_item_t *)g_hash_table_lookup(tapinfo->graph_analysis->ht, &frame_num); if(gai) { frame_label = gai->frame_label; comment = gai->comment; @@ -333,7 +333,7 @@ static int change_frame_graph(voip_calls_tapinfo_t *tapinfo _U_, guint32 frame_n /* Change all the graph items with call_num to new_call_num */ static guint change_call_num_graph(voip_calls_tapinfo_t *tapinfo _U_, guint16 call_num, guint16 new_call_num) { - graph_analysis_item_t *gai; + seq_analysis_item_t *gai; GList *list; guint items_changed; @@ -341,7 +341,7 @@ static guint change_call_num_graph(voip_calls_tapinfo_t *tapinfo _U_, guint16 ca list = g_list_first(tapinfo->graph_analysis->list); while (list) { - gai = (graph_analysis_item_t *)list->data; + gai = (seq_analysis_item_t *)list->data; if (gai->conv_num == call_num) { gai->conv_num = new_call_num; items_changed++; @@ -355,12 +355,12 @@ static guint change_call_num_graph(voip_calls_tapinfo_t *tapinfo _U_, guint16 ca /* Insert the item in the graph list */ static void insert_to_graph_t38(voip_calls_tapinfo_t *tapinfo _U_, packet_info *pinfo, const gchar *frame_label, const gchar *comment, guint16 call_num, address *src_addr, address *dst_addr, guint16 line_style, guint32 frame_num) { - graph_analysis_item_t *gai, *new_gai; + seq_analysis_item_t *gai, *new_gai; GList *list; guint item_num; gboolean inserted; - new_gai = (graph_analysis_item_t *)g_malloc(sizeof(graph_analysis_item_t)); + new_gai = (seq_analysis_item_t *)g_malloc(sizeof(seq_analysis_item_t)); new_gai->fd = packet_list_get_row_data(frame_num); COPY_ADDRESS(&(new_gai->src_addr),src_addr); COPY_ADDRESS(&(new_gai->dst_addr),dst_addr); @@ -385,7 +385,7 @@ static void insert_to_graph_t38(voip_calls_tapinfo_t *tapinfo _U_, packet_info * list = g_list_first(tapinfo->graph_analysis->list); while (list) { - gai = (graph_analysis_item_t *)list->data; + gai = (seq_analysis_item_t *)list->data; if (gai->fd->num > frame_num) { the_tapinfo_struct.graph_analysis->list = g_list_insert(the_tapinfo_struct.graph_analysis->list, new_gai, item_num); g_hash_table_insert(tapinfo->graph_analysis->ht, &new_gai->fd->num, new_gai); @@ -598,8 +598,8 @@ static void RTP_packet_draw(void *prs _U_) GList *rtp_streams_list; voip_rtp_stream_info_t *rtp_listinfo; /* GList *voip_calls_graph_list; */ - graph_analysis_item_t *gai; - graph_analysis_item_t *new_gai; + seq_analysis_item_t *gai; + seq_analysis_item_t *new_gai; guint16 conv_num; guint32 duration; @@ -612,12 +612,12 @@ static void RTP_packet_draw(void *prs _U_) /* using the setup frame number of the RTP stream, we get the call number that it belongs to*/ /* voip_calls_graph_list = g_list_first(the_tapinfo_struct.graph_analysis->list); */ - gai = (graph_analysis_item_t *)g_hash_table_lookup(the_tapinfo_struct.graph_analysis->ht, &rtp_listinfo->setup_frame_number); + gai = (seq_analysis_item_t *)g_hash_table_lookup(the_tapinfo_struct.graph_analysis->ht, &rtp_listinfo->setup_frame_number); if(gai != NULL) { /* Found the setup frame*/ conv_num = gai->conv_num; /* if RTP was already in the Graph, just update the comment information */ - gai = (graph_analysis_item_t *)g_hash_table_lookup(the_tapinfo_struct.graph_analysis->ht, &rtp_listinfo->start_fd->num); + gai = (seq_analysis_item_t *)g_hash_table_lookup(the_tapinfo_struct.graph_analysis->ht, &rtp_listinfo->start_fd->num); if(gai != NULL) { duration = (guint32)(nstime_to_msec(&rtp_listinfo->stop_rel_ts) - nstime_to_msec(&rtp_listinfo->start_rel_ts)); g_free(gai->comment); @@ -625,7 +625,7 @@ static void RTP_packet_draw(void *prs _U_) (rtp_listinfo->is_srtp)?"SRTP":"RTP", rtp_listinfo->npackets, duration/1000,(duration%1000), rtp_listinfo->ssrc); }else { - new_gai = (graph_analysis_item_t *)g_malloc(sizeof(graph_analysis_item_t)); + new_gai = (seq_analysis_item_t *)g_malloc(sizeof(seq_analysis_item_t)); new_gai->fd = rtp_listinfo->start_fd; COPY_ADDRESS(&(new_gai->src_addr),&(rtp_listinfo->src_addr)); COPY_ADDRESS(&(new_gai->dst_addr),&(rtp_listinfo->dest_addr)); @@ -658,8 +658,8 @@ static void RTP_packet_draw(void *prs _U_) voip_rtp_stream_info_t *rtp_listinfo; GList *voip_calls_graph_list; guint item; - graph_analysis_item_t *gai; - graph_analysis_item_t *new_gai; + seq_analysis_item_t *gai; + seq_analysis_item_t *new_gai; guint16 conv_num; guint32 duration; @@ -698,7 +698,7 @@ static void RTP_packet_draw(void *prs _U_) /* add the RTP item to the graph if was not there*/ if (rtp_listinfo->start_fd->numfd->num || !voip_calls_graph_list) { - new_gai = g_malloc(sizeof(graph_analysis_item_t)); + new_gai = g_malloc(sizeof(seq_analysis_item_t)); new_gai->fd = rtp_listinfo->start_fd; COPY_ADDRESS(&(new_gai->src_addr),&(rtp_listinfo->src_addr)); COPY_ADDRESS(&(new_gai->dst_addr),&(rtp_listinfo->dest_addr)); @@ -781,7 +781,7 @@ T38_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const vo GList *list; gchar *frame_label = NULL; gchar *comment = NULL; - graph_analysis_item_t *tmp_gai, *gai = NULL; + seq_analysis_item_t *tmp_gai, *gai = NULL; guint16 line_style = 2; double duration; int conv_num = -1; @@ -793,7 +793,7 @@ T38_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const vo voip_calls_graph_list = g_list_first(tapinfo->graph_analysis->list); while (voip_calls_graph_list) { - tmp_gai = (graph_analysis_item_t *)voip_calls_graph_list->data; + tmp_gai = (seq_analysis_item_t *)voip_calls_graph_list->data; if (pi->setup_frame_number == tmp_gai->fd->num) { gai = tmp_gai; break; @@ -2389,7 +2389,7 @@ MGCPcalls_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, co GList *listGraph; gchar *frame_label = NULL; gchar *comment = NULL; - graph_analysis_item_t *gai; + seq_analysis_item_t *gai; gboolean newcall = FALSE; gboolean fromEndpoint = FALSE; /* true for calls originated in Endpoints, false for calls from MGC */ gdouble diff_time; @@ -2448,7 +2448,7 @@ MGCPcalls_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, co listGraph = g_list_first(tapinfo->graph_analysis->list); while (listGraph) { - gai = (graph_analysis_item_t *)listGraph->data; + gai = (seq_analysis_item_t *)listGraph->data; if (gai->fd->num == pi->req_num) { /* there is a request that match, so look the associated call with this call_num */ list = g_list_first(tapinfo->callsinfo_list); diff --git a/ui/gtk/voip_calls.h b/ui/gtk/voip_calls.h index a364e2b378..9ff41a2a0e 100644 --- a/ui/gtk/voip_calls.h +++ b/ui/gtk/voip_calls.h @@ -171,7 +171,7 @@ typedef struct _voip_calls_tapinfo { int start_packets; int completed_calls; int rejected_calls; - graph_analysis_info_t* graph_analysis; + seq_analysis_info_t* graph_analysis; gboolean reversed; gboolean redraw; /* diff --git a/ui/gtk/voip_calls_dlg.c b/ui/gtk/voip_calls_dlg.c index 8f5b617b53..292fea427c 100644 --- a/ui/gtk/voip_calls_dlg.c +++ b/ui/gtk/voip_calls_dlg.c @@ -181,7 +181,7 @@ voip_calls_on_filter(GtkButton *button _U_, gpointer user_data _U_) GList* lista; GList* listb; voip_calls_info_t *listinfo; - graph_analysis_item_t *gai; + seq_analysis_item_t *gai; size_t filter_length; size_t max_filter_length = 2048; /* What's this based on ? */ int pos; @@ -215,7 +215,7 @@ voip_calls_on_filter(GtkButton *button _U_, gpointer user_data _U_) if (listinfo->selected) { listb = g_list_first(voip_calls_get_info()->graph_analysis->list); while (listb) { - gai = (graph_analysis_item_t *)listb->data; + gai = (seq_analysis_item_t *)listb->data; if (gai->conv_num == listinfo->call_num) { g_string_append_printf(filter_string_fwd, "%sframe.number == %u", is_first?"":" or ", gai->fd->num); is_first = FALSE; @@ -318,8 +318,8 @@ voip_calls_on_select_all(GtkButton *button _U_, gpointer user_data _U_) static gint graph_analysis_sort_compare(gconstpointer a, gconstpointer b) { - const graph_analysis_item_t *entry_a = (const graph_analysis_item_t *)a; - const graph_analysis_item_t *entry_b = (const graph_analysis_item_t *)b; + const seq_analysis_item_t *entry_a = (const seq_analysis_item_t *)a; + const seq_analysis_item_t *entry_b = (const seq_analysis_item_t *)b; if(entry_a->fd->num < entry_b->fd->num) return -1; @@ -334,7 +334,7 @@ graph_analysis_sort_compare(gconstpointer a, gconstpointer b) static void on_graph_bt_clicked(GtkButton *button _U_, gpointer user_data _U_) { - graph_analysis_item_t *gai; + seq_analysis_item_t *gai; GList* lista; GList* listb; voip_calls_info_t *listinfo; @@ -349,7 +349,7 @@ on_graph_bt_clicked(GtkButton *button _U_, gpointer user_data _U_) /* reset the "display" parameter in graph analysis */ listb = g_list_first(voip_calls_get_info()->graph_analysis->list); while (listb) { - gai = (graph_analysis_item_t *)listb->data; + gai = (seq_analysis_item_t *)listb->data; gai->display = FALSE; listb = g_list_next(listb); } @@ -361,7 +361,7 @@ on_graph_bt_clicked(GtkButton *button _U_, gpointer user_data _U_) if (listinfo->selected) { listb = g_list_first(voip_calls_get_info()->graph_analysis->list); while (listb) { - gai = (graph_analysis_item_t *)listb->data; + gai = (seq_analysis_item_t *)listb->data; if (gai->conv_num == listinfo->call_num) { gai->display = TRUE; } @@ -851,8 +851,7 @@ voip_calls_init_tap(const char *dummy _U_, void* userdata _U_) if (graph_analysis_data == NULL) { graph_analysis_data_init(); /* init the Graph Analysys */ - graph_analysis_data = graph_analysis_init(); - graph_analysis_data->graph_info = voip_calls_get_info()->graph_analysis; + graph_analysis_data = graph_analysis_init(voip_calls_get_info()->graph_analysis); } /* Clean up memory used by calls tap */ diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index 3e45c5e713..a2e8829a63 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -68,6 +68,8 @@ set(QTSHARK_H_SRC qcustomplot.h recent_file_status.h search_frame.h + sequence_diagram.h + sequence_dialog.h simple_dialog_qt.h splash_overlay.h summary_dialog.h @@ -133,6 +135,8 @@ set(CLEAN_FILES recent_file_status.cpp related_packet_delegate.cpp search_frame.cpp + sequence_diagram.cpp + sequence_dialog.cpp simple_dialog_qt.cpp splash_overlay.cpp sparkline_delegate.cpp @@ -169,6 +173,7 @@ set(QTSHARK_UI print_dialog.ui profile_dialog.ui search_frame.ui + sequence_dialog.ui splash_overlay.ui summary_dialog.ui tcp_stream_dialog.ui diff --git a/ui/qt/Makefile.common b/ui/qt/Makefile.common index d294285fb1..4bf2cd3bcc 100644 --- a/ui/qt/Makefile.common +++ b/ui/qt/Makefile.common @@ -51,6 +51,7 @@ NODIST_GENERATED_HEADER_FILES = \ ui_print_dialog.h \ ui_profile_dialog.h \ ui_search_frame.h \ + ui_sequence_dialog.h \ ui_splash_overlay.h \ ui_summary_dialog.h \ ui_tcp_stream_dialog.h \ @@ -135,6 +136,8 @@ MOC_HDRS = \ recent_file_status.h \ related_packet_delegate.h \ search_frame.h \ + sequence_diagram.h \ + sequence_dialog.h \ simple_dialog_qt.h \ sparkline_delegate.h \ splash_overlay.h \ @@ -170,6 +173,7 @@ UI_FILES = \ print_dialog.ui \ profile_dialog.ui \ search_frame.ui \ + sequence_dialog.ui \ splash_overlay.ui \ summary_dialog.ui \ tcp_stream_dialog.ui \ @@ -271,6 +275,8 @@ WIRESHARK_QT_SRC = \ recent_file_status.cpp \ related_packet_delegate.cpp \ search_frame.cpp \ + sequence_diagram.cpp \ + sequence_dialog.cpp \ simple_dialog_qt.cpp \ sparkline_delegate.cpp \ summary_dialog.cpp \ diff --git a/ui/qt/QtShark.pro b/ui/qt/QtShark.pro index c13286bbd8..02bd35c3b0 100644 --- a/ui/qt/QtShark.pro +++ b/ui/qt/QtShark.pro @@ -500,6 +500,8 @@ HEADERS += \ qcustomplot.h \ recent_file_status.h \ related_packet_delegate.h \ + sequence_diagram.h \ + sequence_dialog.h \ simple_dialog_qt.h \ sparkline_delegate.h \ syntax_line_edit.h \ @@ -557,6 +559,8 @@ SOURCES += \ recent_file_status.cpp \ related_packet_delegate.cpp \ search_frame.cpp \ + sequence_diagram.cpp \ + sequence_dialog.cpp \ simple_dialog_qt.cpp \ sparkline_delegate.cpp \ splash_overlay.cpp \ diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index e1cf78b10e..1d67527931 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -307,6 +307,7 @@ private slots: void on_actionStopCapture_triggered(); void on_actionSummary_triggered(); + void on_actionStatisticsFlowGraph_triggered(); void openTcpStreamDialog(int graph_type); void on_actionStatisticsTcpStreamStevens_triggered(); void on_actionStatisticsTcpStreamTcptrace_triggered(); diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui index f2c48c9663..a38b25ed22 100644 --- a/ui/qt/main_window.ui +++ b/ui/qt/main_window.ui @@ -332,6 +332,7 @@ + @@ -1321,6 +1322,14 @@ TCP time sequence graph (tcptrace) + + + Flow Graph... + + + Flow sequence diagram + + diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp index de435c56e1..dd69526b23 100644 --- a/ui/qt/main_window_slots.cpp +++ b/ui/qt/main_window_slots.cpp @@ -77,6 +77,7 @@ #include "print_dialog.h" #include "profile_dialog.h" #include "qt_ui_utils.h" +#include "sequence_dialog.h" #include "tcp_stream_dialog.h" #include "time_shift_dialog.h" #include "wireshark_application.h" @@ -1759,6 +1760,15 @@ void MainWindow::on_actionAnalyzeFollowSSLStream_triggered() // Statistics Menu +void MainWindow::on_actionStatisticsFlowGraph_triggered() +{ + SequenceDialog *sequence_dialog = new SequenceDialog(this, cap_file_); + connect(sequence_dialog, SIGNAL(goToPacket(int)), + packet_list_, SLOT(goToPacket(int))); + connect(this, SIGNAL(setCaptureFile(capture_file*)), + sequence_dialog, SLOT(setCaptureFile(capture_file*))); + sequence_dialog->show(); +} void MainWindow::openTcpStreamDialog(int graph_type) { diff --git a/ui/qt/sequence_diagram.cpp b/ui/qt/sequence_diagram.cpp new file mode 100644 index 0000000000..24d33b9d57 --- /dev/null +++ b/ui/qt/sequence_diagram.cpp @@ -0,0 +1,227 @@ +/* sequence_diagram.cpp + * + * $Id: tcp_stream_dialog.h 52102 2013-09-16 17:28:42Z gerald $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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 "sequence_diagram.h" + +#include + +#include +#include +#include +#include + +#include + +const int max_comment_em_width_ = 20; + +// UML-like network node sequence diagrams. +// http://www.ibm.com/developerworks/rational/library/3101.html + +WSCPSeqData::WSCPSeqData() : + key(0), + value(NULL) +{ +} + +WSCPSeqData::WSCPSeqData(double key, seq_analysis_item_t *value) : + key(key), + value(value) +{ +} + +SequenceDiagram::SequenceDiagram(QCPAxis *keyAxis, QCPAxis *valueAxis, QCPAxis *commentAxis) : + QCPAbstractPlottable(keyAxis, valueAxis), + key_axis_(keyAxis), + value_axis_(valueAxis), + comment_axis_(commentAxis), + sainfo_(NULL) +{ + data_ = new WSCPSeqDataMap(); + // xaxis (value): Address + // yaxis (key): Time + // yaxis2 (comment): Extra info ("Comment" in GTK+) + +// valueAxis->setAutoTickStep(false); + QList axes; + axes << value_axis_ << key_axis_ << comment_axis_; + foreach (QCPAxis *axis, axes) { + axis->setAutoTicks(false); + axis->setTickStep(1.0); + axis->setAutoTickLabels(false); + axis->setTicks(false); + axis->setBasePen(QPen(Qt::NoPen)); + } + + value_axis_->grid()->setVisible(true); + + key_axis_->setRangeReversed(true); + key_axis_->grid()->setVisible(false); + + comment_axis_->setRangeReversed(true); + comment_axis_->grid()->setVisible(false); + + QFont comment_font = comment_axis_->tickLabelFont(); + comment_axis_->setTickLabelFont(comment_font); + comment_axis_->setSelectedTickLabelFont(QFont(comment_font.family(), comment_font.pointSize(), QFont::Bold)); + // frame_label + // port_src -----------------> port_dst + +// setTickVectorLabels + // valueAxis->setTickLabelRotation(30); +} + +void SequenceDiagram::setData(seq_analysis_info_t *sainfo) +{ + data_->clear(); + WSCPSeqData new_data; + double cur_key = 0.0; + QVector key_ticks, val_ticks; + QVector key_labels, val_labels, com_labels; + QFontMetrics com_fm(comment_axis_->tickLabelFont()); + int elide_w = com_fm.height() * max_comment_em_width_; + + for (GList *cur = g_list_first(sainfo->list); cur; cur = g_list_next(cur)) { + seq_analysis_item_t *sai = (seq_analysis_item_t *) cur->data; + + new_data.key = cur_key; + new_data.value = sai; + data_->insertMulti(new_data.key, new_data); + + key_ticks.append(cur_key); + key_labels.append(sai->time_str); + com_labels.append(com_fm.elidedText(sai->comment, Qt::ElideRight, elide_w)); + + cur_key++; + } + sainfo_ = sainfo; + + for (unsigned int i = 0; i < sainfo_->num_nodes; i++) { + val_ticks.append(i); + val_labels.append(get_addr_name(&(sainfo_->nodes[i]))); + } + keyAxis()->setTickVector(key_ticks); + keyAxis()->setTickVectorLabels(key_labels); + valueAxis()->setTickVector(val_ticks); + valueAxis()->setTickVectorLabels(val_labels); + comment_axis_->setTickVector(key_ticks); + comment_axis_->setTickVectorLabels(com_labels); +} + +double SequenceDiagram::selectTest(const QPointF &pos, bool onlySelectable, QVariant *details) const +{ + Q_UNUSED(pos); + Q_UNUSED(onlySelectable); + Q_UNUSED(details); + return -1.0; +} + +void SequenceDiagram::draw(QCPPainter *painter) +{ + WSCPSeqDataMap::const_iterator it; + for (it = data_->constBegin(); it != data_->constEnd(); ++it) { + double cur_key = it.key(); + seq_analysis_item_t *sai = (seq_analysis_item_t *) it.value().value; + + if (cur_key < key_axis_->range().lower || cur_key > key_axis_->range().upper) { + continue; + } + if (sai->dst_node > sai->src_node && (sai->dst_node < value_axis_->range().lower || sai->src_node > value_axis_->range().upper)) { + continue; + } + if (sai->src_node > sai->dst_node && (sai->src_node < value_axis_->range().lower || sai->dst_node > value_axis_->range().upper)) { + continue; + } + double ah_size = (QFontMetrics(comment_axis_->tickLabelFont()).height() / 5) + * ((sai->src_node < sai->dst_node) ? 1 : -1); + QPointF arrow_end(coordsToPixels(cur_key, sai->dst_node)); + QLineF arrow_line(coordsToPixels(cur_key, sai->src_node), arrow_end); + QPolygonF arrow_head; + arrow_head + << QPointF(arrow_end.x() - (ah_size*3), arrow_end.y() - ah_size) + << arrow_end + << QPointF(arrow_end.x() - (ah_size*3), arrow_end.y() + ah_size); + if (mainPen().style() != Qt::NoPen && mainPen().color().alpha() != 0) { + painter->setBrush(mainPen().color()); + painter->setPen(mainPen()); + painter->drawLine(arrow_line); + painter->drawPolygon(arrow_head); + } + } +} + +void SequenceDiagram::drawLegendIcon(QCPPainter *painter, const QRectF &rect) const +{ + Q_UNUSED(painter); + Q_UNUSED(rect); +} + +QCPRange SequenceDiagram::getKeyRange(bool &validRange, QCPAbstractPlottable::SignDomain inSignDomain) const +{ + Q_UNUSED(inSignDomain); + QCPRange range; + bool valid = false; + + WSCPSeqDataMap::const_iterator it = data_->constBegin(); + while (it != data_->constEnd()) { + double cur_key = it.key(); + if (!valid) { + range.lower = range.upper = cur_key; + valid = true; + } else if (cur_key < range.lower) { + range.lower = cur_key; + } else if (cur_key > range.upper) { + range.upper = cur_key; + } + ++it; + } + validRange = valid; + return range; +} + +QCPRange SequenceDiagram::getValueRange(bool &validRange, QCPAbstractPlottable::SignDomain inSignDomain) const +{ + Q_UNUSED(inSignDomain); + QCPRange range; + bool valid = false; + + if (sainfo_) { + range.lower = 0; + range.upper = sainfo_->num_nodes; + valid = true; + } + validRange = valid; + return range; +} + +/* + * 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: + */ diff --git a/ui/qt/sequence_diagram.h b/ui/qt/sequence_diagram.h new file mode 100644 index 0000000000..14c3a9ada5 --- /dev/null +++ b/ui/qt/sequence_diagram.h @@ -0,0 +1,107 @@ +/* sequence_diagram.h + * + * $Id: tcp_stream_dialog.h 52102 2013-09-16 17:28:42Z gerald $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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 SEQUENCE_DIAGRAM_H +#define SEQUENCE_DIAGRAM_H + +#include "config.h" + +#include + +#include + +#include "ui/tap-sequence-analysis.h" + +#include +#include +#include "qcustomplot.h" + +// Most of this is probably unnecessary +class WSCPSeqData +{ +public: + WSCPSeqData(); + WSCPSeqData(double key, seq_analysis_item_t *value); + double key; + seq_analysis_item_t *value; +}; +Q_DECLARE_TYPEINFO(WSCPSeqData, Q_MOVABLE_TYPE); + +typedef QMap WSCPSeqDataMap; +typedef QMapIterator WSCPSeqDataMapIterator; +typedef QMutableMapIterator WSCPSeqDataMutableMapIterator; + +// XXX Should we dispense with this class and simply add items to a graph instead? +class SequenceDiagram : public QCPAbstractPlottable +{ + Q_OBJECT +public: + explicit SequenceDiagram(QCPAxis *keyAxis, QCPAxis *valueAxis, QCPAxis *commentAxis); + + // getters: +// double width() const { return mWidth; } +// WSCPSeqDataMap *data() const { return mData; } + + // setters: +// void setWidth(double width); + void setData(seq_analysis_info_t *sainfo); +// void setData(const QVector &key, const QVector &value); + + // non-property methods: +// void addData(const WSCPSeqDataMap &dataMap); +// void addData(const WSCPSeqData &data); +// void addData(double key, double value); +// void addData(const QVector &keys, const QVector &values); + + // reimplemented virtual methods: + virtual void clearData() {} + virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const; + +protected: + virtual void draw(QCPPainter *painter); + virtual void drawLegendIcon(QCPPainter *painter, const QRectF &rect) const; + virtual QCPRange getKeyRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; + virtual QCPRange getValueRange(bool &validRange, SignDomain inSignDomain=sdBoth) const; + +private: + QCPAxis *key_axis_; + QCPAxis *value_axis_; + QCPAxis *comment_axis_; + WSCPSeqDataMap *data_; + seq_analysis_info_t *sainfo_; +}; + +#endif // SEQUENCE_DIAGRAM_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: + */ diff --git a/ui/qt/sequence_dialog.cpp b/ui/qt/sequence_dialog.cpp new file mode 100644 index 0000000000..36ff6e8078 --- /dev/null +++ b/ui/qt/sequence_dialog.cpp @@ -0,0 +1,147 @@ +/* sequence_dialog.cpp + * + * $Id: tcp_stream_dialog.cpp 52108 2013-09-16 21:33:26Z gerald $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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 "sequence_dialog.h" +#include "ui_sequence_dialog.h" + +#include "wsutil/nstime.h" + +#include + +#include + +// To do: +// - Fix horizontal scrolling +// - Save as +// - Sequence item labels +// - Scroll bars +// - Selection +// - Keyboard shortcuts +// - ... + +SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, SequenceType type) : + QDialog(parent), + ui(new Ui::SequenceDialog), + cap_file_(cf) +{ + ui->setupUi(this); + QCustomPlot *sp = ui->sequencePlot; + + seq_diagram_ = new SequenceDiagram(ui->sequencePlot->yAxis, ui->sequencePlot->xAxis2, + ui->sequencePlot->yAxis2); + sp->addPlottable(seq_diagram_); + + sp->xAxis->setVisible(false); + sp->xAxis2->setVisible(true); + sp->yAxis2->setVisible(true); + + one_em_ = QFontMetrics(sp->yAxis->labelFont()).height(); + + sp->setInteractions(QCP::iRangeDrag); + + connect(sp->yAxis, SIGNAL(rangeChanged(QCPRange)), sp->yAxis2, SLOT(setRange(QCPRange))); + + memset (&seq_analysis_, 0, sizeof(seq_analysis_)); + switch (type) { + case any: + seq_analysis_.type = SEQ_ANALYSIS_ANY; + break; + case tcp: + seq_analysis_.type = SEQ_ANALYSIS_TCP; + break; + case voip: + seq_analysis_.type = SEQ_ANALYSIS_VOIP; + break; + } + seq_analysis_.all_packets = TRUE; + + if (parent) { + resize(parent->width(), parent->height() * 4 / 5); + } + + fillDiagram(); +} + +SequenceDialog::~SequenceDialog() +{ + delete ui; +} + +void SequenceDialog::setCaptureFile(capture_file *cf) +{ + if (!cf) { // We only want to know when the file closes. + cap_file_ = NULL; + } +} + +void SequenceDialog::showEvent(QShowEvent *event) +{ + Q_UNUSED(event); + resetAxes(); +} + +void SequenceDialog::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + resetAxes(true); +} + +void SequenceDialog::fillDiagram() +{ + QCustomPlot *sp = ui->sequencePlot; + + sequence_analysis_list_free(&seq_analysis_); + sequence_analysis_list_get(cap_file_, &seq_analysis_); + sequence_analysis_get_nodes(&seq_analysis_); + + seq_diagram_->setData(&seq_analysis_); +// ui->sequencePlot->rescaleAxes(); + sp->replot(); + + resetAxes(); +// tracer_->setGraph(base_graph_); + + // XXX QCustomPlot doesn't seem to draw any sort of focus indicator. + sp->setFocus(); +} + +void SequenceDialog::resetAxes(bool keep_lower) +{ + QCustomPlot *sp = ui->sequencePlot; + double top_pos = -1.0; + if (keep_lower) { + top_pos = sp->yAxis->range().lower; + } + + sp->xAxis->moveRange(sp->xAxis->range().lower * -1); + + double range_ratio = sp->yAxis->axisRect()->height() / one_em_; + sp->yAxis->setRange(top_pos, range_ratio + top_pos); + + sp->replot(); +} + +void SequenceDialog::on_resetButton_clicked() +{ + resetAxes(); +} diff --git a/ui/qt/sequence_dialog.h b/ui/qt/sequence_dialog.h new file mode 100644 index 0000000000..7287e031ee --- /dev/null +++ b/ui/qt/sequence_dialog.h @@ -0,0 +1,78 @@ +/* sequence_dialog.h + * + * $Id: tcp_stream_dialog.cpp 52108 2013-09-16 21:33:26Z gerald $ + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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 SEQUENCE_DIALOG_H +#define SEQUENCE_DIALOG_H + +#include "config.h" + +#include + +#include "cfile.h" + +#include "epan/packet.h" + +#include "sequence_diagram.h" + +#include + +namespace Ui { +class SequenceDialog; +} + +class SequenceDialog : public QDialog +{ + Q_OBJECT + +public: + enum SequenceType { any, tcp, voip }; + + explicit SequenceDialog(QWidget *parent = 0, capture_file *cf = NULL, SequenceType type = any); + ~SequenceDialog(); + +signals: + void goToPacket(int packet_num); + +public slots: + void setCaptureFile(capture_file *cf); + +protected: + void showEvent(QShowEvent *event); + void resizeEvent(QResizeEvent *event); + +private slots: + void on_resetButton_clicked(); + +private: + Ui::SequenceDialog *ui; + SequenceDiagram *seq_diagram_; + capture_file *cap_file_; + seq_analysis_info_t seq_analysis_; + double one_em_; + + void fillDiagram(); + void resetAxes(bool keep_lower = false); + +}; + +#endif // SEQUENCE_DIALOG_H diff --git a/ui/qt/sequence_dialog.ui b/ui/qt/sequence_dialog.ui new file mode 100644 index 0000000000..041738cb04 --- /dev/null +++ b/ui/qt/sequence_dialog.ui @@ -0,0 +1,206 @@ + + + SequenceDialog + + + + 0 + 0 + 679 + 568 + + + + Flow + + + + + + + 0 + 1 + + + + + + + + <small><i>A hint</i></small> + + + + + + + + + Show: + + + + + + + + All packets + + + + + Displayed packets + + + + + + + + Qt::Horizontal + + + + 13 + 20 + + + + + + + + Flow type: + + + + + + + + General + + + + + TCP + + + + + + + + Qt::Horizontal + + + + 13 + 20 + + + + + + + + Addresses: + + + + + + + + Any + + + + + Network + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Reset + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok|QDialogButtonBox::Save + + + + + + + + QCustomPlot + QWidget +
qcustomplot.h
+ 1 +
+
+ + + + buttonBox + accepted() + SequenceDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SequenceDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/ui/qt/tcp_stream_dialog.cpp b/ui/qt/tcp_stream_dialog.cpp index 8b22ad5881..c54d463f2d 100644 --- a/ui/qt/tcp_stream_dialog.cpp +++ b/ui/qt/tcp_stream_dialog.cpp @@ -226,7 +226,7 @@ TCPStreamDialog::~TCPStreamDialog() void TCPStreamDialog::showEvent(QShowEvent *event) { - Q_UNUSED(event) + Q_UNUSED(event); resetAxes(); } @@ -374,7 +374,6 @@ void TCPStreamDialog::fillGraph() int pkts_fwd = 0; int pkts_rev = 0; - time_stamp_map_.clear(); for (struct segment *seg = graph_.segments; seg != NULL; seg = seg->next) { if (!compareHeaders(seg)) { diff --git a/ui/tap-sequence-analysis.c b/ui/tap-sequence-analysis.c new file mode 100644 index 0000000000..01e6962aa3 --- /dev/null +++ b/ui/tap-sequence-analysis.c @@ -0,0 +1,620 @@ +/* tap-sequence-analysis.c + * Flow sequence analysis + * + * $Id$ + * + * Some code from from gtk/flow_graph.c + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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 "config.h" + +#include "file.h" + +#include "tap-sequence-analysis.h" + +#include "epan/addr_resolv.h" +#include "epan/column-utils.h" +#include "epan/packet.h" +#include "epan/tap.h" +#include "epan/dissectors/packet-tcp.h" + +#include "ui/alert_box.h" + +#include + +#define NODE_OVERFLOW MAX_NUM_NODES+1 + +#define NODE_CHARS_WIDTH 20 +#define CONV_TIME_HEADER "Conv.| Time " +#define TIME_HEADER "|Time " +#define CONV_TIME_EMPTY_HEADER " | " +#define TIME_EMPTY_HEADER "| " +#define CONV_TIME_HEADER_LENGTH 16 +#define TIME_HEADER_LENGTH 10 + +/****************************************************************************/ +/* whenever a frame packet is seen by the tap listener */ +/* Add a new frame into the graph */ +static gboolean +seq_analysis_frame_packet( void *ptr, packet_info *pinfo, epan_dissect_t *edt _U_, const void *dummy _U_) +{ + seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr; + + if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){ + int i; + gchar *protocol; + gchar *colinfo; + seq_analysis_item_t *sai; + + protocol = NULL; + colinfo = NULL; + + if (sainfo->any_addr) { + if (pinfo->net_src.type!=AT_NONE && pinfo->net_dst.type!=AT_NONE) { + sai = (seq_analysis_item_t *)g_malloc(sizeof(seq_analysis_item_t)); + COPY_ADDRESS(&(sai->src_addr),&(pinfo->net_src)); + COPY_ADDRESS(&(sai->dst_addr),&(pinfo->net_dst)); + } + else return FALSE; + + } else { + if (pinfo->src.type!=AT_NONE && pinfo->dst.type!=AT_NONE) { + sai = (seq_analysis_item_t *)g_malloc(sizeof(seq_analysis_item_t)); + COPY_ADDRESS(&(sai->src_addr),&(pinfo->src)); + COPY_ADDRESS(&(sai->dst_addr),&(pinfo->dst)); + } + else return FALSE; + } + + sai->fd = pinfo->fd; + + sai->port_src=pinfo->srcport; + sai->port_dst=pinfo->destport; + sai->comment=NULL; + sai->frame_label=NULL; + + if(pinfo->cinfo) { + if (pinfo->cinfo->col_first[COL_INFO]>=0){ + + for (i = pinfo->cinfo->col_first[COL_INFO]; i <= pinfo->cinfo->col_last[COL_INFO]; i++) { + if (pinfo->cinfo->fmt_matx[i][COL_INFO]) { + colinfo = g_strdup(pinfo->cinfo->col_data[i]); + /* break; ? or g_free(colinfo); before g_strdup() */ + } + } + } + + if (pinfo->cinfo->col_first[COL_PROTOCOL]>=0){ + + for (i = pinfo->cinfo->col_first[COL_PROTOCOL]; i <= pinfo->cinfo->col_last[COL_PROTOCOL]; i++) { + if (pinfo->cinfo->fmt_matx[i][COL_PROTOCOL]) { + protocol = g_strdup(pinfo->cinfo->col_data[i]); + /* break; ? or g_free(protocol); before g_strdup() */ + } + } + } + } + + if (colinfo != NULL) { + if (protocol != NULL) { + sai->frame_label = g_strdup_printf("%.19s", colinfo); + sai->comment = g_strdup_printf("%s: %s", protocol, colinfo); + } else { + sai->frame_label = g_strdup_printf("%.19s", colinfo); + sai->comment = g_strdup_printf("%s", colinfo); + } + } else { + /* This will probably never happen...*/ + if (protocol != NULL) { + sai->frame_label = g_strdup_printf("%.19s", protocol); + sai->comment = g_strdup_printf("%s", protocol); + } + } + + g_free(protocol); + g_free(colinfo); + + sai->line_style=1; + sai->conv_num=0; + sai->display=TRUE; + + sainfo->list = g_list_prepend(sainfo->list, sai); + } + + return TRUE; +} + +/****************************************************************************/ +/* whenever a TCP packet is seen by the tap listener */ +/* Add a new tcp frame into the graph */ +static gboolean +seq_analysis_tcp_packet( void *ptr _U_, packet_info *pinfo, epan_dissect_t *edt _U_, const void *tcp_info) +{ + seq_analysis_info_t *sainfo = (seq_analysis_info_t *) ptr; + const struct tcpheader *tcph = (struct tcpheader *)tcp_info; + + if ((sainfo->all_packets)||(pinfo->fd->flags.passed_dfilter==1)){ + /* copied from packet-tcp */ + static const gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG", "ECN", "CWR" }; + guint i, bpos; + gboolean flags_found = FALSE; + gchar flags[64]; + seq_analysis_item_t *sai; + + sai = (seq_analysis_item_t *)g_malloc(sizeof(seq_analysis_item_t)); + sai->fd = pinfo->fd; + if (sainfo->any_addr) { + COPY_ADDRESS(&(sai->src_addr),&(pinfo->net_src)); + COPY_ADDRESS(&(sai->dst_addr),&(pinfo->net_dst)); + } else { + COPY_ADDRESS(&(sai->src_addr),&(pinfo->src)); + COPY_ADDRESS(&(sai->dst_addr),&(pinfo->dst)); + } + sai->port_src=pinfo->srcport; + sai->port_dst=pinfo->destport; + + flags[0] = '\0'; + for (i = 0; i < 8; i++) { + bpos = 1 << i; + if (tcph->th_flags & bpos) { + if (flags_found) { + g_strlcat(flags, ", ", sizeof(flags)); + } + g_strlcat(flags, fstr[i], sizeof(flags)); + flags_found = TRUE; + } + } + if (flags[0] == '\0') { + g_snprintf (flags, sizeof(flags), ""); + } + + if ((tcph->th_have_seglen)&&(tcph->th_seglen!=0)){ + sai->frame_label = g_strdup_printf("%s - Len: %u",flags, tcph->th_seglen); + } + else{ + sai->frame_label = g_strdup(flags); + } + + if (tcph->th_flags & TH_ACK) + sai->comment = g_strdup_printf("Seq = %u Ack = %u",tcph->th_seq, tcph->th_ack); + else + sai->comment = g_strdup_printf("Seq = %u",tcph->th_seq); + + sai->line_style = 1; + sai->conv_num = 0; + sai->display = TRUE; + + sainfo->list = g_list_prepend(sainfo->list, sai); + } + + return TRUE; +} + +void +sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo) +{ + GList *list; + gchar time_str[COL_MAX_LEN]; + + if (!cf || !sainfo) return; + + switch (sainfo->type) { + case SEQ_ANALYSIS_ANY: + register_tap_listener("frame", sainfo, NULL, + TL_REQUIRES_COLUMNS, + NULL, + seq_analysis_frame_packet, + NULL + ); + break; + case SEQ_ANALYSIS_TCP: + register_tap_listener("tcp", sainfo, NULL, + 0, + NULL, + seq_analysis_tcp_packet, + NULL + ); + break; + case SEQ_ANALYSIS_VOIP: + default: + return; + break; + + } + + cf_retap_packets(cf); + sainfo->list = g_list_reverse(sainfo->list); + remove_tap_listener(sainfo); + + /* Fill in the timestamps */ + list = g_list_first(sainfo->list); + while (list) + { + seq_analysis_item_t *seq_item = (seq_analysis_item_t *)list->data; + set_fd_time(cf->epan, seq_item->fd, time_str); + seq_item->time_str = g_strdup(time_str); + list = g_list_next(list); + } +} + +void +sequence_analysis_list_free(seq_analysis_info_t *sainfo) +{ + GList *list; + + if (!sainfo) return; + + /* free the graph data items */ + list = g_list_first(sainfo->list); + while (list) + { + seq_analysis_item_t *seq_item = (seq_analysis_item_t *)list->data; + g_free(seq_item->frame_label); + g_free(seq_item->time_str); + g_free(seq_item->comment); + g_free(list->data); + list = g_list_next(list); + } + g_list_free(sainfo->list); + sainfo->nconv = 0; + sainfo->list = NULL; +} + +/****************************************************************************/ +/* Adds trailing characters to complete the requested length. */ +/****************************************************************************/ + +static void enlarge_string(GString *gstr, guint32 length, char pad) { + + gsize i; + + for (i = gstr->len; i < length; i++) { + g_string_append_c(gstr, pad); + } +} + +/****************************************************************************/ +/* overwrites the characters in a string, between positions p1 and p2, with */ +/* the characters of text_to_insert */ +/* NB: it does not check that p1 and p2 fit into string */ +/****************************************************************************/ + +static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32 p2) { + + gsize len; + gsize pos; + + if (p1 == p2) + return; + + if (p1 > p2) { + pos = p2; + len = p1 - p2; + } + else{ + pos = p1; + len = p2 - p1; + } + + if (len > strlen(text_to_insert)) { + len = strlen(text_to_insert); + } + + if (pos > gstr->len) + pos = gstr->len; + + /* ouch this is ugly but gtk1 needs it */ + if ((pos + len) > gstr->len) + g_string_truncate(gstr, pos); + else + g_string_erase(gstr, pos, len); + + g_string_insert(gstr, pos, text_to_insert); +} + +/* Return the index array if the node is in the array. Return -1 if there is room in the array + * and Return -2 if the array is full + */ +/****************************************************************************/ +static gint add_or_get_node(seq_analysis_info_t *sainfo, address *node) { + guint i; + + if (node->type == AT_NONE) return NODE_OVERFLOW; + + for (i=0; inum_nodes ; i++) { + if ( CMP_ADDRESS(&(sainfo->nodes[i]), node) == 0 ) return i; /* it is in the array */ + } + + if (i == MAX_NUM_NODES) { + return NODE_OVERFLOW; + } else { + sainfo->num_nodes++; + COPY_ADDRESS(&(sainfo->nodes[i]), node); + return i; + } +} + +/* Get the nodes from the list */ +/****************************************************************************/ +int +sequence_analysis_get_nodes(seq_analysis_info_t *sainfo) +{ + GList *list; + seq_analysis_item_t *gai; + int num_items = 0; + + /* fill the node array */ + list = g_list_first(sainfo->list); + while (list) + { + gai = (seq_analysis_item_t *)list->data; + if (gai->display) { + num_items++; +#if 0 /* inverse is always false ? */ + if (!user_data->dlg.inverse) { +#endif + gai->src_node = (guint16)add_or_get_node(sainfo, &(gai->src_addr)); + gai->dst_node = (guint16)add_or_get_node(sainfo, &(gai->dst_addr)); +#if 0 /* inverse is always false ? */ + } else { + gai->dst_node = (guint16)add_or_get_node(sainfo, &(gai->src_addr)); + gai->src_node = (guint16)add_or_get_node(sainfo, &(gai->dst_addr)); + } +#endif + } + list = g_list_next(list); + } + return num_items; +} + +/****************************************************************************/ +gboolean +sequence_analysis_dump_to_file(char *pathname, seq_analysis_info_t *sainfo, capture_file *cf, unsigned int first_node) +{ + guint32 i, display_items, display_nodes; + guint32 start_position, end_position, item_width, header_length; + seq_analysis_item_t *sai; + guint16 first_conv_num = 0; + gboolean several_convs = FALSE; + gboolean first_packet = TRUE; + + GString *label_string, *empty_line, *separator_line, *tmp_str, *tmp_str2; + const char *empty_header; + char src_port[8], dst_port[8]; + gchar *time_str; + GList *list; + + FILE *of; + + of = ws_fopen(pathname, "w"); + if (of==NULL) { + open_failure_alert_box(pathname, errno, TRUE); + return FALSE; + } + + time_str = (gchar *)g_malloc(COL_MAX_LEN); + label_string = g_string_new(""); + empty_line = g_string_new(""); + separator_line = g_string_new(""); + tmp_str = g_string_new(""); + tmp_str2 = g_string_new(""); + + display_items = 0; + list = g_list_first(sainfo->list); + while (list) + { + sai = (seq_analysis_item_t *)list->data; + list = g_list_next(list); + + if (!sai->display) + continue; + + display_items += 1; + if (first_packet) { + first_conv_num = sai->conv_num; + first_packet = FALSE; + } + else if (sai->conv_num != first_conv_num) { + several_convs = TRUE; + } + } + + /* if not items to display */ + if (display_items == 0) + goto exit; + + display_nodes = sainfo->num_nodes; + + /* Write the conv. and time headers */ + if (several_convs) { + fprintf(of, CONV_TIME_HEADER); + empty_header = CONV_TIME_EMPTY_HEADER; + header_length = CONV_TIME_HEADER_LENGTH; + } + else{ + fprintf(of, TIME_HEADER); + empty_header = TIME_EMPTY_HEADER; + header_length = TIME_HEADER_LENGTH; + } + + /* Write the node names on top */ + for (i=0; inodes[i+first_node]))); + enlarge_string(label_string, NODE_CHARS_WIDTH*2, ' '); + fprintf(of, "%s", label_string->str); + g_string_printf(label_string, "| "); + enlarge_string(label_string, NODE_CHARS_WIDTH, ' '); + g_string_append(empty_line, label_string->str); + } + + fprintf(of, "|\n%s", empty_header); + g_string_printf(label_string, "| "); + enlarge_string(label_string, NODE_CHARS_WIDTH, ' '); + fprintf(of, "%s", label_string->str); + + /* Write the node names on top */ + for (i=1; inodes[i+first_node]))); + if (label_string->len < NODE_CHARS_WIDTH) + { + enlarge_string(label_string, NODE_CHARS_WIDTH, ' '); + g_string_append(label_string, "| "); + } + enlarge_string(label_string, NODE_CHARS_WIDTH*2, ' '); + fprintf(of, "%s", label_string->str); + g_string_printf(label_string, "| "); + enlarge_string(label_string, NODE_CHARS_WIDTH, ' '); + g_string_append(empty_line, label_string->str); + } + + fprintf(of, "\n"); + + g_string_append_c(empty_line, '|'); + + enlarge_string(separator_line, (guint32) empty_line->len + header_length, '-'); + + /* + * Draw the items + */ + + list = g_list_first(sainfo->list); + while (list) + { + sai = (seq_analysis_item_t *)list->data; + list = g_list_next(list); + + if (!sai->display) + continue; + + start_position = (sai->src_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2; + + end_position = (sai->dst_node-first_node)*NODE_CHARS_WIDTH+NODE_CHARS_WIDTH/2; + + if (start_position > end_position) { + item_width = start_position-end_position; + } + else if (start_position < end_position) { + item_width = end_position-start_position; + } + else{ /* same origin and destination address */ + end_position = start_position+NODE_CHARS_WIDTH; + item_width = NODE_CHARS_WIDTH; + } + + /* separator between conversations */ + if (sai->conv_num != first_conv_num) { + fprintf(of, "%s\n", separator_line->str); + first_conv_num = sai->conv_num; + } + + /* write the conversation number */ + if (several_convs) { + g_string_printf(label_string, "%i", sai->conv_num); + enlarge_string(label_string, 5, ' '); + fprintf(of, "%s", label_string->str); + } + +#if 0 + /* write the time */ + g_string_printf(label_string, "|%.3f", nstime_to_sec(&sai->fd->rel_ts)); +#endif + /* Write the time, using the same format as in the time col */ + set_fd_time(cf->epan, sai->fd, time_str); + g_string_printf(label_string, "|%s", time_str); + enlarge_string(label_string, 10, ' '); + fprintf(of, "%s", label_string->str); + + /* write the frame label */ + + g_string_printf(tmp_str, "%s", empty_line->str); + overwrite(tmp_str, sai->frame_label, + start_position, + end_position + ); + fprintf(of, "%s", tmp_str->str); + + /* write the comments */ + fprintf(of, "%s\n", sai->comment); + + /* write the arrow and frame label*/ + fprintf(of, "%s", empty_header); + + g_string_printf(tmp_str, "%s", empty_line->str); + + g_string_truncate(tmp_str2, 0); + + if (start_position'); + } + else{ + g_string_printf(tmp_str2, "<"); + enlarge_string(tmp_str2, item_width-1, '-'); + } + + overwrite(tmp_str, tmp_str2->str, + start_position, + end_position + ); + + g_snprintf(src_port, sizeof(src_port), "(%i)", sai->port_src); + g_snprintf(dst_port, sizeof(dst_port), "(%i)", sai->port_dst); + + if (start_positionstr); + } + +exit: + g_string_free(label_string, TRUE); + g_string_free(empty_line, TRUE); + g_string_free(separator_line, TRUE); + g_string_free(tmp_str, TRUE); + g_string_free(tmp_str2, TRUE); + g_free(time_str); + fclose (of); + return TRUE; + +} + +/* + * 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: + */ diff --git a/ui/tap-sequence-analysis.h b/ui/tap-sequence-analysis.h new file mode 100644 index 0000000000..18057db49d --- /dev/null +++ b/ui/tap-sequence-analysis.h @@ -0,0 +1,129 @@ +/* tap-sequence-analysis.h + * Flow sequence analysis + * + * $Id$ + * + * Copied from gtk/graph_analysis.h + * + * Copyright 2004, Verso Technologies Inc. + * By Alejandro Vaquero + * + * based on rtp_analysis.c and io_stat + * + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * 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 __TAP_SEQUENCE_ANALYSIS_H__ +#define __TAP_SEQUENCE_ANALYSIS_H__ + +#include + +#include "cfile.h" +#include "epan/address.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define MAX_NUM_NODES 40 + +typedef enum seq_analysis_type_ { + SEQ_ANALYSIS_ANY, + SEQ_ANALYSIS_TCP, + SEQ_ANALYSIS_VOIP +} seq_analysis_type; + +/** defines an entry for the graph analysis */ +typedef struct _seq_analysis_item { + frame_data *fd; /**< Holds the frame number and time information */ + address src_addr; + guint16 port_src; + address dst_addr; + guint16 port_dst; + gchar *frame_label; /**< the label on top of the arrow */ + gchar *time_str; /**< timestamp */ + gchar *comment; /**< a comment that appears at the left of the graph */ + guint16 conv_num; /**< the conversation number, each conversation will be colored */ + gboolean display; /**< indicate if the packet is displayed or not in the graph */ + guint16 src_node; /**< this is used by graph_analysis.c to identify the node */ + guint16 dst_node; /**< a node is an IP address that will be displayed in columns */ + guint16 line_style; /**< the arrow line width in pixels*/ +} seq_analysis_item_t; + +/** defines the graph analysis structure */ +typedef struct _seq_analysis_info { + seq_analysis_type type; /**< sequence type */ + gboolean all_packets; /**< all packets vs only displayed */ + gboolean any_addr; /**< any addr (DL+net) vs net-only */ + int nconv; /**< number of conversations in the list */ + GList* list; /**< list with the graph analysis items */ + GHashTable *ht; /**< hash table for retrieving graph analysis items */ + address nodes[MAX_NUM_NODES]; /**< horizontal node list */ + guint32 num_nodes; /**< actual number of nodes */ +} seq_analysis_info_t; + +/** Fill in the segment list for sequence analysis + * + * @param cf Capture file to scan + * @param sai Sequence analysis information. A valid type must be set. + */ +void sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo); + +/** Free the segment list + * + * @param sai Sequence analysis information. + */ +void sequence_analysis_list_free(seq_analysis_info_t *sainfo); + +/** Fill in the node address list + * + * @param sai Sequence analysis information. + * @return The number of transaction items (not nodes) processed. + */ +int sequence_analysis_get_nodes(seq_analysis_info_t *sainfo); + +/** Write an ASCII version of the sequence diagram to a file. + * + * @param pathname Pathname of the file to write. + * @param sai Sequence analysis information. + * @param cf Capture file associated with the diagram. + * @param first_node Start drawing at this node. + * @return TRUE on success, FALSE on failure. + */ +gboolean sequence_analysis_dump_to_file(char *pathname, seq_analysis_info_t *sainfo, capture_file *cf, unsigned int first_node); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TAP_SEQUENCE_ANALYSIS_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: + */