/* voip_calls_dlg.c * VoIP calls summary addition for ethereal * * $Id$ * * Copyright 2004, Ericsson , Spain * By Francisco Alcoba * * based on h323_calls_dlg.c * Copyright 2004, Iskratel, Ltd, Kranj * By Miha Jemec * * H323, RTP and Graph Support * By Alejandro Vaquero, alejandro.vaquero@verso.com * Copyright 2005, Verso Technologies Inc. * * Ethereal - 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "register.h" #include "graph_analysis.h" #include "voip_calls_dlg.h" #include "voip_calls.h" #include "globals.h" #include "epan/filesystem.h" #include #include #include "../stat_menu.h" #include "gui_stat_menu.h" #include "dlg_utils.h" #include "gui_utils.h" #include "compat_macros.h" #include "gtkglobals.h" #include "image/clist_ascend.xpm" #include "image/clist_descend.xpm" #include "simple_dialog.h" #include #include #include #include #include static const gchar FWD_LABEL_TEXT[] = "Select one call."; /****************************************************************************/ /* pointer to the one and only dialog window */ static GtkWidget *voip_calls_dlg = NULL; static GtkWidget *clist = NULL; static GtkWidget *top_label = NULL; static GtkWidget *status_label = NULL; static GtkWidget *label_fwd = NULL; /*static GtkWidet *bt_unselect = NULL;*/ static GtkWidget *bt_filter = NULL; static GtkWidget *bt_graph = NULL; static voip_calls_info_t* selected_call_fwd = NULL; /* current selection */ static GList *last_list = NULL; static guint32 calls_nb = 0; /* number of displayed calls */ static guint32 calls_ns = 0; /* number of selected calls */ static graph_analysis_data_t *graph_analysis_data = NULL; #define NUM_COLS 9 static const GdkColor COLOR_SELECT = {0, 0x00ff, 0x80ff, 0x80ff}; static const GdkColor COLOR_DEFAULT = {0, 0xffff, 0xffff, 0xffff}; /****************************************************************************/ /* append a line to clist */ static void add_to_clist(voip_calls_info_t* strinfo) { gchar label_text[256]; gint added_row; gchar *data[NUM_COLS]; gchar field[NUM_COLS][50]; gint c; isup_calls_info_t *tmp_isupinfo; h323_calls_info_t *tmp_h323info; gboolean tmp_bool = FALSE; GdkColor color = COLOR_SELECT; for (c=0;cselected = FALSE;*/ g_snprintf(field[0], 15, "%i.%2i", strinfo->start_sec, strinfo->start_usec/10000); g_snprintf(field[1], 15, "%i.%2i", strinfo->stop_sec, strinfo->stop_usec/10000); /* xxx display_signed_time(data[0], sizeof(field[0]), strinfo->start_sec, strinfo->start_usec, USECS); */ /* display_signed_time(data[1], sizeof(field[0]), strinfo->stop_sec, strinfo->stop_usec, USECS); */ g_snprintf(field[2], 30, "%s", get_addr_name(&(strinfo->initial_speaker))); g_snprintf(field[3], 50, "%s", strinfo->from_identity); g_snprintf(field[4], 50, "%s", strinfo->to_identity); g_snprintf(field[5], 15, "%s", voip_protocol_name[strinfo->protocol]); g_snprintf(field[6], 15, "%u", strinfo->npackets); g_snprintf(field[7], 15, "%s", voip_call_state_name[strinfo->call_state]); /* Add comments based on the protocol */ switch(strinfo->protocol){ case VOIP_ISUP: tmp_isupinfo = strinfo->prot_info; g_snprintf(field[8],30, "%i-%i -> %i-%i", tmp_isupinfo->ni, tmp_isupinfo->opc, tmp_isupinfo->ni, tmp_isupinfo->dpc); break; case VOIP_H323: tmp_h323info = strinfo->prot_info; if (strinfo->call_state == VOIP_CALL_SETUP) tmp_bool = tmp_h323info->is_faststart_Setup; else if ((tmp_h323info->is_faststart_Setup == TRUE) && (tmp_h323info->is_faststart_Proc == TRUE)) tmp_bool = TRUE; g_snprintf(field[8],35, "Tunneling: %s Fast Start: %s", (tmp_h323info->is_h245Tunneling==TRUE?"ON":"OFF"), (tmp_bool==TRUE?"ON":"OFF")); break; default: field[8][0]='\0'; } added_row = gtk_clist_append(GTK_CLIST(clist), data); /* set the background color if selected */ if (strinfo->selected) { calls_ns++; gtk_clist_set_background(GTK_CLIST(clist), added_row, &color); } /* set data pointer of last row to point to user data for that row */ gtk_clist_set_row_data(GTK_CLIST(clist), added_row, strinfo); /* Update the top label with the number of detected calls */ calls_nb++; g_snprintf(label_text, 256, "Detected %d VoIP %s. Selected %d %s.", calls_nb, plurality(calls_nb, "Call", "Calls"), calls_ns, plurality(calls_ns, "Call", "Calls")); gtk_label_set(GTK_LABEL(top_label), label_text); /* Update the status label with the number of total messages */ g_snprintf(label_text, 256, "Total: Calls: %d Start packets: %d Completed calls: %d Rejected calls: %d", g_list_length(voip_calls_get_info()->strinfo_list), voip_calls_get_info()->start_packets, voip_calls_get_info()->completed_calls, voip_calls_get_info()->rejected_calls); gtk_label_set(GTK_LABEL(status_label), label_text); } static void voip_calls_remove_tap_listener(void) { /* Remove the calls tap listener */ remove_tap_listener_sip_calls(); remove_tap_listener_isup_calls(); remove_tap_listener_mtp3_calls(); remove_tap_listener_h225_calls(); remove_tap_listener_h245dg_calls(); remove_tap_listener_q931_calls(); remove_tap_listener_sdp_calls(); remove_tap_listener_rtp(); remove_tap_listener_rtp_event(); if (find_tap_id("mgcp")) { remove_tap_listener_mgcp_calls(); } remove_tap_listener_actrace_calls(); remove_tap_listener_t38(); } /****************************************************************************/ /* CALLBACKS */ /****************************************************************************/ static void voip_calls_on_destroy (GtkObject *object _U_, gpointer user_data _U_) { /* remove_tap_listeners */ voip_calls_remove_tap_listener(); /* Clean up memory used by calls tap */ voip_calls_dlg_reset(NULL); /* Note that we no longer have a "VoIP Calls" dialog box. */ voip_calls_dlg = NULL; graph_analysis_data = NULL; } /****************************************************************************/ static void voip_calls_on_unselect (GtkButton *button _U_, gpointer user_data _U_) { selected_call_fwd = NULL; gtk_clist_unselect_all(GTK_CLIST(clist)); gtk_label_set_text(GTK_LABEL(label_fwd), FWD_LABEL_TEXT); /*gtk_widget_set_sensitive(bt_unselect, FALSE);*/ gtk_widget_set_sensitive(bt_filter, FALSE); gtk_widget_set_sensitive(bt_graph, FALSE); } /****************************************************************************/ static void voip_calls_on_filter (GtkButton *button _U_, gpointer user_data _U_) { const gchar *filter_string; gchar c; GString *filter_string_fwd; const gchar *filter_prepend; gboolean isFirst = TRUE; GList* list; guint filter_length = 0; guint max_filter_length = 2048; sip_calls_info_t *tmp_sipinfo; isup_calls_info_t *tmp_isupinfo; h323_calls_info_t *tmp_h323info; h245_address_t *h245_add = NULL; graph_analysis_item_t *gai; if (selected_call_fwd==NULL) return; filter_string=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget)); filter_length = strlen(filter_string); filter_prepend = ""; while ((c = *filter_string++) != '\0') { if (!isspace((guchar)c)) { /* The filter string isn't blank, so there's already an expression; we OR in the new expression */ filter_prepend = " or "; break; } } filter_string_fwd = g_string_new(filter_prepend); /* look in the Graph and get all the frame_num for this call */ g_string_sprintfa(filter_string_fwd, " ("); list = g_list_first(voip_calls_get_info()->graph_analysis->list); while (list) { gai = list->data; if (gai->conv_num == selected_call_fwd->call_num){ g_string_sprintfa(filter_string_fwd,"%sframe.number == %d", isFirst?"":" or ", gai->frame_num ); isFirst = FALSE; } list = g_list_next (list); } g_string_sprintfa(filter_string_fwd, ") "); filter_length = filter_length + filter_string_fwd->len; if (filter_length < max_filter_length){ gtk_entry_append_text(GTK_ENTRY(main_display_filter_widget), filter_string_fwd->str); } else{ g_string_free(filter_string_fwd, TRUE); filter_string_fwd = g_string_new(filter_prepend); switch(selected_call_fwd->protocol){ case VOIP_SIP: tmp_sipinfo = selected_call_fwd->prot_info; g_string_sprintfa(filter_string_fwd, "(sip.Call-ID == \"%s\") ", tmp_sipinfo->call_identifier ); gtk_entry_append_text(GTK_ENTRY(main_display_filter_widget), filter_string_fwd->str); break; case VOIP_ISUP: tmp_isupinfo = selected_call_fwd->prot_info; g_string_sprintfa(filter_string_fwd, "(isup.cic == %i and frame.number >=%i and frame.number<=%i and mtp3.network_indicator == %i and ((mtp3.dpc == %i) and (mtp3.opc == %i)) or((mtp3.dpc == %i) and (mtp3.opc == %i))) ", tmp_isupinfo->cic,selected_call_fwd->first_frame_num, selected_call_fwd->last_frame_num, tmp_isupinfo->ni, tmp_isupinfo->dpc, tmp_isupinfo->opc, tmp_isupinfo->opc, tmp_isupinfo->dpc ); gtk_entry_append_text(GTK_ENTRY(main_display_filter_widget), filter_string_fwd->str); break; case VOIP_H323: tmp_h323info = selected_call_fwd->prot_info; g_string_sprintfa(filter_string_fwd, "((h225.guid == %s || q931.call_ref == %x:%x || q931.call_ref == %x:%x) ", guid_to_str(&tmp_h323info->guid[0]), (guint8)(tmp_h323info->q931_crv & 0xff), (guint8)((tmp_h323info->q931_crv & 0xff00)>>8), (guint8)(tmp_h323info->q931_crv2 & 0xff), (guint8)((tmp_h323info->q931_crv2 & 0xff00)>>8)); list = g_list_first(tmp_h323info->h245_list); while (list) { h245_add=list->data; g_string_sprintfa(filter_string_fwd, " || (ip.addr == %s && tcp.port == %d && h245) ", ip_to_str((guint8 *)&(h245_add->h245_address)), h245_add->h245_port); list = g_list_next(list); } g_string_sprintfa(filter_string_fwd, ") "); gtk_entry_append_text(GTK_ENTRY(main_display_filter_widget), filter_string_fwd->str); break; case VOIP_MGCP: case VOIP_AC_ISDN: case VOIP_AC_CAS: case MEDIA_T38: /* XXX - not supported */ break; } } g_string_free(filter_string_fwd, TRUE); } /****************************************************************************/ static void on_graph_bt_clicked (GtkButton *button _U_, gpointer user_data _U_) { graph_analysis_item_t *gai; GList* list; GList* list2; voip_calls_info_t *tmp_listinfo; /* reset the "display" parameter in graph analysis */ list2 = g_list_first(voip_calls_get_info()->graph_analysis->list); while (list2){ gai = list2->data; gai->display = FALSE; list2 = g_list_next(list2); } /* set the display for selected calls */ list = g_list_first(voip_calls_get_info()->strinfo_list); while (list){ tmp_listinfo=list->data; if (tmp_listinfo->selected){ list2 = g_list_first(voip_calls_get_info()->graph_analysis->list); while (list2){ gai = list2->data; if (gai->conv_num == tmp_listinfo->call_num){ gai->display = TRUE; } list2 = g_list_next(list2); } } list = g_list_next(list); } /* create or refresh the graph windows */ if (graph_analysis_data->dlg.window == NULL) /* create the window */ graph_analysis_create(graph_analysis_data); else graph_analysis_update(graph_analysis_data); /* refresh it */ } /****************************************************************************/ /* when the user selects a row in the calls list */ static void voip_calls_on_select_row(GtkCList *clist, gint row _U_, gint column _U_, GdkEventButton *event _U_, gpointer user_data _U_) { GdkColor color = COLOR_DEFAULT; gchar label_text[80]; selected_call_fwd = gtk_clist_get_row_data(GTK_CLIST(clist), row); if (selected_call_fwd==NULL) return; if (!selected_call_fwd->selected) calls_ns++; else calls_ns--; g_snprintf(label_text, 80, "Detected %d VoIP %s. Selected %d %s.", calls_nb, plurality(calls_nb, "Call", "Calls"), calls_ns, plurality(calls_ns, "Call", "Calls")); gtk_label_set(GTK_LABEL(top_label), label_text); g_snprintf(label_text, 80, "Selected Call: From %s To %s, starting time %i.%i", selected_call_fwd->from_identity, selected_call_fwd->to_identity, selected_call_fwd->start_sec, selected_call_fwd->start_usec ); gtk_label_set_text(GTK_LABEL(label_fwd), label_text); selected_call_fwd->selected=!selected_call_fwd->selected; if (selected_call_fwd->selected) color = COLOR_SELECT; else color = COLOR_DEFAULT; gtk_clist_set_background(GTK_CLIST(clist), row, &color); if (calls_ns > 0) { gtk_widget_set_sensitive(bt_filter, TRUE); gtk_widget_set_sensitive(bt_graph, TRUE); } else { gtk_widget_set_sensitive(bt_filter, FALSE); gtk_widget_set_sensitive(bt_graph, FALSE); } /* TODO: activate other buttons when implemented */ } /****************************************************************************/ typedef struct column_arrows { GtkWidget *table; GtkWidget *ascend_pm; GtkWidget *descend_pm; } column_arrows; /****************************************************************************/ static void voip_calls_click_column_cb(GtkCList *clist, gint column, gpointer data) { column_arrows *col_arrows = (column_arrows *) data; int i; gtk_clist_freeze(clist); for (i=0; isort_column) { if (clist->sort_type == GTK_SORT_ASCENDING) { clist->sort_type = GTK_SORT_DESCENDING; gtk_widget_show(col_arrows[column].descend_pm); } else { clist->sort_type = GTK_SORT_ASCENDING; gtk_widget_show(col_arrows[column].ascend_pm); } } else { clist->sort_type = GTK_SORT_ASCENDING; gtk_widget_show(col_arrows[column].ascend_pm); gtk_clist_set_sort_column(clist, column); } gtk_clist_thaw(clist); gtk_clist_sort(clist); } /****************************************************************************/ static gint voip_calls_sort_column(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2) { char *text1 = NULL; char *text2 = NULL; guint i1, i2, i3, i4; const GtkCListRow *row1 = (const GtkCListRow *) ptr1; const GtkCListRow *row2 = (const GtkCListRow *) ptr2; text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text; text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text; switch(clist->sort_column){ case 0: case 1: if ((sscanf(text1, "%u.%u", &i1, &i2) != 2) || (sscanf(text2, "%u.%u", &i3, &i4) != 2) ){ return 0; } if (i1>i3) return 1; if (i1strinfo_list), voip_calls_get_info()->start_packets, voip_calls_get_info()->completed_calls, voip_calls_get_info()->rejected_calls); gtk_label_set(GTK_LABEL(status_label), label_text); gtk_clist_freeze(GTK_CLIST(clist)); gtk_clist_clear(GTK_CLIST(clist)); list = g_list_first(list); while (list) { add_to_clist((voip_calls_info_t*)(list->data)); list = g_list_next(list); } gtk_clist_thaw(GTK_CLIST(clist)); g_snprintf(label_text, 256, "Detected %d VoIP %s. Selected %d %s.", calls_nb, plurality(calls_nb, "Call", "Calls"), calls_ns, plurality(calls_ns, "Call", "Calls")); gtk_label_set(GTK_LABEL(top_label), label_text); } last_list = list; } /****************************************************************************/ /* draw function for tap listeners to keep the window up to date */ void voip_calls_dlg_draw(void *ptr _U_) { if (voip_calls_get_info()->redraw) { voip_calls_dlg_update(voip_calls_get_info()->strinfo_list); voip_calls_get_info()->redraw = FALSE; } } /* reset function for tap listeners to clear window, if necessary */ void voip_calls_dlg_reset(void *ptr _U_) { /* Clean up memory used by calls tap */ voip_calls_reset((voip_calls_tapinfo_t*) voip_calls_get_info()); /* close the graph window if open */ if (graph_analysis_data->dlg.window != NULL) { window_cancel_button_cb(NULL, graph_analysis_data->dlg.window); graph_analysis_data->dlg.window = NULL; } } /* init function for tap */ /* Made extern only for "Fax T38 Analysis..." */ void voip_calls_init_tap(const char *dummy _U_, void* userdata _U_) { gint c; gchar *data[NUM_COLS]; gchar field[NUM_COLS][50]; 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; } /* Clean up memory used by calls tap */ voip_calls_reset((voip_calls_tapinfo_t*) voip_calls_get_info()); /* Register the tap listener */ sip_calls_init_tap(); mtp3_calls_init_tap(); isup_calls_init_tap(); h225_calls_init_tap(); h245dg_calls_init_tap(); q931_calls_init_tap(); sdp_calls_init_tap(); rtp_init_tap(); rtp_event_init_tap(); /* We don't register this tap, if we don't have the mgcp plugin loaded.*/ if (find_tap_id("mgcp")) { mgcp_calls_init_tap(); } actrace_calls_init_tap(); t38_init_tap(); /* create dialog box if necessary */ if (voip_calls_dlg == NULL) { voip_calls_dlg_create(); } else { /* There's already a dialog box; reactivate it. */ reactivate_window(voip_calls_dlg); } voip_calls_get_info()->redraw = TRUE; voip_calls_dlg_draw(NULL); voip_calls_get_info()->redraw = TRUE; for (c=0;c