diff options
author | Gerald Combs <gerald@zing.org> | 2015-10-24 17:45:51 -0700 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2015-10-27 15:21:12 +0000 |
commit | 08e44b8b43ad4234a93b8feaa8e8174373188080 (patch) | |
tree | f777056da4035b7b3c4ab78a2ab5eba64e467984 | |
parent | 616dbd78d6afc4f8825ce159de23b19752859605 (diff) |
Convert SIP statistics to the stat tap API.
It looks like this one fell through the cracks because it dynamically
registered itself via register_tap_listener_gtksipstat and wasn't listed
in the "/Telephony/" path in main_menubar.c.
Ping-Bug: 11638
Change-Id: I4c82b36d204207c81e82a19efce98b6a091351ca
Reviewed-on: https://code.wireshark.org/review/11293
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Gerald Combs <gerald@wireshark.org>
-rw-r--r-- | epan/dissectors/packet-sip.c | 318 | ||||
-rw-r--r-- | epan/dissectors/packet-sip.h | 22 | ||||
-rw-r--r-- | ui/gtk/CMakeLists.txt | 1 | ||||
-rw-r--r-- | ui/gtk/Makefile.common | 1 | ||||
-rw-r--r-- | ui/gtk/sip_stat.c | 705 | ||||
-rw-r--r-- | ui/qt/main_window.cpp | 1 | ||||
-rw-r--r-- | ui/qt/main_window.ui | 1 |
7 files changed, 328 insertions, 721 deletions
diff --git a/epan/dissectors/packet-sip.c b/epan/dissectors/packet-sip.c index da2e335ba0..6fc80da83b 100644 --- a/epan/dissectors/packet-sip.c +++ b/epan/dissectors/packet-sip.c @@ -34,12 +34,14 @@ #include "config.h" #include <epan/packet.h> + #include <epan/exceptions.h> +#include <epan/exported_pdu.h> +#include <epan/expert.h> #include <epan/prefs.h> #include <epan/req_resp_hdrs.h> +#include <epan/stat_tap_ui.h> #include <epan/tap.h> -#include <epan/exported_pdu.h> -#include <epan/expert.h> #include <wsutil/str_util.h> @@ -4720,6 +4722,297 @@ guint sip_find_invite(packet_info *pinfo, return result; } +/* TAP STAT INFO */ + +/* + * Much of this is from ui/gtk/sip_stat.c: + * sip_stat 2004 Martin Mathieson + */ + +/* TODO: extra codes to be added from SIP extensions? */ +static const value_string response_code_vals[] = { + { 999, "Unknown response"}, /* Must be first */ + + { 100, "Trying"}, + { 180, "Ringing"}, + { 181, "Call Is Being Forwarded"}, + { 182, "Queued"}, + { 183, "Session Progress"}, + { 199, "Informational - Others" }, + + { 200, "OK"}, + { 202, "Accepted"}, + { 204, "No Notification"}, + { 299, "Success - Others"}, /* used to keep track of other Success packets */ + + { 300, "Multiple Choices"}, + { 301, "Moved Permanently"}, + { 302, "Moved Temporarily"}, + { 305, "Use Proxy"}, + { 380, "Alternative Service"}, + { 399, "Redirection - Others"}, + + { 400, "Bad Request"}, + { 401, "Unauthorized"}, + { 402, "Payment Required"}, + { 403, "Forbidden"}, + { 404, "Not Found"}, + { 405, "Method Not Allowed"}, + { 406, "Not Acceptable"}, + { 407, "Proxy Authentication Required"}, + { 408, "Request Timeout"}, + { 410, "Gone"}, + { 412, "Conditional Request Failed"}, + { 413, "Request Entity Too Large"}, + { 414, "Request-URI Too Long"}, + { 415, "Unsupported Media Type"}, + { 416, "Unsupported URI Scheme"}, + { 420, "Bad Extension"}, + { 421, "Extension Required"}, + { 422, "Session Timer Too Small"}, + { 423, "Interval Too Brief"}, + { 428, "Use Identity Header"}, + { 429, "Provide Referrer Identity"}, + { 430, "Flow Failed"}, + { 433, "Anonymity Disallowed"}, + { 436, "Bad Identity-Info"}, + { 437, "Unsupported Certificate"}, + { 438, "Invalid Identity Header"}, + { 439, "First Hop Lacks Outbound Support"}, + { 440, "Max-Breadth Exceeded"}, + { 470, "Consent Needed"}, + { 480, "Temporarily Unavailable"}, + { 481, "Call/Transaction Does Not Exist"}, + { 482, "Loop Detected"}, + { 483, "Too Many Hops"}, + { 484, "Address Incomplete"}, + { 485, "Ambiguous"}, + { 486, "Busy Here"}, + { 487, "Request Terminated"}, + { 488, "Not Acceptable Here"}, + { 489, "Bad Event"}, + { 491, "Request Pending"}, + { 493, "Undecipherable"}, + { 494, "Security Agreement Required"}, + { 499, "Client Error - Others"}, + + { 500, "Server Internal Error"}, + { 501, "Not Implemented"}, + { 502, "Bad Gateway"}, + { 503, "Service Unavailable"}, + { 504, "Server Time-out"}, + { 505, "Version Not Supported"}, + { 513, "Message Too Large"}, + { 599, "Server Error - Others"}, + + { 600, "Busy Everywhere"}, + { 603, "Decline"}, + { 604, "Does Not Exist Anywhere"}, + { 606, "Not Acceptable"}, + { 699, "Global Failure - Others"}, + + { 0, NULL} +}; +#define RESPONSE_CODE_MIN 100 +#define RESPONSE_CODE_MAX 699 + +typedef enum +{ + REQ_RESP_METHOD_COLUMN, + COUNT_COLUMN, + RESENT_COLUMN, + MIN_SETUP_COLUMN, + AVG_SETUP_COLUMN, + MAX_SETUP_COLUMN +} sip_stat_columns; + +static stat_tap_table_item sip_stat_fields[] = { + {TABLE_ITEM_STRING, TAP_ALIGN_LEFT, "Request Method / Response Code", "%-25s"}, + {TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Count", "%d"}, + {TABLE_ITEM_UINT, TAP_ALIGN_RIGHT, "Resent", "%d"}, + {TABLE_ITEM_FLOAT, TAP_ALIGN_RIGHT, "Min Setup (s)", "%8.2f"}, + {TABLE_ITEM_FLOAT, TAP_ALIGN_RIGHT, "Avg Setup (s)", "%8.2f"}, + {TABLE_ITEM_FLOAT, TAP_ALIGN_RIGHT, "Max Setup (s)", "%8.2f"}, +}; + +static void sip_stat_init(new_stat_tap_ui* new_stat, new_stat_tap_gui_init_cb gui_callback, void* gui_data) +{ + /* XXX Should we have a single request + response table instead? */ + int num_fields = sizeof(sip_stat_fields)/sizeof(stat_tap_table_item); + new_stat_tap_table *req_table = new_stat_tap_init_table("SIP Requests", num_fields, 0, NULL, gui_callback, gui_data); + new_stat_tap_table *resp_table = new_stat_tap_init_table("SIP Responses", num_fields, 0, NULL, gui_callback, gui_data); + stat_tap_table_item_type items[sizeof(sip_stat_fields)/sizeof(stat_tap_table_item)]; + guint i; + + new_stat_tap_add_table(new_stat, req_table); + new_stat_tap_add_table(new_stat, resp_table); + + items[REQ_RESP_METHOD_COLUMN].type = TABLE_ITEM_STRING; + items[COUNT_COLUMN].type = TABLE_ITEM_UINT; + items[COUNT_COLUMN].value.uint_value = 0; + items[RESENT_COLUMN].type = TABLE_ITEM_UINT; + items[RESENT_COLUMN].value.uint_value = 0; + items[MIN_SETUP_COLUMN].type = TABLE_ITEM_FLOAT; + items[MIN_SETUP_COLUMN].value.float_value = 0.0f; + items[AVG_SETUP_COLUMN].type = TABLE_ITEM_FLOAT; + items[AVG_SETUP_COLUMN].value.float_value = 0.0f; + items[MAX_SETUP_COLUMN].type = TABLE_ITEM_FLOAT; + items[MAX_SETUP_COLUMN].value.float_value = 0.0f; + + for (i = 0; i < array_length(sip_methods); i++) { + items[REQ_RESP_METHOD_COLUMN].value.string_value = g_strdup(sip_methods[i]); + new_stat_tap_init_table_row(req_table, i, num_fields, items); + } + + for (i = 0; response_code_vals[i].strptr; i++) { + unsigned response_code = response_code_vals[i].value; + items[REQ_RESP_METHOD_COLUMN].value.string_value = + g_strdup_printf("%u %s", response_code, response_code_vals[i].strptr); + items[REQ_RESP_METHOD_COLUMN].user_data.uint_value = response_code; + new_stat_tap_init_table_row(resp_table, i, num_fields, items); + } +} + +static gboolean +sip_stat_packet(void *tapdata, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *siv_ptr) +{ + new_stat_data_t* stat_data = (new_stat_data_t*) tapdata; + const sip_info_value_t *info_value = (const sip_info_value_t *) siv_ptr; + new_stat_tap_table *cur_table = NULL; + guint cur_row = 0; /* 0 = Unknown for both tables */ + + if (info_value->request_method && info_value->response_code < 1) { + /* Request table */ + new_stat_tap_table *req_table = g_array_index(stat_data->new_stat_tap_data->tables, new_stat_tap_table*, 0); + stat_tap_table_item_type *item_data; + guint element; + + cur_table = req_table; + for (element = 0; element < req_table->num_elements; element++) { + item_data = new_stat_tap_get_field_data(req_table, element, REQ_RESP_METHOD_COLUMN); + if (g_ascii_strcasecmp(info_value->request_method, item_data->value.string_value) == 0) { + cur_row = element; + break; + } + } + + } else if (info_value->response_code > 0) { + /* Response table */ + new_stat_tap_table *resp_table = g_array_index(stat_data->new_stat_tap_data->tables, new_stat_tap_table*, 1); + guint response_code = info_value->response_code; + stat_tap_table_item_type *item_data; + guint element; + + cur_table = resp_table; + if (response_code < RESPONSE_CODE_MIN || response_code > RESPONSE_CODE_MAX) { + response_code = 999; + } else if (!try_val_to_str(response_code, response_code_vals)) { + response_code = ((response_code / 100) * 100) + 99; + } + + for (element = 0; element < resp_table->num_elements; element++) { + item_data = new_stat_tap_get_field_data(resp_table, element, REQ_RESP_METHOD_COLUMN); + if (item_data->user_data.uint_value == response_code) { + cur_row = element; + break; + } + } + + } else { + return FALSE; + } + + if (cur_table) { + stat_tap_table_item_type *item_data; + + item_data = new_stat_tap_get_field_data(cur_table, cur_row, COUNT_COLUMN); + item_data->value.uint_value++; + new_stat_tap_set_field_data(cur_table, cur_row, COUNT_COLUMN, item_data); + + if (info_value->resend) { + item_data = new_stat_tap_get_field_data(cur_table, cur_row, RESENT_COLUMN); + item_data->value.uint_value++; + new_stat_tap_set_field_data(cur_table, cur_row, RESENT_COLUMN, item_data); + } + + if (info_value->setup_time > 0) { + stat_tap_table_item_type *min_item_data = new_stat_tap_get_field_data(cur_table, cur_row, MIN_SETUP_COLUMN); + stat_tap_table_item_type *avg_item_data = new_stat_tap_get_field_data(cur_table, cur_row, AVG_SETUP_COLUMN); + stat_tap_table_item_type *max_item_data = new_stat_tap_get_field_data(cur_table, cur_row, MAX_SETUP_COLUMN); + double setup_time = (double) info_value->setup_time / 1000; + unsigned count; + + min_item_data->user_data.uint_value++; /* We store the setup count in MIN_SETUP_COLUMN */ + count = min_item_data->user_data.uint_value; + avg_item_data->user_data.float_value += setup_time; /* We store the total setup time in AVG_SETUP_COLUMN */ + + if (count <= 1) { + min_item_data->value.float_value = setup_time; + avg_item_data->value.float_value = setup_time; + max_item_data->value.float_value = setup_time; + } else { + if (setup_time < min_item_data->value.float_value) { + min_item_data->value.float_value = setup_time; + } + avg_item_data->value.float_value = avg_item_data->user_data.float_value / count; + if (setup_time > max_item_data->value.float_value) { + max_item_data->value.float_value = setup_time; + } + } + + new_stat_tap_set_field_data(cur_table, cur_row, MIN_SETUP_COLUMN, min_item_data); + new_stat_tap_set_field_data(cur_table, cur_row, AVG_SETUP_COLUMN, avg_item_data); + new_stat_tap_set_field_data(cur_table, cur_row, MAX_SETUP_COLUMN, max_item_data); + } + } + + return TRUE; +} + +static void +sip_stat_reset(new_stat_tap_table* table) +{ + guint element; + stat_tap_table_item_type* item_data; + + for (element = 0; element < table->num_elements; element++) + { + item_data = new_stat_tap_get_field_data(table, element, COUNT_COLUMN); + item_data->value.uint_value = 0; + new_stat_tap_set_field_data(table, element, COUNT_COLUMN, item_data); + + item_data = new_stat_tap_get_field_data(table, element, RESENT_COLUMN); + item_data->value.uint_value = 0; + new_stat_tap_set_field_data(table, element, RESENT_COLUMN, item_data); + + item_data = new_stat_tap_get_field_data(table, element, RESENT_COLUMN); + item_data->value.uint_value = 0; + new_stat_tap_set_field_data(table, element, RESENT_COLUMN, item_data); + + item_data = new_stat_tap_get_field_data(table, element, MIN_SETUP_COLUMN); + item_data->user_data.uint_value = 0; + item_data->value.float_value = 0.0f; + new_stat_tap_set_field_data(table, element, MIN_SETUP_COLUMN, item_data); + + item_data = new_stat_tap_get_field_data(table, element, AVG_SETUP_COLUMN); + item_data->user_data.float_value = 0; + item_data->value.float_value = 0.0f; + new_stat_tap_set_field_data(table, element, AVG_SETUP_COLUMN, item_data); + + item_data = new_stat_tap_get_field_data(table, element, MAX_SETUP_COLUMN); + item_data->value.float_value = 0.0f; + new_stat_tap_set_field_data(table, element, MAX_SETUP_COLUMN, item_data); + } +} + +static void +sip_stat_free_table_item(new_stat_tap_table* table _U_, guint row _U_, guint column, stat_tap_table_item_type* field_data) +{ + if (column != REQ_RESP_METHOD_COLUMN) return; + g_free((char*)field_data->value.string_value); + field_data->value.string_value = NULL; +} + /* Register the protocol with Wireshark */ void proto_register_sip(void) { @@ -6003,6 +6296,25 @@ void proto_register_sip(void) module_t *sip_module; expert_module_t* expert_sip; + static tap_param sip_stat_params[] = { + { PARAM_FILTER, "filter", "Filter", NULL, TRUE } + }; + + static new_stat_tap_ui sip_stat_table = { + REGISTER_STAT_GROUP_TELEPHONY, + "SIP Statistics", + "sip", + "sip,stat", + sip_stat_init, + sip_stat_packet, + sip_stat_reset, + sip_stat_free_table_item, + NULL, + sizeof(sip_stat_fields)/sizeof(stat_tap_table_item), sip_stat_fields, + sizeof(sip_stat_params)/sizeof(tap_param), sip_stat_params, + NULL + }; + /* Register the protocol name and description */ proto_sip = proto_register_protocol("Session Initiation Protocol", "SIP", "sip"); @@ -6097,6 +6409,8 @@ void proto_register_sip(void) ext_hdr_subdissector_table = register_dissector_table("sip.hdr", "SIP Extension header", FT_STRING, BASE_NONE); + register_new_stat_tap_ui(&sip_stat_table); + /* compile patterns */ ws_mempbrk_compile(&pbrk_comma_semi, ",;"); ws_mempbrk_compile(&pbrk_whitespace, " \t\r\n"); diff --git a/epan/dissectors/packet-sip.h b/epan/dissectors/packet-sip.h index 41177b3a09..11d4c8e149 100644 --- a/epan/dissectors/packet-sip.h +++ b/epan/dissectors/packet-sip.h @@ -26,19 +26,19 @@ typedef struct _sip_info_value_t { - gchar *request_method; - guint response_code; - guchar resend; - guint32 setup_time; + gchar *request_method; + guint response_code; + gboolean resend; + guint32 setup_time; /* added for VoIP calls analysis, see ui/voip_calls.c*/ - gchar *tap_call_id; - gchar *tap_from_addr; - gchar *tap_to_addr; - guint32 tap_cseq_number; - gchar *reason_phrase; + gchar *tap_call_id; + gchar *tap_from_addr; + gchar *tap_to_addr; + guint32 tap_cseq_number; + gchar *reason_phrase; } sip_info_value_t; -extern void dfilter_store_sip_from_addr(tvbuff_t *tvb,proto_tree *tree,guint parameter_offset, - guint parameter_len); +extern void dfilter_store_sip_from_addr(tvbuff_t *tvb, proto_tree *tree, + guint parameter_offset, guint parameter_len); #endif diff --git a/ui/gtk/CMakeLists.txt b/ui/gtk/CMakeLists.txt index 371801ca93..84a0685a7a 100644 --- a/ui/gtk/CMakeLists.txt +++ b/ui/gtk/CMakeLists.txt @@ -219,7 +219,6 @@ set(WIRESHARK_TAP_SRC sctp_chunk_stat.c sctp_chunk_stat_dlg.c sctp_stat_dlg.c - sip_stat.c stats_tree_stat.c tcp_graph.c voip_calls_dlg.c diff --git a/ui/gtk/Makefile.common b/ui/gtk/Makefile.common index a46e656caa..1995db6f68 100644 --- a/ui/gtk/Makefile.common +++ b/ui/gtk/Makefile.common @@ -170,7 +170,6 @@ WIRESHARK_TAP_SRC = \ sctp_chunk_stat.c \ sctp_chunk_stat_dlg.c \ sctp_stat_dlg.c \ - sip_stat.c \ stats_tree_stat.c \ tcp_graph.c \ voip_calls_dlg.c \ diff --git a/ui/gtk/sip_stat.c b/ui/gtk/sip_stat.c deleted file mode 100644 index 236eb97e0c..0000000000 --- a/ui/gtk/sip_stat.c +++ /dev/null @@ -1,705 +0,0 @@ -/* sip_stat.c - * sip_stat 2004 Martin Mathieson - * - * Copied from http_stat.c - * - * Wireshark - Network traffic analyzer - * By Gerald Combs <gerald@wireshark.org> - * Copyright 1998 Gerald Combs - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include <string.h> - -#include <gtk/gtk.h> - -#include <epan/packet_info.h> -#include <epan/tap.h> -#include <epan/dissectors/packet-sip.h> - -#include "ui/simple_dialog.h" - -#include "ui/gtk/gui_utils.h" -#include "ui/gtk/dlg_utils.h" -#include "ui/gtk/tap_param_dlg.h" -#include "ui/gtk/main.h" - - -#define SUM_STR_MAX 1024 - -/* Info about a grid */ -typedef struct { - GtkWidget *grid; - guint row_count; -} grid_info_t; - -/* Used to keep track of the statistics for an entire program interface */ -typedef struct _sip_stats_t { - char *filter; - GtkWidget *win; - GHashTable *hash_responses; - GHashTable *hash_requests; - guint32 packets; /* number of sip packets, including continuations */ - guint32 resent_packets; - guint32 average_setup_time; - guint32 max_setup_time; - guint32 min_setup_time; - guint32 no_of_completed_calls; - guint64 total_setup_time; - GtkWidget *packets_label; - GtkWidget *resent_label; - GtkWidget *average_setup_time_label; - - GtkWidget *request_box; /* container for INVITE, ... */ - - grid_info_t informational_table_info; /* Status code between 100 and 199 */ - grid_info_t success_table_info; /* 200 and 299 */ - grid_info_t redirection_table_info; /* 300 and 399 */ - grid_info_t client_error_table_info; /* 400 and 499 */ - grid_info_t server_errors_table_info; /* 500 and 599 */ - grid_info_t global_failures_table_info; /* 600 and 699 */ -} sipstat_t; - -/* Used to keep track of the stats for a specific response code - * for example it can be { 3, 404, "Not Found" ,...} - * which means we captured 3 reply sip/1.1 404 Not Found */ -typedef struct _sip_response_code_t { - guint32 packets; /* 3 */ - guint response_code; /* 404 */ - const gchar *name; /* "Not Found" */ - GtkWidget *widget; /* Label where we display it */ - grid_info_t *table_info; /* Info about table in which we put it, - e.g. client_error_table_info */ - sipstat_t *sp; /* Pointer back to main struct */ -} sip_response_code_t; - -/* Used to keep track of the stats for a specific request string */ -typedef struct _sip_request_method_t { - gchar *response; /* eg. : INVITE */ - guint32 packets; - GtkWidget *widget; - sipstat_t *sp; /* Pointer back to main struct */ -} sip_request_method_t; - -/* TODO: extra codes to be added from SIP extensions? */ -static const value_string vals_status_code[] = { - { 100, "Trying"}, - { 180, "Ringing"}, - { 181, "Call Is Being Forwarded"}, - { 182, "Queued"}, - { 183, "Session Progress"}, - { 199, "Informational - Others" }, - - { 200, "OK"}, - { 202, "Accepted"}, - { 204, "No Notification"}, - { 299, "Success - Others"}, /* used to keep track of other Success packets */ - - { 300, "Multiple Choices"}, - { 301, "Moved Permanently"}, - { 302, "Moved Temporarily"}, - { 305, "Use Proxy"}, - { 380, "Alternative Service"}, - { 399, "Redirection - Others"}, - - { 400, "Bad Request"}, - { 401, "Unauthorized"}, - { 402, "Payment Required"}, - { 403, "Forbidden"}, - { 404, "Not Found"}, - { 405, "Method Not Allowed"}, - { 406, "Not Acceptable"}, - { 407, "Proxy Authentication Required"}, - { 408, "Request Timeout"}, - { 410, "Gone"}, - { 412, "Conditional Request Failed"}, - { 413, "Request Entity Too Large"}, - { 414, "Request-URI Too Long"}, - { 415, "Unsupported Media Type"}, - { 416, "Unsupported URI Scheme"}, - { 420, "Bad Extension"}, - { 421, "Extension Required"}, - { 422, "Session Timer Too Small"}, - { 423, "Interval Too Brief"}, - { 428, "Use Identity Header"}, - { 429, "Provide Referrer Identity"}, - { 430, "Flow Failed"}, - { 433, "Anonymity Disallowed"}, - { 436, "Bad Identity-Info"}, - { 437, "Unsupported Certificate"}, - { 438, "Invalid Identity Header"}, - { 439, "First Hop Lacks Outbound Support"}, - { 440, "Max-Breadth Exceeded"}, - { 470, "Consent Needed"}, - { 480, "Temporarily Unavailable"}, - { 481, "Call/Transaction Does Not Exist"}, - { 482, "Loop Detected"}, - { 483, "Too Many Hops"}, - { 484, "Address Incomplete"}, - { 485, "Ambiguous"}, - { 486, "Busy Here"}, - { 487, "Request Terminated"}, - { 488, "Not Acceptable Here"}, - { 489, "Bad Event"}, - { 491, "Request Pending"}, - { 493, "Undecipherable"}, - { 494, "Security Agreement Required"}, - { 499, "Client Error - Others"}, - - { 500, "Server Internal Error"}, - { 501, "Not Implemented"}, - { 502, "Bad Gateway"}, - { 503, "Service Unavailable"}, - { 504, "Server Time-out"}, - { 505, "Version Not Supported"}, - { 513, "Message Too Large"}, - { 599, "Server Error - Others"}, - - { 600, "Busy Everywhere"}, - { 603, "Decline"}, - { 604, "Does Not Exist Anywhere"}, - { 606, "Not Acceptable"}, - { 699, "Global Failure - Others"}, - - { 0, NULL} -}; - -void register_tap_listener_gtksipstat(void); - - -/* Create tables for responses and requests */ -static void -sip_init_hash(sipstat_t *sp) -{ - int i; - - /* Create responses table */ - sp->hash_responses = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); - - /* Add all response codes */ - for (i=0; vals_status_code[i].strptr; i++) - { - sip_response_code_t *sc = (sip_response_code_t *)g_malloc(sizeof(sip_response_code_t)); - - sc->packets = 0; - sc->response_code = vals_status_code[i].value; - sc->name = vals_status_code[i].strptr; - sc->widget = NULL; - sc->table_info = NULL; - sc->sp = sp; - g_hash_table_insert(sc->sp->hash_responses, GUINT_TO_POINTER(vals_status_code[i].value), sc); - } - - /* Create empty requests table */ - sp->hash_requests = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); -} - -/* Draw the entry for an individual request message */ -static void -sip_draw_hash_requests(gchar *key _U_, sip_request_method_t *data, gchar *unused _U_) -{ - gchar string_buff[SUM_STR_MAX]; - - g_assert(data != NULL); - - if (data->packets == 0) - { - return; - } - - /* Build string showing method and count */ - g_snprintf(string_buff, sizeof(string_buff), - " %-11s : %3d packets", data->response, data->packets); - if (data->widget == NULL) - { - /* Create new label */ - data->widget = gtk_label_new(string_buff); - gtk_misc_set_alignment(GTK_MISC(data->widget), 0.0f, 0.5f); - gtk_box_pack_start(GTK_BOX(data->sp->request_box), data->widget, FALSE, FALSE, 0); - gtk_widget_show(data->widget); - } - else - { - /* Update existing label */ - gtk_label_set_text(GTK_LABEL(data->widget), string_buff); - } -} - -/* Draw an individual response entry */ -static void -sip_draw_hash_responses(gint *key _U_ , sip_response_code_t *data, gchar *unused _U_) -{ - gchar string_buff[SUM_STR_MAX]; - - g_assert(data != NULL); - - if (data->packets == 0) - { - return; - } - - /* Create an entry in the relevant box of the window */ - if (data->widget == NULL) - { - guint x; - GtkWidget *tmp; - guint i = data->response_code; - - /* Out of valid range - ignore */ - if ((i < 100) || (i >= 700)) - { - return; - } - - /* Find the table matching the code */ - if (i < 200) - { - data->table_info = &(data->sp->informational_table_info); - } - else if (i < 300) - { - data->table_info = &(data->sp->success_table_info); - } - else if (i < 400) - { - data->table_info = &(data->sp->redirection_table_info); - } - else if (i < 500) - { - data->table_info = &(data->sp->client_error_table_info); - } - else if (i < 600) - { - data->table_info = &(data->sp->server_errors_table_info); - } - else - { - data->table_info = &(data->sp->global_failures_table_info); - } - - /* Get number of rows in table */ - x = data->table_info->row_count; - - /* Create a new label with this response, e.g. "SIP 180 Ringing" */ - g_snprintf(string_buff, sizeof(string_buff), - "SIP %3d %s ", data->response_code, data->name); - tmp = gtk_label_new(string_buff); - - /* Insert the label in the correct place in the table */ - ws_gtk_grid_attach_defaults(GTK_GRID(data->table_info->grid), tmp, 0, x, 1, 1); - gtk_label_set_justify(GTK_LABEL(tmp), GTK_JUSTIFY_LEFT); - gtk_widget_show(tmp); - - /* Show number of packets */ - g_snprintf(string_buff, sizeof(string_buff), "%9d", data->packets); - data->widget = gtk_label_new(string_buff); - - /* Show this widget in the right place */ - ws_gtk_grid_attach_defaults(GTK_GRID(data->table_info->grid), data->widget, 1, x, 1, 1); - gtk_label_set_justify(GTK_LABEL(data->widget), GTK_JUSTIFY_RIGHT); - gtk_widget_show(data->widget); - - data->table_info->row_count += 1; - } else - { - /* Just update the existing label string */ - g_snprintf(string_buff, sizeof(string_buff), "%9d", data->packets); - gtk_label_set_text(GTK_LABEL(data->widget), string_buff); - } -} - -static void -sip_reset_hash_responses(gchar *key _U_, sip_response_code_t *data, gpointer ptr _U_) -{ - data->packets = 0; -} - -static void -sip_reset_hash_requests(gchar *key _U_ , sip_request_method_t *data, gpointer ptr _U_) -{ - data->packets = 0; -} - -static void -sipstat_reset(void *psp) -{ - sipstat_t *sp = (sipstat_t *)psp; - if (sp) - { - sp->packets = 0; - sp->resent_packets = 0; - sp->average_setup_time = 0; - sp->max_setup_time = 0; - sp->max_setup_time = 0; - sp->no_of_completed_calls = 0; - sp->total_setup_time = 0; - g_hash_table_foreach(sp->hash_responses, (GHFunc)sip_reset_hash_responses, NULL); - g_hash_table_foreach(sp->hash_requests, (GHFunc)sip_reset_hash_requests, NULL); - } -} - -/* Main entry point to SIP tap */ -static int -sipstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *pri) -{ - const sip_info_value_t *value = (const sip_info_value_t *)pri; - sipstat_t *sp = (sipstat_t *)psp; - - /* Total number of packets, including continuation packets */ - sp->packets++; - - /* Update resent count if flag set */ - if (value->resend) - { - sp->resent_packets++; - } - - /* Calculate average setup time */ - if (value->setup_time) - { - sp->no_of_completed_calls++; - /* Check if it's the first value */ - if ( sp->total_setup_time == 0 ) - { - sp->average_setup_time = value->setup_time; - sp->total_setup_time = value->setup_time; - sp->max_setup_time = value->setup_time; - sp->min_setup_time = value->setup_time; - } else - { - sp->total_setup_time = sp->total_setup_time + value->setup_time; - if (sp->max_setup_time < value->setup_time) - { - sp->max_setup_time = value->setup_time; - } - if (sp->min_setup_time > value->setup_time) - { - sp->min_setup_time = value->setup_time; - } - /* Calculate average */ - sp->average_setup_time = (guint32)(sp->total_setup_time / sp->no_of_completed_calls); - } - } - - /* Looking at both requests and responses */ - if (value->response_code != 0) - { - /* Responses */ - sip_response_code_t *sc; - - /* Look up response code in hash table */ - sc = (sip_response_code_t *)g_hash_table_lookup(sp->hash_responses, GUINT_TO_POINTER(value->response_code)); - if (sc == NULL) - { - /* Non-standard status code; we classify it as others - * in the relevant category - * (Informational, Success, Redirection, Client Error, Server Error, Global Failure) - */ - guint key; - guint i = value->response_code; - - - if ((i < 100) || (i >= 700)) - { - /* Forget about crazy values */ - return 0; - } - else if (i < 200) - { - key = 199; /* Hopefully, this status code will never be used */ - } - else if (i < 300) - { - key = 299; - } - else if (i < 400) - { - key = 399; - } - else if (i < 500) - { - key = 499; - } - else if (i < 600) - { - key = 599; - } - else - { - key = 699; - } - - /* Now look up this fallback code to get its text description */ - sc = (sip_response_code_t *)g_hash_table_lookup(sp->hash_responses, GUINT_TO_POINTER(key)); - if (sc == NULL) - { - return 0; - } - } - sc->packets++; - } - else if (value->request_method) - { - /* Requests */ - sip_request_method_t *sc; - - /* Look up the request method in the table */ - sc = (sip_request_method_t *)g_hash_table_lookup(sp->hash_requests, value->request_method); - if (sc == NULL) - { - /* First of this type. Create structure and initialise */ - sc = (sip_request_method_t *)g_malloc(sizeof(sip_request_method_t)); - sc->response = g_strdup(value->request_method); - sc->packets = 1; - sc->widget = NULL; - sc->sp = sp; - /* Insert it into request table */ - g_hash_table_insert(sp->hash_requests, sc->response, sc); - } - else - { - /* Already existed, just update count for that method */ - sc->packets++; - } - /* g_free(value->request_method); */ - } - else - { - /* No request method set. Just ignore */ - return 0; - } - - return 1; -} - -/* Redraw the whole stats window */ -static void -sipstat_draw(void *psp) -{ - gchar string_buff[SUM_STR_MAX]; - sipstat_t *sp = (sipstat_t *)psp; - - /* Set summary label */ - g_snprintf(string_buff, sizeof(string_buff), - "SIP stats (%d packets)", sp->packets); - gtk_label_set_text(GTK_LABEL(sp->packets_label), string_buff); - - /* Set resend count label */ - g_snprintf(string_buff, sizeof(string_buff), - "(%d resent packets)", sp->resent_packets); - gtk_label_set_text(GTK_LABEL(sp->resent_label), string_buff); - - /* Draw responses and requests from their tables */ - g_hash_table_foreach(sp->hash_responses, (GHFunc)sip_draw_hash_responses, NULL); - g_hash_table_foreach(sp->hash_requests, (GHFunc)sip_draw_hash_requests, NULL); - - /* Set resend count label */ - g_snprintf(string_buff, sizeof(string_buff), - "Average setup time %d ms\n Min %d ms\n Max %d ms", - sp->average_setup_time, sp->min_setup_time, sp->max_setup_time); - gtk_label_set_text(GTK_LABEL(sp->average_setup_time_label), string_buff); - - gtk_widget_show_all(sp->win); -} - -/* When window is destroyed, clean up */ - -static void -win_destroy_cb(GtkWindow *win _U_, gpointer data) -{ - sipstat_t *sp = (sipstat_t *)data; - - remove_tap_listener(sp); - - g_hash_table_destroy(sp->hash_responses); - g_hash_table_destroy(sp->hash_requests); - g_free(sp->filter); - g_free(sp); -} - - -static void -init_table(GtkWidget *main_vb, const gchar *title, grid_info_t *tbl_info) -{ - GtkWidget *fr; - - fr = gtk_frame_new(title); - gtk_box_pack_start(GTK_BOX(main_vb), fr, TRUE, TRUE, 0); - - /* table (within that frame) */ - (*tbl_info).grid = ws_gtk_grid_new(); - gtk_container_add(GTK_CONTAINER(fr), (*tbl_info).grid); - (*tbl_info).row_count = 0; -} - -/* Create a new instance of gtk_sipstat. */ -static void -gtk_sipstat_init(const char *opt_arg, void *userdata _U_) -{ - sipstat_t *sp; - const char *filter; - GString *error_string; - char *title; - GtkWidget *main_vb, *separator, *request_fr; - GtkWidget *bt_close; - GtkWidget *bbox; - - - if (strncmp(opt_arg, "sip,stat,", 9) == 0) - { - /* Skip those characters from filter to display */ - filter = opt_arg + 9; - } - else - { - /* No filter */ - filter = NULL; - } - - /* Create sip stats window structure */ - sp = (sipstat_t *)g_malloc(sizeof(sipstat_t)); - sp->win = dlg_window_new("sip-stat"); /* transient_for top_level */ - gtk_window_set_destroy_with_parent(GTK_WINDOW(sp->win), TRUE); - - /* Set title to include any filter given */ - if (filter) - { - sp->filter = g_strdup(filter); - title = g_strdup_printf("SIP statistics with filter: %s", filter); - } - else - { - sp->filter = NULL; - title = g_strdup("SIP statistics"); - } - - gtk_window_set_title(GTK_WINDOW(sp->win), title); - g_free(title); - - - /* Create container for all widgets */ - main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 12, FALSE); - gtk_container_set_border_width(GTK_CONTAINER(main_vb), 12); - gtk_container_add(GTK_CONTAINER(sp->win), main_vb); - - /* Initialise & show number of packets */ - sp->packets = 0; - sp->packets_label = gtk_label_new("SIP stats (0 SIP packets)"); - gtk_box_pack_start(GTK_BOX(main_vb), sp->packets_label, TRUE, TRUE, 0); - - sp->resent_packets = 0; - sp->resent_label = gtk_label_new("(0 resent packets)"); - gtk_box_pack_start(GTK_BOX(main_vb), sp->resent_label, TRUE, TRUE, 0); - gtk_widget_show(sp->resent_label); - - init_table(main_vb, "Informational SIP 1xx", &(sp->informational_table_info)); - init_table(main_vb, "Success SIP 2xx", &(sp->success_table_info)); - init_table(main_vb, "Redirection SIP 3xx", &(sp->redirection_table_info)); - init_table(main_vb, "Client errors SIP 4xx", &(sp->client_error_table_info)); - init_table(main_vb, "Server errors SIP 5xx", &(sp->server_errors_table_info)); - init_table(main_vb, "Global failures SIP 6xx", &(sp->global_failures_table_info)); - - /* Separator between requests and responses */ - separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - gtk_box_pack_start(GTK_BOX(main_vb), separator, TRUE, TRUE, 0); - - /* Request table and frame */ - request_fr = gtk_frame_new("List of request methods"); - gtk_box_pack_start(GTK_BOX(main_vb), request_fr, TRUE, TRUE, 0); - gtk_container_set_border_width(GTK_CONTAINER(request_fr), 0); - - sp->request_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 10, FALSE); - gtk_container_add(GTK_CONTAINER(request_fr), sp->request_box); - - sp->average_setup_time = 0; - sp->max_setup_time = 0; - sp->min_setup_time = 0; - sp->average_setup_time_label = gtk_label_new("(Not calculated)"); - gtk_box_pack_start(GTK_BOX(main_vb), sp->average_setup_time_label, TRUE, TRUE, 0); - gtk_widget_show(sp->average_setup_time_label); - - - /* Register this tap listener now */ - error_string = register_tap_listener("sip", - sp, - filter, - 0, - sipstat_reset, - sipstat_packet, - sipstat_draw); - if (error_string) - { - /* Error. We failed to attach to the tap. Clean up */ - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str); - g_free(sp->filter); - g_free(sp); - g_string_free(error_string, TRUE); - return; - } - - /* Button row. */ - bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL); - gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0); - - bt_close = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE); - window_set_cancel_button(sp->win, bt_close, window_cancel_button_cb); - - g_signal_connect(sp->win, "delete_event", G_CALLBACK(window_delete_event_cb), NULL); - g_signal_connect(sp->win, "destroy", G_CALLBACK(win_destroy_cb), sp); - - /* Display up-to-date contents */ - gtk_widget_show_all(sp->win); - window_present(sp->win); - - sip_init_hash(sp); - cf_retap_packets(&cfile); - gdk_window_raise(gtk_widget_get_window(sp->win)); -} - -static tap_param sip_stat_params[] = { - { PARAM_FILTER, "filter", "Filter", NULL, TRUE } -}; - -static tap_param_dlg sip_stat_dlg = { - "SIP Packet Counter", - "sip,stat", - gtk_sipstat_init, - -1, - G_N_ELEMENTS(sip_stat_params), - sip_stat_params, - NULL -}; - -/* Register this tap listener and add menu item. */ -void -register_tap_listener_gtksipstat(void) -{ - register_param_stat(&sip_stat_dlg, "_SIP", REGISTER_STAT_GROUP_TELEPHONY); -} - -/* - * Editor modelines - http://www.wireshark.org/tools/modelines.html - * - * Local variables: - * c-basic-offset: 4 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - * - * vi: set shiftwidth=4 tabstop=8 expandtab: - * :indentSize=4:tabSize=8:noTabs=true: - */ diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp index 4d0c28899a..fb723573d3 100644 --- a/ui/qt/main_window.cpp +++ b/ui/qt/main_window.cpp @@ -2160,6 +2160,7 @@ void MainWindow::addDynamicMenus() wsApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteRlcStatistics); wsApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_LTE, main_ui_->actionTelephonyLteRlcGraph); wsApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY_MTP3, main_ui_->actionTelephonyMtp3Summary); + wsApp->addDynamicMenuGroupItem(REGISTER_STAT_GROUP_TELEPHONY, main_ui_->actionTelephonySipFlows); // Fill in each menu foreach (register_stat_group_t menu_group, menu_groups) { diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui index 8010411277..761f160cb1 100644 --- a/ui/qt/main_window.ui +++ b/ui/qt/main_window.ui @@ -565,7 +565,6 @@ <addaction name="menuTelephonySCTP"/> <addaction name="actionTelephonySMPPOperations"/> <addaction name="actionTelephonyUCPMessages"/> - <addaction name="actionTelephonySipFlows"/> </widget> <widget class="QMenu" name="menuEdit"> <property name="title"> |