2 * dcerpc_stat 2002 Ronnie Sahlberg
4 * $Id: dcerpc_stat.c,v 1.33 2003/12/13 22:23:18 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 %d.%d: %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;
195 GString *error_string;
198 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){
216 fprintf(stderr, "ethereal: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
221 rs=g_malloc(sizeof(rpcstat_t));
222 if (major < 0 || major > 255 || minor < 0 || minor > 255)
223 rs->prog = NULL; /* bogus major or minor */
225 rs->prog=dcerpc_get_proto_name(&uuid, (guint16) ((minor<<8)|(major&0xff)) );
228 fprintf(stderr,"ethereal: dcerpcstat_init() Protocol with uuid:%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x v%d.%d 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);
231 hf_opnum=dcerpc_get_proto_hf_opnum(&uuid, (guint16) ((minor<<8)|(major&0xff)) );
232 procs=dcerpc_get_proto_sub_dissector(&uuid, (guint16) ((minor<<8)|(major&0xff)) );
234 rs->ver=(minor<<8)|(major&0xff);
236 rs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
237 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
238 dcerpcstat_set_title(rs);
239 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
241 vbox=gtk_vbox_new(FALSE, 0);
242 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
243 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
244 gtk_widget_show(vbox);
246 title_string=dcerpcstat_gen_title(rs);
247 stat_label=gtk_label_new(title_string);
248 g_free(title_string);
249 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
250 gtk_widget_show(stat_label);
252 snprintf(filter_string,255,"Filter:%s",filter?filter:"");
253 filter_label=gtk_label_new(filter_string);
254 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
255 gtk_widget_show(filter_label);
257 for(i=0,max_procs=0;procs[i].name;i++){
258 if(procs[i].num>max_procs){
259 max_procs=procs[i].num;
262 rs->num_procedures=max_procs+1;
264 /* We must display TOP LEVEL Widget before calling init_srt_table() */
265 gtk_widget_show(rs->win);
268 init_srt_table(&rs->srt_table, max_procs+1, vbox, proto_registrar_get_nth(hf_opnum)->abbrev);
270 init_srt_table(&rs->srt_table, max_procs+1, vbox, NULL);
273 for(i=0;i<(max_procs+1);i++){
278 for(j=0;procs[j].name;j++){
280 proc_name=procs[j].name;
284 init_srt_table_row(&rs->srt_table, i, proc_name);
288 error_string=register_tap_listener("dcerpc", rs, filter, (void*)dcerpcstat_reset, (void*)dcerpcstat_packet, (void*)dcerpcstat_draw);
290 /* error, we failed to attach to the tap. clean up */
291 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
292 g_string_free(error_string, TRUE);
293 free_srt_table_data(&rs->srt_table);
299 gtk_widget_show_all(rs->win);
300 redissect_packets(&cfile);
305 static e_uuid_t *dcerpc_uuid_program=NULL;
306 static guint16 dcerpc_version;
307 static GtkWidget *dlg=NULL;
308 static GtkWidget *prog_menu;
309 static GtkWidget *vers_opt, *vers_menu;
310 static GtkWidget *filter_entry;
311 static dcerpc_uuid_key *current_uuid_key=NULL;
312 static dcerpc_uuid_value *current_uuid_value=NULL;
313 static dcerpc_uuid_key *new_uuid_key=NULL;
314 static dcerpc_uuid_value *new_uuid_value=NULL;
318 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
323 str = g_string_new("dcerpc,srt");
324 g_string_sprintfa(str,
325 ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d",
326 dcerpc_uuid_program->Data1, dcerpc_uuid_program->Data2,
327 dcerpc_uuid_program->Data3,
328 dcerpc_uuid_program->Data4[0], dcerpc_uuid_program->Data4[1],
329 dcerpc_uuid_program->Data4[2], dcerpc_uuid_program->Data4[3],
330 dcerpc_uuid_program->Data4[4], dcerpc_uuid_program->Data4[5],
331 dcerpc_uuid_program->Data4[6], dcerpc_uuid_program->Data4[7],
332 dcerpc_version&0xff, dcerpc_version>>8);
333 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
335 g_string_sprintfa(str, ",%s", filter);
338 gtk_dcerpcstat_init(str->str);
339 g_string_free(str, TRUE);
344 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
355 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
357 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
358 GtkWidget *menu_item;
361 if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
365 sprintf(vs,"%d.%d",k->ver&0xff,k->ver>>8);
366 menu_item=gtk_menu_item_new_with_label(vs);
367 SIGNAL_CONNECT(menu_item, "activate", dcerpcstat_version_select,
369 gtk_widget_show(menu_item);
370 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
372 if(dcerpc_version==0xffff){
373 dcerpc_version=k->ver;
381 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
383 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
385 dcerpc_uuid_program=&k->uuid;
387 /* change version menu */
388 dcerpc_version=0xffff;
389 gtk_object_destroy(GTK_OBJECT(vers_menu));
390 vers_menu=gtk_menu_new();
391 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
392 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
396 static GtkWidget *program_submenu_menu;
397 static GtkWidget *program_submenu_item;
398 static GtkWidget *program_submenu_label;
399 static int program_subitem_index;
400 static char *first_menu_name;
402 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
404 GtkWidget *program_menu_item;
408 switch(program_subitem_index%15){
411 first_menu_name=v->name;
412 snprintf(str,63,"%s ...",v->name);
413 program_submenu_item=gtk_menu_item_new();
414 box=gtk_hbox_new(TRUE,0);
415 gtk_container_add(GTK_CONTAINER(program_submenu_item), box);
417 program_submenu_label=gtk_label_new(str);
418 gtk_box_pack_start(GTK_BOX(box), program_submenu_label, TRUE, TRUE, 0);
419 gtk_widget_show(program_submenu_label);
420 gtk_widget_show(box);
422 gtk_menu_append(GTK_MENU(prog_menu), program_submenu_item);
423 gtk_widget_show(program_submenu_item);
425 program_submenu_menu=gtk_menu_new();
426 gtk_menu_item_set_submenu(GTK_MENU_ITEM(program_submenu_item), program_submenu_menu);
429 snprintf(str,63,"%s - %s",first_menu_name,v->name);
430 gtk_label_set_text(GTK_LABEL(program_submenu_label), str);
434 program_subitem_index++;
436 program_menu_item=gtk_menu_item_new_with_label(v->name);
437 SIGNAL_CONNECT(program_menu_item, "activate", dcerpcstat_program_select, k);
439 gtk_widget_show(program_menu_item);
440 gtk_menu_append(GTK_MENU(program_submenu_menu), program_menu_item);
442 if(!dcerpc_uuid_program){
443 dcerpc_uuid_program=&k->uuid;
450 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
452 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
453 dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
455 /* first time called, just set new_uuid to this one */
456 if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
462 /* if we havent got a current one yet, just check the new
463 and scan for the first one alphabetically */
464 if(current_uuid_key==NULL){
465 if(strcmp(new_uuid_value->name, v->name)>0){
473 /* searching for the next one we are only interested in those
474 that sorts alphabetically after the current one */
475 if(strcmp(current_uuid_value->name, v->name)>=0){
476 /* this one doesnt so just skip it */
480 /* is it the first potential new entry? */
481 if(new_uuid_key==NULL){
487 /* does it sort before the current new one? */
488 if(strcmp(new_uuid_value->name, v->name)>0){
506 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
508 gtk_widget_destroy(GTK_WIDGET(parent_w));
513 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
516 GtkWidget *prog_box, *prog_label, *prog_opt;
517 GtkWidget *vers_label;
518 GtkWidget *filter_box, *filter_bt;
519 GtkWidget *bbox, *start_button, *cancel_button;
521 static construct_args_t args = {
522 "Service Response Time Statistics Filter",
527 /* if the window is already open, bring it to front and
528 un-minimize it, as necessary */
530 reactivate_window(dlg);
534 dlg=dlg_window_new("Ethereal: Compute DCE-RPC SRT statistics");
535 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
537 dlg_box=gtk_vbox_new(FALSE, 10);
538 gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
539 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
540 gtk_widget_show(dlg_box);
543 prog_box=gtk_hbox_new(FALSE, 3);
546 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
547 prog_label=gtk_label_new("Program:");
548 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
549 gtk_widget_show(prog_label);
552 prog_opt=gtk_option_menu_new();
553 prog_menu=gtk_menu_new();
554 current_uuid_key=NULL;
555 current_uuid_value=NULL;
557 program_submenu_item=NULL;
558 program_submenu_menu=NULL;
559 program_subitem_index=0;
563 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
565 dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
567 current_uuid_key=new_uuid_key;
568 current_uuid_value=new_uuid_value;
569 } while(new_uuid_key!=NULL);
571 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
572 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
573 gtk_widget_show(prog_opt);
576 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
577 vers_label=gtk_label_new("Version:");
578 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
579 gtk_widget_show(vers_label);
582 vers_opt=gtk_option_menu_new();
583 vers_menu=gtk_menu_new();
584 dcerpc_version=0xffff;
585 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
586 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
587 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
588 gtk_widget_show(vers_opt);
590 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
591 gtk_widget_show(prog_box);
594 filter_box=gtk_hbox_new(FALSE, 3);
597 filter_bt=gtk_button_new_with_label("Filter:");
598 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
599 gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
600 gtk_widget_show(filter_bt);
603 filter_entry=gtk_entry_new();
604 gtk_widget_set_usize(filter_entry, 300, -2);
607 filter_entry=gtk_entry_new();
608 gtk_widget_set_usize(filter_entry, 300, -2);
610 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
611 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
613 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
615 gtk_widget_show(filter_entry);
617 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
618 gtk_widget_show(filter_box);
621 bbox=gtk_hbutton_box_new();
622 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_DEFAULT_STYLE);
623 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
624 gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
625 gtk_widget_show(bbox);
627 /* the start button */
628 start_button=gtk_button_new_with_label("Create Stat");
629 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
630 dcerpcstat_start_button_clicked, NULL);
631 gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
632 GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
633 gtk_widget_grab_default(start_button);
634 gtk_widget_show(start_button);
636 #if GTK_MAJOR_VERSION < 2
637 cancel_button=gtk_button_new_with_label("Cancel");
639 cancel_button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
641 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
642 GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
643 gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
644 gtk_widget_show(cancel_button);
646 /* Catch the "activate" signal on the filter text entry, so that
647 if the user types Return there, we act as if the "Create Stat"
648 button had been selected, as happens if Return is typed if some
649 widget that *doesn't* handle the Return key has the input
651 dlg_set_activate(filter_entry, start_button);
653 /* Catch the "key_press_event" signal in the window, so that we can
654 catch the ESC key being pressed and act as if the "Cancel" button
655 had been selected. */
656 dlg_set_cancel(dlg, cancel_button);
658 /* Give the initial focus to the "Filter" entry box. */
659 gtk_widget_grab_focus(filter_entry);
661 gtk_widget_show_all(dlg);
665 register_tap_listener_gtkdcerpcstat(void)
667 register_ethereal_tap("dcerpc,srt,", gtk_dcerpcstat_init);
671 register_tap_menu_gtkdcerpcstat(void)
673 register_tap_menu_item("Statistics/Service Response Time/DCE-RPC...",
674 gtk_dcerpcstat_cb, NULL, NULL);