2 * dcerpc_stat 2002 Ronnie Sahlberg
4 * $Id: dcerpc_stat.c,v 1.32 2003/12/13 17:10:21 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 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.
38 #include "epan/packet_info.h"
39 #include "epan/epan.h"
40 #include "simple_dialog.h"
41 #include "dlg_utils.h"
44 #include "../register.h"
45 #include "packet-dcerpc.h"
46 #include "../globals.h"
47 #include "filter_prefs.h"
48 #include "compat_macros.h"
49 #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;
66 uuid_equal(e_uuid_t *uuid1, e_uuid_t *uuid2)
68 if( (uuid1->Data1!=uuid2->Data1)
69 ||(uuid1->Data2!=uuid2->Data2)
70 ||(uuid1->Data3!=uuid2->Data3)
71 ||(uuid1->Data4[0]!=uuid2->Data4[0])
72 ||(uuid1->Data4[1]!=uuid2->Data4[1])
73 ||(uuid1->Data4[2]!=uuid2->Data4[2])
74 ||(uuid1->Data4[3]!=uuid2->Data4[3])
75 ||(uuid1->Data4[4]!=uuid2->Data4[4])
76 ||(uuid1->Data4[5]!=uuid2->Data4[5])
77 ||(uuid1->Data4[6]!=uuid2->Data4[6])
78 ||(uuid1->Data4[7]!=uuid2->Data4[7]) ){
85 dcerpcstat_gen_title(rpcstat_t *rs)
89 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));
94 dcerpcstat_set_title(rpcstat_t *rs)
98 title = dcerpcstat_gen_title(rs);
99 gtk_window_set_title(GTK_WINDOW(rs->win), title);
104 dcerpcstat_reset(rpcstat_t *rs)
106 reset_srt_table_data(&rs->srt_table);
107 dcerpcstat_set_title(rs);
112 dcerpcstat_packet(rpcstat_t *rs, packet_info *pinfo, epan_dissect_t *edt _U_, dcerpc_info *ri)
117 if(!ri->call_data->req_frame){
118 /* we have not seen the request so we dont know the delta*/
121 if(ri->call_data->opnum>=rs->num_procedures){
122 /* dont handle this since its outside of known table */
126 /* we are only interested in reply packets */
131 /* we are only interested in certain program/versions */
132 if( (!uuid_equal( (&ri->call_data->uuid), (&rs->uuid)))
133 ||(ri->call_data->ver!=rs->ver)){
138 add_srt_table_data(&rs->srt_table, ri->call_data->opnum, &ri->call_data->req_time, pinfo);
145 dcerpcstat_draw(rpcstat_t *rs)
147 draw_srt_table_data(&rs->srt_table);
151 /* since the gtk2 implementation of tap is multithreaded we must protect
152 * remove_tap_listener() from modifying the list while draw_tap_listener()
153 * is running. the other protected block is in main.c
155 * there should not be any other critical regions in gtk2
157 void protect_thread_critical_region(void);
158 void unprotect_thread_critical_region(void);
160 win_destroy_cb(GtkWindow *win _U_, gpointer data)
162 rpcstat_t *rs=(rpcstat_t *)data;
164 protect_thread_critical_region();
165 remove_tap_listener(rs);
166 unprotect_thread_critical_region();
168 free_srt_table_data(&rs->srt_table);
174 /* When called, this function will create a new instance of gtk-dcerpcstat.
177 gtk_dcerpcstat_init(char *optarg)
180 guint32 i, max_procs;
182 char filter_string[256];
184 GtkWidget *stat_label;
185 GtkWidget *filter_label;
186 dcerpc_sub_dissector *procs;
188 int d1,d2,d3,d40,d41,d42,d43,d44,d45,d46,d47;
192 GString *error_string;
195 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){
213 fprintf(stderr, "ethereal: invalid \"-z dcerpc,srt,<uuid>,<major version>.<minor version>[,<filter>]\" argument\n");
218 rs=g_malloc(sizeof(rpcstat_t));
219 if (major < 0 || major > 255 || minor < 0 || minor > 255)
220 rs->prog = NULL; /* bogus major or minor */
222 rs->prog=dcerpc_get_proto_name(&uuid, (guint16) ((minor<<8)|(major&0xff)) );
225 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);
228 hf_opnum=dcerpc_get_proto_hf_opnum(&uuid, (guint16) ((minor<<8)|(major&0xff)) );
229 procs=dcerpc_get_proto_sub_dissector(&uuid, (guint16) ((minor<<8)|(major&0xff)) );
231 rs->ver=(minor<<8)|(major&0xff);
233 rs->win=gtk_window_new(GTK_WINDOW_TOPLEVEL);
234 gtk_window_set_default_size(GTK_WINDOW(rs->win), 550, 400);
235 dcerpcstat_set_title(rs);
236 SIGNAL_CONNECT(rs->win, "destroy", win_destroy_cb, rs);
238 vbox=gtk_vbox_new(FALSE, 0);
239 gtk_container_add(GTK_CONTAINER(rs->win), vbox);
240 gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
241 gtk_widget_show(vbox);
243 title_string=dcerpcstat_gen_title(rs);
244 stat_label=gtk_label_new(title_string);
245 g_free(title_string);
246 gtk_box_pack_start(GTK_BOX(vbox), stat_label, FALSE, FALSE, 0);
247 gtk_widget_show(stat_label);
249 snprintf(filter_string,255,"Filter:%s",filter?filter:"");
250 filter_label=gtk_label_new(filter_string);
251 gtk_box_pack_start(GTK_BOX(vbox), filter_label, FALSE, FALSE, 0);
252 gtk_widget_show(filter_label);
254 for(i=0,max_procs=0;procs[i].name;i++){
255 if(procs[i].num>max_procs){
256 max_procs=procs[i].num;
259 rs->num_procedures=max_procs+1;
261 /* We must display TOP LEVEL Widget before calling init_srt_table() */
262 gtk_widget_show(rs->win);
265 init_srt_table(&rs->srt_table, max_procs+1, vbox, proto_registrar_get_nth(hf_opnum)->abbrev);
267 init_srt_table(&rs->srt_table, max_procs+1, vbox, NULL);
270 for(i=0;i<(max_procs+1);i++){
275 for(j=0;procs[j].name;j++){
277 proc_name=procs[j].name;
281 init_srt_table_row(&rs->srt_table, i, proc_name);
285 error_string=register_tap_listener("dcerpc", rs, filter, (void*)dcerpcstat_reset, (void*)dcerpcstat_packet, (void*)dcerpcstat_draw);
287 /* error, we failed to attach to the tap. clean up */
288 simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
289 g_string_free(error_string, TRUE);
290 free_srt_table_data(&rs->srt_table);
296 gtk_widget_show_all(rs->win);
297 redissect_packets(&cfile);
302 static e_uuid_t *dcerpc_uuid_program=NULL;
303 static guint16 dcerpc_version;
304 static GtkWidget *dlg=NULL;
305 static GtkWidget *prog_menu;
306 static GtkWidget *vers_opt, *vers_menu;
307 static GtkWidget *filter_entry;
308 static dcerpc_uuid_key *current_uuid_key=NULL;
309 static dcerpc_uuid_value *current_uuid_value=NULL;
310 static dcerpc_uuid_key *new_uuid_key=NULL;
311 static dcerpc_uuid_value *new_uuid_value=NULL;
315 dcerpcstat_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
320 str = g_string_new("dcerpc,srt");
321 g_string_sprintfa(str,
322 ",%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x,%d.%d",
323 dcerpc_uuid_program->Data1, dcerpc_uuid_program->Data2,
324 dcerpc_uuid_program->Data3,
325 dcerpc_uuid_program->Data4[0], dcerpc_uuid_program->Data4[1],
326 dcerpc_uuid_program->Data4[2], dcerpc_uuid_program->Data4[3],
327 dcerpc_uuid_program->Data4[4], dcerpc_uuid_program->Data4[5],
328 dcerpc_uuid_program->Data4[6], dcerpc_uuid_program->Data4[7],
329 dcerpc_version&0xff, dcerpc_version>>8);
330 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
332 g_string_sprintfa(str, ",%s", filter);
335 gtk_dcerpcstat_init(str->str);
336 g_string_free(str, TRUE);
341 dcerpcstat_version_select(GtkWidget *item _U_, gpointer key)
352 dcerpcstat_find_vers(gpointer *key, gpointer *value _U_, gpointer *user_data _U_)
354 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
355 GtkWidget *menu_item;
358 if(!uuid_equal((&k->uuid), dcerpc_uuid_program)){
362 sprintf(vs,"%d.%d",k->ver&0xff,k->ver>>8);
363 menu_item=gtk_menu_item_new_with_label(vs);
364 SIGNAL_CONNECT(menu_item, "activate", dcerpcstat_version_select,
366 gtk_widget_show(menu_item);
367 gtk_menu_append(GTK_MENU(vers_menu), menu_item);
369 if(dcerpc_version==0xffff){
370 dcerpc_version=k->ver;
378 dcerpcstat_program_select(GtkWidget *item _U_, gpointer key)
380 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
382 dcerpc_uuid_program=&k->uuid;
384 /* change version menu */
385 dcerpc_version=0xffff;
386 gtk_object_destroy(GTK_OBJECT(vers_menu));
387 vers_menu=gtk_menu_new();
388 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
389 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
393 static GtkWidget *program_submenu_menu;
394 static GtkWidget *program_submenu_item;
395 static GtkWidget *program_submenu_label;
396 static int program_subitem_index;
397 static char *first_menu_name;
399 dcerpcstat_add_program_to_menu(dcerpc_uuid_key *k, dcerpc_uuid_value *v)
401 GtkWidget *program_menu_item;
405 switch(program_subitem_index%15){
408 first_menu_name=v->name;
409 snprintf(str,63,"%s ...",v->name);
410 program_submenu_item=gtk_menu_item_new();
411 box=gtk_hbox_new(TRUE,0);
412 gtk_container_add(GTK_CONTAINER(program_submenu_item), box);
414 program_submenu_label=gtk_label_new(str);
415 gtk_box_pack_start(GTK_BOX(box), program_submenu_label, TRUE, TRUE, 0);
416 gtk_widget_show(program_submenu_label);
417 gtk_widget_show(box);
419 gtk_menu_append(GTK_MENU(prog_menu), program_submenu_item);
420 gtk_widget_show(program_submenu_item);
422 program_submenu_menu=gtk_menu_new();
423 gtk_menu_item_set_submenu(GTK_MENU_ITEM(program_submenu_item), program_submenu_menu);
426 snprintf(str,63,"%s - %s",first_menu_name,v->name);
427 gtk_label_set_text(GTK_LABEL(program_submenu_label), str);
431 program_subitem_index++;
433 program_menu_item=gtk_menu_item_new_with_label(v->name);
434 SIGNAL_CONNECT(program_menu_item, "activate", dcerpcstat_program_select, k);
436 gtk_widget_show(program_menu_item);
437 gtk_menu_append(GTK_MENU(program_submenu_menu), program_menu_item);
439 if(!dcerpc_uuid_program){
440 dcerpc_uuid_program=&k->uuid;
447 dcerpcstat_find_next_program(gpointer *key, gpointer *value, gpointer *user_data _U_)
449 dcerpc_uuid_key *k=(dcerpc_uuid_key *)key;
450 dcerpc_uuid_value *v=(dcerpc_uuid_value *)value;
452 /* first time called, just set new_uuid to this one */
453 if((current_uuid_key==NULL)&&(new_uuid_key==NULL)){
459 /* if we havent got a current one yet, just check the new
460 and scan for the first one alphabetically */
461 if(current_uuid_key==NULL){
462 if(strcmp(new_uuid_value->name, v->name)>0){
470 /* searching for the next one we are only interested in those
471 that sorts alphabetically after the current one */
472 if(strcmp(current_uuid_value->name, v->name)>=0){
473 /* this one doesnt so just skip it */
477 /* is it the first potential new entry? */
478 if(new_uuid_key==NULL){
484 /* does it sort before the current new one? */
485 if(strcmp(new_uuid_value->name, v->name)>0){
503 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
505 gtk_widget_destroy(GTK_WIDGET(parent_w));
510 gtk_dcerpcstat_cb(GtkWidget *w _U_, gpointer d _U_)
513 GtkWidget *prog_box, *prog_label, *prog_opt;
514 GtkWidget *vers_label;
515 GtkWidget *filter_box, *filter_bt;
516 GtkWidget *bbox, *start_button, *cancel_button;
518 static construct_args_t args = {
519 "Service Response Time Statistics Filter",
524 /* if the window is already open, bring it to front and
525 un-minimize it, as necessary */
527 reactivate_window(dlg);
531 dlg=dlg_window_new("Ethereal: Compute DCE-RPC SRT statistics");
532 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
534 dlg_box=gtk_vbox_new(FALSE, 10);
535 gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
536 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
537 gtk_widget_show(dlg_box);
540 prog_box=gtk_hbox_new(FALSE, 3);
543 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
544 prog_label=gtk_label_new("Program:");
545 gtk_box_pack_start(GTK_BOX(prog_box), prog_label, FALSE, FALSE, 0);
546 gtk_widget_show(prog_label);
549 prog_opt=gtk_option_menu_new();
550 prog_menu=gtk_menu_new();
551 current_uuid_key=NULL;
552 current_uuid_value=NULL;
554 program_submenu_item=NULL;
555 program_submenu_menu=NULL;
556 program_subitem_index=0;
560 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_next_program, NULL);
562 dcerpcstat_add_program_to_menu(new_uuid_key, new_uuid_value);
564 current_uuid_key=new_uuid_key;
565 current_uuid_value=new_uuid_value;
566 } while(new_uuid_key!=NULL);
568 gtk_option_menu_set_menu(GTK_OPTION_MENU(prog_opt), prog_menu);
569 gtk_box_pack_start(GTK_BOX(prog_box), prog_opt, TRUE, TRUE, 0);
570 gtk_widget_show(prog_opt);
573 gtk_container_set_border_width(GTK_CONTAINER(prog_box), 10);
574 vers_label=gtk_label_new("Version:");
575 gtk_box_pack_start(GTK_BOX(prog_box), vers_label, FALSE, FALSE, 0);
576 gtk_widget_show(vers_label);
579 vers_opt=gtk_option_menu_new();
580 vers_menu=gtk_menu_new();
581 dcerpc_version=0xffff;
582 g_hash_table_foreach(dcerpc_uuids, (GHFunc)dcerpcstat_find_vers, NULL);
583 gtk_option_menu_set_menu(GTK_OPTION_MENU(vers_opt), vers_menu);
584 gtk_box_pack_start(GTK_BOX(prog_box), vers_opt, TRUE, TRUE, 0);
585 gtk_widget_show(vers_opt);
587 gtk_box_pack_start(GTK_BOX(dlg_box), prog_box, TRUE, TRUE, 0);
588 gtk_widget_show(prog_box);
591 filter_box=gtk_hbox_new(FALSE, 3);
594 filter_bt=gtk_button_new_with_label("Filter:");
595 SIGNAL_CONNECT(filter_bt, "clicked", display_filter_construct_cb, &args);
596 gtk_box_pack_start(GTK_BOX(filter_box), filter_bt, FALSE, FALSE, 0);
597 gtk_widget_show(filter_bt);
600 filter_entry=gtk_entry_new();
601 gtk_widget_set_usize(filter_entry, 300, -2);
604 filter_entry=gtk_entry_new();
605 gtk_widget_set_usize(filter_entry, 300, -2);
607 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
608 filter=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
610 gtk_entry_set_text(GTK_ENTRY(filter_entry), filter);
612 gtk_widget_show(filter_entry);
614 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
615 gtk_widget_show(filter_box);
618 bbox=gtk_hbutton_box_new();
619 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_DEFAULT_STYLE);
620 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
621 gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
622 gtk_widget_show(bbox);
624 /* the start button */
625 start_button=gtk_button_new_with_label("Create Stat");
626 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
627 dcerpcstat_start_button_clicked, NULL);
628 gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
629 GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
630 gtk_widget_grab_default(start_button);
631 gtk_widget_show(start_button);
633 #if GTK_MAJOR_VERSION < 2
634 cancel_button=gtk_button_new_with_label("Cancel");
636 cancel_button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
638 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
639 GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
640 gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
641 gtk_widget_show(cancel_button);
643 /* Catch the "activate" signal on the filter text entry, so that
644 if the user types Return there, we act as if the "Create Stat"
645 button had been selected, as happens if Return is typed if some
646 widget that *doesn't* handle the Return key has the input
648 dlg_set_activate(filter_entry, start_button);
650 /* Catch the "key_press_event" signal in the window, so that we can
651 catch the ESC key being pressed and act as if the "Cancel" button
652 had been selected. */
653 dlg_set_cancel(dlg, cancel_button);
655 /* Give the initial focus to the "Filter" entry box. */
656 gtk_widget_grab_focus(filter_entry);
658 gtk_widget_show_all(dlg);
662 register_tap_listener_gtkdcerpcstat(void)
664 register_ethereal_tap("dcerpc,srt,", gtk_dcerpcstat_init);
668 register_tap_menu_gtkdcerpcstat(void)
670 register_tap_menu_item("Statistics/Service Response Time/DCE-RPC...",
671 gtk_dcerpcstat_cb, NULL, NULL);