/* tap-rpcstat.c
* rpcstat 2002 Ronnie Sahlberg
*
- * $Id: tap-rpcstat.c,v 1.7 2003/04/23 03:50:59 guy Exp $
+ * $Id$
*
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * 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 tethereal.
- * It is only used by tethereal and not ethereal
+/* This module provides rpc call/reply RTT statistics to tshark.
+ * It is only used by tshark and not wireshark
*
* It serves as an example on how to use the tap api.
*/
#include <string.h>
#include "epan/packet_info.h"
-#include "tap.h"
-#include "packet-rpc.h"
-#include "register.h"
+#include <epan/tap.h>
+#include <epan/stat_cmd_args.h>
+#include <epan/dissectors/packet-rpc.h>
/* used to keep track of statistics for a specific procedure */
typedef struct _rpc_procedure_t {
- char *proc;
+ const char *proc;
int num;
nstime_t min;
nstime_t max;
/* used to keep track of the statistics for an entire program interface */
typedef struct _rpcstat_t {
- char *prog;
+ const char *prog;
char *filter;
guint32 program;
guint32 version;
-/* This callback is never used by tethereal but it is here for completeness.
+/* This callback is never used by tshark but it is here for completeness.
* When registering below, we could just have left this function as NULL.
*
- * When used by ethereal, this function will be called whenever we would need
- * to reset all state. Such as when ethereal opens a new file, when it
+ * When used by wireshark, this function will be called whenever we would need
+ * 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
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;
* later.
*
* This function should be as lightweight as possible since it executes together
- * with the normal ethereal dissectors. Try to push as much processing as
+ * with the normal wireshark dissectors. Try to push as much processing as
* 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.
*
* 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
* !0: state has changed, call (*draw) sometime later
*/
static int
-rpcstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, void *pri)
+rpcstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
{
rpcstat_t *rs=prs;
- rpc_call_info_value *ri=pri;
+ const rpc_call_info_value *ri=pri;
nstime_t delta;
rpc_procedure_t *rp;
rp=&(rs->procedures[ri->proc]);
/* calculate time delta between request and reply */
- delta.secs=pinfo->fd->abs_secs-ri->req_time.secs;
- delta.nsecs=pinfo->fd->abs_usecs*1000-ri->req_time.nsecs;
- if(delta.nsecs<0){
- delta.nsecs+=1000000000;
- delta.secs--;
- }
+ nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->req_time);
- if((rp->max.secs==0)
- && (rp->max.nsecs==0) ){
+ if(rp->num==0){
rp->max.secs=delta.secs;
rp->max.nsecs=delta.nsecs;
}
- if((rp->min.secs==0)
- && (rp->min.nsecs==0) ){
+ if(rp->num==0){
rp->min.secs=delta.secs;
rp->min.nsecs=delta.nsecs;
}
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;
rp->tot.secs++;
}
+
rp->num++;
return 1;
}
-/* This callback is used when tethereal wants us to draw/update our
- * data to the output device. Since this is tethereal only output is
+/* This callback is used when tshark wants us to draw/update our
+ * data to the output device. Since this is tshark only output is
* stdout.
- * Tethereal will only call this callback once, which is when tethereal has
+ * TShark will only call this callback once, which is when tshark has
* finished reading all packets and exists.
- * If used with ethereal 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
{
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("Procedure Calls Min RTT Max RTT Avg RTT\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=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;
td=0;
}
- printf("%-15s %6d %3d.%05d %3d.%05d %3d.%05d\n",
+ printf("%-15s %6d %3d.%05d %3d.%05d %3" G_GINT64_MODIFIER "u.%05" 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,
/* When called, this function will create a new instance of rpcstat.
* program and version are whick onc-rpc program/version we want to
* collect statistics for.
- * This function is called from tethereal when it parses the -Z rpc, arguments
+ * This function is called from tshark when it parses the -z rpc, arguments
* and it creates a new instance to store statistics in and registers this
* new instance for the rpc tap.
*/
static void
-rpcstat_init(char *optarg)
+rpcstat_init(const char *optarg, void* userdata _U_)
{
rpcstat_t *rs;
guint32 i;
int program, version;
int pos=0;
- char *filter=NULL;
-
+ const char *filter=NULL;
+ GString *error_string;
if(sscanf(optarg,"rpc,rtt,%d,%d,%n",&program,&version,&pos)==2){
if(pos){
filter=NULL;
}
} else {
- fprintf(stderr, "tethereal: invalid \"-z rpc,rtt,<program>,<version>[,<filter>]\" argument\n");
+ fprintf(stderr, "tshark: invalid \"-z rpc,rtt,<program>,<version>[,<filter>]\" argument\n");
exit(1);
}
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;
}
rpc_max_proc=-1;
g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_procs, NULL);
if(rpc_min_proc==-1){
- fprintf(stderr,"tethereal: Invalid -Z rpc,rrt,%d,%d\n",rpc_program,rpc_version);
- fprintf(stderr," Program:%d version:%d is not supported by tethereal.\n", rpc_program, rpc_version);
+ fprintf(stderr,"tshark: Invalid -z rpc,rrt,%d,%d\n",rpc_program,rpc_version);
+ fprintf(stderr," Program:%d version:%d isn't supported by tshark.\n", rpc_program, rpc_version);
exit(1);
}
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;
/* 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?)
*
*/
- if(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);
g_free(rs->filter);
g_free(rs);
- fprintf(stderr,"tethereal: rpcstat_init() failed to attach to tap.\n");
+ fprintf(stderr, "tshark: Couldn't register rpc,rtt tap: %s\n",
+ error_string->str);
+ g_string_free(error_string, TRUE);
exit(1);
}
}
void
register_tap_listener_rpcstat(void)
{
- register_ethereal_tap("rpc,rtt,", rpcstat_init);
+ register_stat_cmd_arg("rpc,rtt,", rpcstat_init,NULL);
}