2 * rpc_stat 2002 Ronnie Sahlberg
4 * $Id: rpc_stat.c,v 1.42 2004/02/27 19:07:20 ulfl Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 /* This module provides rpc call/reply SRT (Server Response Time) statistics
28 * It serves as an example on how to use the tap api.
37 #include <epan/packet_info.h>
38 #include <epan/epan.h>
41 #include "simple_dialog.h"
43 #include "dlg_utils.h"
45 #include "../register.h"
46 #include "packet-rpc.h"
47 #include "../globals.h"
48 #include "filter_prefs.h"
49 #include "compat_macros.h"
50 #include "service_response_time_table.h"
52 extern GtkWidget *main_display_filter_widget;
54 /* used to keep track of the statistics for an entire program interface */
55 typedef struct _rpcstat_t {
57 srt_stat_table srt_table;
61 guint32 num_procedures;
65 rpcstat_gen_title(rpcstat_t *rs)
69 title = g_strdup_printf("ONC-RPC Service Response Time statistics for %s version %d: %s",
70 rs->prog, rs->version, cf_get_display_name(&cfile));
75 rpcstat_set_title(rpcstat_t *rs)
79 title = rpcstat_gen_title(rs);
80 gtk_window_set_title(GTK_WINDOW(rs->win), title);
85 rpcstat_reset(rpcstat_t *rs)
87 reset_srt_table_data(&rs->srt_table);
88 rpcstat_set_title(rs);
93 rpcstat_packet(rpcstat_t *rs, packet_info *pinfo, epan_dissect_t *edt _U_, rpc_call_info_value *ri)
95 if(ri->proc>=rs->num_procedures){
96 /* dont handle this since its outside of known table */
99 /* we are only interested in reply packets */
103 /* we are only interested in certain program/versions */
104 if( (ri->prog!=rs->program) || (ri->vers!=rs->version) ){
108 add_srt_table_data(&rs->srt_table, ri->proc, &ri->req_time, pinfo);
114 rpcstat_draw(rpcstat_t *rs)
116 draw_srt_table_data(&rs->srt_table);
121 static guint32 rpc_program=0;
122 static guint32 rpc_version=0;
123 static gint32 rpc_min_vers=-1;
124 static gint32 rpc_max_vers=-1;
125 static gint32 rpc_min_proc=-1;
126 static gint32 rpc_max_proc=-1;
129 rpcstat_find_procs(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
131 rpc_proc_info_key *k=(rpc_proc_info_key *)key;
133 if(k->prog!=rpc_program){
136 if(k->vers!=rpc_version){
139 if(rpc_min_proc==-1){
140 rpc_min_proc=k->proc;
141 rpc_max_proc=k->proc;
143 if((gint32)k->proc<rpc_min_proc){
144 rpc_min_proc=k->proc;
146 if((gint32)k->proc>rpc_max_proc){
147 rpc_max_proc=k->proc;
154 rpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
156 rpc_proc_info_key *k=(rpc_proc_info_key *)key;
158 if(k->prog!=rpc_program){
161 if(rpc_min_vers==-1){
162 rpc_min_vers=k->vers;
163 rpc_max_vers=k->vers;
165 if((gint32)k->vers<rpc_min_vers){
166 rpc_min_vers=k->vers;
168 if((gint32)k->vers>rpc_max_vers){
169 rpc_max_vers=k->vers;
175 /* since the gtk2 implementation of tap is multithreaded we must protect
176 * remove_tap_listener() from modifying the list while draw_tap_listener()
177 * is running. the other protected block is in main.c
179 * there should not be any other critical regions in gtk2
181 void protect_thread_critical_region(void);
182 void unprotect_thread_critical_region(void);
184 win_destroy_cb(GtkWindow *win _U_, gpointer data)
186 rpcstat_t *rs=(rpcstat_t *)data;
188 protect_thread_critical_region();
189 remove_tap_listener(rs);
190 unprotect_thread_critical_region();
192 free_srt_table_data(&rs->srt_table);
196 /* When called, this function will create a new instance of gtk2-rpcstat.
199 gtk_rpcstat_init(char *optarg)
204 char filter_string[256];
206 GtkWidget *stat_label;
207 GtkWidget *filter_label;
208 int program, version, pos;
210 GString *error_string;
212 header_field_info *hfi;
215 if(sscanf(optarg,"rpc,srt,%d,%d,%n",&program,&version,&pos)==2){
222 fprintf(stderr, "ethereal: invalid \"-z rpc,srt,<program>,<version>[,<filter>]\" argument\n");
228 rs=g_malloc(sizeof(rpcstat_t));
229 rs->prog=rpc_prog_name(rpc_program);
230 rs->program=rpc_program;
231 rs->version=rpc_version;
232 hf_index=rpc_prog_hf(rpc_program, rpc_version);
233 hfi=proto_registrar_get_nth(hf_index);
235 rs->win=window_new(GTK_WINDOW_TOPLEVEL, NULL);
236 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
237 rpcstat_set_title(rs);
238 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
240 vbox=gtk_vbox_new(FALSE, 0);
241 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
242 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
243 gtk_widget_show(vbox);
245 title_string = rpcstat_gen_title(rs);
246 stat_label=gtk_label_new(title_string);
247 g_free(title_string);
248 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
249 gtk_widget_show(stat_label);
251 snprintf(filter_string,255,"Filter:%s",filter?filter:"");
252 filter_label=gtk_label_new(filter_string);
253 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
254 gtk_widget_show(filter_label);
258 g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_procs, NULL);
259 rs->num_procedures=rpc_max_proc+1;
261 /* We must display TOP LEVEL Widget before calling init_srt_table() */
262 gtk_widget_show(rs->win);
264 init_srt_table(&rs->srt_table, rpc_max_proc+1, vbox, hfi->abbrev);
266 for(i=0;i<rs->num_procedures;i++){
267 init_srt_table_row(&rs->srt_table, i, rpc_proc_name(rpc_program, rpc_version, i));
271 error_string=register_tap_listener("rpc", rs, filter, (void*)rpcstat_reset, (void*)rpcstat_packet, (void*)rpcstat_draw);
273 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, error_string->str);
274 g_string_free(error_string, TRUE);
275 free_srt_table_data(&rs->srt_table);
281 gtk_widget_show_all(rs->win);
282 retap_packets(&cfile);
288 static GtkWidget *dlg=NULL;
289 static GtkWidget *prog_menu;
290 static GtkWidget *vers_opt, *vers_menu;
291 static GtkWidget *filter_entry;
295 rpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
300 str = g_string_new("rpc,srt");
301 g_string_sprintfa(str, ",%d,%d", rpc_program, rpc_version);
302 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
304 g_string_sprintfa(str, ",%s", filter);
307 gtk_rpcstat_init(str->str);
308 g_string_free(str, TRUE);
313 rpcstat_version_select(GtkWidget *item _U_, gpointer key)
323 rpcstat_program_select(GtkWidget *item _U_, gpointer key)
325 rpc_prog_info_key *k=(rpc_prog_info_key *)key;
330 /* change version menu */
332 gtk_object_destroy(GTK_OBJECT(vers_menu));
333 vers_menu=gtk_menu_new();
336 g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_vers, NULL);
337 rpc_version=rpc_min_vers;
338 for(i=rpc_min_vers;i<=rpc_max_vers;i++){
339 GtkWidget *menu_item;
342 menu_item=gtk_menu_item_new_with_label(vs);
343 SIGNAL_CONNECT(menu_item, "activate", rpcstat_version_select,
346 gtk_widget_show(menu_item);
347 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
349 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
353 rpcstat_list_programs(gpointer *key, gpointer *value, gpointer *user_data _U_)
355 rpc_prog_info_key *k=(rpc_prog_info_key *)key;
356 rpc_prog_info_value *v=(rpc_prog_info_value *)value;
357 GtkWidget *menu_item;
359 menu_item=gtk_menu_item_new_with_label(v->progname);
360 SIGNAL_CONNECT(menu_item, "activate", rpcstat_program_select, k);
362 gtk_widget_show(menu_item);
363 gtk_menu_append(GTK_MENU(prog_menu), menu_item);
379 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
381 gtk_widget_destroy(GTK_WIDGET(parent_w));
385 gtk_rpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
388 GtkWidget *prog_box, *prog_label, *prog_opt;
389 GtkWidget *vers_label;
390 GtkWidget *filter_box, *filter_bt;
391 GtkWidget *bbox, *start_button, *cancel_button;
394 static construct_args_t args = {
395 "Service Response Time Statistics Filter",
400 /* if the window is already open, bring it to front */
402 gdk_window_raise(dlg->window);
406 dlg=dlg_window_new("Ethereal: Compute ONC-RPC SRT statistics");
407 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
409 dlg_box=gtk_vbox_new(FALSE, 10);
410 gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
411 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
412 gtk_widget_show(dlg_box);
415 prog_box=gtk_hbox_new(FALSE, 10);
418 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
419 prog_label=gtk_label_new("Program:");
420 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
421 gtk_widget_show(prog_label);
424 prog_opt=gtk_option_menu_new();
425 prog_menu=gtk_menu_new();
426 g_hash_table_foreach(rpc_progs, (GHFunc)rpcstat_list_programs, NULL);
427 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
428 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
429 gtk_widget_show(prog_opt);
432 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
433 vers_label=gtk_label_new("Version:");
434 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
435 gtk_widget_show(vers_label);
438 vers_opt=gtk_option_menu_new();
439 vers_menu=gtk_menu_new();
442 g_hash_table_foreach(rpc_procs, (GHFunc)rpcstat_find_vers, NULL);
443 rpc_version=rpc_min_vers;
444 for(i=rpc_min_vers;i<=rpc_max_vers;i++){
445 GtkWidget *menu_item;
448 menu_item=gtk_menu_item_new_with_label(vs);
449 SIGNAL_CONNECT(menu_item, "activate", rpcstat_version_select,
452 gtk_widget_show(menu_item);
453 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
455 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
456 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
457 gtk_widget_show(vers_opt);
459 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
460 gtk_widget_show(prog_box);
463 filter_box=gtk_hbox_new(FALSE, 3);
466 filter_bt=BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_DISPLAY_FILTER_ENTRY);
467 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
468 gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
469 gtk_widget_show(filter_bt);
472 filter_entry=gtk_entry_new();
473 WIDGET_SET_SIZE(filter_entry, 300, -1);
474 SIGNAL_CONNECT(filter_entry, "changed", filter_te_syntax_check_cb, NULL);
476 /* filter prefs dialog */
477 OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_entry);
478 /* filter prefs dialog */
480 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
481 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
483 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
485 gtk_widget_show(filter_entry);
487 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
488 gtk_widget_show(filter_box);
491 bbox = dlg_button_row_new(ETHEREAL_STOCK_CREATE_STAT, GTK_STOCK_CANCEL, NULL);
492 gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
493 gtk_widget_show(bbox);
495 start_button = OBJECT_GET_DATA(bbox, ETHEREAL_STOCK_CREATE_STAT);
496 gtk_widget_grab_default(start_button );
497 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
498 rpcstat_start_button_clicked, NULL);
500 cancel_button = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
501 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
503 /* Catch the "activate" signal on the filter text entry, so that
504 if the user types Return there, we act as if the "Create Stat"
505 button had been selected, as happens if Return is typed if some
506 widget that *doesn't* handle the Return key has the input
508 dlg_set_activate(filter_entry, start_button);
510 /* Catch the "key_press_event" signal in the window, so that we can
511 catch the ESC key being pressed and act as if the "Cancel" button
512 had been selected. */
513 dlg_set_cancel(dlg, cancel_button);
515 /* Give the initial focus to the "Filter" entry box. */
516 gtk_widget_grab_focus(filter_entry);
518 gtk_widget_show_all(dlg);
523 register_tap_listener_gtkrpcstat(void)
525 register_ethereal_tap("rpc,srt,", gtk_rpcstat_init);
527 register_tap_menu_item("ONC-RPC...", REGISTER_TAP_GROUP_RESPONSE_TIME,
528 gtk_rpcstat_cb, NULL, NULL, NULL);