2 * dcerpc_stat 2002 Ronnie Sahlberg
4 * $Id: dcerpc_stat.c,v 1.39 2004/01/13 22:49:14 guy 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 statistics to ethereal,
26 * and displays them graphically.
27 * It is only used by ethereal and not tethereal
29 * It serves as an example on how to use the tap api.
40 #include "epan/packet_info.h"
41 #include "epan/epan.h"
43 #include "simple_dialog.h"
44 #include "dlg_utils.h"
47 #include "../register.h"
48 #include "packet-dcerpc.h"
49 #include "../globals.h"
50 #include "filter_prefs.h"
51 #include "compat_macros.h"
52 #include "service_response_time_table.h"
55 extern GtkWidget *main_display_filter_widget;
57 /* used to keep track of the statistics for an entire program interface */
58 typedef struct _rpcstat_t {
60 srt_stat_table srt_table;
69 uuid_equal(e_uuid_t *uuid1, e_uuid_t *uuid2)
71 if( (uuid1->Data1!=uuid2->Data1)
72 ||(uuid1->Data2!=uuid2->Data2)
73 ||(uuid1->Data3!=uuid2->Data3)
74 ||(uuid1->Data4[0]!=uuid2->Data4[0])
75 ||(uuid1->Data4[1]!=uuid2->Data4[1])
76 ||(uuid1->Data4[2]!=uuid2->Data4[2])
77 ||(uuid1->Data4[3]!=uuid2->Data4[3])
78 ||(uuid1->Data4[4]!=uuid2->Data4[4])
79 ||(uuid1->Data4[5]!=uuid2->Data4[5])
80 ||(uuid1->Data4[6]!=uuid2->Data4[6])
81 ||(uuid1->Data4[7]!=uuid2->Data4[7]) ){
88 dcerpcstat_gen_title(rpcstat_t *rs)
92 title = g_strdup_printf("DCE-RPC Service Response Time statistics for %s version %u.%u: %s", rs->prog, rs->ver&0xff, rs->ver>>8, cf_get_display_name(&cfile));
97 dcerpcstat_set_title(rpcstat_t *rs)
101 title = dcerpcstat_gen_title(rs);
102 gtk_window_set_title(GTK_WINDOW(rs->win), title);
107 dcerpcstat_reset(rpcstat_t *rs)
109 reset_srt_table_data(&rs->srt_table);
110 dcerpcstat_set_title(rs);
115 dcerpcstat_packet(rpcstat_t *rs, packet_info *pinfo, epan_dissect_t *edt _U_, dcerpc_info *ri)
120 if(!ri->call_data->req_frame){
121 /* we have not seen the request so we dont know the delta*/
124 if(ri->call_data->opnum>=rs->num_procedures){
125 /* dont handle this since its outside of known table */
129 /* we are only interested in reply packets */
134 /* we are only interested in certain program/versions */
135 if( (!uuid_equal( (&ri->call_data->uuid), (&rs->uuid)))
136 ||(ri->call_data->ver!=rs->ver)){
141 add_srt_table_data(&rs->srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
148 dcerpcstat_draw(rpcstat_t *rs)
150 draw_srt_table_data(&rs->srt_table);
154 /* since the gtk2 implementation of tap is multithreaded we must protect
155 * remove_tap_listener() from modifying the list while draw_tap_listener()
156 * is running. the other protected block is in main.c
158 * there should not be any other critical regions in gtk2
160 void protect_thread_critical_region(void);
161 void unprotect_thread_critical_region(void);
163 win_destroy_cb(GtkWindow *win _U_, gpointer data)
165 rpcstat_t *rs=(rpcstat_t *)data;
167 protect_thread_critical_region();
168 remove_tap_listener(rs);
169 unprotect_thread_critical_region();
171 free_srt_table_data(&rs->srt_table);
177 /* When called, this function will create a new instance of gtk-dcerpcstat.
180 gtk_dcerpcstat_init(char *optarg)
183 guint32 i, max_procs;
185 char filter_string[256];
187 GtkWidget *stat_label;
188 GtkWidget *filter_label;
189 dcerpc_sub_dissector *procs;
191 int d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
196 GString *error_string;
199 if(sscanf(optarg,"dcerpc,srt,%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d,%n", &d1,&d2,&d3,&d40,&d41,&d42,&d43,&d44,&d45,&d46,&d47,&major,&minor,&pos)==13){
217 fprintf(stderr, "ethereal: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
220 if (major < 0 || major > 255) {
221 fprintf(stderr,"ethereal: dcerpcstat_init() Major version number %d is invalid - must be positive and <= 255\n", major);
224 if (minor < 0 || minor > 255) {
225 fprintf(stderr,"ethereal: dcerpcstat_init() Minor version number %d is invalid - must be positive and <= 255\n", minor);
228 ver = ((minor<<8)|(major&0xff));
231 rs=g_malloc(sizeof(rpcstat_t));
232 rs->prog=dcerpc_get_proto_name(&uuid, ver);
235 fprintf(stderr,"ethereal: dcerpcstat_init() Protocol with uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x v%u.%u not supported\n",uuid.Data1,uuid.Data2,uuid.Data3,uuid.Data4[0],uuid.Data4[1],uuid.Data4[2],uuid.Data4[3],uuid.Data4[4],uuid.Data4[5],uuid.Data4[6],uuid.Data4[7],major,minor);
238 hf_opnum=dcerpc_get_proto_hf_opnum(&uuid, ver);
239 procs=dcerpc_get_proto_sub_dissector(&uuid, ver);
243 rs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
244 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
245 dcerpcstat_set_title(rs);
246 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
248 vbox=gtk_vbox_new(FALSE, 0);
249 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
250 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
251 gtk_widget_show(vbox);
253 title_string=dcerpcstat_gen_title(rs);
254 stat_label=gtk_label_new(title_string);
255 g_free(title_string);
256 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
257 gtk_widget_show(stat_label);
259 snprintf(filter_string,255,"Filter:%s",filter?filter:"");
260 filter_label=gtk_label_new(filter_string);
261 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
262 gtk_widget_show(filter_label);
264 for(i=0,max_procs=0;procs[i].name;i++){
265 if(procs[i].num>max_procs){
266 max_procs=procs[i].num;
269 rs->num_procedures=max_procs+1;
271 /* We must display TOP LEVEL Widget before calling init_srt_table() */
272 gtk_widget_show(rs->win);
275 init_srt_table(&rs->srt_table, max_procs+1, vbox, proto_registrar_get_nth(hf_opnum)->abbrev);
277 init_srt_table(&rs->srt_table, max_procs+1, vbox, NULL);
280 for(i=0;i<(max_procs+1);i++){
285 for(j=0;procs[j].name;j++){
287 proc_name=procs[j].name;
291 init_srt_table_row(&rs->srt_table, i, proc_name);
295 error_string=register_tap_listener("dcerpc", rs, filter, (void*)dcerpcstat_reset, (void*)dcerpcstat_packet, (void*)dcerpcstat_draw);
297 /* error, we failed to attach to the tap. clean up */
298 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
299 g_string_free(error_string, TRUE);
300 free_srt_table_data(&rs->srt_table);
306 gtk_widget_show_all(rs->win);
307 retap_packets(&cfile);
312 static e_uuid_t *dcerpc_uuid_program=NULL;
313 static guint16 dcerpc_version;
314 static GtkWidget *dlg=NULL;
315 static GtkWidget *prog_menu;
316 static GtkWidget *vers_opt, *vers_menu;
317 static GtkWidget *filter_entry;
318 static dcerpc_uuid_key *current_uuid_key=NULL;
319 static dcerpc_uuid_value *current_uuid_value=NULL;
320 static dcerpc_uuid_key *new_uuid_key=NULL;
321 static dcerpc_uuid_value *new_uuid_value=NULL;
325 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
330 str = g_string_new("dcerpc,srt");
331 g_string_sprintfa(str,
332 ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%u.%u",
333 dcerpc_uuid_program->Data1, dcerpc_uuid_program->Data2,
334 dcerpc_uuid_program->Data3,
335 dcerpc_uuid_program->Data4[0], dcerpc_uuid_program->Data4[1],
336 dcerpc_uuid_program->Data4[2], dcerpc_uuid_program->Data4[3],
337 dcerpc_uuid_program->Data4[4], dcerpc_uuid_program->Data4[5],
338 dcerpc_uuid_program->Data4[6], dcerpc_uuid_program->Data4[7],
339 dcerpc_version&0xff, dcerpc_version>>8);
340 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
342 g_string_sprintfa(str, ",%s", filter);
345 gtk_dcerpcstat_init(str->str);
346 g_string_free(str, TRUE);
351 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
362 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
364 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
365 GtkWidget *menu_item;
368 if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
372 sprintf(vs,"%u.%u",k->ver&0xff,k->ver>>8);
373 menu_item=gtk_menu_item_new_with_label(vs);
374 SIGNAL_CONNECT(menu_item, "activate", dcerpcstat_version_select,
376 gtk_widget_show(menu_item);
377 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
379 if(dcerpc_version==0xffff){
380 dcerpc_version=k->ver;
388 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
390 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
392 dcerpc_uuid_program=&k->uuid;
394 /* change version menu */
395 dcerpc_version=0xffff;
396 gtk_object_destroy(GTK_OBJECT(vers_menu));
397 vers_menu=gtk_menu_new();
398 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
399 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
403 static GtkWidget *program_submenu_menu;
404 static GtkWidget *program_submenu_item;
405 static GtkWidget *program_submenu_label;
406 static int program_subitem_index;
407 static char *first_menu_name;
409 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
411 GtkWidget *program_menu_item;
415 switch(program_subitem_index%15){
418 first_menu_name=v->name;
419 snprintf(str,63,"%s ...",v->name);
420 program_submenu_item=gtk_menu_item_new();
421 box=gtk_hbox_new(TRUE,0);
422 gtk_container_add(GTK_CONTAINER(program_submenu_item), box);
424 program_submenu_label=gtk_label_new(str);
425 gtk_box_pack_start(GTK_BOX(box), program_submenu_label, TRUE, TRUE, 0);
426 gtk_widget_show(program_submenu_label);
427 gtk_widget_show(box);
429 gtk_menu_append(GTK_MENU(prog_menu), program_submenu_item);
430 gtk_widget_show(program_submenu_item);
432 program_submenu_menu=gtk_menu_new();
433 gtk_menu_item_set_submenu(GTK_MENU_ITEM(program_submenu_item), program_submenu_menu);
436 snprintf(str,63,"%s - %s",first_menu_name,v->name);
437 gtk_label_set_text(GTK_LABEL(program_submenu_label), str);
441 program_subitem_index++;
443 program_menu_item=gtk_menu_item_new_with_label(v->name);
444 SIGNAL_CONNECT(program_menu_item, "activate", dcerpcstat_program_select, k);
446 gtk_widget_show(program_menu_item);
447 gtk_menu_append(GTK_MENU(program_submenu_menu), program_menu_item);
449 if(!dcerpc_uuid_program){
450 dcerpc_uuid_program=&k->uuid;
457 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
459 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
460 dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
462 /* first time called, just set new_uuid to this one */
463 if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
469 /* if we havent got a current one yet, just check the new
470 and scan for the first one alphabetically */
471 if(current_uuid_key==NULL){
472 if(strcmp(new_uuid_value->name, v->name)>0){
480 /* searching for the next one we are only interested in those
481 that sorts alphabetically after the current one */
482 if(strcmp(current_uuid_value->name, v->name)>=0){
483 /* this one doesnt so just skip it */
487 /* is it the first potential new entry? */
488 if(new_uuid_key==NULL){
494 /* does it sort before the current new one? */
495 if(strcmp(new_uuid_value->name, v->name)>0){
513 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
515 gtk_widget_destroy(GTK_WIDGET(parent_w));
520 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
523 GtkWidget *prog_box, *prog_label, *prog_opt;
524 GtkWidget *vers_label;
525 GtkWidget *filter_box, *filter_bt;
526 GtkWidget *bbox, *start_button, *cancel_button;
528 static construct_args_t args = {
529 "Service Response Time Statistics Filter",
534 /* if the window is already open, bring it to front and
535 un-minimize it, as necessary */
537 reactivate_window(dlg);
541 dlg=dlg_window_new("Ethereal: Compute DCE-RPC SRT statistics");
542 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
544 dlg_box=gtk_vbox_new(FALSE, 10);
545 gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
546 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
547 gtk_widget_show(dlg_box);
550 prog_box=gtk_hbox_new(FALSE, 3);
553 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
554 prog_label=gtk_label_new("Program:");
555 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
556 gtk_widget_show(prog_label);
559 prog_opt=gtk_option_menu_new();
560 prog_menu=gtk_menu_new();
561 current_uuid_key=NULL;
562 current_uuid_value=NULL;
564 program_submenu_item=NULL;
565 program_submenu_menu=NULL;
566 program_subitem_index=0;
570 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
572 dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
574 current_uuid_key=new_uuid_key;
575 current_uuid_value=new_uuid_value;
576 } while(new_uuid_key!=NULL);
578 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
579 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
580 gtk_widget_show(prog_opt);
583 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
584 vers_label=gtk_label_new("Version:");
585 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
586 gtk_widget_show(vers_label);
589 vers_opt=gtk_option_menu_new();
590 vers_menu=gtk_menu_new();
591 dcerpc_version=0xffff;
592 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
593 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
594 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
595 gtk_widget_show(vers_opt);
597 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
598 gtk_widget_show(prog_box);
601 filter_box=gtk_hbox_new(FALSE, 3);
604 filter_bt=gtk_button_new_with_label("Filter:");
605 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
606 gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
607 gtk_widget_show(filter_bt);
610 filter_entry=gtk_entry_new();
611 WIDGET_SET_SIZE(filter_entry, 300, -2);
614 filter_entry=gtk_entry_new();
615 WIDGET_SET_SIZE(filter_entry, 300, -2);
617 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
618 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
620 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
622 gtk_widget_show(filter_entry);
624 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
625 gtk_widget_show(filter_box);
628 bbox=gtk_hbutton_box_new();
629 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_DEFAULT_STYLE);
630 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
631 gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
632 gtk_widget_show(bbox);
634 /* the start button */
635 start_button=gtk_button_new_with_label("Create Stat");
636 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
637 dcerpcstat_start_button_clicked, NULL);
638 gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
639 GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
640 gtk_widget_grab_default(start_button);
641 gtk_widget_show(start_button);
643 cancel_button=BUTTON_NEW_FROM_STOCK(GTK_STOCK_CANCEL);
644 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
645 GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
646 gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
647 gtk_widget_show(cancel_button);
649 /* Catch the "activate" signal on the filter text entry, so that
650 if the user types Return there, we act as if the "Create Stat"
651 button had been selected, as happens if Return is typed if some
652 widget that *doesn't* handle the Return key has the input
654 dlg_set_activate(filter_entry, start_button);
656 /* Catch the "key_press_event" signal in the window, so that we can
657 catch the ESC key being pressed and act as if the "Cancel" button
658 had been selected. */
659 dlg_set_cancel(dlg, cancel_button);
661 /* Give the initial focus to the "Filter" entry box. */
662 gtk_widget_grab_focus(filter_entry);
664 gtk_widget_show_all(dlg);
668 register_tap_listener_gtkdcerpcstat(void)
670 register_ethereal_tap("dcerpc,srt,", gtk_dcerpcstat_init);
674 register_tap_menu_gtkdcerpcstat(void)
676 register_tap_menu_item("_Statistics/Service Response Time/DCE-RPC...",
677 gtk_dcerpcstat_cb, NULL, NULL, NULL);