2 * boop_stat 2003 Jean-Michel FAYARD
4 * $Id: bootp_stat.c,v 1.9 2003/12/17 22:13:06 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 /* #define DEBUG do{ printf("%s:%d ",__FILE__,__LINE__);} while(0); */
34 #include "epan/packet_info.h"
35 #include "epan/epan.h"
37 #include "simple_dialog.h"
38 #include "dlg_utils.h"
40 #include "../register.h"
41 #include "../globals.h"
42 #include "compat_macros.h"
44 typedef const char* bootp_info_value_t;
46 /* used to keep track of the statictics for an entire program interface */
47 typedef struct _dhcp_stats_t {
51 GtkWidget *table_message_type;
52 guint index; /* Number of to display */
54 /* used to keep track of a single DHCP message type */
55 typedef struct _dhcp_message_type_t {
58 GtkWidget *widget;/* label in which we print the number of packets */
59 dhcpstat_t *sp; /* entire program interface */
60 } dhcp_message_type_t;
62 static GtkWidget *dlg=NULL;
63 static GtkWidget *filter_entry;
66 dhcp_free_hash( gpointer key _U_ , gpointer value, gpointer user_data _U_ )
71 dhcp_reset_hash(gchar *key _U_ , dhcp_message_type_t *data, gpointer ptr _U_ )
76 /* Update the entry corresponding to the number of packets of a special DHCP Message Type
77 * or create it if it don't exist.
80 dhcp_draw_message_type(gchar *key _U_, dhcp_message_type_t *data, gchar * string_buff )
82 if ((data==NULL) || (data->packets==0))
84 if (data->widget==NULL){ /* create an entry in the table */
86 int x = 2*((data->sp->index) % 2);
87 int y = (data->sp->index) /2;
90 /* Maybe we should display the hexadecimal value ? */
91 /* sprintf(string_buff, "%s (0X%x)", data->name, *key); */
92 tmp = gtk_label_new( data->name /* string_buff */ );
93 gtk_table_attach_defaults(GTK_TABLE(data->sp->table_message_type), tmp, x, x+1, y, y+1);
94 gtk_label_set_justify(GTK_LABEL(tmp), GTK_JUSTIFY_LEFT);
97 sprintf( string_buff, "%9d", data->packets );
98 data->widget = gtk_label_new( string_buff );
99 gtk_table_attach_defaults(GTK_TABLE(data->sp->table_message_type), data->widget, x+1, x+2, y, y+1);
100 gtk_label_set_justify(GTK_LABEL(data->widget), GTK_JUSTIFY_LEFT);
101 gtk_widget_show( data->widget );
105 /* Just update the label string */
106 sprintf( string_buff, "%9d", data->packets );
107 gtk_label_set( GTK_LABEL(data->widget), string_buff);
111 dhcpstat_reset(void *psp)
114 g_hash_table_foreach( sp->hash, (GHFunc)dhcp_reset_hash, NULL);
117 dhcpstat_packet(void *psp, packet_info *pinfo _U_, epan_dissect_t *edt _U_, void *pri)
120 bootp_info_value_t value=pri;
121 dhcp_message_type_t *sc;
125 sc = g_hash_table_lookup(
129 /*g_warning("%s:%d What's Wrong for %s, doc ?", __FILE__, __LINE__, value);*/
130 sc = g_malloc( sizeof(dhcp_message_type_t) );
140 /*g_warning("sc(%s)->packets++", sc->name);*/
148 dhcpstat_draw(void *psp)
155 g_hash_table_foreach( sp->hash, (GHFunc) dhcp_draw_message_type, str );
156 if (index != sp->index){
157 /* We have inserted a new entry corresponding to a status code ,
158 * let's resize the table */
159 gtk_table_resize ( GTK_TABLE(sp->table_message_type), sp->index % 2 , 4);
166 /* since the gtk2 implementation of tap is multithreaded we must protect
167 * remove_tap_listener() from modifying the list while draw_tap_listener()
168 * is running. the other protected block is in main.c
170 * there should not be any other critical regions in gtk2
172 void protect_thread_critical_region(void);
173 void unprotect_thread_critical_region(void);
175 win_destroy_cb(GtkWindow *win _U_, gpointer data)
177 dhcpstat_t *sp=(dhcpstat_t *)data;
179 protect_thread_critical_region();
180 remove_tap_listener(sp);
181 unprotect_thread_critical_region();
184 g_hash_table_foreach( sp->hash, (GHFunc)dhcp_free_hash, NULL);
185 g_hash_table_destroy( sp->hash);
191 /* When called, this function will create a new instance of gtk2-dhcpstat.
194 gtk_dhcpstat_init(char *optarg)
199 GString *error_string;
200 GtkWidget *message_type_fr;
202 if (!strncmp (optarg, "bootp,stat,", 11)){
208 sp = g_malloc( sizeof(dhcpstat_t) );
209 sp->hash = g_hash_table_new( g_str_hash, g_str_equal);
211 sp->filter=g_malloc(strlen(filter)+1);
212 strcpy(sp->filter,filter);
213 title=g_strdup_printf("DHCP statistics with filter: %s", filter);
216 title=g_strdup("DHCP statistics");
219 /* top level window */
220 sp->win = gtk_window_new( GTK_WINDOW_TOPLEVEL);
221 gtk_window_set_title( GTK_WINDOW(sp->win), title );
223 SIGNAL_CONNECT( sp->win, "destroy", win_destroy_cb, sp);
225 /* Status Codes frame */
226 message_type_fr = gtk_frame_new("DHCP Message Type");
227 gtk_container_add(GTK_CONTAINER(sp->win), message_type_fr);
228 gtk_widget_show(message_type_fr);
230 sp->table_message_type = gtk_table_new( 0, 4, FALSE);
231 gtk_table_set_col_spacings( GTK_TABLE(sp->table_message_type), 10);
232 gtk_container_add( GTK_CONTAINER( message_type_fr), sp->table_message_type);
233 gtk_container_set_border_width( GTK_CONTAINER(sp->table_message_type) , 10);
234 sp->index = 0; /* Nothing to display yet */
237 error_string = register_tap_listener(
245 /* error, we failed to attach to the tap. clean up */
246 simple_dialog( ESD_TYPE_WARN, NULL, error_string->str );
249 g_string_free(error_string, TRUE);
253 gtk_widget_destroy( dlg );
255 gtk_widget_show_all( sp->win );
256 redissect_packets(&cfile);
262 dhcp_start_button_clicked(GtkWidget *item _U_, gpointer data _U_)
267 str = g_string_new("dhcp,stat,");
268 filter=(char *)gtk_entry_get_text(GTK_ENTRY(filter_entry));
269 str = g_string_append(str, filter);
270 gtk_dhcpstat_init(str->str);
271 g_string_free(str, TRUE);
281 dlg_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
283 gtk_widget_destroy(GTK_WIDGET(parent_w));
287 gtk_dhcpstat_cb(GtkWidget *w _U_, gpointer d _U_)
290 GtkWidget *filter_box, *filter_label;
291 GtkWidget *bbox, *start_button, *cancel_button;
293 /* if the window is already open, bring it to front */
295 gdk_window_raise(dlg->window);
299 dlg=dlg_window_new("Ethereal: Compute DHCP statistics");
300 SIGNAL_CONNECT(dlg, "destroy", dlg_destroy_cb, NULL);
302 dlg_box=gtk_vbox_new(FALSE, 10);
303 gtk_container_border_width(GTK_CONTAINER(dlg_box), 10);
304 gtk_container_add(GTK_CONTAINER(dlg), dlg_box);
305 gtk_widget_show(dlg_box);
308 filter_box=gtk_hbox_new(FALSE, 3);
311 filter_label=gtk_label_new("Filter:");
312 gtk_box_pack_start(GTK_BOX(filter_box), filter_label, FALSE, FALSE, 0);
313 gtk_widget_show(filter_label);
316 filter_entry=gtk_entry_new();
317 WIDGET_SET_SIZE(filter_entry, 300, -2);
318 gtk_box_pack_start(GTK_BOX(filter_box), filter_entry, TRUE, TRUE, 0);
319 gtk_widget_show(filter_entry);
321 gtk_box_pack_start(GTK_BOX(dlg_box), filter_box, TRUE, TRUE, 0);
322 gtk_widget_show(filter_box);
325 bbox = gtk_hbutton_box_new();
326 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_DEFAULT_STYLE);
327 gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
328 gtk_box_pack_start(GTK_BOX(dlg_box), bbox, FALSE, FALSE, 0);
329 gtk_widget_show(bbox);
331 /* the start button */
332 start_button=gtk_button_new_with_label("Create Stat");
333 SIGNAL_CONNECT_OBJECT(start_button, "clicked",
334 dhcp_start_button_clicked, NULL);
335 gtk_box_pack_start(GTK_BOX(bbox), start_button, TRUE, TRUE, 0);
336 GTK_WIDGET_SET_FLAGS(start_button, GTK_CAN_DEFAULT);
337 gtk_widget_grab_default(start_button);
338 gtk_widget_show(start_button);
340 #if GTK_MAJOR_VERSION < 2
341 cancel_button=gtk_button_new_with_label("Cancel");
343 cancel_button=gtk_button_new_from_stock(GTK_STOCK_CANCEL);
345 SIGNAL_CONNECT(cancel_button, "clicked", dlg_cancel_cb, dlg);
346 GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
347 gtk_box_pack_start(GTK_BOX(bbox), cancel_button, TRUE, TRUE, 0);
348 gtk_widget_show(cancel_button);
350 /* Catch the "activate" signal on the filter text entry, so that
351 if the user types Return there, we act as if the "Create Stat"
352 button had been selected, as happens if Return is typed if
353 some widget that *doesn't* handle the Return key has the input
355 dlg_set_activate(filter_entry, start_button);
357 /* Catch the "key_press_event" signal in the window, so that we can
358 catch the ESC key being pressed and act as if the "Cancel" button
359 had been selected. */
360 dlg_set_cancel(dlg, cancel_button);
362 /* Give the initial focus to the "Filter" entry box. */
363 gtk_widget_grab_focus(filter_entry);
365 gtk_widget_show_all(dlg);
370 register_tap_listener_gtkdhcpstat(void)
372 register_ethereal_tap("bootp,stat,", gtk_dhcpstat_init);
376 register_tap_menu_gtkdhcpstat(void)
378 register_tap_menu_item("Statistics/Watch protocol/BOOTP-DHCP...",
379 gtk_dhcpstat_cb, NULL, NULL, NULL);