diff options
author | Michael Mann <mmann78@netscape.net> | 2015-06-20 12:22:22 -0400 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2015-06-22 15:13:39 +0000 |
commit | 8f390d497577937dee7311f345b77c840ba42e15 (patch) | |
tree | d59679646ab38e4c22d7773cd00003719be028e7 /epan | |
parent | 8b230eabddf11becf4ae895fba17f43a3415716e (diff) | |
download | wireshark-8f390d497577937dee7311f345b77c840ba42e15.tar.gz |
Refactor RTD stats.
Very similar to the refactoring of SRT stats, it provides more commonality of the stats for all GUI interfaces. Currently implemented for TShark and GTK. Affected dissectors: MEGACO, MGCP, Radius
Change-Id: Icb73a7e603dc3502b39bf696227fcaae37d4ed21
Reviewed-on: https://code.wireshark.org/review/8998
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/Makefile.common | 2 | ||||
-rw-r--r-- | epan/dissectors/packet-megaco.c | 212 | ||||
-rw-r--r-- | epan/dissectors/packet-mgcp.c | 99 | ||||
-rw-r--r-- | epan/dissectors/packet-radius.c | 147 | ||||
-rw-r--r-- | epan/rtd_table.c | 205 | ||||
-rw-r--r-- | epan/rtd_table.h | 183 |
7 files changed, 849 insertions, 0 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 87b2d298f9..fec0cf3a2d 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -1629,6 +1629,7 @@ set(LIBWIRESHARK_FILES reassemble.c reedsolomon.c req_resp_hdrs.c + rtd_table.c show_exception.c sminmpec.c srt_table.c diff --git a/epan/Makefile.common b/epan/Makefile.common index ec2ee1926e..a8c3bb5ad1 100644 --- a/epan/Makefile.common +++ b/epan/Makefile.common @@ -79,6 +79,7 @@ LIBWIRESHARK_SRC = \ reassemble.c \ reedsolomon.c \ req_resp_hdrs.c \ + rtd_table.c \ show_exception.c \ sminmpec.c \ srt_table.c \ @@ -232,6 +233,7 @@ LIBWIRESHARK_INCLUDES = \ reassemble.h \ reedsolomon.h \ req_resp_hdrs.h \ + rtd_table.h \ rtp_pt.h \ sctpppids.h \ show_exception.h \ diff --git a/epan/dissectors/packet-megaco.c b/epan/dissectors/packet-megaco.c index ac6e23ae1d..e822245059 100644 --- a/epan/dissectors/packet-megaco.c +++ b/epan/dissectors/packet-megaco.c @@ -46,6 +46,8 @@ #include <epan/exceptions.h> #include <epan/gcp.h> #include <epan/tap.h> +#include <epan/rtd_table.h> +#include <epan/prefs-int.h> #include "packet-tpkt.h" #include "packet-h245.h" #include "packet-ip.h" @@ -201,6 +203,215 @@ static const value_string megaco_context_vals[] = { static gint megaco_tvb_skip_wsp(tvbuff_t *tvb, gint offset); static gint megaco_tvb_skip_wsp_return(tvbuff_t *tvb, gint offset); +#define NUM_TIMESTATS 12 + +static const value_string megaco_message_type[] = { + { 0, "ADD "}, + { 1, "MOVE"}, + { 2, "MDFY"}, + { 3, "SUBT"}, + { 4, "AUCP"}, + { 5, "AUVL"}, + { 6, "NTFY"}, + { 7, "SVCC"}, + { 8, "TOPO"}, + { 9, "NONE"}, + { 10, "ALL "}, + { 0, NULL} +}; + +#define GCP_CMD_REPLY_CASE \ + case GCP_CMD_ADD_REPLY: \ + case GCP_CMD_MOVE_REPLY: \ + case GCP_CMD_MOD_REPLY: \ + case GCP_CMD_SUB_REPLY: \ + case GCP_CMD_AUDITCAP_REPLY: \ + case GCP_CMD_AUDITVAL_REPLY: \ + case GCP_CMD_NOTIFY_REPLY: \ + case GCP_CMD_SVCCHG_REPLY: \ + case GCP_CMD_TOPOLOGY_REPLY: \ + case GCP_CMD_REPLY: + +#define GCP_CMD_REQ_CASE \ + case GCP_CMD_ADD_REQ: \ + case GCP_CMD_MOVE_REQ: \ + case GCP_CMD_MOD_REQ: \ + case GCP_CMD_SUB_REQ: \ + case GCP_CMD_AUDITCAP_REQ: \ + case GCP_CMD_AUDITVAL_REQ: \ + case GCP_CMD_NOTIFY_REQ: \ + case GCP_CMD_SVCCHG_REQ: \ + case GCP_CMD_TOPOLOGY_REQ: \ + case GCP_CMD_CTX_ATTR_AUDIT_REQ: \ + case GCP_CMD_OTHER_REQ: + +static gboolean +megacostat_is_duplicate_reply(const gcp_cmd_t* cmd) +{ + switch (cmd->type) { + + GCP_CMD_REPLY_CASE + { + gcp_cmd_msg_t *cmd_msg; + /* cycle through commands to find same command in the transaction */ + for (cmd_msg = cmd->trx->cmds; + (cmd_msg != NULL) && (cmd_msg->cmd->msg->framenum != cmd->msg->framenum); + cmd_msg = cmd_msg->next) { + if (cmd_msg->cmd->type == cmd->type) + return TRUE; + } + + return FALSE; + } + break; + default: + return FALSE; + break; + } +} + +static gboolean +megacostat_had_request(const gcp_cmd_t* cmd) +{ + switch (cmd->type) { + + GCP_CMD_REPLY_CASE + { + gcp_cmd_msg_t *cmd_msg; + /* cycle through commands to find a request in the transaction */ + for (cmd_msg = cmd->trx->cmds; + (cmd_msg != NULL) && (cmd_msg->cmd->msg->framenum != cmd->msg->framenum); + cmd_msg = cmd_msg->next) { + + switch (cmd_msg->cmd->type) { + + GCP_CMD_REQ_CASE + return TRUE; + break; + default: + return FALSE; + break; + } + } + + return FALSE; + } + break; + default: + return FALSE; + break; + } +} + +static void +megacostat_filtercheck(const char *opt_arg _U_, const char **filter _U_, char** err) +{ + pref_t *megaco_ctx_track, *h248_ctx_track; + + megaco_ctx_track = prefs_find_preference(prefs_find_module("megaco"), "ctx_info"); + h248_ctx_track = prefs_find_preference(prefs_find_module("h248"), "ctx_info"); + + if (!megaco_ctx_track || !h248_ctx_track) { + /* No such preferences */ + return; + } + + if (!*megaco_ctx_track->varp.boolp || !*h248_ctx_track->varp.boolp) { + *err = g_strdup_printf("Track Context option at Protocols -> MEGACO and Protocols -> H248 preferences\n" + "has to be set to true to enable measurement of service response times.\n"); + } +} + +static int +megacostat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pmi) +{ + rtd_data_t* rtd_data = (rtd_data_t*)pms; + rtd_stat_table* ms = &rtd_data->stat_table; + const gcp_cmd_t *mi=(const gcp_cmd_t*)pmi; + nstime_t delta; + int ret = 0; + + switch (mi->type) { + + GCP_CMD_REQ_CASE + if(!mi->trx->initial) { + /* Track Context is probably disabled, we cannot + * measure service response time */ + return 0; + } + + else if(mi->trx->initial->framenum != mi->msg->framenum){ + /* Duplicate is ignored */ + ms->time_stats[0].req_dup_num++; + } + else { + ms->time_stats[0].open_req_num++; + } + break; + + GCP_CMD_REPLY_CASE + if(megacostat_is_duplicate_reply(mi)){ + /* Duplicate is ignored */ + ms->time_stats[0].rsp_dup_num++; + } + else if (!megacostat_had_request(mi)) { + /* no request was seen */ + ms->time_stats[0].disc_rsp_num++; + } + else { + ms->time_stats[0].open_req_num--; + /* calculate time delta between request and response */ + nstime_delta(&delta, &pinfo->fd->abs_ts, &mi->trx->initial->time); + + switch(mi->type) { + + case GCP_CMD_ADD_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[0]),&delta, pinfo); + break; + case GCP_CMD_MOVE_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[1]),&delta, pinfo); + break; + case GCP_CMD_MOD_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[2]),&delta, pinfo); + break; + case GCP_CMD_SUB_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[3]),&delta, pinfo); + break; + case GCP_CMD_AUDITCAP_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[4]),&delta, pinfo); + break; + case GCP_CMD_AUDITVAL_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[5]),&delta, pinfo); + break; + case GCP_CMD_NOTIFY_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[6]),&delta, pinfo); + break; + case GCP_CMD_SVCCHG_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[7]),&delta, pinfo); + break; + case GCP_CMD_TOPOLOGY_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[8]),&delta, pinfo); + break; + case GCP_CMD_REPLY: + time_stat_update(&(ms->time_stats[0].rtd[9]),&delta, pinfo); + break; + default: + time_stat_update(&(ms->time_stats[0].rtd[11]),&delta, pinfo); + } + + time_stat_update(&(ms->time_stats[0].rtd[10]),&delta, pinfo); + ret = 1; + } + break; + + default: + break; + } + + return ret; +} + + /* * The various functions that either dissect some * subpart of MEGACO. These aren't really proto dissectors but they @@ -3575,6 +3786,7 @@ proto_register_megaco(void) ws_mempbrk_compile(&pbrk_whitespace, " \t\r\n"); ws_mempbrk_compile(&pbrk_braces, "{}"); + register_rtd_table(proto_megaco, NULL, 1, NUM_TIMESTATS, megaco_message_type, megacostat_packet, megacostat_filtercheck); } /* Register all the bits needed with the filtering engine */ diff --git a/epan/dissectors/packet-mgcp.c b/epan/dissectors/packet-mgcp.c index aabe2a3915..21b5fdfdbb 100644 --- a/epan/dissectors/packet-mgcp.c +++ b/epan/dissectors/packet-mgcp.c @@ -42,6 +42,7 @@ #include <epan/prefs.h> #include <epan/conversation.h> #include <epan/tap.h> +#include <epan/rtd_table.h> #include "packet-mgcp.h" @@ -279,6 +280,102 @@ static void dissect_mgcp_localconnectionoptions(proto_tree *parent_tree, tvbuff_ static void mgcp_raw_text_add(tvbuff_t *tvb, proto_tree *tree); +#define NUM_TIMESTATS 11 + +static const value_string mgcp_mesage_type[] = { + { 0, "Overall"}, + { 1, "EPCF "}, + { 2, "CRCX "}, + { 3, "MDCX "}, + { 4, "DLCX "}, + { 5, "RQNT "}, + { 6, "NTFY "}, + { 7, "AUEP "}, + { 8, "AUCX "}, + { 9, "RSIP "}, + { 0, NULL} +}; + +static int +mgcpstat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pmi) +{ + rtd_data_t* rtd_data = (rtd_data_t*)pms; + rtd_stat_table* ms = &rtd_data->stat_table; + const mgcp_info_t *mi = (const mgcp_info_t *)pmi; + nstime_t delta; + int ret = 0; + + switch (mi->mgcp_type) { + + case MGCP_REQUEST: + if (mi->is_duplicate) { + /* Duplicate is ignored */ + ms->time_stats[0].req_dup_num++; + } + else { + ms->time_stats[0].open_req_num++; + } + break; + + case MGCP_RESPONSE: + if (mi->is_duplicate) { + /* Duplicate is ignored */ + ms->time_stats[0].rsp_dup_num++; + } + else if (!mi->request_available) { + /* no request was seen */ + ms->time_stats[0].disc_rsp_num++; + } + else { + ms->time_stats[0].open_req_num--; + /* calculate time delta between request and response */ + nstime_delta(&delta, &pinfo->fd->abs_ts, &mi->req_time); + + time_stat_update(&(ms->time_stats[0].rtd[0]), &delta, pinfo); + + if (g_ascii_strncasecmp(mi->code, "EPCF", 4) == 0 ) { + time_stat_update(&(ms->time_stats[0].rtd[1]), &delta, pinfo); + } + else if (g_ascii_strncasecmp(mi->code, "CRCX", 4) == 0 ) { + time_stat_update(&(ms->time_stats[0].rtd[2]), &delta, pinfo); + } + else if (g_ascii_strncasecmp(mi->code, "MDCX", 4) == 0 ) { + time_stat_update(&(ms->time_stats[0].rtd[3]), &delta, pinfo); + } + else if (g_ascii_strncasecmp(mi->code, "DLCX", 4) == 0 ) { + time_stat_update(&(ms->time_stats[0].rtd[4]), &delta, pinfo); + } + else if (g_ascii_strncasecmp(mi->code, "RQNT", 4) == 0 ) { + time_stat_update(&(ms->time_stats[0].rtd[5]), &delta, pinfo); + } + else if (g_ascii_strncasecmp(mi->code, "NTFY", 4) == 0 ) { + time_stat_update(&(ms->time_stats[0].rtd[6]), &delta, pinfo); + } + else if (g_ascii_strncasecmp(mi->code, "AUEP", 4) == 0 ) { + time_stat_update(&(ms->time_stats[0].rtd[7]), &delta, pinfo); + } + else if (g_ascii_strncasecmp(mi->code, "AUCX", 4) == 0 ) { + time_stat_update(&(ms->time_stats[0].rtd[8]), &delta, pinfo); + } + else if (g_ascii_strncasecmp(mi->code, "RSIP", 4) == 0 ) { + time_stat_update(&(ms->time_stats[0].rtd[9]), &delta, pinfo); + } + else { + time_stat_update(&(ms->time_stats[0].rtd[10]), &delta, pinfo); + } + + ret = 1; + } + break; + + default: + break; + } + + return ret; +} + + /* * Some functions which should be moved to a library * as I think that people may find them of general usefulness. @@ -2258,6 +2355,8 @@ void proto_register_mgcp(void) &global_mgcp_message_count); mgcp_tap = register_tap("mgcp"); + + register_rtd_table(proto_mgcp, NULL, 1, NUM_TIMESTATS, mgcp_mesage_type, mgcpstat_packet, NULL); } /* The registration hand-off routine */ diff --git a/epan/dissectors/packet-radius.c b/epan/dissectors/packet-radius.c index 2f02fa4a09..dc5176ee46 100644 --- a/epan/dissectors/packet-radius.c +++ b/epan/dissectors/packet-radius.c @@ -63,6 +63,7 @@ #include <epan/sminmpec.h> #include <epan/conversation.h> #include <epan/tap.h> +#include <epan/rtd_table.h> #include <epan/addr_resolv.h> #include <wsutil/filesystem.h> #include <wsutil/report_err.h> @@ -212,6 +213,150 @@ static const value_string radius_pkt_type_codes[] = }; static value_string_ext radius_pkt_type_codes_ext = VALUE_STRING_EXT_INIT(radius_pkt_type_codes); +typedef enum _radius_category { + RADIUS_CAT_OVERALL = 0, + RADIUS_CAT_ACCESS, + RADIUS_CAT_ACCOUNTING, + RADIUS_CAT_PASSWORD, + RADIUS_CAT_RESOURCE_FREE, + RADIUS_CAT_RESOURCE_QUERY, + RADIUS_CAT_NAS_REBOOT, + RADIUS_CAT_EVENT, + RADIUS_CAT_DISCONNECT, + RADIUS_CAT_COA, + RADIUS_CAT_OTHERS, + RADIUS_CAT_NUM_TIMESTATS +} radius_category; + +static const value_string radius_message_code[] = { + { RADIUS_CAT_OVERALL, "Overall"}, + { RADIUS_CAT_ACCESS, "Access"}, + { RADIUS_CAT_ACCOUNTING, "Accounting"}, + { RADIUS_CAT_PASSWORD, "Password"}, + { RADIUS_CAT_RESOURCE_FREE, "Resource Free"}, + { RADIUS_CAT_RESOURCE_QUERY, "Resource Query"}, + { RADIUS_CAT_NAS_REBOOT, "NAS Reboot"}, + { RADIUS_CAT_EVENT, "Event"}, + { RADIUS_CAT_DISCONNECT, "Disconnect"}, + { RADIUS_CAT_COA, "CoA"}, + { RADIUS_CAT_OTHERS, "Other"}, + { 0, NULL} +}; + +static int +radiusstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri) +{ + rtd_data_t* rtd_data = (rtd_data_t*)prs; + rtd_stat_table* rs = &rtd_data->stat_table; + const radius_info_t *ri=(radius_info_t *)pri; + nstime_t delta; + radius_category radius_cat = RADIUS_CAT_OTHERS; + int ret = 0; + + switch (ri->code) { + case RADIUS_PKT_TYPE_ACCESS_REQUEST: + case RADIUS_PKT_TYPE_ACCESS_ACCEPT: + case RADIUS_PKT_TYPE_ACCESS_REJECT: + radius_cat = RADIUS_CAT_ACCESS; + break; + case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST: + case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE: + radius_cat = RADIUS_CAT_ACCOUNTING; + break; + case RADIUS_PKT_TYPE_PASSWORD_REQUEST: + case RADIUS_PKT_TYPE_PASSWORD_ACK: + case RADIUS_PKT_TYPE_PASSWORD_REJECT: + radius_cat = RADIUS_CAT_PASSWORD; + break; + case RADIUS_PKT_TYPE_RESOURCE_FREE_REQUEST: + case RADIUS_PKT_TYPE_RESOURCE_FREE_RESPONSE: + radius_cat = RADIUS_CAT_RESOURCE_FREE; + break; + case RADIUS_PKT_TYPE_RESOURCE_QUERY_REQUEST: + case RADIUS_PKT_TYPE_RESOURCE_QUERY_RESPONSE: + radius_cat = RADIUS_CAT_RESOURCE_QUERY; + break; + case RADIUS_PKT_TYPE_NAS_REBOOT_REQUEST: + case RADIUS_PKT_TYPE_NAS_REBOOT_RESPONSE: + radius_cat = RADIUS_CAT_NAS_REBOOT; + break; + case RADIUS_PKT_TYPE_EVENT_REQUEST: + case RADIUS_PKT_TYPE_EVENT_RESPONSE: + radius_cat = RADIUS_CAT_EVENT; + break; + case RADIUS_PKT_TYPE_DISCONNECT_REQUEST: + case RADIUS_PKT_TYPE_DISCONNECT_ACK: + case RADIUS_PKT_TYPE_DISCONNECT_NAK: + radius_cat = RADIUS_CAT_DISCONNECT; + break; + case RADIUS_PKT_TYPE_COA_REQUEST: + case RADIUS_PKT_TYPE_COA_ACK: + case RADIUS_PKT_TYPE_COA_NAK: + radius_cat = RADIUS_CAT_COA; + break; + } + + switch (ri->code) { + + case RADIUS_PKT_TYPE_ACCESS_REQUEST: + case RADIUS_PKT_TYPE_ACCOUNTING_REQUEST: + case RADIUS_PKT_TYPE_PASSWORD_REQUEST: + case RADIUS_PKT_TYPE_EVENT_REQUEST: + case RADIUS_PKT_TYPE_DISCONNECT_REQUEST: + case RADIUS_PKT_TYPE_COA_REQUEST: + if(ri->is_duplicate){ + /* Duplicate is ignored */ + rs->time_stats[RADIUS_CAT_OVERALL].req_dup_num++; + rs->time_stats[radius_cat].req_dup_num++; + } + else { + rs->time_stats[RADIUS_CAT_OVERALL].open_req_num++; + rs->time_stats[radius_cat].open_req_num++; + } + break; + + case RADIUS_PKT_TYPE_ACCESS_ACCEPT: + case RADIUS_PKT_TYPE_ACCESS_REJECT: + case RADIUS_PKT_TYPE_ACCOUNTING_RESPONSE: + case RADIUS_PKT_TYPE_PASSWORD_ACK: + case RADIUS_PKT_TYPE_PASSWORD_REJECT: + case RADIUS_PKT_TYPE_EVENT_RESPONSE: + case RADIUS_PKT_TYPE_DISCONNECT_ACK: + case RADIUS_PKT_TYPE_DISCONNECT_NAK: + case RADIUS_PKT_TYPE_COA_ACK: + case RADIUS_PKT_TYPE_COA_NAK: + if(ri->is_duplicate){ + /* Duplicate is ignored */ + rs->time_stats[RADIUS_CAT_OVERALL].rsp_dup_num++; + rs->time_stats[radius_cat].rsp_dup_num++; + } + else if (!ri->request_available) { + /* no request was seen */ + rs->time_stats[RADIUS_CAT_OVERALL].disc_rsp_num++; + rs->time_stats[radius_cat].disc_rsp_num++; + } + else { + rs->time_stats[RADIUS_CAT_OVERALL].open_req_num--; + rs->time_stats[radius_cat].open_req_num--; + /* calculate time delta between request and response */ + nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->req_time); + + time_stat_update(&(rs->time_stats[RADIUS_CAT_OVERALL].rtd[0]),&delta, pinfo); + time_stat_update(&(rs->time_stats[radius_cat].rtd[0]),&delta, pinfo); + + ret = 1; + } + break; + + default: + break; + } + + return ret; +} + + + /* * Init Hash table stuff for conversation */ @@ -2130,6 +2275,8 @@ proto_register_radius(void) dict->vendors_by_id = g_hash_table_new(g_direct_hash,g_direct_equal); dict->vendors_by_name = g_hash_table_new(g_str_hash,g_str_equal); dict->tlvs_by_name = g_hash_table_new(g_str_hash,g_str_equal); + + register_rtd_table(proto_radius, NULL, RADIUS_CAT_NUM_TIMESTATS, 1, radius_message_code, radiusstat_packet, NULL); } void diff --git a/epan/rtd_table.c b/epan/rtd_table.c new file mode 100644 index 0000000000..a74a32adb2 --- /dev/null +++ b/epan/rtd_table.c @@ -0,0 +1,205 @@ +/* rtd_table.c + * Helper routines common to all RTD taps. + * Based on srt_table.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 "packet_info.h" +#include "proto.h" +#include "rtd_table.h" + +struct register_rtd { + int proto_id; /* protocol id (0-indexed) */ + const char* tap_listen_str; /* string used in register_tap_listener (NULL to use protocol name) */ + tap_packet_cb rtd_func; /* function to be called for new incoming packets for RTD */ + guint num_tables; + guint num_timestats; + const value_string* vs_type; + rtd_filter_check_cb filter_check; +}; + +int get_rtd_proto_id(register_rtd_t* rtd) +{ + if (!rtd) { + return -1; + } + return rtd->proto_id; +} + +const char* get_rtd_tap_listener_name(register_rtd_t* rtd) +{ + return rtd->tap_listen_str; +} + +tap_packet_cb get_rtd_packet_func(register_rtd_t* rtd) +{ + return rtd->rtd_func; +} + +const value_string* get_rtd_value_string(register_rtd_t* rtd) +{ + return rtd->vs_type; +} + +static GSList *registered_rtd_tables = NULL; + +static gint +insert_sorted_by_table_name(gconstpointer aparam, gconstpointer bparam) +{ + const register_rtd_t *a = (register_rtd_t *)aparam; + const register_rtd_t *b = (register_rtd_t *)bparam; + + return g_ascii_strcasecmp(proto_get_protocol_short_name(find_protocol_by_id(a->proto_id)), proto_get_protocol_short_name(find_protocol_by_id(b->proto_id))); +} + +void +register_rtd_table(const int proto_id, const char* tap_listener, guint num_tables, guint num_timestats, const value_string* vs_type, + tap_packet_cb rtd_packet_func, rtd_filter_check_cb filter_check_cb) +{ + register_rtd_t *table; + DISSECTOR_ASSERT(rtd_packet_func); + + table = g_new(register_rtd_t,1); + + table->proto_id = proto_id; + if (tap_listener != NULL) + table->tap_listen_str = tap_listener; + else + table->tap_listen_str = proto_get_protocol_filter_name(proto_id); + table->rtd_func = rtd_packet_func; + table->num_tables = num_tables; + table->num_timestats = num_timestats; + table->vs_type = vs_type; + table->filter_check = filter_check_cb; + + registered_rtd_tables = g_slist_insert_sorted(registered_rtd_tables, table, insert_sorted_by_table_name); +} + +void free_rtd_table(register_rtd_t* rtd _U_, rtd_stat_table* table, rtd_gui_free_cb gui_callback, void *callback_data) +{ + guint i; + + for (i = 0; i < table->num_rtds; i++) + { + g_free(table->time_stats[i].rtd); + } + g_free(table->time_stats); + + /* Give GUI the first crack at it before we clean up */ + if (gui_callback) + gui_callback(table, callback_data); +} + +void reset_rtd_table(rtd_stat_table* table, rtd_gui_reset_cb gui_callback, void *callback_data) +{ + guint i = 0; + + for (i = 0; i < table->num_rtds; i++) + memset(table->time_stats[i].rtd, 0, sizeof(timestat_t)*table->time_stats[i].num_timestat); + + /* Give GUI the first crack at it before we clean up */ + if (gui_callback) + gui_callback(table, callback_data); + +} + +register_rtd_t* get_rtd_table_by_name(const char* name) +{ + guint i, size = g_slist_length(registered_rtd_tables); + register_rtd_t* rtd; + GSList *slist; + + for (i = 0; i < size; i++) { + slist = g_slist_nth(registered_rtd_tables, i); + rtd = (register_rtd_t*)slist->data; + + if (strcmp(name, proto_get_protocol_filter_name(rtd->proto_id)) == 0) + return rtd; + } + + return NULL; +} + +gchar* rtd_table_get_tap_string(register_rtd_t* rtd) +{ + GString *cmd_str = g_string_new(proto_get_protocol_filter_name(rtd->proto_id)); + g_string_append(cmd_str, ",rtd"); + return g_string_free(cmd_str, FALSE); +} + +void rtd_table_get_filter(register_rtd_t* rtd, const char *opt_arg, const char **filter, char** err) +{ + gchar* cmd_str = rtd_table_get_tap_string(rtd); + guint len = strlen(cmd_str); + *filter=NULL; + *err=NULL; + + if (!strncmp(opt_arg, cmd_str, len)) + { + if (opt_arg[len] == ',') + { + *filter = opt_arg + len+1; + } + } + + if (rtd->filter_check) + rtd->filter_check(opt_arg, filter, err); + + g_free(cmd_str); +} + +void rtd_table_dissector_init(register_rtd_t* rtd, rtd_stat_table* table, rtd_gui_init_cb gui_callback, void *callback_data) +{ + guint i; + + table->num_rtds = rtd->num_tables; + table->time_stats = g_new0(rtd_timestat, rtd->num_tables); + + for (i = 0; i < table->num_rtds; i++) + { + table->time_stats[i].num_timestat = rtd->num_timestats; + table->time_stats[i].rtd = g_new0(timestat_t, rtd->num_timestats); + } + + if (gui_callback) + gui_callback(table, callback_data); +} + +void rtd_table_iterate_tables(GFunc func, gpointer user_data) +{ + g_slist_foreach(registered_rtd_tables, func, user_data); +} + +/* + * 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/epan/rtd_table.h b/epan/rtd_table.h new file mode 100644 index 0000000000..168c8beb4e --- /dev/null +++ b/epan/rtd_table.h @@ -0,0 +1,183 @@ +/* rtd_table.h + * GUI independent helper routines common to all Response Time Delay (RTD) taps. + * Based on srt_table.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __RTD_TABLE_H__ +#define __RTD_TABLE_H__ + +#include "tap.h" +#include "timestats.h" +#include "value_string.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _rtd_timestat { + guint num_timestat; /**< number of elements on rtd array */ + timestat_t* rtd; + guint32 open_req_num; + guint32 disc_rsp_num; + guint32 req_dup_num; + guint32 rsp_dup_num; +} rtd_timestat; + +/** Statistics table */ +typedef struct _rtd_stat_table { + char *filter; + guint num_rtds; /**< number of elements on time_stats array */ + rtd_timestat* time_stats; +} rtd_stat_table; + +/** tap data + */ +typedef struct _rtd_data_t { + rtd_stat_table stat_table; /**< RTD table data */ + void *user_data; /**< "GUI" specifics (if necessary) */ +} rtd_data_t; + +/** Structure for information about a registered service response table */ +struct register_rtd; +typedef struct register_rtd register_rtd_t; + +typedef void (*rtd_gui_init_cb)(rtd_stat_table* rtd, void* gui_data); +typedef void (*rtd_gui_reset_cb)(rtd_stat_table* rtd, void* gui_data); +typedef void (*rtd_gui_free_cb)(rtd_stat_table* rtd, void* gui_data); +typedef void (*rtd_init_cb)(struct register_rtd* rtd, rtd_gui_init_cb gui_callback, void* gui_data); +typedef void (*rtd_filter_check_cb)(const char *opt_arg, const char **filter, char** err); + +/** Register the response time delay table. + * + * @param proto_id is the protocol with conversation + * @param tap_listener string for register_tap_listener (NULL to just use protocol name) + * @param num_timestats number of timestamps in the table + * @param vs_type value_string for the stat types + * @param rtd_packet_func the tap processing function + * @param filter_check_cb callback for verification of filter or other dissector checks + */ +WS_DLL_PUBLIC void register_rtd_table(const int proto_id, const char* tap_listener, guint num_tables, guint num_timestats, const value_string* vs_type, + tap_packet_cb rtd_packet_func, rtd_filter_check_cb filter_check_cb); + +/** Get protocol ID from RTD + * + * @param rtd Registered RTD + * @return protocol id of RTD + */ +WS_DLL_PUBLIC int get_rtd_proto_id(register_rtd_t* rtd); + +/** Get string for register_tap_listener call. Typically just dissector name + * + * @param rtd Registered RTD + * @return string for register_tap_listener call + */ +WS_DLL_PUBLIC const char* get_rtd_tap_listener_name(register_rtd_t* rtd); + +/** Get tap function handler from RTD + * + * @param rtd Registered RTD + * @return tap function handler of RTD + */ +WS_DLL_PUBLIC tap_packet_cb get_rtd_packet_func(register_rtd_t* rtd); + +/** Get value_string used for RTD + * + * @param rtd Registered RTD + * @return value_string of RTD + */ +WS_DLL_PUBLIC const value_string* get_rtd_value_string(register_rtd_t* rtd); + +/** Get RTD table by its dissector name + * + * @param name dissector name to fetch. + * @return RTD table pointer or NULL. + */ +WS_DLL_PUBLIC register_rtd_t* get_rtd_table_by_name(const char* name); + +/** Free the RTD table data. + * + * @param srt Registered RTD + * @param srt_array RTD table array + * @param gui_callback optional callback from GUI + * @param callback_data callback data needed for GUI + */ +WS_DLL_PUBLIC void free_rtd_table(register_rtd_t* rtd, rtd_stat_table* table, rtd_gui_free_cb gui_callback, void *callback_data); + +/** Reset table data in the RTD. + * + * @param table RTD table + * @param gui_callback optional callback from GUI + * @param callback_data callback data needed for GUI + */ +WS_DLL_PUBLIC void reset_rtd_table(rtd_stat_table* table, rtd_gui_reset_cb gui_callback, void *callback_data); + +/** Interator to walk RTD tables and execute func + * Used for initialization + * + * @param func action to be performed on all converation tables + * @param user_data any data needed to help perform function + */ +WS_DLL_PUBLIC void rtd_table_iterate_tables(GFunc func, gpointer user_data); + +/** Return filter used for register_tap_listener + * + * @param srt Registered RTD + * @param opt_arg passed in opt_arg from GUI + * @param filter returned filter string to be used for registering tap + * @param err returned error if opt_arg string can't be successfully handled. Caller must free memory + */ +WS_DLL_PUBLIC void rtd_table_get_filter(register_rtd_t* rtd, const char *opt_arg, const char **filter, char** err); + +/** "Common" initialization function for all GUIs + * + * @param srt Registered RTD + * @param table RTD table + * @param gui_callback optional GUI callback function + * @param callback_data optional GUI callback data + */ +WS_DLL_PUBLIC void rtd_table_dissector_init(register_rtd_t* rtd, rtd_stat_table* table, rtd_gui_init_cb gui_callback, void *callback_data); + +/** Helper function to get tap string name + * Caller is responsible for freeing returned string + * + * @param srt Registered RTD + * @return RTD tap string + */ +WS_DLL_PUBLIC gchar* rtd_table_get_tap_string(register_rtd_t* rtd); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __RTD_TABLE_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: + */ |