Don't increment after reading last outheader value (as reported by clang).
[metze/wireshark/wip.git] / tap-rpcstat.c
index 5ba75043a047db2a398e2d08a6a1cb9f638cf6d9..b61e09333f49a7236bcf6deaeb04af7be1b3698d 100644 (file)
@@ -6,23 +6,23 @@
  * 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.
  */
 
-/* This module provides rpc call/reply RTT statistics to tshark.
+/* This module provides rpc call/reply SRT statistics to tshark.
  * It is only used by tshark and not wireshark
  *
  * It serves as an example on how to use the tap api.
@@ -43,7 +43,9 @@
 #include <epan/tap.h>
 #include <epan/stat_cmd_args.h>
 #include <epan/dissectors/packet-rpc.h>
-#include "register.h"
+
+#define MICROSECS_PER_SEC   1000000
+#define NANOSECS_PER_SEC    1000000000
 
 /* used to keep track of statistics for a specific procedure */
 typedef struct _rpc_procedure_t {
@@ -73,7 +75,7 @@ typedef struct _rpcstat_t {
  * to reset all state. Such as when wireshark opens a new file, when it
  * starts a new capture, when it rescans the packetlist after some prefs have
  * changed etc.
- * So if your aplication has some state it needs to clean up in those
+ * So if your application has some state it needs to clean up in those
  * situations, here is a good place to put that code.
  */
 static void
@@ -83,7 +85,7 @@ rpcstat_reset(void *prs)
        guint32 i;
 
        for(i=0;i<rs->num_procedures;i++){
-               rs->procedures[i].num=0;        
+               rs->procedures[i].num=0;
                rs->procedures[i].min.secs=0;
                rs->procedures[i].min.nsecs=0;
                rs->procedures[i].max.secs=0;
@@ -106,7 +108,7 @@ rpcstat_reset(void *prs)
  * possible into (*draw) instead since that function executes asynchronously
  * and does not affect the main threads performance.
  *
- * If it is possible, try to do all "filtering" explicitely as we do below in 
+ * If it is possible, try to do all "filtering" explicitely as we do below in
  * this example since you will get MUCH better performance than applying
  * a similar display-filter in the register call.
  *
@@ -118,7 +120,7 @@ rpcstat_reset(void *prs)
  * we were called for the proper program and version. We didnt apply a filter
  * when we registered so we will be called for ALL rpc packets and not just
  * the ones we are collecting stats for.
- * 
+ *
  *
  * function returns :
  *  0: no updates, no need to call (*draw) later
@@ -173,11 +175,11 @@ rpcstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const voi
                rp->max.secs=delta.secs;
                rp->max.nsecs=delta.nsecs;
        }
-       
+
        rp->tot.secs += delta.secs;
        rp->tot.nsecs += delta.nsecs;
-       if(rp->tot.nsecs>1000000000){
-               rp->tot.nsecs-=1000000000;
+       if(rp->tot.nsecs > NANOSECS_PER_SEC){
+               rp->tot.nsecs -= NANOSECS_PER_SEC;
                rp->tot.secs++;
        }
 
@@ -191,7 +193,7 @@ rpcstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const voi
  * stdout.
  * TShark will only call this callback once, which is when tshark has
  * finished reading all packets and exists.
- * If used with wireshark this may be called any time, perhaps once every 3 
+ * If used with wireshark this may be called any time, perhaps once every 3
  * seconds or so.
  * This function may even be called in parallell with (*reset) or (*draw)
  * so make sure there are no races. The data in the rpcstat_t can thus change
@@ -202,36 +204,29 @@ rpcstat_draw(void *prs)
 {
        rpcstat_t *rs=prs;
        guint32 i;
-#ifdef G_HAVE_UINT64
        guint64 td;
-#else
-       guint32 td;
-#endif
        printf("\n");
-       printf("===================================================================\n");
-       printf("%s Version %d RTT Statistics:\n", rs->prog, rs->version);
+       printf("=======================================================\n");
+       printf("%s Version %d SRT Statistics:\n", rs->prog, rs->version);
        printf("Filter: %s\n",rs->filter?rs->filter:"");
-       printf("Procedure        Calls   Min RTT   Max RTT   Avg RTT\n");
+       printf("Procedure        Calls    Min SRT    Max SRT    Avg SRT\n");
        for(i=0;i<rs->num_procedures;i++){
-               /* scale it to units of 10us.*/
-               /* for long captures with a large tot time, this can overflow on 32bit */
-               td=(int)rs->procedures[i].tot.secs;
-               td=td*100000+(int)rs->procedures[i].tot.nsecs/10000;
-               if(rs->procedures[i].num){
-                       td/=rs->procedures[i].num;
-               } else {
-                       td=0;
+               if(rs->procedures[i].num==0){
+                       continue;
                }
+               /* Scale the average SRT in units of 1us and round to the nearest us. */
+               td = ((guint64)(rs->procedures[i].tot.secs)) * NANOSECS_PER_SEC + rs->procedures[i].tot.nsecs;
+               td = ((td / rs->procedures[i].num) + 500) / 1000;
 
-               printf("%-15s %6d %3d.%05d %3d.%05d %3d.%05d\n",
+               printf("%-15s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
                        rs->procedures[i].proc,
                        rs->procedures[i].num,
-                       (int)rs->procedures[i].min.secs,rs->procedures[i].min.nsecs/10000,
-                       (int)rs->procedures[i].max.secs,rs->procedures[i].max.nsecs/10000,
-                       td/100000, td%100000
+                       (int)(rs->procedures[i].min.secs),(rs->procedures[i].min.nsecs+500)/1000,
+                       (int)(rs->procedures[i].max.secs),(rs->procedures[i].max.nsecs+500)/1000,
+                       td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
                );
        }
-       printf("===================================================================\n");
+       printf("=======================================================\n");
 }
 
 static guint32 rpc_program=0;
@@ -298,8 +293,7 @@ rpcstat_init(const char *optarg, void* userdata _U_)
        rs->program=program;
        rs->version=version;
        if(filter){
-               rs->filter=g_malloc(strlen(filter)+1);
-               strcpy(rs->filter, filter);
+               rs->filter=g_strdup(filter);
        } else {
                rs->filter=NULL;
        }
@@ -319,7 +313,7 @@ rpcstat_init(const char *optarg, void* userdata _U_)
        rs->procedures=g_malloc(sizeof(rpc_procedure_t)*(rs->num_procedures+1));
        for(i=0;i<rs->num_procedures;i++){
                rs->procedures[i].proc=rpc_proc_name(program, version, i);
-               rs->procedures[i].num=0;        
+               rs->procedures[i].num=0;
                rs->procedures[i].min.secs=0;
                rs->procedures[i].min.nsecs=0;
                rs->procedures[i].max.secs=0;
@@ -331,14 +325,14 @@ rpcstat_init(const char *optarg, void* userdata _U_)
 /* It is possible to create a filter and attach it to the callbacks. Then the
  * callbacks would only be invoked if the filter matched.
  * Evaluating filters is expensive and if we can avoid it and not use them
- * we gain performance. 
- * In this case we do the filtering for protocol and version inside the 
+ * we gain performance.
+ * In this case we do the filtering for protocol and version inside the
  * callback itself but use whatever filter the user provided.
  * (Perhaps the user only want the stats for nis+ traffic for certain objects?)
  *
  */
 
-       error_string=register_tap_listener("rpc", rs, filter, rpcstat_reset, rpcstat_packet, rpcstat_draw);
+       error_string=register_tap_listener("rpc", rs, filter, 0, rpcstat_reset, rpcstat_packet, rpcstat_draw);
        if(error_string){
                /* error, we failed to attach to the tap. clean up */
                g_free(rs->procedures);