2 * Routines for packet capture info dialog
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include <epan/packet.h>
35 #include "../capture.h"
36 #include "../capture_info.h"
37 #include "../capture_ui_utils.h"
38 #include "../capture-pcap-util.h"
40 #include "ui/gtk/dlg_utils.h"
41 #include "ui/gtk/gui_utils.h"
42 #include "ui/gtk/main.h"
43 #include "ui/gtk/help_dlg.h"
44 #include "ui/gtk/stock_icons.h"
48 #include "airpcap_loader.h"
49 #include "airpcap_gui_utils.h"
50 #include "airpcap_dlg.h"
54 /* a single capture counter value (with title, pointer to value and GtkWidgets) */
55 /* as the packet_counts is a struct, not an array, keep a pointer to the */
56 /* corresponding value packet_counts, to speed up (and simplify) output of values */
60 GtkWidget
*label
, *value_lb
, *percent_pb
, *percent_lb
;
61 } capture_info_counts_t
;
63 /* all data we need to know of this dialog, after creation finished */
66 GtkWidget
*running_time_lb
;
67 capture_info_counts_t counts
[PACKET_COUNTS_SIZE
];
73 /* Workhorse for stopping capture */
75 capture_info_stop(capture_session
*cap_session
)
78 airpcap_set_toolbar_stop_capture(airpcap_if_active
);
80 capture_stop(cap_session
);
83 /* "delete-event" signal callback. Note different signature than "clicked" signal callback */
85 capture_info_delete_cb(GtkWidget
*w _U_
, GdkEvent
*event _U_
, gpointer data
) {
86 capture_info_stop((capture_session
*)data
);
90 /* "clicked" signal callback */
92 capture_info_stop_clicked_cb(GtkButton
*w _U_
, gpointer data
) {
93 capture_info_stop((capture_session
*)data
);
97 capture_info_ui_update_cb(gpointer data
)
99 capture_info
*cinfo
= (capture_info
*)data
;
100 capture_info_ui_t
*info
= (capture_info_ui_t
*)cinfo
->ui
;
102 if (!info
) /* ...which might happen on slow displays? */
105 cinfo
->running_time
= time(NULL
) - info
->start_time
;
106 capture_info_ui_update(cinfo
);
107 return TRUE
; /* call the timer again */
111 /* create the capture info dialog */
112 /* will keep pointers to the fields in the counts parameter */
114 capture_info_ui_create(capture_info
*cinfo
, capture_session
*cap_session
)
116 capture_options
*capture_opts
= cap_session
->capture_opts
;
118 GtkWidget
*main_vb
, *stop_bt
, *counts_grid
;
119 GtkWidget
*counts_fr
, *running_grid
, *running_label
, *lb
, *bbox
, *ci_help
;
120 capture_info_ui_t
*info
;
126 info
= g_new0(capture_info_ui_t
,1);
127 info
->counts
[0].title
= "Total";
128 info
->counts
[0].value_ptr
= &(cinfo
->counts
->total
);
129 info
->counts
[1].title
= "SCTP";
130 info
->counts
[1].value_ptr
= &(cinfo
->counts
->sctp
);
131 info
->counts
[2].title
= "TCP";
132 info
->counts
[2].value_ptr
= &(cinfo
->counts
->tcp
);
133 info
->counts
[3].title
= "UDP";
134 info
->counts
[3].value_ptr
= &(cinfo
->counts
->udp
);
135 info
->counts
[4].title
= "ICMP";
136 info
->counts
[4].value_ptr
= &(cinfo
->counts
->icmp
);
137 info
->counts
[5].title
= "ARP";
138 info
->counts
[5].value_ptr
= &(cinfo
->counts
->arp
);
139 info
->counts
[6].title
= "OSPF";
140 info
->counts
[6].value_ptr
= &(cinfo
->counts
->ospf
);
141 info
->counts
[7].title
= "GRE";
142 info
->counts
[7].value_ptr
= &(cinfo
->counts
->gre
);
143 info
->counts
[8].title
= "NetBIOS";
144 info
->counts
[8].value_ptr
= &(cinfo
->counts
->netbios
);
145 info
->counts
[9].title
= "IPX";
146 info
->counts
[9].value_ptr
= &(cinfo
->counts
->ipx
);
147 info
->counts
[10].title
= "VINES";
148 info
->counts
[10].value_ptr
= &(cinfo
->counts
->vines
);
149 info
->counts
[11].title
= "Other";
150 info
->counts
[11].value_ptr
= &(cinfo
->counts
->other
);
151 info
->counts
[12].title
= "I2C Events";
152 info
->counts
[12].value_ptr
= &(cinfo
->counts
->i2c_event
);
153 info
->counts
[13].title
= "I2C Data";
154 info
->counts
[13].value_ptr
= &(cinfo
->counts
->i2c_data
);
157 * Create the dialog window, with a title that includes the interface.
159 * If we have a descriptive name for the interface, show that,
160 * rather than its raw name. On NT 5.x (2K/XP/Server2K3), the
161 * interface name is something like "\Device\NPF_{242423..."
162 * which is pretty useless to the normal user. On other platforms,
163 * it might be less cryptic, but if a more descriptive name is
164 * available, we should still use that.
166 str
= g_string_new("");
168 if (capture_opts
->ifaces
->len
< 2)
170 if (capture_opts
->ifaces
->len
< 4)
173 for (i
= 0; i
< capture_opts
->ifaces
->len
; i
++) {
174 interface_options interface_opts
;
176 interface_opts
= g_array_index(capture_opts
->ifaces
, interface_options
, i
);
177 descr
= get_interface_descriptive_name(interface_opts
.name
);
179 if (capture_opts
->ifaces
->len
> 2) {
180 g_string_append_printf(str
, ",");
182 g_string_append_printf(str
, " ");
183 if (i
== capture_opts
->ifaces
->len
- 1) {
184 g_string_append_printf(str
, "and ");
187 g_string_append_printf(str
, "%s", descr
);
191 g_string_append_printf(str
, "%u interfaces", capture_opts
->ifaces
->len
);
193 title_iface
= g_strdup_printf("Wireshark: Capture from %s", str
->str
);
194 g_string_free(str
, TRUE
);
195 cap_w_title
= create_user_window_title(title_iface
);
197 info
->cap_w
= dlg_window_new(cap_w_title
);
200 /* Container for capture display widgets */
201 main_vb
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 1, FALSE
);
202 gtk_container_set_border_width(GTK_CONTAINER(main_vb
), 5);
203 gtk_container_add(GTK_CONTAINER(info
->cap_w
), main_vb
);
204 gtk_widget_show(main_vb
);
206 counts_fr
= gtk_frame_new("Captured Packets");
207 gtk_box_pack_start(GTK_BOX(main_vb
), counts_fr
, FALSE
, FALSE
, 3);
208 gtk_widget_show(counts_fr
);
210 /* Individual statistic elements */
211 counts_grid
= ws_gtk_grid_new();
212 ws_gtk_grid_set_homogeneous(GTK_GRID(counts_grid
), TRUE
);
213 gtk_container_add(GTK_CONTAINER(counts_fr
), counts_grid
);
214 gtk_container_set_border_width(GTK_CONTAINER(counts_grid
), 5);
215 gtk_widget_show(counts_grid
);
217 ws_gtk_grid_set_row_spacing(GTK_GRID(counts_grid
), 0);
218 ws_gtk_grid_set_column_spacing(GTK_GRID(counts_grid
), 5);
220 for (i
= 0; i
< PACKET_COUNTS_SIZE
; i
++) {
221 info
->counts
[i
].label
= gtk_label_new(info
->counts
[i
].title
);
222 gtk_misc_set_alignment(GTK_MISC(info
->counts
[i
].label
), 0.0f
, 0.5f
);
224 info
->counts
[i
].value_lb
= gtk_label_new("0");
225 gtk_misc_set_alignment(GTK_MISC(info
->counts
[i
].value_lb
), 0.5f
, 0.5f
);
228 /* do not build a progress bar for the "total" row */
229 /* (as this could suggest a "buffer full" to the user) */
230 /* simply put a label here */
231 info
->counts
[i
].percent_pb
= gtk_label_new("% of total");
233 /* build a progress bar in the other rows */
234 info
->counts
[i
].percent_pb
= gtk_progress_bar_new();
236 /* downsize the default size of this progress bar in x direction (def:150), */
237 /* otherwise it will become too large and the dialog will look ugly */
238 /* XXX: use a TreeView instead of a grid in order to fix this */
239 gtk_widget_set_size_request(info
->counts
[i
].percent_pb
, 70, -1);
242 info
->counts
[i
].percent_lb
= gtk_label_new("0.0%");
243 gtk_misc_set_alignment(GTK_MISC(info
->counts
[i
].percent_lb
), 1.0f
, 0.5f
);
245 ws_gtk_grid_attach_extended(GTK_GRID(counts_grid
), info
->counts
[i
].label
,
246 0, i
, 1, 1, (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), (GtkAttachOptions
)0, 0, 0);
247 ws_gtk_grid_attach_extended(GTK_GRID(counts_grid
), info
->counts
[i
].value_lb
,
248 1, i
, 1, 1, (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), (GtkAttachOptions
)0, 0, 0);
249 ws_gtk_grid_attach_extended(GTK_GRID(counts_grid
), info
->counts
[i
].percent_pb
,
250 2, i
, 1, 1, (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), (GtkAttachOptions
)0, 0, 0);
251 ws_gtk_grid_attach_extended(GTK_GRID(counts_grid
), info
->counts
[i
].percent_lb
,
252 3, i
, 1, 1, (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), (GtkAttachOptions
)0, 0, 0);
254 gtk_widget_show(info
->counts
[i
].label
);
255 gtk_widget_show(info
->counts
[i
].value_lb
);
256 gtk_widget_show(info
->counts
[i
].percent_pb
);
257 /* don't show percentages for the "total" row */
259 gtk_widget_show(info
->counts
[i
].percent_lb
);
264 running_grid
= ws_gtk_grid_new();
265 ws_gtk_grid_set_homogeneous(GTK_GRID(running_grid
), TRUE
);
267 running_label
= gtk_label_new("Running");
268 gtk_misc_set_alignment(GTK_MISC(running_label
), 0.0f
, 0.0f
);
269 gtk_widget_show(running_label
);
270 ws_gtk_grid_attach_extended(GTK_GRID(running_grid
), running_label
,
271 0, 0, 1, 1, (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), (GtkAttachOptions
)0, 0, 0);
273 info
->running_time_lb
= gtk_label_new("00:00:00");
274 gtk_misc_set_alignment(GTK_MISC(info
->running_time_lb
), 0.5f
, 0.0f
);
275 gtk_widget_show(info
->running_time_lb
);
276 ws_gtk_grid_attach_extended(GTK_GRID(running_grid
), info
->running_time_lb
,
277 1, 0, 1, 1, (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), (GtkAttachOptions
)0, 5, 0); /* effect: pads *all* the columns ?? */
279 /* two dummy cols to match the 4 cols above */
280 lb
= gtk_label_new("");
282 ws_gtk_grid_attach_extended(GTK_GRID(running_grid
), lb
,
283 2, 0, 1, 1, (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), (GtkAttachOptions
)0, 0, 0);
284 lb
= gtk_label_new("");
286 ws_gtk_grid_attach_extended(GTK_GRID(running_grid
), lb
,
287 3, 0, 1, 1, (GtkAttachOptions
)(GTK_EXPAND
|GTK_FILL
), (GtkAttachOptions
)0, 0, 0);
289 gtk_box_pack_start(GTK_BOX(main_vb
), running_grid
, FALSE
, FALSE
, 3);
290 gtk_widget_show(running_grid
);
292 /* allow user to either click a stop button, or the close button on
293 the window to stop a capture in progress. */
294 bbox
= dlg_button_row_new(WIRESHARK_STOCK_CAPTURE_STOP
, GTK_STOCK_HELP
, NULL
);
295 gtk_box_pack_start(GTK_BOX(main_vb
), bbox
, FALSE
, FALSE
, 3);
296 gtk_widget_show(bbox
);
298 stop_bt
= (GtkWidget
*)g_object_get_data(G_OBJECT(bbox
), WIRESHARK_STOCK_CAPTURE_STOP
);
299 window_set_cancel_button(info
->cap_w
, stop_bt
, NULL
);
300 g_signal_connect(stop_bt
, "clicked", G_CALLBACK(capture_info_stop_clicked_cb
), cap_session
);
301 g_signal_connect(info
->cap_w
, "delete_event", G_CALLBACK(capture_info_delete_cb
), cap_session
);
303 ci_help
= (GtkWidget
*)g_object_get_data(G_OBJECT(bbox
), GTK_STOCK_HELP
);
304 gtk_widget_set_tooltip_text(ci_help
, "Get help about this dialog");
305 g_signal_connect(ci_help
, "clicked", G_CALLBACK(topic_cb
), (gpointer
)HELP_CAPTURE_INFO_DIALOG
);
307 gtk_widget_show(info
->cap_w
);
308 window_present(info
->cap_w
);
310 info
->start_time
= time(NULL
);
314 /* update the dialog once a second, even if no packets rushing in */
315 info
->timer_id
= g_timeout_add(1000, capture_info_ui_update_cb
,cinfo
);
319 /* update the capture info dialog */
320 /* As this function is a bit time critical while capturing, */
321 /* prepare everything possible in the capture_info_ui_create() function above! */
322 void capture_info_ui_update(
327 capture_info_ui_t
*info
= (capture_info_ui_t
*)cinfo
->ui
;
329 if (!info
) /* ...which might happen on slow displays? */
332 /* display running time */
333 g_snprintf(label_str
, sizeof(label_str
), "%02ld:%02ld:%02ld",
334 (long)(cinfo
->running_time
/3600), (long)((cinfo
->running_time
%3600)/60),
335 (long)(cinfo
->running_time
%60));
336 gtk_label_set_text(GTK_LABEL(info
->running_time_lb
), label_str
);
338 /* if we have new packets, update all rows */
339 if (cinfo
->new_packets
) {
341 for (i
= 0; i
< PACKET_COUNTS_SIZE
; i
++) {
342 g_snprintf(label_str
, sizeof(label_str
), "%d", *info
->counts
[i
].value_ptr
);
343 gtk_label_set_text(GTK_LABEL(info
->counts
[i
].value_lb
), label_str
);
345 pb_frac
= (*info
->counts
[0].value_ptr
!= 0) ?
346 ((float)*info
->counts
[i
].value_ptr
/ *info
->counts
[0].value_ptr
) : 0.0f
;
348 /* don't try to update the "total" row progress bar */
350 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(info
->counts
[i
].percent_pb
), pb_frac
);
351 g_snprintf(label_str
, sizeof(label_str
), "%.1f%%", pb_frac
* 100.0);
352 gtk_label_set_text(GTK_LABEL(info
->counts
[i
].percent_lb
), label_str
);
358 /* destroy the capture info dialog again */
359 void capture_info_ui_destroy(
362 capture_info_ui_t
*info
= (capture_info_ui_t
*)cinfo
->ui
;
364 if (!info
) /* ...which probably shouldn't happen */
367 g_source_remove(info
->timer_id
);
369 /* called from capture engine, so it's ok to destroy the dialog here */
370 gtk_grab_remove(GTK_WIDGET(info
->cap_w
));
371 window_destroy(GTK_WIDGET(info
->cap_w
));
377 #endif /* HAVE_LIBPCAP */