Ethereal-dev: [Ethereal-dev] new tap for mgcp

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Lars Roland <Lars.Roland@xxxxxxx>
Date: Mon, 03 Mar 2003 04:30:54 +0100
Hi,

I wrote a new tap for mgcp, so here is it. I have used some code from tap-smbstat, which was very useful.

Two functions had to be added to the plugin-api. all changes are attached in the patch.

Has to be tested on linux. It can be invoked by "-z mgcp,rtd[,filter]" (like smb,rtt).

There is still a small bug (at least on MS Win). If you invoke without second comma and without any second invocation with second comma present, calculation fails (all results are zero). I have looked at it, but I can't find the reason.
This is coded in the same way as in "tap-smbstat.c".
Does this happen with "smb,rtt" , too?

Best regards,
Lars
/* tap-mgcpstat.c
 * mgcpstat   2003 Lars Roland
 *
 * $Id: $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxxxxxx>
 * 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 "tap.h"
#include "epan/value_string.h"
#include "register.h"

/* A simple MGCP type that is occasionally handy */
typedef enum _mgcp_type {
  MGCP_REQUEST,
  MGCP_RESPONSE,
  MGCP_OTHERS
} mgcp_type_t;

/* Container for tapping relevant data */
typedef struct _mgcp_info_t {
  mgcp_type_t mgcp_type;
  char code[5];
  long transid;	
} mgcp_info_t;	

/* Item of request list */
typedef struct _mgcp_call_t {
	long transid;
	char code[5];
	nstime_t req_time;
	nstime_t rsp_time;
	gboolean responded;
	struct _mgcp_call_t *prev;
	struct _mgcp_call_t *next;
} mgcp_call_t;

/* Summary of response-time calculations*/
typedef struct _rtd_t {
	long int num;
	nstime_t min;
	nstime_t max;
	nstime_t tot;
} rtd_t;

/* used to keep track of the statistics for an entire program interface */
typedef struct _mgcpstat_t {
	char *filter;
	mgcp_call_t *liststart;
	mgcp_call_t *listend;
	long int num;
	long int req_num;
	long int rsp_num;
} mgcpstat_t;

/* A Function to update a mgcp_rtd_t struct */

void
rtd_stat_update(rtd_t *rtd,nstime_t delta)
{
	rtd->num++;
	if((rtd->max.secs==0)
	&& (rtd->max.nsecs==0) ){
		rtd->max.secs=delta.secs;
		rtd->max.nsecs=delta.nsecs;
	}
	
	if((rtd->min.secs==0)
	&& (rtd->min.nsecs==0) ){
		rtd->min.secs=delta.secs;
		rtd->min.nsecs=delta.nsecs;
	}
	
	if( (delta.secs<rtd->min.secs)
	||( (delta.secs==rtd->min.secs)
	  &&(delta.nsecs<rtd->min.nsecs) ) ){
		rtd->min.secs=delta.secs;
		rtd->min.nsecs=delta.nsecs;
	}
	
	if( (delta.secs>rtd->max.secs)
	||( (delta.secs==rtd->max.secs)
	  &&(delta.nsecs>rtd->max.nsecs) ) ){
		rtd->max.secs=delta.secs;
		rtd->max.nsecs=delta.nsecs;
	}
		
	rtd->tot.secs += delta.secs;
	rtd->tot.nsecs += delta.nsecs;
	if(rtd->tot.nsecs>1000000000){
		rtd->tot.nsecs-=1000000000;
		rtd->tot.secs++;	
	}
	
	
}

static int
mgcpstat_packet(void *pms, packet_info *pinfo, epan_dissect_t *edt _U_, void *pmi)
{
	mgcpstat_t *ms=(mgcpstat_t *)pms;
	mgcp_info_t *mi=pmi;
	mgcp_call_t *active_mc=NULL;
	int i;
	
	ms->num++;
	if(mi->mgcp_type==MGCP_REQUEST){
		if(ms->liststart==NULL){
			/* init open-request list */
			ms->liststart=g_malloc(sizeof(mgcp_call_t));
			ms->listend=ms->liststart;
			ms->listend->prev=NULL;
			ms->listend->next=NULL;
			ms->listend->transid=mi->transid;
			strcpy(ms->listend->code,mi->code);
			ms->listend->req_time.secs=pinfo->fd->abs_secs;
			ms->listend->req_time.nsecs=pinfo->fd->abs_usecs*1000;
			ms->listend->rsp_time.secs=0;
			ms->listend->rsp_time.nsecs=0;
			ms->listend->responded=FALSE;
		}
		else {
			/* add item to open-request list*/
			ms->listend->next=g_malloc(sizeof(mgcp_call_t));
			ms->listend->next->prev=ms->listend;
			ms->listend->next->next=NULL;
			ms->listend=ms->listend->next;
			ms->listend->transid=mi->transid;
			strcpy(ms->listend->code,mi->code);
			ms->listend->req_time.secs=pinfo->fd->abs_secs;
			ms->listend->req_time.nsecs=pinfo->fd->abs_usecs*1000;
			ms->listend->rsp_time.secs=0;
			ms->listend->rsp_time.nsecs=0;
			ms->listend->responded=FALSE;
		}
		ms->req_num++;	
	}	
	else if(mi->mgcp_type==MGCP_RESPONSE){
		/* Packet is a response, look for matching request */
		ms->rsp_num++;
		if(ms->listend!=NULL){
			/* walk through list*/
			active_mc=ms->listend;
			for(i=0;i<ms->req_num;i++){
				/* check for match */
				if(active_mc->transid==mi->transid && !(active_mc->responded)){
					active_mc->rsp_time.secs=pinfo->fd->abs_secs;
					active_mc->rsp_time.nsecs=pinfo->fd->abs_usecs*1000;
					active_mc->responded=TRUE;
					return 1;
				}
				active_mc=active_mc->prev;
			}
		}	
	}
	return 0;
}

static void
mgcpstat_draw(void *pms)
{
	mgcpstat_t *ms=(mgcpstat_t *)pms;
	rtd_t mr;
	mgcp_call_t *active_mc=NULL;
	nstime_t delta;
	int i;
	
#ifdef G_HAVE_UINT64
	guint64 avg;
#else
	guint32 avg;
#endif
        mr.num=0;
        mr.min.secs=0;
        mr.min.nsecs=0;
        mr.max.secs=0;
        mr.max.nsecs=0;
        mr.tot.secs=0;
        mr.tot.nsecs=0;
        	
        active_mc=ms->liststart;
	/* Calculation of rtd-statistics */
	for(i=0;i<ms->req_num;i++){
		if(active_mc->responded==TRUE){
			/* rtd-calculation */
			
			delta.secs=active_mc->rsp_time.secs-active_mc->req_time.secs;
			delta.nsecs=active_mc->rsp_time.nsecs-active_mc->req_time.nsecs;
			
			if(delta.nsecs<0){
				delta.nsecs+=1000000000;
				delta.secs--;
			}
			
			rtd_stat_update(&mr,delta);

		}
		active_mc=active_mc->next;
	}

	/* calculating average rtd */
	/* scale it to units of 10us.*/
	/* for long captures with a large tot time, this can overflow on 32bit */
	avg=(int)mr.tot.secs;
	avg=avg*100000+(int)mr.tot.nsecs/10000;
	if(mr.num){
		avg/=mr.num;
	} else {
		avg=0;
	}

	/* printing results */
	printf("\n");
	printf("===================================================================\n");
	printf("MGCP Response Time Delay (RTD) Statistics:\n");
	printf("Filter: %s\n",ms->filter?ms->filter:"");
        printf("Open requests: %d\n",ms->req_num-mr.num);
        printf("Messages   |     Min RTD     |     Max RTD     |     Avg RTD \n");
        printf("%7d    |  %5d.%03d msec |  %5d.%03d msec | %5d.%03d msec\n",
        	mr.num,
		(int)((mr.min.secs*1000)+(mr.min.nsecs/1000000)),(mr.min.nsecs%1000000)/1000,
		(int)((mr.max.secs*1000)+(mr.max.nsecs/1000000)),(mr.min.nsecs%1000000)/1000,
		avg/100, avg%100
	);
        printf("===================================================================\n");
}


static void
mgcpstat_init(char *optarg)
{
	mgcpstat_t *ms;
	char *filter=NULL;


	if(!strncmp(optarg,"mgcp,rtd,",9)){
		filter=optarg+9;
	} else {
		filter=NULL;
	}

	ms=g_malloc(sizeof(mgcpstat_t));
	if(filter){
		ms->filter=g_malloc(strlen(filter)+1);
		strcpy(ms->filter, filter);
	} else {
		ms->filter=NULL;
	}

	ms->liststart=NULL;
	ms->listend=NULL;

	ms->req_num=0;
	ms->rsp_num=0;
        ms->num=0;

	if(register_tap_listener("mgcp", ms, filter, NULL, mgcpstat_packet, mgcpstat_draw)){
		/* error, we failed to attach to the tap. clean up */
		g_free(ms->filter);
		g_free(ms);

		fprintf(stderr,"tethereal: mgcpstat_init() failed to attach to tap.\n");
		exit(1);
	}
}


void
register_tap_listener_mgcpstat(void)
{
	register_ethereal_tap("mgcp,rtd", mgcpstat_init, NULL, NULL);
}

Index: ethereal/Makefile.nmake
===================================================================
RCS file: /cvsroot/ethereal/Makefile.nmake,v
retrieving revision 1.284
diff -u -r1.284 Makefile.nmake
--- ethereal/Makefile.nmake	2 Mar 2003 21:52:09 -0000	1.284
+++ ethereal/Makefile.nmake	3 Mar 2003 02:09:54 -0000
@@ -357,6 +357,7 @@
 	tap-dcerpcstat.c	\
 	tap-iostat.c		\
 	tap-iousers.c		\
+	tap-mgcpstat.c		\
 	tap-protocolinfo.c	\
 	tap-protohierstat.c	\
 	tap-rpcstat.c		\
Index: ethereal/epan/plugins.c
===================================================================
RCS file: /cvsroot/ethereal/epan/plugins.c,v
retrieving revision 1.62
diff -u -r1.62 plugins.c
--- ethereal/epan/plugins.c	8 Dec 2002 22:22:03 -0000	1.62
+++ ethereal/epan/plugins.c	3 Mar 2003 02:09:56 -0000
@@ -65,6 +65,7 @@
 #include "packet-giop.h"
 #include "packet-tpkt.h"
 #include "packet-tcp.h"
+#include "tap.h"
 #include "plugins/plugin_table.h"
 static plugin_address_table_t	patable;
 #endif
@@ -487,7 +488,10 @@
 	patable.p_fragment_delete		= fragment_delete;
 	patable.p_show_fragment_tree		= show_fragment_tree;
 	patable.p_show_fragment_seq_tree	= show_fragment_seq_tree;
-
+	
+	patable.p_register_tap			= register_tap;
+	patable.p_tap_queue_packet		= tap_queue_packet;
+	
 #endif
 
 #ifdef WIN32
Index: ethereal/plugins/plugin_api.c
===================================================================
RCS file: /cvsroot/ethereal/plugins/plugin_api.c,v
retrieving revision 1.43
diff -u -r1.43 plugin_api.c
--- ethereal/plugins/plugin_api.c	14 Nov 2002 18:54:53 -0000	1.43
+++ ethereal/plugins/plugin_api.c	3 Mar 2003 02:09:57 -0000
@@ -210,4 +210,7 @@
 	p_fragment_delete			= pat->p_fragment_delete;
 	p_show_fragment_tree			= pat->p_show_fragment_tree;
 	p_show_fragment_seq_tree		= pat->p_show_fragment_seq_tree;
+
+	p_register_tap				= pat->p_register_tap;
+	p_tap_queue_packet			= pat->p_tap_queue_packet;
 }
Index: ethereal/plugins/plugin_api.h
===================================================================
RCS file: /cvsroot/ethereal/plugins/plugin_api.h,v
retrieving revision 1.44
diff -u -r1.44 plugin_api.h
--- ethereal/plugins/plugin_api.h	14 Nov 2002 18:54:53 -0000	1.44
+++ ethereal/plugins/plugin_api.h	3 Mar 2003 02:09:57 -0000
@@ -240,7 +240,10 @@
 #define fragment_delete			(*p_fragment_delete)
 #define show_fragment_tree		(*p_show_fragment_tree)
 #define show_fragment_seq_tree		(*p_show_fragment_seq_tree)
-                                                
+
+#define register_tap			(*p_register_tap)
+#define tap_queue_packet		(*p_tap_queue_packet)
+
 #endif
 
 #include <epan/packet.h>
@@ -250,6 +253,7 @@
 #include "packet-giop.h"
 #include "packet-tpkt.h"
 #include "packet-tcp.h"
+#include "tap.h"
 
 #include "plugin_table.h"
 
Index: ethereal/plugins/plugin_api_decls.h
===================================================================
RCS file: /cvsroot/ethereal/plugins/plugin_api_decls.h,v
retrieving revision 1.6
diff -u -r1.6 plugin_api_decls.h
--- ethereal/plugins/plugin_api_decls.h	14 Nov 2002 18:54:53 -0000	1.6
+++ ethereal/plugins/plugin_api_decls.h	3 Mar 2003 02:09:57 -0000
@@ -250,3 +250,5 @@
 addr_show_fragment_tree			p_show_fragment_tree;
 addr_show_fragment_seq_tree		p_show_fragment_seq_tree;
 
+addr_register_tap			p_register_tap;
+addr_tap_queue_packet			p_tap_queue_packet;
Index: ethereal/plugins/plugin_table.h
===================================================================
RCS file: /cvsroot/ethereal/plugins/plugin_table.h,v
retrieving revision 1.56
diff -u -r1.56 plugin_table.h
--- ethereal/plugins/plugin_table.h	2 Dec 2002 23:34:40 -0000	1.56
+++ ethereal/plugins/plugin_table.h	3 Mar 2003 02:09:58 -0000
@@ -279,6 +279,9 @@
 typedef gboolean (*addr_show_fragment_tree)(fragment_data *, const fragment_items *, proto_tree *, packet_info *, tvbuff_t *);
 typedef gboolean (*addr_show_fragment_seq_tree)(fragment_data *, const fragment_items *, proto_tree *, packet_info *, tvbuff_t *);
 
+typedef int (*addr_register_tap)(char *);
+typedef void (*addr_tap_queue_packet)(int, packet_info *, void *);
+
 typedef struct  {
 
 #include "plugin_api_decls.h"
Index: ethereal/plugins/mgcp/packet-mgcp.c
===================================================================
RCS file: /cvsroot/ethereal/plugins/mgcp/packet-mgcp.c,v
retrieving revision 1.35
diff -u -r1.35 packet-mgcp.c
--- ethereal/plugins/mgcp/packet-mgcp.c	28 Aug 2002 20:39:07 -0000	1.35
+++ ethereal/plugins/mgcp/packet-mgcp.c	3 Mar 2003 02:10:00 -0000
@@ -105,6 +105,10 @@
 static int ett_mgcp = -1;
 static int ett_mgcp_param = -1;
 
+/*
+ * Define the tap for mgcp
+ */
+static int mgcp_tap = -1;
 
 /*
  * Here are the global variables associated with
@@ -140,7 +144,6 @@
 static int callagent_tcp_port = 0;
 static int callagent_udp_port = 0;
 
-
 /* A simple MGCP type that is occasionally handy */
 typedef enum _mgcp_type {
   MGCP_REQUEST,
@@ -148,6 +151,13 @@
   MGCP_OTHERS
 } mgcp_type_t;
 
+/* Container for tapping relevant data */
+typedef struct _mgcp_info_t {
+  mgcp_type_t mgcp_type;
+  char code[5];
+  long transid;	
+} mgcp_info_t;	
+
 /* Some basic utility functions that are specific to this dissector */
 static gboolean is_mgcp_verb(tvbuff_t *tvb, gint offset, gint maxlength);
 static gboolean is_mgcp_rspcode(tvbuff_t *tvb, gint offset, gint maxlength);
@@ -161,7 +171,7 @@
  */
 static void dissect_mgcp_message(tvbuff_t *tvb, packet_info *pinfo,
 				 proto_tree *tree,proto_tree *mgcp_tree, proto_tree *ti);
-static void dissect_mgcp_firstline(tvbuff_t *tvb,
+static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo,
 				   proto_tree *tree);
 static void dissect_mgcp_params(tvbuff_t *tvb,
 				proto_tree *tree);
@@ -287,7 +297,7 @@
   gint sectionlen;
   gint tvb_sectionend,tvb_sectionbegin, tvb_len, tvb_current_len;
   tvbuff_t *next_tvb;
-
+    
   /* Initialize variables */
   tvb_sectionend = 0;
   tvb_sectionbegin = tvb_sectionend;
@@ -312,7 +322,7 @@
       sectionlen = tvb_find_line_end(tvb,0,-1,&tvb_sectionend,FALSE);
       if( sectionlen > 0){
 	dissect_mgcp_firstline(tvb_new_subset(tvb, tvb_sectionbegin,
-					      sectionlen,-1),
+					      sectionlen,-1), pinfo,
 			       mgcp_tree);
       }
       tvb_sectionbegin = tvb_sectionend;
@@ -548,6 +558,8 @@
                                  "Display the number of MGCP messages "
                                  "found in a packet in the protocol column.",
                                  &global_mgcp_message_count);
+  
+  mgcp_tap = register_tap("mgcp");
 }
 
 /* The registration hand-off routine */
@@ -864,10 +876,13 @@
  * tree - The tree from which to hang the structured information parsed
  *        from the first line of the MGCP message.
  */
-static void dissect_mgcp_firstline(tvbuff_t *tvb,
+static void dissect_mgcp_firstline(tvbuff_t *tvb, packet_info *pinfo,
 				   proto_tree *tree){
   gint tvb_current_offset,tvb_previous_offset,tvb_len,tvb_current_len;
   gint tokennum, tokenlen;
+  static mgcp_info_t mi;
+  char *transid;
+  char *code;
   mgcp_type_t mgcp_type = MGCP_OTHERS;
   proto_item* (*my_proto_tree_add_string)(proto_tree*, int, tvbuff_t*, gint,
 					  gint, const char*);
@@ -875,6 +890,8 @@
   tvb_len = tvb_length(tvb);
   tvb_current_len = tvb_len;
   tvb_current_offset = tvb_previous_offset;
+  code = NULL;
+  transid = NULL;
 
   if(tree){
     tokennum = 0;
@@ -898,29 +915,33 @@
 	tokenlen = tvb_current_offset - tvb_previous_offset;
       }
       if(tokennum == 0){
+        code = g_malloc(tokenlen);
+        code = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
+        strncpy(mi.code,code,4);
+        mi.code[4] = '\0';
 	if(is_mgcp_verb(tvb,tvb_previous_offset,tvb_current_len)){
 	  mgcp_type = MGCP_REQUEST;
 	  my_proto_tree_add_string(tree,hf_mgcp_req_verb, tvb,
 				   tvb_previous_offset, tokenlen,
-				   tvb_format_text(tvb,tvb_previous_offset
-						   ,tokenlen));
+				   code);
 	}
 	else if (is_mgcp_rspcode(tvb,tvb_previous_offset,tvb_current_len)){
 	  mgcp_type = MGCP_RESPONSE;
 	  my_proto_tree_add_string(tree,hf_mgcp_rsp_rspcode, tvb,
 				   tvb_previous_offset, tokenlen,
-				   tvb_format_text(tvb,tvb_previous_offset
-						   ,tokenlen));
+				   code);
 	}
 	else {
 	  break;
 	}
       }
       if(tokennum == 1){
+      	transid = g_malloc(tokenlen);
+        transid = tvb_format_text(tvb,tvb_previous_offset,tokenlen);
+        mi.transid = atol(transid);
 	my_proto_tree_add_string(tree,hf_mgcp_transid, tvb,
 				 tvb_previous_offset, tokenlen,
-				 tvb_format_text(tvb,tvb_previous_offset,
-						 tokenlen));
+				 transid);
       }
       if(tokennum == 2){
 	if(mgcp_type == MGCP_REQUEST){
@@ -975,7 +996,9 @@
     default:
       break;
     }
+    mi.mgcp_type = mgcp_type;  
   }
+  tap_queue_packet(mgcp_tap, pinfo, &mi);
 }
 
 /*