The arc function was only used to draw filled ellipses. Change code to
[obnox/wireshark/wip.git] / gtk / mcast_stream_dlg.c
1 /* mcast_stream_dlg.c
2  *
3  * Copyright 2006, Iskratel , Slovenia
4  * By Jakob Bratkovic <j.bratkovic@iskratel.si> and
5  * Miha Jemec <m.jemec@iskratel.si>
6  *
7  * $Id$
8  *
9  * based on rtp_stream_dlg.c
10  * Copyright 2003, Alcatel Business Systems
11  * By Lars Ruoff <lars.ruoff@gmx.net>
12  *
13  * Wireshark - Network traffic analyzer
14  * By Gerald Combs <gerald@wireshark.org>
15  * Copyright 1998 Gerald Combs
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation,  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #  include <config.h>
34 #endif
35
36 #include <string.h>
37 #include <locale.h>
38
39 #include "gtk/gtk.h"
40
41 #include "epan/filesystem.h"
42 #include <epan/address.h>
43 #include <epan/addr_resolv.h>
44 #include <epan/strutil.h>
45
46 #include "../globals.h"
47 #include "../stat_menu.h"
48 #include "../simple_dialog.h"
49
50 #include "gtk/mcast_stream_dlg.h"
51 #include "gtk/mcast_stream.h"
52 #include "gtk/gui_stat_menu.h"
53 #include "gtk/dlg_utils.h"
54 #include "gtk/gui_utils.h"
55 #include "gtk/gtkglobals.h"
56
57 /* Capture callback data keys */
58 #define E_MCAST_ENTRY_1     "burst_interval"
59 #define E_MCAST_ENTRY_2     "burst_alarm"
60 #define E_MCAST_ENTRY_3     "buffer_alarm"
61 #define E_MCAST_ENTRY_4     "stream_speed"
62 #define E_MCAST_ENTRY_5     "total_speed"
63
64 static const gchar FWD_LABEL_TEXT[] = "Select a stream with left mouse button";
65 static const gchar PAR_LABEL_TEXT[] = "\nBurst int: ms   Burst alarm: pps    Buffer alarm: KB    Stream empty speed: Mbps    Total empty speed: Mbps\n";
66
67 /****************************************************************************/
68 static GtkWidget *mcast_stream_dlg = NULL;
69 static GtkWidget *mcast_params_dlg = NULL;
70
71 static GtkListStore *list_store = NULL;
72 static GtkTreeIter list_iter;
73 static GtkWidget *list_w    = NULL;
74 static GtkWidget *top_label = NULL;
75 static GtkWidget *label_fwd = NULL;
76 static GtkWidget *label_par = NULL;
77 static GtkWidget *bt_filter = NULL;
78
79 static mcast_stream_info_t* selected_stream_fwd = NULL;  /* current selection */
80 static GList *last_list = NULL;
81
82 static guint32 streams_nb = 0;     /* number of displayed streams */
83
84 enum
85 {
86         MC_COL_SRC_ADDR,
87         MC_COL_SRC_PORT,
88         MC_COL_DST_ADDR,
89         MC_COL_DST_PORT,
90         MC_COL_PACKETS,
91         MC_COL_PPS,
92         MC_COL_AVG_BW,
93         MC_COL_MAX_BW,
94         MC_COL_MAX_BURST,
95         MC_COL_BURST_ALARM,
96         MC_COL_MAX_BUFFER,
97         MC_COL_BUFFER_ALARM,
98         MC_COL_DATA,
99         NUM_COLS /* The number of columns */
100 };
101
102 /****************************************************************************/
103 /* CALLBACKS                                                                */
104 /****************************************************************************/
105 static void
106 mcaststream_on_destroy(GObject *object _U_, gpointer user_data _U_)
107 {
108         /* Remove the stream tap listener */
109         remove_tap_listener_mcast_stream();
110
111         /* Is there a params window open? */
112         if (mcast_params_dlg != NULL)
113                 window_destroy(mcast_params_dlg);
114
115         /* Clean up memory used by stream tap */
116         mcaststream_reset((mcaststream_tapinfo_t*)mcaststream_get_info());
117
118         /* Note that we no longer have a "Mcast Streams" dialog box. */
119         mcast_stream_dlg = NULL;
120 }
121
122
123 /****************************************************************************/
124 static void
125 mcaststream_on_unselect(GtkButton *button _U_, gpointer user_data _U_)
126 {
127         GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_w));
128         gtk_tree_selection_unselect_all(selection);
129
130         selected_stream_fwd = NULL;
131         gtk_label_set_text(GTK_LABEL(label_fwd), FWD_LABEL_TEXT);
132         gtk_widget_set_sensitive(bt_filter, FALSE);
133 }
134
135
136 /****************************************************************************/
137 static void
138 mcaststream_on_filter(GtkButton *button _U_, gpointer user_data _U_)
139 {
140         gchar *filter_string_fwd = NULL;
141         gchar ip_version[3];
142
143         if (selected_stream_fwd==NULL)
144                 return;
145
146         if (selected_stream_fwd->src_addr.type==AT_IPv6){
147                 g_strlcpy(ip_version,"v6",sizeof(ip_version));
148         } else {
149                 ip_version[0] = '\0';
150         }
151         filter_string_fwd = g_strdup_printf(
152                 "(ip%s.src==%s && udp.srcport==%u && ip%s.dst==%s && udp.dstport==%u)",
153                 ip_version,
154                 ep_address_to_str(&(selected_stream_fwd->src_addr)),
155                 selected_stream_fwd->src_port,
156                 ip_version,
157                 ep_address_to_str(&(selected_stream_fwd->dest_addr)),
158                 selected_stream_fwd->dest_port);
159
160         gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), filter_string_fwd);
161         g_free(filter_string_fwd);
162
163 /*
164         main_filter_packets(&cfile, filter_string, FALSE);
165         mcaststream_dlg_update(mcaststream_get_info()->strinfo_list);
166 */
167 }
168
169 /****************************************************************************/
170 /* when the user selects a row in the stream list */
171 static void
172 mcaststream_on_select_row(GtkTreeSelection *selection, gpointer data _U_)
173 {
174         gchar label_text[80];
175
176         if (gtk_tree_selection_get_selected(selection, NULL, &list_iter))
177         {
178                 gtk_tree_model_get(GTK_TREE_MODEL(list_store), &list_iter, MC_COL_DATA, &selected_stream_fwd, -1);
179                 g_snprintf(label_text, sizeof(label_text), "Selected: %s:%u -> %s:%u",
180                         get_addr_name(&(selected_stream_fwd->src_addr)),
181                         selected_stream_fwd->src_port,
182                         get_addr_name(&(selected_stream_fwd->dest_addr)),
183                         selected_stream_fwd->dest_port
184                 );
185                 gtk_label_set_text(GTK_LABEL(label_fwd), label_text);
186                 gtk_widget_set_sensitive(bt_filter, TRUE);
187         } else {
188                 selected_stream_fwd = NULL;
189                 gtk_label_set_text(GTK_LABEL(label_fwd), FWD_LABEL_TEXT);
190                 gtk_widget_set_sensitive(bt_filter, FALSE);
191         }
192 }
193
194
195 /****************************************************************************/
196 /* INTERFACE                                                                */
197 /****************************************************************************/
198 static void
199 mcast_params_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
200 {
201         /* Note that we no longer have a mcast params dialog box. */
202         mcast_params_dlg = NULL;
203 }
204
205
206 static void
207 mcast_params_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
208 {
209         GtkWidget   *fnumber_te;
210         const gchar *fnumber_text;
211         gint32       fnumber;
212         char        *p;
213
214         fnumber_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), E_MCAST_ENTRY_1);
215         fnumber_text = gtk_entry_get_text(GTK_ENTRY(fnumber_te));
216         fnumber = strtoul(fnumber_text, &p, 10);
217         if ( (p == fnumber_text || *p != '\0') || (fnumber <= 0) || (fnumber > 1000) ) {
218                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "The burst interval should be between 1 and 1000 ms.");
219                 return;
220         }
221         mcast_stream_burstint = fnumber;
222
223         fnumber_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), E_MCAST_ENTRY_2);
224         fnumber_text = gtk_entry_get_text(GTK_ENTRY(fnumber_te));
225         fnumber = strtoul(fnumber_text, &p, 10);
226         if ( (p == fnumber_text || *p != '\0') || (fnumber <= 0) ) {
227                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "The burst alarm threshold you entered isn't valid.");
228                 return;
229         }
230         mcast_stream_trigger = fnumber;
231
232         fnumber_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), E_MCAST_ENTRY_3);
233         fnumber_text = gtk_entry_get_text(GTK_ENTRY(fnumber_te));
234         fnumber = strtoul(fnumber_text, &p, 10);
235         if ( (p == fnumber_text || *p != '\0') || (fnumber <= 0) ) {
236                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "The buffer alarm threshold you entered isn't valid.");
237                 return;
238         }
239         mcast_stream_bufferalarm = fnumber;
240
241         fnumber_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), E_MCAST_ENTRY_4);
242         fnumber_text = gtk_entry_get_text(GTK_ENTRY(fnumber_te));
243         fnumber = strtoul(fnumber_text, &p, 10);
244         if ( (p == fnumber_text || *p != '\0') || (fnumber <= 0) || (fnumber > 10000000) ) {
245                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "The stream empty speed should be between 1 and 10000000");
246                 return;
247         }
248         mcast_stream_emptyspeed = fnumber;
249
250         fnumber_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), E_MCAST_ENTRY_5);
251         fnumber_text = gtk_entry_get_text(GTK_ENTRY(fnumber_te));
252         fnumber = strtoul(fnumber_text, &p, 10);
253         if ( (p == fnumber_text || *p != '\0') || (fnumber <= 0) || (fnumber > 10000000) ) {
254                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "The total empty speed should be between 1 and 10000000");
255                 return;
256         }
257         mcast_stream_cumulemptyspeed = fnumber;
258
259         window_destroy(GTK_WIDGET(parent_w));
260
261         /* Clean up memory used by stream tap */
262         mcaststream_reset((mcaststream_tapinfo_t*)mcaststream_get_info());
263         /* retap all packets */
264         cf_retap_packets(&cfile);
265
266 }
267
268
269 static void
270 mcast_on_params(GtkButton *button _U_, gpointer data _U_)
271 {
272         GtkWidget *main_vb;
273         GtkWidget *label, *hbuttonbox, *table;
274         GtkWidget *ok_bt, *cancel_bt;
275         GtkWidget *entry1, *entry2, *entry3, *entry4, *entry5;
276         gchar label_text[51];
277
278         if (mcast_params_dlg != NULL) {
279                 /* There's already a Params dialog box; reactivate it. */
280                 reactivate_window(mcast_params_dlg);
281                 return;
282         }
283
284         mcast_params_dlg = dlg_window_new("Wireshark: Set parameters for Multicast Stream Analysis");
285         gtk_window_set_destroy_with_parent(GTK_WINDOW(mcast_params_dlg), TRUE);
286         gtk_window_set_default_size(GTK_WINDOW(mcast_params_dlg), 210, 210);
287
288         gtk_widget_show(mcast_params_dlg);
289
290         /* Container for each row of widgets */
291         main_vb = gtk_vbox_new(FALSE, 3);
292         gtk_container_set_border_width(GTK_CONTAINER(main_vb), 2);
293         gtk_container_add(GTK_CONTAINER(mcast_params_dlg), main_vb);
294         gtk_widget_show(main_vb);
295
296         table = gtk_table_new(6, 2, FALSE);
297         gtk_container_add (GTK_CONTAINER (main_vb), table);
298
299         label = gtk_label_new("  Burst measurement interval (ms)  ");
300         gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
301         entry1 = gtk_entry_new();
302         g_snprintf(label_text, sizeof(label_text), "%u", mcast_stream_burstint);
303         gtk_entry_set_text(GTK_ENTRY(entry1), label_text);
304         gtk_table_attach_defaults(GTK_TABLE(table), entry1, 1, 2, 0, 1);
305         label = gtk_label_new("  Burst alarm threshold (packets)   ");
306         gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
307         entry2 = gtk_entry_new();
308         g_snprintf(label_text, sizeof(label_text), "%u", mcast_stream_trigger);
309         gtk_entry_set_text(GTK_ENTRY(entry2), label_text);
310         gtk_table_attach_defaults(GTK_TABLE(table), entry2, 1, 2, 1, 2);
311         label = gtk_label_new("  Buffer alarm threshold (bytes)     ");
312         gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
313         entry3 = gtk_entry_new();
314         g_snprintf(label_text, sizeof(label_text), "%u", mcast_stream_bufferalarm);
315         gtk_entry_set_text(GTK_ENTRY(entry3), label_text);
316         gtk_table_attach_defaults(GTK_TABLE(table), entry3, 1, 2, 2, 3);
317         label = gtk_label_new("  Stream empty speed (kbit/s)      ");
318         gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 3, 4);
319         entry4 = gtk_entry_new();
320         g_snprintf(label_text, sizeof(label_text), "%u", mcast_stream_emptyspeed);
321         gtk_entry_set_text(GTK_ENTRY(entry4), label_text);
322         gtk_table_attach_defaults(GTK_TABLE(table), entry4, 1, 2, 3, 4);
323         label = gtk_label_new("  Total empty speed (kbit/s)       ");
324         gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 4, 5);
325         entry5 = gtk_entry_new();
326         g_snprintf(label_text, sizeof(label_text), "%u", mcast_stream_cumulemptyspeed);
327         gtk_entry_set_text(GTK_ENTRY(entry5), label_text);
328         gtk_table_attach_defaults(GTK_TABLE(table), entry5, 1, 2, 4, 5);
329
330         gtk_widget_show (table);
331
332         /* button row */
333         hbuttonbox = gtk_hbutton_box_new();
334         gtk_table_attach_defaults(GTK_TABLE(table), hbuttonbox, 0, 2, 5, 6);
335         ok_bt = gtk_button_new_from_stock(GTK_STOCK_OK);
336         gtk_container_add (GTK_CONTAINER(hbuttonbox), ok_bt);
337         cancel_bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
338         gtk_container_add (GTK_CONTAINER(hbuttonbox), cancel_bt);
339 #if GTK_CHECK_VERSION(2,18,0)
340         gtk_widget_set_can_default(cancel_bt, TRUE);
341 #else
342         GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
343 #endif
344         gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_END);
345         gtk_box_set_spacing(GTK_BOX(hbuttonbox), 0);
346
347         g_signal_connect(mcast_params_dlg, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
348         g_signal_connect(mcast_params_dlg, "destroy", G_CALLBACK(mcast_params_destroy_cb), NULL);
349         g_signal_connect(ok_bt, "clicked", G_CALLBACK(mcast_params_ok_cb), mcast_params_dlg);
350         window_set_cancel_button(mcast_params_dlg, cancel_bt, window_cancel_button_cb);
351
352         /* Attach pointers to needed widgets */
353         g_object_set_data(G_OBJECT(mcast_params_dlg), E_MCAST_ENTRY_1, entry1);
354         g_object_set_data(G_OBJECT(mcast_params_dlg), E_MCAST_ENTRY_2, entry2);
355         g_object_set_data(G_OBJECT(mcast_params_dlg), E_MCAST_ENTRY_3, entry3);
356         g_object_set_data(G_OBJECT(mcast_params_dlg), E_MCAST_ENTRY_4, entry4);
357         g_object_set_data(G_OBJECT(mcast_params_dlg), E_MCAST_ENTRY_5, entry5);
358
359         gtk_widget_show_all(mcast_params_dlg);
360         window_present(mcast_params_dlg);
361 }
362
363
364 /****************************************************************************/
365 /* append a line to list */
366 static void
367 add_to_list_store(mcast_stream_info_t* strinfo)
368 {
369         gchar label_text[256];
370         gchar *data[NUM_COLS];
371         int i;
372         char *savelocale;
373
374         /* save the current locale */
375         savelocale = setlocale(LC_NUMERIC, NULL);
376         /* switch to "C" locale to avoid problems with localized decimal separators
377                 in g_snprintf("%f") functions */
378         setlocale(LC_NUMERIC, "C");
379         data[0] = g_strdup(get_addr_name(&(strinfo->src_addr)));
380         data[1] = g_strdup_printf("%u", strinfo->src_port);
381         data[2] = g_strdup(get_addr_name(&(strinfo->dest_addr)));
382         data[3] = g_strdup_printf("%u", strinfo->dest_port);
383         data[4] = g_strdup_printf("%u", strinfo->npackets);
384         data[5] = g_strdup_printf("%u /s", strinfo->apackets);
385         data[6] = g_strdup_printf("%2.1f Mbps", strinfo->average_bw);
386         data[7] = g_strdup_printf("%2.1f Mbps", strinfo->element.maxbw);
387         data[8] = g_strdup_printf("%u / %dms", strinfo->element.topburstsize, mcast_stream_burstint);
388         data[9] = g_strdup_printf("%u", strinfo->element.numbursts);
389         data[10] = g_strdup_printf("%.1f KB", (float)strinfo->element.topbuffusage/1000);
390         data[11] = g_strdup_printf("%u", strinfo->element.numbuffalarms);
391
392         /* restore previous locale setting */
393         setlocale(LC_NUMERIC, savelocale);
394
395         /* Acquire an iterator */
396         gtk_list_store_append(list_store, &list_iter);
397
398         /* Fill the new row */
399         gtk_list_store_set(list_store, &list_iter,
400                             MC_COL_SRC_ADDR, data[0],
401                             MC_COL_SRC_PORT, data[1],
402                             MC_COL_DST_ADDR, data[2],
403                             MC_COL_DST_PORT, data[3],
404                             MC_COL_PACKETS, data[4],
405                             MC_COL_PPS, data[5],
406                             MC_COL_AVG_BW, data[6],
407                             MC_COL_MAX_BW, data[7],
408                             MC_COL_MAX_BURST, data[8],
409                             MC_COL_BURST_ALARM, data[9],
410                             MC_COL_MAX_BUFFER, data[10],
411                             MC_COL_BUFFER_ALARM, data[11],
412                             MC_COL_DATA, strinfo,
413                             -1);
414
415         for (i = 0; i < NUM_COLS-1; i++)
416                 g_free(data[i]);
417
418         /* Update the top label with the number of detected streams */
419         g_snprintf(label_text, sizeof(label_text),
420                 "Detected %d Multicast streams,   Average Bw: %.1f Mbps   Max Bw: %.1f Mbps   Max burst: %d / %dms   Max buffer: %.1f KB",
421                 ++streams_nb,
422                 mcaststream_get_info()->allstreams->average_bw, mcaststream_get_info()->allstreams->element.maxbw,
423                 mcaststream_get_info()->allstreams->element.topburstsize, mcast_stream_burstint,
424                 (float)(mcaststream_get_info()->allstreams->element.topbuffusage)/1000);
425         gtk_label_set_text(GTK_LABEL(top_label), label_text);
426
427         g_snprintf(label_text, sizeof(label_text), "\nBurst int: %u ms   Burst alarm: %u pps   Buffer alarm: %u Bytes   Stream empty speed: %u Kbps   Total empty speed: %u Kbps\n",
428                 mcast_stream_burstint, mcast_stream_trigger, mcast_stream_bufferalarm, mcast_stream_emptyspeed, mcast_stream_cumulemptyspeed);
429         gtk_label_set_text(GTK_LABEL(label_par), label_text);
430 }
431
432 /****************************************************************************/
433 /* Create list view */
434 static void
435 create_list_view(void)
436 {
437         GtkTreeViewColumn *column;
438         GtkCellRenderer   *renderer;
439         GtkTreeSortable   *sortable;
440         GtkTreeView       *list_view;
441         GtkTreeSelection  *selection;
442
443         /* Create the store */
444         list_store = gtk_list_store_new(NUM_COLS,       /* Total number of columns */
445                                         G_TYPE_STRING,  /* Source address */
446                                         G_TYPE_STRING,  /* Source port */
447                                         G_TYPE_STRING,  /* Destination address */
448                                         G_TYPE_STRING,  /* Destination port */
449                                         G_TYPE_STRING,  /* Packets */
450                                         G_TYPE_STRING,  /* Packets per second */
451                                         G_TYPE_STRING,  /* Average bandwidth */
452                                         G_TYPE_STRING,  /* Max. bandwidth */
453                                         G_TYPE_STRING,  /* Max. burst */
454                                         G_TYPE_STRING,  /* Burst alarms */
455                                         G_TYPE_STRING,  /* Max. buffers */
456                                         G_TYPE_STRING,  /* Buffer alarms */
457                                         G_TYPE_POINTER  /* Data */
458                                        );
459
460         /* Create a view */
461         list_w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store));
462
463         list_view = GTK_TREE_VIEW(list_w);
464         sortable = GTK_TREE_SORTABLE(list_store);
465
466         /* Speed up the list display */
467         gtk_tree_view_set_fixed_height_mode(list_view, TRUE);
468
469         /* Setup the sortable columns */
470         gtk_tree_sortable_set_sort_column_id(sortable, MC_COL_SRC_ADDR, GTK_SORT_ASCENDING);
471         gtk_tree_view_set_headers_clickable(list_view, FALSE);
472
473         /* The view now holds a reference.  We can get rid of our own reference */
474         g_object_unref(G_OBJECT(list_store));
475
476         /*
477          * Create the first column packet, associating the "text" attribute of the
478          * cell_renderer to the first column of the model
479          */
480         renderer = gtk_cell_renderer_text_new();
481         column = gtk_tree_view_column_new_with_attributes("Src IP addr", renderer,
482                 "text", MC_COL_SRC_ADDR,
483                 NULL);
484         gtk_tree_view_column_set_sort_column_id(column, MC_COL_SRC_ADDR);
485         gtk_tree_view_column_set_resizable(column, TRUE);
486         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
487         gtk_tree_view_column_set_min_width(column, 60);
488         gtk_tree_view_column_set_fixed_width(column, 100);
489         /* Add the column to the view. */
490         gtk_tree_view_append_column(list_view, column);
491
492         /* Source port */
493         renderer = gtk_cell_renderer_text_new();
494         column = gtk_tree_view_column_new_with_attributes("Src port", renderer,
495                 "text", MC_COL_SRC_PORT,
496                 NULL);
497         gtk_tree_view_column_set_sort_column_id(column, MC_COL_SRC_PORT);
498         gtk_tree_view_column_set_resizable(column, TRUE);
499         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
500         gtk_tree_view_column_set_min_width(column, 60);
501         gtk_tree_view_column_set_fixed_width(column, 80);
502         gtk_tree_view_append_column(list_view, column);
503
504         /* Destination address */
505         renderer = gtk_cell_renderer_text_new();
506         column = gtk_tree_view_column_new_with_attributes("Dst IP addr", renderer,
507                 "text", MC_COL_DST_ADDR,
508                 NULL);
509         gtk_tree_view_column_set_sort_column_id(column, MC_COL_DST_ADDR);
510         gtk_tree_view_column_set_resizable(column, TRUE);
511         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
512         gtk_tree_view_column_set_min_width(column, 60);
513         gtk_tree_view_column_set_fixed_width(column, 100);
514         gtk_tree_view_append_column(list_view, column);
515
516         /* Destination port */
517         renderer = gtk_cell_renderer_text_new();
518         column = gtk_tree_view_column_new_with_attributes("Dst port", renderer,
519                 "text", MC_COL_DST_PORT,
520                 NULL);
521         gtk_tree_view_column_set_sort_column_id(column, MC_COL_DST_PORT);
522         gtk_tree_view_column_set_resizable(column, TRUE);
523         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
524         gtk_tree_view_column_set_min_width(column, 60);
525         gtk_tree_view_column_set_fixed_width(column, 80);
526         gtk_tree_view_append_column(list_view, column);
527
528         /* Packets */
529         renderer = gtk_cell_renderer_text_new();
530         column = gtk_tree_view_column_new_with_attributes("Packets", renderer,
531                 "text", MC_COL_PACKETS,
532                 NULL);
533         gtk_tree_view_column_set_sort_column_id(column, MC_COL_PACKETS);
534         gtk_tree_view_column_set_resizable(column, TRUE);
535         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
536         gtk_tree_view_column_set_min_width(column, 60);
537         gtk_tree_view_column_set_fixed_width(column, 80);
538         gtk_tree_view_append_column(list_view, column);
539
540         /* Packets/s */
541         renderer = gtk_cell_renderer_text_new();
542         column = gtk_tree_view_column_new_with_attributes("Packets/s", renderer,
543                 "text", MC_COL_PPS,
544                 NULL);
545         gtk_tree_view_column_set_sort_column_id(column, MC_COL_PPS);
546         gtk_tree_view_column_set_resizable(column, TRUE);
547         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
548         gtk_tree_view_column_set_min_width(column, 60);
549         gtk_tree_view_column_set_fixed_width(column, 90);
550         gtk_tree_view_append_column(list_view, column);
551
552         /* Average bandwidth */
553         renderer = gtk_cell_renderer_text_new();
554         column = gtk_tree_view_column_new_with_attributes("Avg Bw", renderer,
555                 "text", MC_COL_AVG_BW,
556                 NULL);
557         gtk_tree_view_column_set_sort_column_id(column, MC_COL_AVG_BW);
558         gtk_tree_view_column_set_resizable(column, TRUE);
559         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
560         gtk_tree_view_column_set_min_width(column, 70);
561         gtk_tree_view_column_set_fixed_width(column, 80);
562         gtk_tree_view_append_column(list_view, column);
563
564         /* Max. bandwidth */
565         renderer = gtk_cell_renderer_text_new();
566         column = gtk_tree_view_column_new_with_attributes("Max Bw", renderer,
567                 "text", MC_COL_MAX_BW,
568                 NULL);
569         gtk_tree_view_column_set_sort_column_id(column, MC_COL_MAX_BW);
570         gtk_tree_view_column_set_resizable(column, TRUE);
571         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
572         gtk_tree_view_column_set_min_width(column, 70);
573         gtk_tree_view_column_set_fixed_width(column, 80);
574         gtk_tree_view_append_column(list_view, column);
575
576         /* Max. bursts */
577         renderer = gtk_cell_renderer_text_new();
578         column = gtk_tree_view_column_new_with_attributes("Max bursts", renderer,
579                 "text", MC_COL_MAX_BURST,
580                 NULL);
581         gtk_tree_view_column_set_sort_column_id(column, MC_COL_MAX_BURST);
582         gtk_tree_view_column_set_resizable(column, TRUE);
583         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
584         gtk_tree_view_column_set_min_width(column, 70);
585         gtk_tree_view_column_set_fixed_width(column, 100);
586         gtk_tree_view_append_column(list_view, column);
587
588         /* Burst alarms*/
589         renderer = gtk_cell_renderer_text_new();
590         column = gtk_tree_view_column_new_with_attributes("Burst alarms", renderer,
591                 "text", MC_COL_BURST_ALARM,
592                 NULL);
593         gtk_tree_view_column_set_sort_column_id(column, MC_COL_BURST_ALARM);
594         gtk_tree_view_column_set_resizable(column, TRUE);
595         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
596         gtk_tree_view_column_set_min_width(column, 90);
597         gtk_tree_view_column_set_fixed_width(column, 110);
598         gtk_tree_view_append_column(list_view, column);
599
600         /* Max. buffers */
601         renderer = gtk_cell_renderer_text_new();
602         column = gtk_tree_view_column_new_with_attributes("Max buffers", renderer,
603                 "text", MC_COL_MAX_BUFFER,
604                 NULL);
605         gtk_tree_view_column_set_sort_column_id(column, MC_COL_MAX_BUFFER);
606         gtk_tree_view_column_set_resizable(column, TRUE);
607         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
608         gtk_tree_view_column_set_min_width(column, 90);
609         gtk_tree_view_column_set_fixed_width(column, 100);
610         gtk_tree_view_append_column(list_view, column);
611
612         /* Buffer alarms */
613         renderer = gtk_cell_renderer_text_new();
614         column = gtk_tree_view_column_new_with_attributes("Buffer alarms", renderer,
615                 "text", MC_COL_BUFFER_ALARM,
616                 NULL);
617         gtk_tree_view_column_set_sort_column_id(column, MC_COL_BUFFER_ALARM);
618         gtk_tree_view_column_set_resizable(column, TRUE);
619         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
620         gtk_tree_view_column_set_min_width(column, 90);
621         gtk_tree_view_column_set_fixed_width(column, 120);
622         gtk_tree_view_append_column(list_view, column);
623
624         /* Now enable the sorting of each column */
625         gtk_tree_view_set_rules_hint(list_view, TRUE);
626         gtk_tree_view_set_headers_clickable(list_view, TRUE);
627
628         /* Setup the selection handler */
629         selection = gtk_tree_view_get_selection(list_view);
630         gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
631
632         g_signal_connect(G_OBJECT(selection), "changed", /* (un)select_row */
633                          G_CALLBACK(mcaststream_on_select_row),
634                          NULL);
635
636 }
637
638
639 /****************************************************************************/
640 /* Create dialog */
641 static void
642 mcaststream_dlg_create(void)
643 {
644         GtkWidget *mcaststream_dlg_w;
645         GtkWidget *main_vb;
646         GtkWidget *scrolledwindow;
647         GtkWidget *hbuttonbox;
648         /*GtkWidget *bt_unselect;*/
649         GtkWidget *bt_params;
650         GtkWidget *bt_close;
651
652         const gchar *title_name_ptr;
653         gchar *win_name;
654
655         title_name_ptr = cf_get_display_name(&cfile);
656         win_name = g_strdup_printf("%s - UDP Multicast Streams", title_name_ptr);
657         mcaststream_dlg_w = dlg_window_new(win_name);
658
659         gtk_window_set_default_size(GTK_WINDOW(mcaststream_dlg_w), 620, 400);
660
661         main_vb = gtk_vbox_new (FALSE, 0);
662         gtk_container_add(GTK_CONTAINER(mcaststream_dlg_w), main_vb);
663         gtk_container_set_border_width (GTK_CONTAINER (main_vb), 12);
664
665         top_label = gtk_label_new ("Detected 0 Multicast streams");
666         gtk_box_pack_start (GTK_BOX (main_vb), top_label, FALSE, FALSE, 8);
667
668         scrolledwindow = scrolled_window_new (NULL, NULL);
669         gtk_box_pack_start (GTK_BOX (main_vb), scrolledwindow, TRUE, TRUE, 0);
670
671         create_list_view();
672         gtk_container_add(GTK_CONTAINER(scrolledwindow), list_w);
673
674         gtk_widget_show(mcaststream_dlg_w);
675
676         label_fwd = gtk_label_new (FWD_LABEL_TEXT);
677         gtk_box_pack_start (GTK_BOX (main_vb), label_fwd, FALSE, FALSE, 0);
678
679         label_par = gtk_label_new (PAR_LABEL_TEXT);
680         gtk_box_pack_start (GTK_BOX (main_vb), label_par, FALSE, FALSE, 0);
681
682         /* button row */
683         hbuttonbox = gtk_hbutton_box_new ();
684         gtk_box_pack_start (GTK_BOX (main_vb), hbuttonbox, FALSE, FALSE, 0);
685         gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
686         gtk_box_set_spacing (GTK_BOX (hbuttonbox), 0);
687
688         /*bt_unselect = gtk_button_new_with_label ("Unselect");
689           gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_unselect);
690           gtk_widget_set_tooltip_text (bt_unselect, "Undo stream selection");*/
691
692         bt_params = gtk_button_new_with_label ("Set parameters");
693         gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_params);
694         gtk_widget_set_tooltip_text (bt_params, "Set buffer, limit and speed parameters");
695
696         bt_filter = gtk_button_new_with_label ("Prepare Filter");
697         gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_filter);
698         gtk_widget_set_tooltip_text (bt_filter, "Prepare a display filter of the selected stream");
699
700         bt_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
701         gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_close);
702         gtk_widget_set_tooltip_text (bt_close, "Close this dialog");
703 #if GTK_CHECK_VERSION(2,18,0)
704         gtk_widget_set_can_default(bt_close, TRUE);
705 #else
706         GTK_WIDGET_SET_FLAGS(bt_close, GTK_CAN_DEFAULT);
707 #endif
708
709         /*g_signal_connect(bt_unselect, "clicked", G_CALLBACK(mcaststream_on_unselect), NULL);*/
710         g_signal_connect(bt_params, "clicked", G_CALLBACK(mcast_on_params), NULL);
711         g_signal_connect(bt_filter, "clicked", G_CALLBACK(mcaststream_on_filter), NULL);
712         window_set_cancel_button(mcaststream_dlg_w, bt_close, window_cancel_button_cb);
713
714         g_signal_connect(mcaststream_dlg_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
715         g_signal_connect(mcaststream_dlg_w, "destroy", G_CALLBACK(mcaststream_on_destroy), NULL);
716
717         gtk_widget_show_all(mcaststream_dlg_w);
718         window_present(mcaststream_dlg_w);
719
720         mcaststream_on_unselect(NULL, NULL);
721
722         mcast_stream_dlg = mcaststream_dlg_w;
723
724         g_free(win_name);
725
726 }
727
728
729 /****************************************************************************/
730 /* PUBLIC                                                                   */
731 /****************************************************************************/
732
733 /****************************************************************************/
734 /* update the contents of the dialog box clist */
735 /* list: pointer to list of mcast_stream_info_t* */
736 void
737 mcaststream_dlg_update(GList *list)
738 {
739         if (mcast_stream_dlg != NULL) {
740                 gtk_list_store_clear(list_store);
741                 streams_nb = 0;
742
743                 list = g_list_first(list);
744                 while (list)
745                 {
746                         add_to_list_store((mcast_stream_info_t*)(list->data));
747                         list = g_list_next(list);
748                 }
749
750                 mcaststream_on_unselect(NULL, NULL);
751         }
752
753         last_list = list;
754 }
755
756
757 /****************************************************************************/
758 /* update the contents of the dialog box clist */
759 /* list: pointer to list of mcast_stream_info_t* */
760 void
761 mcaststream_dlg_show(GList *list)
762 {
763         if (mcast_stream_dlg != NULL) {
764                 /* There's already a dialog box; reactivate it. */
765                 reactivate_window(mcast_stream_dlg);
766                 /* Another list since last call? */
767                 if (list != last_list) {
768                         mcaststream_dlg_update(list);
769                 }
770         }
771         else {
772                 /* Create and show the dialog box */
773                 mcaststream_dlg_create();
774                 mcaststream_dlg_update(list);
775         }
776 }
777
778
779 /****************************************************************************/
780 /* entry point when called via the GTK menu */
781 #ifdef MAIN_MENU_USE_UIMANAGER
782 void
783 mcaststream_launch(GtkAction *action _U_, gpointer user_data _U_)
784 #else
785 static void
786 mcaststream_launch(GtkWidget *w _U_, gpointer data _U_)
787 #endif
788 {
789         /* Register the tap listener */
790         register_tap_listener_mcast_stream();
791
792         /* Scan for Mcast streams (redissect all packets) */
793         mcaststream_scan();
794
795         /* Show the dialog box with the list of streams */
796         mcaststream_dlg_show(mcaststream_get_info()->strinfo_list);
797
798         /* Tap listener will be removed and cleaned up in mcaststream_on_destroy */
799 }
800
801 /****************************************************************************/
802 void
803 register_tap_listener_mcast_stream_dlg(void)
804 {
805 #ifdef MAIN_MENU_USE_UIMANAGER
806 #else
807         register_stat_menu_item("UDP Multicast Streams", REGISTER_STAT_GROUP_UNSORTED,
808             mcaststream_launch, NULL, NULL, NULL);
809 #endif
810 }