diff options
-rw-r--r-- | epan/camel-persistentdata.c | 798 | ||||
-rw-r--r-- | epan/camel-persistentdata.h | 126 | ||||
-rw-r--r-- | gtk/camel_counter.c | 233 | ||||
-rw-r--r-- | gtk/camel_srt.c | 248 | ||||
-rw-r--r-- | tap-camelcounter.c | 146 | ||||
-rw-r--r-- | tap-camelsrt.c | 276 |
6 files changed, 1827 insertions, 0 deletions
diff --git a/epan/camel-persistentdata.c b/epan/camel-persistentdata.c new file mode 100644 index 0000000000..ff3c06be7b --- /dev/null +++ b/epan/camel-persistentdata.c @@ -0,0 +1,798 @@ +/* + * camel-persistentdata.c + * Source for lists and hash tables used in wireshark's camel dissector + * for calculation of delays in camel calls + * Copyright 2006 Florent Drouin + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <glib.h> +#include <stdio.h> +#include <string.h> + +#include <epan/emem.h> +#include "epan/packet.h" +#include "epan/conversation.h" +#include "epan/camel-persistentdata.h" +#include "epan/dissectors/packet-tcap.h" +#include "epan/dissectors/packet-mtp3.h" + +static gint camelsrt_call_equal(gconstpointer k1, gconstpointer k2); +static guint camelsrt_call_hash(gconstpointer k); +static struct camelsrt_call_t * find_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key, + packet_info *pinfo); +static struct camelsrt_call_t * new_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key, + packet_info *pinfo); + +static void update_camelsrt_call(struct camelsrt_call_t * p_camelsrt_call, + packet_info *pinfo, + guint msg_category _U_); + +static struct camelsrt_call_t * append_camelsrt_call(struct camelsrt_call_t * prev_call, + packet_info *pinfo); + +static void camelsrt_begin_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camelsrt_info); + +static void camelsrt_request_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camelsrt_info, + guint srt_type); + +static void camelsrt_report_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camelsrt_info, + guint srt_type); + +static void camelsrt_close_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camelsrt_info); + +static void camelsrt_display_DeltaTime(proto_tree *tree, + tvbuff_t *tvb, + nstime_t* value_ptr, + guint category); + +static void raz_camelsrt_call (struct camelsrt_call_t * p_camelsrt_call); + +void camelsrt_tcap_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct tcaphash_context_t * tcap_context); + +/* When several Camel components are received in a single TCAP message, + we have to use several buffers for the stored parameters + because else this data are erased during TAP dissector call */ +#define MAX_CAMEL_INSTANCE 10 +int camelsrt_global_current=0; +struct camelsrt_info_t camelsrt_global_info[MAX_CAMEL_INSTANCE]; + +/* Configuration parameters to enable or disable the Service Response Time */ +extern gboolean gcamel_HandleSRT; +gboolean gcamel_PersistentSRT=FALSE; +gboolean gcamel_DisplaySRT=FALSE; +gboolean gcamel_StatSRT=FALSE; + +extern int camel_tap; + +extern int hf_camelsrt_SessionId; +extern int hf_camelsrt_RequestNumber; +extern int hf_camelsrt_Duplicate; +extern int hf_camelsrt_RequestFrame; +extern int hf_camelsrt_ResponseFrame; +extern int hf_camelsrt_DeltaTime; +extern int hf_camelsrt_SessionTime; +extern int hf_camelsrt_DeltaTime31; +extern int hf_camelsrt_DeltaTime75; +extern int hf_camelsrt_DeltaTime65; +extern int hf_camelsrt_DeltaTime22; +extern int hf_camelsrt_DeltaTime35; +extern int hf_camelsrt_DeltaTime80; + +/* Global hash tables*/ +static GHashTable *srt_calls = NULL; +guint32 camelsrt_global_SessionId=1; + +/* + * DEBUG fonctions + */ + +#undef DEBUG_CAMELSRT +/* #define DEBUG_CAMELSRT */ + +#ifdef DEBUG_CAMELSRT +#include <stdio.h> +#include <stdarg.h> +static unsigned debug_level = 99; + +static void dbg(unsigned level, char* fmt, ...) { + va_list ap; + + if (level > debug_level) return; + va_start(ap,fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} +#endif + +/* + * Functions needed for Hash-Table + */ + +/* compare 2 keys */ +static gint camelsrt_call_equal(gconstpointer k1, gconstpointer k2) +{ + const struct camelsrt_call_info_key_t * key1 = (const struct camelsrt_call_info_key_t *) k1; + const struct camelsrt_call_info_key_t * key2 = (const struct camelsrt_call_info_key_t *) k2; + + return (key1->SessionIdKey == key2->SessionIdKey) ; +} + +/* calculate a hash key */ +static guint camelsrt_call_hash(gconstpointer k) +{ + const struct camelsrt_call_info_key_t * key = (const struct camelsrt_call_info_key_t *) k; + return key->SessionIdKey; +} + +/* + * Find the dialog by Key and Time + */ +static struct camelsrt_call_t * find_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key, + packet_info *pinfo) +{ + struct camelsrt_call_t * p_camelsrt_call = NULL; + p_camelsrt_call = (struct camelsrt_call_t *)g_hash_table_lookup(srt_calls, p_camelsrt_call_key); + + if(p_camelsrt_call) { +#ifdef DEBUG_CAMELSRT + dbg(10,"D%d ", p_camelsrt_call->session_id); +#endif + } else { +#ifdef DEBUG_CAMELSRT + dbg(23,"Not in hash "); +#endif + } + + return p_camelsrt_call; +} + +/* + * New record to create, to identify a new transaction + */ +static struct camelsrt_call_t * new_camelsrt_call(struct camelsrt_call_info_key_t * p_camelsrt_call_key, + packet_info *pinfo) + +{ + struct camelsrt_call_info_key_t * p_new_camelsrt_call_key; + struct camelsrt_call_t * p_new_camelsrt_call = NULL; + + /* Register the transaction in the hash table + with the tcap transaction Id as main Key + Once created, this entry will be updated later */ + + p_new_camelsrt_call_key = se_alloc(sizeof(struct camelsrt_call_info_key_t)); + p_new_camelsrt_call_key->SessionIdKey = p_camelsrt_call_key->SessionIdKey; + p_new_camelsrt_call = se_alloc(sizeof(struct camelsrt_call_t)); + raz_camelsrt_call(p_new_camelsrt_call); + p_new_camelsrt_call->session_id = camelsrt_global_SessionId++; +#ifdef DEBUG_CAMELSRT + dbg(10,"D%d ", p_new_camelsrt_call->session_id); +#endif + /* store it */ + g_hash_table_insert(srt_calls, p_new_camelsrt_call_key, p_new_camelsrt_call); + return p_new_camelsrt_call; +} + +/* + * Update a record with the data of the Request + */ +static void update_camelsrt_call(struct camelsrt_call_t * p_camelsrt_call, + packet_info *pinfo, + guint msg_category _U_) +{ + p_camelsrt_call->category[msg_category].req_num = pinfo->fd->num; + p_camelsrt_call->category[msg_category].rsp_num = 0; + p_camelsrt_call->category[msg_category].responded = FALSE; + p_camelsrt_call->category[msg_category].req_time = pinfo->fd->abs_ts; +} + + +/* + * Routine called when the TAP is initialized. + * so hash table are (re)created + */ +void camelsrt_init_routine(void) +{ + + /* free hash-tables and mem_chunks for SRT */ + if (srt_calls != NULL) { +#ifdef DEBUG_CAMELSRT + dbg(16,"Destroy hash "); +#endif + g_hash_table_destroy(srt_calls); + } + + /* create new hash-tables and mem_chunks for SRT */ + srt_calls = g_hash_table_new(camelsrt_call_hash, camelsrt_call_equal); +#ifdef DEBUG_CAMELSRT + dbg(16,"Create hash "); +#endif + /* Reset the session counter */ + camelsrt_global_SessionId=1; + + /* The Display of SRT is enable + * 1) For wireshark only if Persistent Stat is enable + * 2) For Tshark, if the SRT handling is enable + */ + gcamel_DisplaySRT=gcamel_PersistentSRT || gcamel_HandleSRT&gcamel_StatSRT; +} + +/* + * Service Response Time analyze, called just after the camel dissector + * According to the camel operation, we + * - open/close a context for the camel session + * - look for a request, or look for the corresponding response + */ +void camelsrt_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camelsrt_info) +{ + +#ifdef DEBUG_CAMELSRT + dbg(10,"tcap_session #%d ", p_camelsrt_info->tcap_session_id); +#endif + + switch (p_camelsrt_info->opcode) { + + case 0: /*InitialDP*/ + camelsrt_begin_call_matching(tvb, pinfo, tree, p_camelsrt_info); + camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_VOICE_INITIALDP); + break; + case 60: /*InitialDPSMS*/ + camelsrt_begin_call_matching(tvb, pinfo, tree, p_camelsrt_info); + camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_SMS_INITIALDP); + break; + case 78: /*InitialDPGPRS*/ + camelsrt_begin_call_matching(tvb, pinfo, tree, p_camelsrt_info); + camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_GPRS_INITIALDP); + break; + + case 23: /*RequestReportBCSMEvent*/ + break; + + case 63: /*RequestReportSMSEvent*/ + break; + + case 81: /*RequestReportGPRSEvent*/ + break; + + case 24: /*EventReportBCSMEvent*/ + camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_VOICE_DISC ); + break; + + case 64: /*EventReportSMS*/ + /* Session has been explicity closed without TC_END */ + camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info); + tcapsrt_close(p_camelsrt_info->tcap_context, pinfo); + break; + + case 80: /*EventReportGPRS*/ + camelsrt_begin_call_matching(tvb, pinfo, tree, p_camelsrt_info); + camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_GPRS_REPORT); + break; + + case 35: /*ApplyCharging*/ + camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_VOICE_ACR1 ); + break; + + case 71: /*ApplyChargingGPRS*/ + break; + + case 36: /*ApplyChargingReport*/ + camelsrt_request_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_VOICE_ACR1 ); + break; + + case 72: /*ApplyChargingReportGPRS*/ + break; + + case 31: /*Continue*/ + camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_VOICE_INITIALDP); + break; + case 65: /*ContinueSMS*/ + camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_SMS_INITIALDP); + break; + case 75: /*ContinueGPRS*/ + camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_GPRS_INITIALDP); + camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_GPRS_REPORT); + break; + + case 22: /*ReleaseCall*/ + camelsrt_report_call_matching(tvb, pinfo, tree, p_camelsrt_info, + CAMELSRT_VOICE_DISC); + /* Session has been closed by Network */ + camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info); + break; + + case 66: /*ReleaseSMS*/ + /* Session has been closed by Network */ + camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info); + tcapsrt_close(p_camelsrt_info->tcap_context,pinfo); + break; + + case 79: /*ReleaseGPRS*/ + /* Session has been closed by Network */ + camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info); + break; + } /* switch opcode */ +} + +/* + * Callback function for the TCAP dissector + * This callback function is used to inform the camel layer, that the session + * has been Closed or Aborted by a TCAP message without Camel component + * So, we can close the context for camel session, and update the stats. + */ +void camelsrt_tcap_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct tcaphash_context_t * p_tcap_context) +{ + struct camelsrt_info_t * p_camelsrt_info; + +#ifdef DEBUG_CAMELSRT + dbg(11,"Camel_CallBack "); +#endif + p_camelsrt_info=camelsrt_razinfo(); + + p_camelsrt_info->tcap_context=p_tcap_context; + if (p_tcap_context) { +#ifdef DEBUG_CAMELSRT + dbg(11,"Close TCAP "); +#endif + p_camelsrt_info->tcap_session_id = p_tcap_context->session_id; + camelsrt_close_call_matching(tvb, pinfo, tree, p_camelsrt_info); + tap_queue_packet(camel_tap, pinfo, p_camelsrt_info); + } +} + + +/* + * Create the record identifiying the Camel session + * As the Tcap session id given by the TCAP dissector is uniq, it will be + * used as main key. + */ +static void camelsrt_begin_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camelsrt_info) +{ + struct camelsrt_call_t * p_camelsrt_call; + struct camelsrt_call_info_key_t camelsrt_call_key; + + p_camelsrt_info->bool_msginfo[CAMELSRT_SESSION]=TRUE; + + /* prepare the key data */ + camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id; + + /* look up the request */ +#ifdef DEBUG_CAMELSRT + dbg(10,"\n Session begin #%d\n", pinfo->fd->num); + dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey); +#endif + p_camelsrt_call = (struct camelsrt_call_t *)g_hash_table_lookup(srt_calls, &camelsrt_call_key); + if (p_camelsrt_call) { + /* We have seen this request before -> do nothing */ +#ifdef DEBUG_CAMELSRT + dbg(22,"Already seen "); +#endif + } else { /* p_camelsrt_call has not been found */ +#ifdef DEBUG_CAMELSRT + dbg(10,"New key %lu ",camelsrt_call_key.SessionIdKey); +#endif + p_camelsrt_call = new_camelsrt_call(&camelsrt_call_key, pinfo); + p_camelsrt_call->tcap_context=p_camelsrt_info->tcap_context; + update_camelsrt_call(p_camelsrt_call, pinfo,CAMELSRT_SESSION); + +#ifdef DEBUG_CAMELSRT + dbg(11,"Update Callback "); +#endif + p_camelsrt_call->tcap_context->callback=camelsrt_tcap_matching; + } +} + +/* + * Register the request, and try to find the response + * + */ +static void camelsrt_request_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camelsrt_info, + guint srt_type ) +{ + struct camelsrt_call_t * p_camelsrt_call; + struct camelsrt_call_info_key_t camelsrt_call_key; + proto_item *ti; + +#ifdef DEBUG_CAMELSRT + dbg(10,"\n %s #%d\n", val_to_str(srt_type, camelSRTtype_naming, "Unk"),pinfo->fd->num); +#endif + + /* look only for matching request, if matching conversation is available. */ + camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id; + +#ifdef DEBUG_CAMELSRT + dbg(11,"Search key %lu ", camelsrt_call_key.SessionIdKey); +#endif + p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key, pinfo); + if(p_camelsrt_call) { +#ifdef DEBUG_CAMELSRT + dbg(12,"Found "); +#endif + if (gcamel_DisplaySRT) + proto_tree_add_uint(tree, hf_camelsrt_SessionId, tvb, 0,0, p_camelsrt_call->session_id); + + + /* Hmm.. As there are several slices ApplyChargingReport/ApplyCharging + * we will prepare the measurement for 3 slices with 3 categories */ + if (srt_type==CAMELSRT_VOICE_ACR1) { + if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num == 0) { + srt_type=CAMELSRT_VOICE_ACR1; + } else if ( (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num == 0) + && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0) + && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num < pinfo->fd->num) ) { + srt_type=CAMELSRT_VOICE_ACR2; + } else if ( (p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num == 0) + && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num != 0) + && (p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num < pinfo->fd->num) ) { + srt_type=CAMELSRT_VOICE_ACR3; + } else if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0 + && p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num > pinfo->fd->num) { + srt_type=CAMELSRT_VOICE_ACR1; + } else if ( p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num != 0 + && p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num > pinfo->fd->num) { + srt_type=CAMELSRT_VOICE_ACR2; + } else if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num != 0 + && p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].rsp_num > pinfo->fd->num) { + srt_type=CAMELSRT_VOICE_ACR3; + } +#ifdef DEBUG_CAMELSRT + dbg(70,"Request ACR %u ",srt_type); + dbg(70,"ACR1 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].rsp_num); + dbg(70,"ACR2 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].rsp_num); + dbg(70,"ACR3 %u %u",p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num, p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].rsp_num); +#endif + } /* not ACR */ + p_camelsrt_info->bool_msginfo[srt_type]=TRUE; + + + if (p_camelsrt_call->category[srt_type].req_num == 0) { + /* We have not yet seen a request to that call, so this must be the first request + remember its frame number. */ +#ifdef DEBUG_CAMELSRT + dbg(5,"Set reqlink #%d ", pinfo->fd->num); +#endif + update_camelsrt_call(p_camelsrt_call, pinfo, srt_type); + } else { + /* We have seen a request to this call - but was it *this* request? */ + if (p_camelsrt_call->category[srt_type].req_num != pinfo->fd->num) { + + if (srt_type!=CAMELSRT_VOICE_DISC) { + /* No, so it's a duplicate resquest. Mark it as such. */ +#ifdef DEBUG_CAMELSRT + dbg(21,"Display_duplicate with req %d ", p_camelsrt_call->category[srt_type].req_num); +#endif + p_camelsrt_info->msginfo[srt_type].is_duplicate = TRUE; + if (gcamel_DisplaySRT) + proto_tree_add_uint_hidden(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77); + + } else { + /* Ignore duplicate frame */ + if (pinfo->fd->num > p_camelsrt_call->category[srt_type].req_num) { + p_camelsrt_call->category[srt_type].req_num = pinfo->fd->num; +#ifdef DEBUG_CAMELSRT + dbg(5,"DISC Set reqlink #%d ", pinfo->fd->num); +#endif + update_camelsrt_call(p_camelsrt_call, pinfo, srt_type); + } /* greater frame */ + } /* DISC */ + } /* req_num already seen */ + } /* req_num != 0 */ + + /* add link to response frame, if available */ + if ( gcamel_DisplaySRT && + (p_camelsrt_call->category[srt_type].rsp_num != 0) && + (p_camelsrt_call->category[srt_type].req_num != 0) && + (p_camelsrt_call->category[srt_type].req_num == pinfo->fd->num) ) { +#ifdef DEBUG_CAMELSRT + dbg(20,"Display_framersplink %d ",p_camelsrt_call->category[srt_type].rsp_num); +#endif + ti = proto_tree_add_uint_format(tree, hf_camelsrt_RequestFrame, tvb, 0, 0, + p_camelsrt_call->category[srt_type].rsp_num, + "Linked response %s in frame %u", + val_to_str(srt_type, camelSRTtype_naming, "Unk"), + p_camelsrt_call->category[srt_type].rsp_num); + PROTO_ITEM_SET_GENERATED(ti); + } /* frame valid */ + }/* call reference */ +} + + +/* + * Check if the received message is a response to a previous request + * registered is the camel session context. + */ +static void camelsrt_report_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camelsrt_info, + guint srt_type ) +{ + struct camelsrt_call_t * p_camelsrt_call; + struct camelsrt_call_info_key_t camelsrt_call_key; + nstime_t delta; + proto_item *ti; + +#ifdef DEBUG_CAMELSRT + dbg(10,"\n %s #%d\n", val_to_str(srt_type, camelSRTtype_naming, "Unk"),pinfo->fd->num); +#endif + camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id; + /* look only for matching request, if matching conversation is available. */ + +#ifdef DEBUG_CAMELSRT + dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey); +#endif + p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key, pinfo); + if(p_camelsrt_call) { +#ifdef DEBUG_CAMELSRT + dbg(12,"Found, req=%d ",p_camelsrt_call->category[srt_type].req_num); +#endif + if ( gcamel_DisplaySRT ) + proto_tree_add_uint(tree, hf_camelsrt_SessionId, tvb, 0,0, p_camelsrt_call->session_id); + + if (srt_type==CAMELSRT_VOICE_ACR1) { + if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num != 0 + && p_camelsrt_call->category[CAMELSRT_VOICE_ACR3].req_num < pinfo->fd->num) { + srt_type=CAMELSRT_VOICE_ACR1; + } else if ( p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num != 0 + && p_camelsrt_call->category[CAMELSRT_VOICE_ACR2].req_num < pinfo->fd->num) { + srt_type=CAMELSRT_VOICE_ACR2; + } else if (p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num != 0 + && p_camelsrt_call->category[CAMELSRT_VOICE_ACR1].req_num < pinfo->fd->num) { + srt_type=CAMELSRT_VOICE_ACR1; + } +#ifdef DEBUG_CAMELSRT + dbg(70,"Report ACR %u ",srt_type); +#endif + } /* not ACR */ + p_camelsrt_info->bool_msginfo[srt_type]=TRUE; + + if (p_camelsrt_call->category[srt_type].rsp_num == 0) { + if ( (p_camelsrt_call->category[srt_type].req_num != 0) + && (pinfo->fd->num > p_camelsrt_call->category[srt_type].req_num) ){ + /* We have not yet seen a response to that call, so this must be the first response; + remember its frame number only if response comes after request */ +#ifdef DEBUG_CAMELSRT + dbg(14,"Set reslink #%d req %d ",pinfo->fd->num, p_camelsrt_call->category[srt_type].req_num); +#endif + p_camelsrt_call->category[srt_type].rsp_num = pinfo->fd->num; + + } else { +#ifdef DEBUG_CAMELSRT + dbg(2,"badreslink #%d req %u ",pinfo->fd->num, p_camelsrt_call->category[srt_type].req_num); +#endif + } /* req_num != 0 */ + } else { /* rsp_num != 0 */ + /* We have seen a response to this call - but was it *this* response? */ + if (p_camelsrt_call->category[srt_type].rsp_num != pinfo->fd->num) { + /* No, so it's a duplicate response. Mark it as such. */ +#ifdef DEBUG_CAMELSRT + dbg(21,"Display_duplicate rsp=%d ", p_camelsrt_call->category[srt_type].rsp_num); +#endif + p_camelsrt_info->msginfo[srt_type].is_duplicate = TRUE; + if ( gcamel_DisplaySRT ) + proto_tree_add_uint_hidden(tree, hf_camelsrt_Duplicate, tvb, 0,0, 77); + } + } /* rsp_num != 0 */ + + if ( (p_camelsrt_call->category[srt_type].req_num != 0) && + (p_camelsrt_call->category[srt_type].rsp_num != 0) && + (p_camelsrt_call->category[srt_type].rsp_num == pinfo->fd->num) ) { + + p_camelsrt_call->category[srt_type].responded = TRUE; + p_camelsrt_info->msginfo[srt_type].request_available = TRUE; +#ifdef DEBUG_CAMELSRT + dbg(20,"Display_frameReqlink %d ",p_camelsrt_call->category[srt_type].req_num); +#endif + /* Indicate the frame to which this is a reply. */ + if ( gcamel_DisplaySRT ) { + ti = proto_tree_add_uint_format(tree, hf_camelsrt_ResponseFrame, tvb, 0, 0, + p_camelsrt_call->category[srt_type].req_num, + "Linked request %s in frame %u", + val_to_str(srt_type, camelSRTtype_naming, "Unk"), + p_camelsrt_call->category[srt_type].req_num); + PROTO_ITEM_SET_GENERATED(ti); + } + /* Calculate Service Response Time */ + nstime_delta(&delta, &pinfo->fd->abs_ts, &p_camelsrt_call->category[srt_type].req_time); + + p_camelsrt_info->msginfo[srt_type].is_delta_time = TRUE; + p_camelsrt_info->msginfo[srt_type].delta_time = delta; /* give it to tap */ + p_camelsrt_info->msginfo[srt_type].req_time = p_camelsrt_call->category[srt_type].req_time; + + /* display Service Response Time and make it filterable */ + camelsrt_display_DeltaTime(tree, tvb, &delta, srt_type); + + } /*req_num != 0 && not duplicate */ + } /* call reference found */ +} + +/* + * Update the Camel session info, and close the session. + * Then remove the associated context, if we do not have persistentSRT enable + */ +static void camelsrt_close_call_matching(tvbuff_t *tvb, + packet_info * pinfo _U_, + proto_tree *tree, + struct camelsrt_info_t * p_camelsrt_info) +{ + struct camelsrt_call_t * p_camelsrt_call; + struct camelsrt_call_info_key_t camelsrt_call_key; + nstime_t delta; + + p_camelsrt_info->bool_msginfo[CAMELSRT_SESSION]=TRUE; +#ifdef DEBUG_CAMELSRT + dbg(10,"\n Session end #%d\n", pinfo->fd->num); +#endif + /* look only for matching request, if matching conversation is available. */ + camelsrt_call_key.SessionIdKey = p_camelsrt_info->tcap_session_id; + +#ifdef DEBUG_CAMELSRT + dbg(11,"Search key %lu ",camelsrt_call_key.SessionIdKey); +#endif + p_camelsrt_call = find_camelsrt_call(&camelsrt_call_key, pinfo); + if(p_camelsrt_call) { +#ifdef DEBUG_CAMELSRT + dbg(12,"Found "); +#endif + /* Calculate Service Response Time */ + nstime_delta(&delta, &pinfo->fd->abs_ts, &p_camelsrt_call->category[CAMELSRT_SESSION].req_time); + p_camelsrt_call->category[CAMELSRT_SESSION].responded = TRUE; + p_camelsrt_info->msginfo[CAMELSRT_SESSION].request_available = TRUE; + p_camelsrt_info->msginfo[CAMELSRT_SESSION].is_delta_time = TRUE; + p_camelsrt_info->msginfo[CAMELSRT_SESSION].delta_time = delta; /* give it to tap */ + p_camelsrt_info->msginfo[CAMELSRT_SESSION].req_time = p_camelsrt_call->category[CAMELSRT_SESSION].req_time; + + if ( !gcamel_PersistentSRT ) { + g_hash_table_remove(srt_calls, &camelsrt_call_key); +#ifdef DEBUG_CAMELSRT + dbg(20,"remove hash "); +#endif + } else { +#ifdef DEBUG_CAMELSRT + dbg(20,"keep hash "); +#endif + } + } /* call reference found */ +} + +/* + * Display the delta time between two messages in a field corresponding + * to the category (hf_camelsrt_DeltaTimexx). + */ +static void camelsrt_display_DeltaTime(proto_tree *tree, + tvbuff_t *tvb, + nstime_t* value_ptr, + guint category) +{ + proto_item *ti; + + if ( gcamel_DisplaySRT ) { + switch(category) { + case CAMELSRT_VOICE_INITIALDP: + ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime31, tvb, 0, 0, value_ptr); + PROTO_ITEM_SET_GENERATED(ti); + break; + + case CAMELSRT_VOICE_ACR1: + case CAMELSRT_VOICE_ACR2: + case CAMELSRT_VOICE_ACR3: + ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime22, tvb, 0, 0, value_ptr); + PROTO_ITEM_SET_GENERATED(ti); + break; + + case CAMELSRT_VOICE_DISC: + ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime35, tvb, 0, 0, value_ptr); + PROTO_ITEM_SET_GENERATED(ti); + break; + + case CAMELSRT_GPRS_INITIALDP: + ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime75, tvb, 0, 0, value_ptr); + PROTO_ITEM_SET_GENERATED(ti); + break; + + case CAMELSRT_GPRS_REPORT: + ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime80, tvb, 0, 0, value_ptr); + PROTO_ITEM_SET_GENERATED(ti); + break; + + case CAMELSRT_SMS_INITIALDP: + ti = proto_tree_add_time(tree, hf_camelsrt_DeltaTime65, tvb, 0, 0, value_ptr); + PROTO_ITEM_SET_GENERATED(ti); + break; + + default: + break; + } + } +} + +/* + * Initialize the Message Info used by the main dissector + * Data are linked to a TCAP transaction + */ +struct camelsrt_info_t * camelsrt_razinfo(void) +{ + struct camelsrt_info_t * p_camelsrt_info ; + + /* Global buffer for packet extraction */ + camelsrt_global_current++; + if(camelsrt_global_current==MAX_CAMEL_INSTANCE){ + camelsrt_global_current=0; + } + + p_camelsrt_info=&camelsrt_global_info[camelsrt_global_current]; + memset(p_camelsrt_info,0,sizeof(struct camelsrt_info_t)); + + p_camelsrt_info->opcode=255; + + return p_camelsrt_info; +} + +/* + * Initialize the data per call for the Service Response Time Statistics + * Data are linked to a Camel operation in a TCAP transaction + */ +static void raz_camelsrt_call (struct camelsrt_call_t * p_camelsrt_call) +{ + memset(p_camelsrt_call,0,sizeof(struct camelsrt_call_t)); +} diff --git a/epan/camel-persistentdata.h b/epan/camel-persistentdata.h new file mode 100644 index 0000000000..44147882dc --- /dev/null +++ b/epan/camel-persistentdata.h @@ -0,0 +1,126 @@ +/*
+ * camel-persistentdata.h
+ * Definitions for lists and hash tables used in wireshark's camel dissector
+ * for calculation of delays in camel-transactions
+ * Copyright 2006 Florent Drouin
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __camelsrt_HASH__
+#define __camelsrt_HASH__
+
+#include "epan/packet.h"
+#include "epan/conversation.h"
+#include "epan/dissectors/packet-camel.h"
+#include "epan/tcap-persistentdata.h"
+
+#define NB_CAMELSRT_CATEGORY 9+1 /* Number of type of message */
+/* for example TC_BEGIN with InitalDP, and TC_CONT with RequestReportBCSMEvent
+ is a category, we want to measure the delay between the two messages */
+
+#define CAMELSRT_SESSION 1
+
+#define CAMELSRT_VOICE_INITIALDP 2
+#define CAMELSRT_VOICE_ACR1 3
+#define CAMELSRT_VOICE_ACR2 4
+#define CAMELSRT_VOICE_ACR3 5
+#define CAMELSRT_VOICE_DISC 6
+
+#define CAMELSRT_GPRS_INITIALDP 7
+#define CAMELSRT_GPRS_REPORT 8
+
+#define CAMELSRT_SMS_INITIALDP 9
+
+static const value_string camelSRTtype_naming[]= {
+ { CAMELSRT_SESSION, "TCAP_Session" },
+ { CAMELSRT_VOICE_INITIALDP, "InialDP/Continue" },
+ { CAMELSRT_VOICE_ACR1, "Slice1_ACR/ACH" },
+ { CAMELSRT_VOICE_ACR2, "Slice2_ACR/ACH" },
+ { CAMELSRT_VOICE_ACR3, "Slice3_ACR/ACH" },
+ { CAMELSRT_VOICE_DISC, "EvtRepBSCM/Release" },
+ { CAMELSRT_SMS_INITIALDP, "InitialDP/ContinueSMS" },
+ { CAMELSRT_GPRS_INITIALDP, "InitialDP/ContinueGPRS" },
+ { CAMELSRT_GPRS_REPORT, "EvtRepGPRS/ContinueGPRS" },
+ { 0,NULL}
+};
+
+/* If we have a request message and its response,
+ (eg: ApplyCharging, ApplyChargingReport)
+ the frames numbers are stored in this structure */
+
+struct camelsrt_category_t {
+ guint32 req_num; /* frame number request seen */
+ guint32 rsp_num; /* frame number response seen */
+ nstime_t req_time; /* arrival time of request */
+ gboolean responded; /* true, if request has been responded */
+};
+
+/* List of stored parameters for a Camel dialogue
+ All this parameters are linked to the hash table key below (use of Tid)
+ In case of same Tid reused, the Camel parameters are chained.
+ The right dialogue will be identified with the arrival time of the InitialDP */
+
+struct camelsrt_call_t {
+ guint32 session_id; /* Identify the session, with an internal number */
+ struct tcaphash_context_t * tcap_context;
+ struct camelsrt_category_t category[NB_CAMELSRT_CATEGORY];
+};
+
+
+/* The Key for the hash table is the TCAP origine transaction identifier
+ of the TC_BEGIN containing the InitialDP */
+
+struct camelsrt_call_info_key_t {
+ guint32 SessionIdKey;
+};
+
+/* Info for a couple of messages (or category)
+ The request must be available, not duplicated,
+ and once the corresponding response received,
+ we can deduce the Delta Time between Request/response */
+
+struct camelsrt_msginfo_t {
+ gboolean request_available;
+ gboolean is_duplicate;
+ gboolean is_delta_time;
+ nstime_t req_time;
+ nstime_t delta_time;
+};
+
+/* List of infos to store for the analyse */
+
+struct camelsrt_info_t {
+ guint32 tcap_session_id;
+ void * tcap_context;
+ guint8 opcode; /* operation code of message received */
+ guint8 bool_msginfo[NB_CAMELSRT_CATEGORY]; /* category for the received message */
+ struct camelsrt_msginfo_t msginfo[NB_CAMELSRT_CATEGORY];
+};
+
+void camelsrt_init_routine(void);
+
+struct camelsrt_info_t * camelsrt_razinfo(void);
+
+void camelsrt_call_matching(tvbuff_t *tvb,
+ packet_info * pinfo _U_,
+ proto_tree *tree,
+ struct camelsrt_info_t * p_camel_info);
+
+#endif /* __camelsrt_HASH__*/
diff --git a/gtk/camel_counter.c b/gtk/camel_counter.c new file mode 100644 index 0000000000..600eac0e75 --- /dev/null +++ b/gtk/camel_counter.c @@ -0,0 +1,233 @@ +/* camel_counter.c + * camel message counter for Wireshark + * Copyright 2006 Florent Drouin (based on h225_counter.c from Lars Roland) + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <string.h> +#include <gtk/gtk.h> + +#include "epan/packet_info.h" +#include "epan/epan.h" +#include "epan/value_string.h" +#include "epan/tap.h" + +#include "register.h" +#include "timestats.h" +#include "simple_dialog.h" +#include "file.h" +#include "globals.h" +#include "stat_menu.h" +#include "tap_dfilter_dlg.h" + +#include "gtk/main.h" +#include "gtk/dlg_utils.h" +#include "gtk/gui_utils.h" +#include "gtk/gui_stat_util.h" +#include "gtk/compat_macros.h" +#include "epan/camel-persistentdata.h" + +static void gtk_camelcounter_reset(void *phs); +static int gtk_camelcounter_packet(void *phs, + packet_info *pinfo _U_, + epan_dissect_t *edt _U_, + const void *phi); +static void gtk_camelcounter_draw(void *phs); +static void win_destroy_cb(GtkWindow *win _U_, gpointer data); +static void gtk_camelcounter_init(const char *optarg, void *userdata _U_); +void register_tap_listener_gtk_camelcounter(void); + +/* following values represent the size of their valuestring arrays */ + +struct camelcounter_t { + GtkWidget *win; + GtkWidget *vbox; + char *filter; + GtkWidget *scrolled_window; + GtkCList *table; + guint32 camel_msg[camel_MAX_NUM_OPR_CODES]; +}; + +static void gtk_camelcounter_reset(void *phs) +{ + struct camelcounter_t * p_counter= ( struct camelcounter_t *) phs; + int i; + + /* Erase Message Type count */ + for(i=0;i<camel_MAX_NUM_OPR_CODES;i++) { + p_counter->camel_msg[i]=0; + } +} + + +/* + * If there is a valid camel operation, increase the value in the array of counter + */ +static int gtk_camelcounter_packet(void *phs, + packet_info *pinfo _U_, + epan_dissect_t *edt _U_, + const void *phi) +{ + struct camelcounter_t * p_counter =(struct camelcounter_t *)phs; + const struct camelsrt_info_t * pi=phi; + if (pi->opcode != 255) + p_counter->camel_msg[pi->opcode]++; + + return 1; +} + +static void gtk_camelcounter_draw(void *phs) +{ + struct camelcounter_t *p_counter=(struct camelcounter_t *)phs; + int i; + char *str[2]; + + for(i=0;i<2;i++) { + str[i]=g_malloc(sizeof(char[256])); + } + /* Now print Message and Reason Counter Table */ + /* clear list before printing */ + gtk_clist_clear(p_counter->table); + + for(i=0;i<camel_MAX_NUM_OPR_CODES;i++) { + /* Message counter */ + if(p_counter->camel_msg[i]!=0) { + g_snprintf(str[0], sizeof(char[256]), + "Request %s", val_to_str(i,camel_opr_code_strings,"Unknown message ")); + g_snprintf(str[1], sizeof(char[256]), + "%d", p_counter->camel_msg[i]); + gtk_clist_append(p_counter->table, str); + } + } /* Message Type */ + gtk_widget_show(GTK_WIDGET(p_counter->table)); +} + +void protect_thread_critical_region(void); +void unprotect_thread_critical_region(void); + +static void win_destroy_cb(GtkWindow *win _U_, gpointer data) +{ + struct camelcounter_t *hs=(struct camelcounter_t *)data; + + protect_thread_critical_region(); + remove_tap_listener(hs); + unprotect_thread_critical_region(); + + if(hs->filter){ + g_free(hs->filter); + hs->filter=NULL; + } + g_free(hs); +} + +static const gchar *titles[]={ + "Message Type or Reason", + "Count" }; + +static void gtk_camelcounter_init(const char *optarg, void *userdata _U_) +{ + struct camelcounter_t *p_camelcounter; + const char *filter=NULL; + const char *emptyfilter=""; + GString *error_string; + GtkWidget *bbox; + GtkWidget *close_bt; + + if(strncmp(optarg,"camel,counter,",14) == 0){ + filter=optarg+14; + } else { + filter=NULL; + } + + p_camelcounter=g_malloc(sizeof(struct camelcounter_t)); + p_camelcounter->filter=g_strdup(filter); + + gtk_camelcounter_reset(p_camelcounter); + + p_camelcounter->win=window_new(GTK_WINDOW_TOPLEVEL, "Ethereal: CAMEL counters"); + gtk_window_set_default_size(GTK_WINDOW(p_camelcounter->win), 500, 300); + + p_camelcounter->vbox=gtk_vbox_new(FALSE, 3); + gtk_container_set_border_width(GTK_CONTAINER(p_camelcounter->vbox), 12); + + init_main_stat_window(p_camelcounter->win, p_camelcounter->vbox, "CAMEL Messages Counters", filter); + + /* init a scrolled window*/ + p_camelcounter->scrolled_window = scrolled_window_new(NULL, NULL); + + p_camelcounter->table = create_stat_table(p_camelcounter->scrolled_window, p_camelcounter->vbox, 2, titles); + + if (filter) { + error_string=register_tap_listener("CAMEL", p_camelcounter, filter, + gtk_camelcounter_reset, + gtk_camelcounter_packet, + gtk_camelcounter_draw); + } else { + error_string=register_tap_listener("CAMEL", p_camelcounter, emptyfilter, + gtk_camelcounter_reset, + gtk_camelcounter_packet, + gtk_camelcounter_draw); + } + + if(error_string){ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str); + g_string_free(error_string, TRUE); + g_free(p_camelcounter); + return; + } + + /* Button row. */ + bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL); + gtk_box_pack_end(GTK_BOX(p_camelcounter->vbox), bbox, FALSE, FALSE, 0); + + close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE); + window_set_cancel_button(p_camelcounter->win, close_bt, window_cancel_button_cb); + + SIGNAL_CONNECT(p_camelcounter->win, "delete_event", window_delete_event_cb, NULL); + SIGNAL_CONNECT(p_camelcounter->win, "destroy", win_destroy_cb, p_camelcounter); + + gtk_widget_show_all(p_camelcounter->win); + window_present(p_camelcounter->win); + + cf_retap_packets(&cfile, FALSE); +} + +static tap_dfilter_dlg camel_counter_dlg = { + "CAMEL Messages and Response Status", + "camel,counter", + gtk_camelcounter_init, + -1 +}; + +void /* Next line mandatory */ +register_tap_listener_gtk_camelcounter(void) +{ + register_dfilter_stat(&camel_counter_dlg, "GSM/CAMEL", + REGISTER_STAT_GROUP_TELEPHONY); + +} diff --git a/gtk/camel_srt.c b/gtk/camel_srt.c new file mode 100644 index 0000000000..fed4a8b1e0 --- /dev/null +++ b/gtk/camel_srt.c @@ -0,0 +1,248 @@ +/* camel_srt.c + * camel Service Response Time statistics for Wireshark + * Copyright 2006 Florent Drouin (based on h225_ras_srt.c from Lars Roland) + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <string.h> +#include <gtk/gtk.h> + +#include "epan/packet_info.h" +#include "epan/epan.h" +#include "epan/value_string.h" +#include "epan/tap.h" + +#include "register.h" +#include "timestats.h" +#include "simple_dialog.h" +#include "file.h" +#include "globals.h" +#include "stat_menu.h" +#include "tap_dfilter_dlg.h" + +#include "gtk/main.h" +#include "gtk/dlg_utils.h" +#include "gtk/gui_utils.h" +#include "gtk/gui_stat_util.h" +#include "gtk/compat_macros.h" +#include "gtk/service_response_time_table.h" + +#include "epan/camel-persistentdata.h" + +/* used to keep track of the statistics for an entire program interface */ +struct camelsrt_t { + GtkWidget *win; + srt_stat_table camel_srt_table; +}; + +static void camelsrt_set_title(struct camelsrt_t * p_camelsrt); +static void camelsrt_reset(void *phs); +static int camelsrt_packet(void *phs, + packet_info *pinfo _U_, + epan_dissect_t *edt _U_, + const void *phi); + +static void camelsrt_draw(void *phs); +static void win_destroy_cb(GtkWindow *win _U_, gpointer data); +static void gtk_camelsrt_init(const char *optarg, void *userdata _U_); +void register_tap_listener_gtk_camelsrt(void); + +/* + * + */ +static void camelsrt_set_title(struct camelsrt_t * p_camelsrt) +{ + char * title; + title = g_strdup_printf("CAMEL Service Response Time statistics: %s", + cf_get_display_name(&cfile)); + gtk_window_set_title(GTK_WINDOW(p_camelsrt->win), title); + g_free(title); +} + +static void camelsrt_reset(void *phs) +{ + struct camelsrt_t *hs=(struct camelsrt_t *)phs; + reset_srt_table_data(&hs->camel_srt_table); + camelsrt_set_title(hs); +} + +/* + * Count the delta time between Request and Response + * As we can make several measurement per message, we use a boolean array for the category + * Then, if the measurement is provided, check if it is valid, and update the table + */ +static int camelsrt_packet(void *phs, + packet_info *pinfo _U_, + epan_dissect_t *edt _U_, + const void *phi) +{ + struct camelsrt_t *hs=(struct camelsrt_t *)phs; + const struct camelsrt_info_t * pi=phi; + int i; + + for (i=1; i<NB_CAMELSRT_CATEGORY; i++) { + if ( pi->bool_msginfo[i] && + pi->msginfo[i].is_delta_time + && pi->msginfo[i].request_available + && !pi->msginfo[i].is_duplicate ) { + + add_srt_table_data(&hs->camel_srt_table, i, &pi->msginfo[i].req_time, pinfo); + + } + } /* category */ + return 1; +} + + +static void camelsrt_draw(void *phs) +{ + struct camelsrt_t *hs=(struct camelsrt_t *)phs; + draw_srt_table_data(&hs->camel_srt_table); +} + +/* + * Routine for Display + */ +static void win_destroy_cb(GtkWindow *win _U_, gpointer data) +{ + struct camelsrt_t *hs=(struct camelsrt_t *)data; + + protect_thread_critical_region(); + remove_tap_listener(hs); + unprotect_thread_critical_region(); + + free_srt_table_data(&hs->camel_srt_table); + g_free(hs); +} + +static void gtk_camelsrt_init(const char *optarg, void *userdata _U_) +{ + struct camelsrt_t * p_camelsrt; + const char *filter=NULL; + const char *emptyfilter=""; + + GtkWidget *cmd_label; + GtkWidget *main_label; + GtkWidget *filter_label; + char filter_string[256]; + GString *error_string; + GtkWidget *vbox; + GtkWidget *bbox; + GtkWidget *close_bt; + int i; + + if(strncmp(optarg,"camel,srt,",10) == 0){ + filter=optarg+10; + } else { + filter=NULL; + } + + p_camelsrt=g_malloc(sizeof(struct camelsrt_t)); + + p_camelsrt->win=window_new(GTK_WINDOW_TOPLEVEL, "camel-srt"); + gtk_window_set_default_size(GTK_WINDOW(p_camelsrt->win), 550, 400); + camelsrt_set_title(p_camelsrt); + + vbox=gtk_vbox_new(FALSE, 3); + gtk_container_add(GTK_CONTAINER(p_camelsrt->win), vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 12); + + main_label=gtk_label_new("CAMEL Service Response Time statistics"); + gtk_box_pack_start(GTK_BOX(vbox), main_label, FALSE, FALSE, 0); + gtk_widget_show(main_label); + + g_snprintf(filter_string,255,"Filter:%s",filter?filter:""); + filter_label=gtk_label_new(filter_string); + gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0); + gtk_widget_show(filter_label); + + cmd_label=gtk_label_new("CAMEL Commands"); + gtk_box_pack_start(GTK_BOX(vbox), cmd_label, FALSE, FALSE, 0); + gtk_widget_show(cmd_label); + + /* We must display TOP LEVEL Widget before calling init_srt_table() */ + gtk_widget_show_all(p_camelsrt->win); + + init_srt_table(&p_camelsrt->camel_srt_table, NB_CAMELSRT_CATEGORY, vbox, NULL); + for(i=0 ;i<NB_CAMELSRT_CATEGORY; i++) { + init_srt_table_row(&p_camelsrt->camel_srt_table, i, + val_to_str(i,camelSRTtype_naming,"Unknown")); + } + + if (filter) { + error_string=register_tap_listener("CAMEL", + p_camelsrt, + filter, + camelsrt_reset, + camelsrt_packet, + camelsrt_draw); + } else { + error_string=register_tap_listener("CAMEL", + p_camelsrt, + emptyfilter, + camelsrt_reset, + camelsrt_packet, + camelsrt_draw); + } + + if(error_string){ + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str); + g_string_free(error_string, TRUE); + g_free(p_camelsrt); + return; + } + + /* Button row. */ + bbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL); + gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + close_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CLOSE); + window_set_cancel_button(p_camelsrt->win, close_bt, window_cancel_button_cb); + + SIGNAL_CONNECT(p_camelsrt->win, "delete_event", window_delete_event_cb, NULL); + SIGNAL_CONNECT(p_camelsrt->win, "destroy", win_destroy_cb, p_camelsrt); + + gtk_widget_show_all(p_camelsrt->win); + window_present(p_camelsrt->win); + cf_retap_packets(&cfile, FALSE); + +} + +static tap_dfilter_dlg camel_srt_dlg = { + "CAMEL Service Response Time", + "camel,srt", + gtk_camelsrt_init, + -1 +}; + +void /* Next line mandatory */ +register_tap_listener_gtk_camelsrt(void) +{ + register_dfilter_stat(&camel_srt_dlg, "CAMEL", + REGISTER_STAT_GROUP_RESPONSE_TIME); +} diff --git a/tap-camelcounter.c b/tap-camelcounter.c new file mode 100644 index 0000000000..b5ab177d15 --- /dev/null +++ b/tap-camelcounter.c @@ -0,0 +1,146 @@ +/* tap_camelcounter.c + * camel message counter for tshark + * Copyright 2006 Florent DROUIN + * This part of code is extracted from tap-h225counter.c from Lars Roland + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <string.h> +#include "epan/packet_info.h" +#include "epan/tap.h" +#include "epan/value_string.h" +#include "register.h" +#include "epan/stat_cmd_args.h" +#include "epan/camel-persistentdata.h" + +void register_tap_listener_camelcounter(void); + +/* used to keep track of the statistics for an entire program interface */ +struct camelcounter_t { + char *filter; + guint32 camel_msg[camel_MAX_NUM_OPR_CODES]; +}; + + +static void camelcounter_reset(void *phs) +{ + struct camelcounter_t * p_counter= ( struct camelcounter_t *) phs; + memset(p_counter,0,sizeof(struct camelcounter_t)); +} + +static int camelcounter_packet(void *phs, + packet_info *pinfo _U_, + epan_dissect_t *edt _U_, + const void *phi) +{ + struct camelcounter_t * p_counter =(struct camelcounter_t *)phs; + const struct camelsrt_info_t * pi=phi; + if (pi->opcode != 255) + p_counter->camel_msg[pi->opcode]++; + + return 1; +} + + +static void camelcounter_draw(void *phs) +{ + struct camelcounter_t * p_counter= (struct camelcounter_t *)phs; + int i; + printf("\n"); + printf("CAMEL Message and Response Status Counter:\n"); + printf("------------------------------------------\n"); + + for(i=0;i<camel_MAX_NUM_OPR_CODES;i++) { + /* Message counter */ + if(p_counter->camel_msg[i]!=0) { + printf("%30s ", val_to_str(i,camel_opr_code_strings,"Unknown message ")); + printf("%6d\n", p_counter->camel_msg[i]); + } + } /* Message Type */ + printf("------------------------------------------\n"); +} + +static void camelcounter_init(const char *optarg, void* userdata _U_) +{ + struct camelcounter_t *p_camelcounter; + const char *filter=NULL; + const char *emptyfilter=""; + GString *error_string; + + if(!strncmp(optarg,"camel,counter,",13)){ + filter=optarg+13; + } else { + filter=NULL; + } + + p_camelcounter = g_malloc(sizeof(struct camelcounter_t)); + if(filter){ + p_camelcounter->filter=g_malloc(strlen(filter)+1); + strcpy(p_camelcounter->filter,filter); + } else { + p_camelcounter->filter=NULL; + } + + camelcounter_reset(p_camelcounter); + + if (filter) { + error_string=register_tap_listener("CAMEL", + p_camelcounter, + filter, + NULL, + camelcounter_packet, + camelcounter_draw); + } else { + error_string=register_tap_listener("CAMEL", + p_camelcounter, + emptyfilter, + NULL, + camelcounter_packet, + camelcounter_draw); + } + + if(error_string){ + /* error, we failed to attach to the tap. clean up */ + g_free(p_camelcounter->filter); + g_free(p_camelcounter); + + fprintf(stderr, "tshark: Couldn't register camel,counter tap: %s\n", + error_string->str); + g_string_free(error_string, TRUE); + exit(1); + } +} + + +void /* Next line mandatory */ +register_tap_listener_camelcounter(void) +{ + register_stat_cmd_arg("camel,counter", camelcounter_init, NULL); +} diff --git a/tap-camelsrt.c b/tap-camelsrt.c new file mode 100644 index 0000000000..25387022a7 --- /dev/null +++ b/tap-camelsrt.c @@ -0,0 +1,276 @@ +/* tap_camelsrt.c + * CAMEL Service Response Time statistics for tshark + * Copyright 2006 Florent Drouin (based on tap_h225rassrt.c from Lars Roland) + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include <string.h> +#include "epan/packet_info.h" +#include <epan/tap.h> +#include "epan/value_string.h" +#include "register.h" +#include "epan/dissectors/packet-camel.h" +#include "epan/camel-persistentdata.h" +#include "timestats.h" +#include "epan/stat_cmd_args.h" + +#undef MIN +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + +void register_tap_listener_camelsrt(void); + +/* Save the the first NUM_RAS_STATS stats in the array to calculate percentile */ +#define NUM_RAS_STATS 500000 + +/* Number of couple message Request/Response to analyze*/ +#define NB_CRITERIA 7 + +/* used to keep track of the statistics for an entire program interface */ +struct camelsrt_t { + char *filter; + guint32 count[NB_CAMELSRT_CATEGORY]; + timestat_t stats[NB_CAMELSRT_CATEGORY]; + nstime_t delta_time[NB_CAMELSRT_CATEGORY][NUM_RAS_STATS]; +}; + +/* Check if we have to inhibit the display or not */ +extern gboolean gcamel_StatSRT; +extern gboolean gtcap_StatSRT; + +/* Reset the counter */ +static void camelsrt_reset(void *phs) +{ + struct camelsrt_t *hs=(struct camelsrt_t *)phs; + memset(hs,0,sizeof(struct camelsrt_t)); +} + + +static int camelsrt_packet(void *phs, + packet_info *pinfo _U_, + epan_dissect_t *edt _U_, + const void *phi) +{ + struct camelsrt_t *hs=(struct camelsrt_t *)phs; + const struct camelsrt_info_t * pi=phi; + int i; + + for (i=0; i<NB_CAMELSRT_CATEGORY; i++) { + if (pi->bool_msginfo[i] && + pi->msginfo[i].is_delta_time + && pi->msginfo[i].request_available + && !pi->msginfo[i].is_duplicate ) { + + time_stat_update(&(hs->stats[i]), + &(pi->msginfo[i].delta_time), + pinfo); + + if (hs->count[i] < NUM_RAS_STATS) { + hs->delta_time[i][hs->count[i]++] + = pi->msginfo[i].delta_time; + } + } + } + return 1; +} + + +static void camelsrt_draw(void *phs) +{ + struct camelsrt_t *hs=(struct camelsrt_t *)phs; + guint j,z; + guint32 li; + int somme,iteration=0; + timestat_t *rtd_temp; + double x,delay,delay_max,delay_min,delta; + double criteria[NB_CRITERIA]={ 5.0, 10.0, 75.0, 90.0, 95.0,99.0,99.90 }; + double delay_criteria[NB_CRITERIA]; + + printf("\n"); + printf("Camel Service Response Time (SRT) Statistics:\n"); + printf("=================================================================================================\n"); + printf("| Category | Measure | Min SRT | Max SRT | Avg SRT | Min frame | Max frame |\n"); + printf("|-------------------------|---------|-----------|-----------|-----------|-----------|-----------|\n"); + + j=1; + printf("|%24s |%8u |%8.2f s |%8.2f s |%8.2f s |%10u |%10u |\n", + val_to_str(j,camelSRTtype_naming,"Unknown Message 0x%02x"), + hs->stats[j].num, + nstime_to_sec(&(hs->stats[j].min)), + nstime_to_sec(&(hs->stats[j].max)), + get_average(&(hs->stats[j].tot),hs->stats[j].num)/1000.0, + hs->stats[j].min_num, + hs->stats[j].max_num + ); + for(j=2; j<NB_CAMELSRT_CATEGORY; j++) { + if(hs->stats[j].num==0){ + printf("|%24s |%8u |%8.2f ms|%8.2f ms|%8.2f ms|%10u |%10u |\n", + val_to_str(j,camelSRTtype_naming,"Unknown Message 0x%02x"), + 0, 0.0, 0.0, 0.0, 0, 0); + continue; + } + + printf("|%24s |%8u |%8.2f ms|%8.2f ms|%8.2f ms|%10u |%10u |\n", + val_to_str(j,camelSRTtype_naming,"Unknown Message 0x%02x"), + hs->stats[j].num, + MIN(9999,nstime_to_msec(&(hs->stats[j].min))), + MIN(9999,nstime_to_msec(&(hs->stats[j].max))), + MIN(9999,get_average(&(hs->stats[j].tot),hs->stats[j].num)), + hs->stats[j].min_num, + hs->stats[j].max_num + ); + } /* j category */ + + printf("=================================================================================================\n"); + /* + * Display 95% + */ + + printf("| Category/Criteria |"); + for(z=0; z<NB_CRITERIA; z++) printf("%7.2f%% |", criteria[z]); + printf("\n"); + + printf("|-------------------------|"); + for(z=0; z<NB_CRITERIA; z++) printf("---------|"); + printf("\n"); + /* calculate the delay max to have a given number of messages (in percentage) */ + for(j=2;j<NB_CAMELSRT_CATEGORY;j++) { + + rtd_temp = &(hs->stats[j]); + + if (hs->count[j]>0) { + /* Calculate the delay to answer to p% of the MS */ + for(z=0; z<NB_CRITERIA; z++) { + iteration=0; + delay_max=(double)rtd_temp->max.secs*1000 +(double)rtd_temp->max.nsecs/1000000; + delay_min=(double)rtd_temp->min.secs*1000 +(double)rtd_temp->min.nsecs/1000000; + delay=delay_min; + delta=delay_max-delay_min; + while( (delta > 0.001) && (iteration < 10000) ) { + somme=0; + iteration++; + + for(li=0;li<hs->count[j];li++) { + x=hs->delta_time[j][li].secs*1000 + + (double)hs->delta_time[j][li].nsecs/1000000; + if (x <= delay) somme++; + } + if ( somme*100 > hs->count[j]*criteria[z] ) { /* trop grand */ + delay_max=delay; + delay=(delay_max+delay_min)/2; + delta=delay_max-delay_min; + } else { /* trop petit */ + delay_min=delay; + delay=(delay_max+delay_min)/2; + delta=delay_max-delay_min; + } + } /* while */ + delay_criteria[z]=delay; + } /* z criteria */ + /* Append the result to the table */ + printf("X%24s |", val_to_str(j, camelSRTtype_naming, "Unknown") ); + for(z=0; z<NB_CRITERIA; z++) printf("%8.2f |", MIN(9999,delay_criteria[z])); + printf("\n"); + } else { /* count */ + printf("X%24s |", val_to_str(j, camelSRTtype_naming, "Unknown") ); + for(z=0; z<NB_CRITERIA; z++) printf("%8.2f |", 0.0); + printf("\n"); + } /* count */ + }/* j category */ + printf("==========================="); + for(z=0; z<NB_CRITERIA; z++) printf("=========="); + printf("\n"); +} + +static void camelsrt_init(const char *optarg, void* userdata _U_) +{ + struct camelsrt_t *p_camelsrt; + const char *filter=NULL; + const char *emptyfilter=""; + + GString *error_string; + + if(!strncmp(optarg,"camel,srt,",9)){ + filter=optarg+9; + } else { + filter=NULL; + } + + p_camelsrt = g_malloc(sizeof(struct camelsrt_t)); + if(filter){ + p_camelsrt->filter=g_malloc(strlen(filter)+1); + strcpy(p_camelsrt->filter,filter); + } else { + p_camelsrt->filter=NULL; + } + camelsrt_reset(p_camelsrt); + + if (filter) { + error_string=register_tap_listener("CAMEL", + p_camelsrt, + filter, + NULL, + camelsrt_packet, + camelsrt_draw); + } else { + error_string=register_tap_listener("CAMEL", + p_camelsrt, + emptyfilter, + NULL, + camelsrt_packet, + camelsrt_draw); + } + + if(error_string){ + /* error, we failed to attach to the tap. clean up */ + g_free(p_camelsrt->filter); + g_free(p_camelsrt); + + fprintf(stderr, "tshark: Couldn't register camel,srt tap: %s\n", + error_string->str); + g_string_free(error_string, TRUE); + exit(1); + } + + /* + * If we are using tshark, we have to display the stats, even if the stats are not persistent + * As the frame are proceeded in the chronological order, we do not need persistent stats + * Whereas, with wireshark, it is not possible to have the correct display, if the stats are + * not saved along the analyze + */ + gtcap_StatSRT=TRUE; + gcamel_StatSRT=TRUE; +} + + +void /* Next line mandatory */ +register_tap_listener_camelsrt(void) +{ + register_stat_cmd_arg("camel,srt", camelsrt_init, NULL); +} |