bdb141e4d0483f02e1f607a4eed103bb82f9472a
[metze/wireshark/wip.git] / ui / gtk / lbm_uimflow_dlg.c
1 /* lbm_uimflow_dlg.c
2  * Routines for LBMC UIM flow graph
3  *
4  * Copyright (c) 2005-2014 Informatica Corporation. All Rights Reserved.
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #include "config.h"
26 #include <glib.h>
27 #include <epan/to_str.h>
28 #include <epan/funnel.h>
29 #include <epan/packet.h>
30 #include <epan/tap.h>
31 #include <epan/stat_groups.h>
32 #include <gtk/gtk.h>
33 #include "ui/gtk/gui_utils.h"
34 #include "ui/gtk/dlg_utils.h"
35 #include <cfile.h>
36 #include <globals.h>
37 #include "ui/gtk/graph_analysis.h"
38 #include <epan/dissectors/packet-lbm.h>
39 #include "lbm_uimflow_dlg.h"
40
41 typedef enum
42 {
43     select_all_packets,
44     select_displayed_packets
45 } lbmc_uim_flow_select_t;
46
47 typedef struct
48 {
49     gboolean have_tap_listener;
50     int tap_identifier;
51     seq_analysis_info_t * graph_analysis;
52     graph_analysis_data_t * graph_analysis_data;
53     GtkWidget * flow_graph_dialog;
54     lbmc_uim_flow_select_t packet_select_type;
55     GtkWidget * select_all_radio_button;
56     GtkWidget * select_displayed_radio_button;
57 } lbm_uimflow_dialog_t;
58
59 static lbm_uimflow_dialog_t dialog_data = { FALSE, -1, NULL, NULL, NULL, select_displayed_packets, NULL, NULL };
60
61 static void lbmc_uim_flow_graph_data_init(void)
62 {
63     dialog_data.graph_analysis = sequence_analysis_info_new();
64     dialog_data.graph_analysis->type = SEQ_ANALYSIS_ANY;
65     dialog_data.graph_analysis->all_packets = TRUE;
66     dialog_data.graph_analysis->any_addr = TRUE;
67 }
68
69 static void lbmc_uim_flow_toggle_select_all_cb(GtkWidget * widget _U_, gpointer user_data _U_)
70 {
71     /* is the button now active? */
72     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog_data.select_all_radio_button)))
73     {
74         dialog_data.packet_select_type = select_all_packets;
75     }
76 }
77
78 static void lbmc_uim_flow_toggle_select_displayed_cb(GtkWidget * widget _U_, gpointer user_data _U_)
79 {
80     /* is the button now active? */
81     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog_data.select_displayed_radio_button)))
82     {
83         dialog_data.packet_select_type = select_displayed_packets;
84     }
85 }
86
87 static void lbmc_uim_flow_tap_reset(void * tap_data _U_)
88 {
89     if (dialog_data.graph_analysis != NULL)
90     {
91         /* free the graph data items */
92         sequence_analysis_list_free(dialog_data.graph_analysis);
93     }
94 }
95
96 static int lbmc_uim_flow_graph_add_to_graph(packet_info * pinfo, const lbm_uim_stream_info_t * stream_info)
97 {
98     lbm_uim_stream_endpoint_t epa;
99     lbm_uim_stream_endpoint_t epb;
100     seq_analysis_item_t * item;
101     gchar * ctxinst1 = NULL;
102     gchar * ctxinst2 = NULL;
103     gboolean swap_endpoints = FALSE;
104     int rc;
105
106     if (stream_info->endpoint_a.type != stream_info->endpoint_b.type)
107     {
108         return (1);
109     }
110     if (stream_info->endpoint_a.type == lbm_uim_instance_stream)
111     {
112         rc = memcmp((void *)stream_info->endpoint_a.stream_info.ctxinst.ctxinst,
113             (void *)stream_info->endpoint_b.stream_info.ctxinst.ctxinst,
114             LBM_CONTEXT_INSTANCE_BLOCK_SZ);
115         if (rc <= 0)
116         {
117             swap_endpoints = FALSE;
118         }
119         else
120         {
121             swap_endpoints = TRUE;
122         }
123     }
124     else
125     {
126         if (stream_info->endpoint_a.stream_info.dest.domain < stream_info->endpoint_b.stream_info.dest.domain)
127         {
128             swap_endpoints = FALSE;
129         }
130         else if (stream_info->endpoint_a.stream_info.dest.domain > stream_info->endpoint_b.stream_info.dest.domain)
131         {
132             swap_endpoints = TRUE;
133         }
134         else
135         {
136             int compare;
137
138             compare = CMP_ADDRESS(&(stream_info->endpoint_a.stream_info.dest.addr), &(stream_info->endpoint_b.stream_info.dest.addr));
139             if (compare < 0)
140             {
141                 swap_endpoints = FALSE;
142             }
143             else if (compare > 0)
144             {
145                 swap_endpoints = TRUE;
146             }
147             else
148             {
149                 if (stream_info->endpoint_a.stream_info.dest.port <= stream_info->endpoint_b.stream_info.dest.port)
150                 {
151                     swap_endpoints = FALSE;
152                 }
153                 else
154                 {
155                     swap_endpoints = TRUE;
156                 }
157             }
158         }
159     }
160     if (swap_endpoints == FALSE)
161     {
162         epa = stream_info->endpoint_a;
163         epb = stream_info->endpoint_b;
164     }
165     else
166     {
167         epb = stream_info->endpoint_a;
168         epa = stream_info->endpoint_b;
169     }
170     item = (seq_analysis_item_t *)g_malloc(sizeof(seq_analysis_item_t));
171     COPY_ADDRESS(&(item->src_addr), &(pinfo->src));
172     COPY_ADDRESS(&(item->dst_addr), &(pinfo->dst));
173     item->fd = pinfo->fd;
174     item->port_src = pinfo->srcport;
175     item->port_dst = pinfo->destport;
176     if (stream_info->description == NULL)
177     {
178         item->frame_label = g_strdup_printf("(%" G_GUINT32_FORMAT ")", stream_info->sqn);
179     }
180     else
181     {
182         item->frame_label = g_strdup_printf("%s (%" G_GUINT32_FORMAT ")", stream_info->description, stream_info->sqn);
183     }
184     if (epa.type == lbm_uim_instance_stream)
185     {
186         ctxinst1 = bytes_to_ep_str(epa.stream_info.ctxinst.ctxinst, sizeof(epa.stream_info.ctxinst.ctxinst));
187         ctxinst2 = bytes_to_ep_str(epb.stream_info.ctxinst.ctxinst, sizeof(epb.stream_info.ctxinst.ctxinst));
188         item->comment = g_strdup_printf("%s <-> %s [%" G_GUINT64_FORMAT "]",
189             ctxinst1,
190             ctxinst2,
191             stream_info->channel);
192     }
193     else
194     {
195         item->comment = g_strdup_printf("%" G_GUINT32_FORMAT ":%s:%" G_GUINT16_FORMAT " <-> %" G_GUINT32_FORMAT ":%s:%" G_GUINT16_FORMAT " [%" G_GUINT64_FORMAT "]",
196             epa.stream_info.dest.domain,
197             ep_address_to_str(&(epa.stream_info.dest.addr)),
198             epa.stream_info.dest.port,
199             epb.stream_info.dest.domain,
200             ep_address_to_str(&(epb.stream_info.dest.addr)),
201             epb.stream_info.dest.port,
202             stream_info->channel);
203     }
204     item->conv_num = (guint16)LBM_CHANNEL_ID(stream_info->channel);
205     item->display = TRUE;
206     item->line_style = 1;
207     g_queue_push_tail(dialog_data.graph_analysis->items, item);
208     return (1);
209 }
210
211 static gboolean lbmc_uim_flow_tap_packet(void * tap_data _U_, packet_info * pinfo, epan_dissect_t * edt _U_, const void * stream_info)
212 {
213     const lbm_uim_stream_info_t * info = (const lbm_uim_stream_info_t *)stream_info;
214     if ((dialog_data.packet_select_type == select_all_packets) || (pinfo->fd->flags.passed_dfilter == 1))
215     {
216         lbmc_uim_flow_graph_add_to_graph(pinfo, info);
217         return (TRUE);
218     }
219     return (FALSE);
220 }
221
222 static void lbmc_uim_flow_tap_draw(void * tap_data _U_)
223 {
224     return;
225 }
226
227 static void lbmc_uim_flow_remove_tap_listener(void)
228 {
229     remove_tap_listener(&(dialog_data.tap_identifier));
230     dialog_data.have_tap_listener = FALSE;
231 }
232
233 static void lbmc_uim_flow_graph_on_ok_cb(GtkButton * button _U_, gpointer user_data)
234 {
235     GList * list = NULL;
236     gchar time_str[COL_MAX_LEN];
237
238     if (dialog_data.have_tap_listener == TRUE)
239     {
240         /* remove_tap_listeners */
241         lbmc_uim_flow_remove_tap_listener();
242     }
243
244     /* Scan for displayed packets (retap all packets) */
245     if (dialog_data.have_tap_listener == FALSE)
246     {
247         GString * err_msg;
248
249         err_msg = register_tap_listener("lbm_uim",
250             &(dialog_data.tap_identifier),
251             NULL,
252             TL_REQUIRES_COLUMNS,
253             lbmc_uim_flow_tap_reset,
254             lbmc_uim_flow_tap_packet,
255             lbmc_uim_flow_tap_draw);
256         if (err_msg != NULL)
257         {
258             fprintf(stderr, "register_tap_listener: %s\n", err_msg->str);
259             g_string_free(err_msg, TRUE);
260         }
261         dialog_data.have_tap_listener = TRUE;
262     }
263     cf_retap_packets(&cfile);
264     /* Fill in the timestamps. */
265     list = g_queue_peek_nth_link(dialog_data.graph_analysis->items, 0);
266     while (list != NULL)
267     {
268         seq_analysis_item_t * seq_item = (seq_analysis_item_t *)list->data;
269         set_fd_time(cfile.epan, seq_item->fd, time_str);
270         seq_item->time_str = g_strdup(time_str);
271         list = g_list_next(list);
272     }
273     if (dialog_data.graph_analysis_data->dlg.window != NULL)
274     {
275         graph_analysis_update(dialog_data.graph_analysis_data);
276     }
277     else
278     {
279         dialog_data.graph_analysis_data->dlg.parent_w = (GtkWidget *)user_data;
280         graph_analysis_create(dialog_data.graph_analysis_data);
281     }
282 }
283
284 static void lbmc_uim_flow_graph_on_destroy_cb(GtkWidget * widget _U_, gpointer user_data _U_)
285 {
286     /* remove_tap_listeners */
287     lbmc_uim_flow_remove_tap_listener();
288
289     /* Clean up memory used by tap */
290     lbmc_uim_flow_tap_reset(NULL);
291
292     g_assert(dialog_data.graph_analysis != NULL);
293     g_assert(dialog_data.graph_analysis_data != NULL);
294
295     sequence_analysis_info_free(dialog_data.graph_analysis);
296     dialog_data.graph_analysis = NULL;
297
298     g_free(dialog_data.graph_analysis_data);
299     dialog_data.graph_analysis_data = NULL;
300
301     /* Note that we no longer have a "Flow Graph" dialog box. */
302     dialog_data.flow_graph_dialog = NULL;
303 }
304
305 static void lbmc_uim_flow_graph_dlg_create(void)
306 {
307     GtkWidget * flow_graph_dlg_w = NULL;
308     GtkWidget * main_vb = NULL;
309     GtkWidget * hbuttonbox = NULL;
310     GtkWidget * bt_cancel = NULL;
311     GtkWidget * bt_ok = NULL;
312     GtkWidget * range_fr = NULL;
313     GtkWidget * range_grid = NULL;
314
315     flow_graph_dlg_w = dlg_window_new("Wireshark: UIM Flow Graph");
316     gtk_window_set_destroy_with_parent(GTK_WINDOW(flow_graph_dlg_w), TRUE);
317
318     gtk_window_set_default_size(GTK_WINDOW(flow_graph_dlg_w), 250, 150);
319
320     main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
321     gtk_container_add(GTK_CONTAINER(flow_graph_dlg_w), main_vb);
322     gtk_container_set_border_width(GTK_CONTAINER(main_vb), 7);
323
324     gtk_widget_show(flow_graph_dlg_w);
325
326     /*** Packet range frame ***/
327     range_fr = gtk_frame_new("Choose packets");
328     gtk_box_pack_start(GTK_BOX(main_vb), range_fr, FALSE, FALSE, 5);
329
330     range_grid = ws_gtk_grid_new();
331     gtk_container_set_border_width(GTK_CONTAINER(range_grid), 5);
332     gtk_container_add(GTK_CONTAINER(range_fr), range_grid);
333
334     /* Process all packets */
335     dialog_data.select_all_radio_button = gtk_radio_button_new_with_mnemonic_from_widget(NULL, "_All packets");
336     gtk_widget_set_tooltip_text(dialog_data.select_all_radio_button, ("Process all packets"));
337     g_signal_connect(dialog_data.select_all_radio_button, "toggled", G_CALLBACK(lbmc_uim_flow_toggle_select_all_cb), NULL);
338     ws_gtk_grid_attach_extended(GTK_GRID(range_grid), dialog_data.select_all_radio_button, 0, 0, 1, 1,
339                                 (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0);
340     if (dialog_data.packet_select_type == select_all_packets)
341     {
342         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog_data.select_all_radio_button), TRUE);
343     }
344     gtk_widget_show(dialog_data.select_all_radio_button);
345
346     /* Process displayed packets */
347     dialog_data.select_displayed_radio_button =
348         gtk_radio_button_new_with_mnemonic_from_widget(GTK_RADIO_BUTTON(dialog_data.select_all_radio_button), "_Displayed packets");
349     gtk_widget_set_tooltip_text(dialog_data.select_displayed_radio_button, ("Process displayed packets"));
350     g_signal_connect(dialog_data.select_displayed_radio_button, "toggled", G_CALLBACK(lbmc_uim_flow_toggle_select_displayed_cb), NULL);
351     ws_gtk_grid_attach_extended(GTK_GRID(range_grid), dialog_data.select_displayed_radio_button, 0, 1, 1, 1,
352                                 (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0);
353     if (dialog_data.packet_select_type == select_displayed_packets)
354     {
355         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog_data.select_displayed_radio_button), TRUE);
356     }
357     gtk_widget_show(dialog_data.select_displayed_radio_button);
358
359     gtk_widget_show(range_grid);
360     gtk_widget_show(range_fr);
361
362     /* button row */
363     hbuttonbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
364     gtk_box_pack_start(GTK_BOX(main_vb), hbuttonbox, FALSE, FALSE, 5);
365     gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_SPREAD);
366     gtk_box_set_spacing(GTK_BOX(hbuttonbox), 30);
367
368     bt_ok = gtk_button_new_from_stock(GTK_STOCK_OK);
369     gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_ok);
370     gtk_widget_set_tooltip_text(bt_ok, "Show the flow graph");
371     g_signal_connect(bt_ok, "clicked", G_CALLBACK(lbmc_uim_flow_graph_on_ok_cb), flow_graph_dlg_w);
372     gtk_widget_show(bt_ok);
373
374     bt_cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
375     gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_cancel);
376 #if GTK_CHECK_VERSION(2,18,0)
377     gtk_widget_set_can_default(bt_cancel, TRUE);
378 #else
379     GTK_WIDGET_SET_FLAGS(bt_cancel, GTK_CAN_DEFAULT);
380 #endif
381     gtk_widget_set_tooltip_text(bt_cancel, "Cancel this dialog");
382     window_set_cancel_button(flow_graph_dlg_w, bt_cancel, window_cancel_button_cb);
383
384     g_signal_connect(flow_graph_dlg_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
385     g_signal_connect(flow_graph_dlg_w, "destroy", G_CALLBACK(lbmc_uim_flow_graph_on_destroy_cb), NULL);
386
387     gtk_widget_show_all(flow_graph_dlg_w);
388     window_present(flow_graph_dlg_w);
389
390     dialog_data.flow_graph_dialog = flow_graph_dlg_w;
391 }
392
393 static void lbmc_uim_flow_graph_init_tap(const char * dummy _U_, void * user_data _U_)
394 {
395     /*
396         The storage allocated by lbmc_uim_flow_graph_data_init() and lbmc_uim_graph_analysis_init()
397         will be considered to be "associated with" the dialog_data.flow_graph_dialog dialog box. It will be freed
398         when the dialog_data.flow_graph_dialog dialog box is destroyed.
399     */
400     if (dialog_data.flow_graph_dialog != NULL)
401     {
402         g_assert(dialog_data.graph_analysis != NULL);
403         g_assert(dialog_data.graph_analysis_data != NULL);
404         /* There's already a dialog box; reactivate it. */
405         reactivate_window(dialog_data.flow_graph_dialog);
406     }
407     else
408     {
409         g_assert(dialog_data.graph_analysis == NULL);
410         g_assert(dialog_data.graph_analysis_data == NULL);
411         /* initialize graph items store */
412         lbmc_uim_flow_graph_data_init();
413
414         /* init the Graph Analysis */
415         dialog_data.graph_analysis_data = graph_analysis_init(dialog_data.graph_analysis);
416
417         lbmc_uim_flow_graph_dlg_create();
418     }
419 }
420
421 void lbmc_uim_flow_menu_cb(gpointer arg _U_)
422 {
423     lbmc_uim_flow_graph_init_tap("", NULL);
424 }
425
426 /*
427  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
428  *
429  * Local variables:
430  * c-basic-offset: 4
431  * tab-width: 4
432  * indent-tabs-mode: nil
433  * End:
434  *
435  * vi: set shiftwidth=4 tabstop=4 expandtab:
436  * :indentSize=4:tabSize=4:noTabs=true:
437  */