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 <[EMAIL PROTECTED]>
 * 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);
 }
 
 /*

Reply via email to