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