1aa90d8b90b6ff8aebed913ddec7c28581d0bb5a
[jlayton/wireshark.git] / ui / qt / lbm_stream_dialog.cpp
1 /* lbm_stream_dialog.cpp
2  *
3  * Copyright (c) 2005-2014 Informatica Corporation. All Rights Reserved.
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 // Adapted from stats_tree_packet.cpp
25
26 #include "lbm_stream_dialog.h"
27 #include <ui_lbm_stream_dialog.h>
28
29 #include "file.h"
30
31 #include "qt_ui_utils.h"
32 #include "wireshark_application.h"
33
34 #include <QClipboard>
35 #include <QMessageBox>
36 #include <QTreeWidget>
37 #include <QTreeWidgetItemIterator>
38 #include <epan/packet_info.h>
39 #include <epan/to_str.h>
40 #include <epan/tap.h>
41 #include <epan/dissectors/packet-lbm.h>
42
43 #include <QDebug>
44
45 namespace
46 {
47     static const int Stream_Column = 0;
48     static const int EndpointA_Column = 1;
49     static const int EndpointB_Column = 2;
50     static const int Messages_Column = 3;
51     static const int Bytes_Column = 4;
52     static const int FirstFrame_Column = 5;
53     static const int LastFrame_Column = 6;
54 }
55
56 class LBMSubstreamEntry
57 {
58     public:
59         LBMSubstreamEntry(guint64 channel, guint32 substream_id, const address * source_address, guint16 source_port, const address * destination_address, guint16 destination_port);
60         ~LBMSubstreamEntry(void);
61         void processPacket(guint32 frame, guint32 bytes);
62         void setItem(QTreeWidgetItem * item);
63         QTreeWidgetItem * getItem(void)
64         {
65             return (m_item);
66         }
67
68     private:
69         LBMSubstreamEntry(void) { }
70         void fillItem(gboolean update_only = TRUE);
71         guint64 m_channel;
72         guint32 m_substream_id;
73         QString m_endpoint_a;
74         QString m_endpoint_b;
75         guint32 m_first_frame;
76         guint32 m_flast_frame;
77         guint32 m_messages;
78         guint32 m_bytes;
79         QTreeWidgetItem * m_item;
80 };
81
82 LBMSubstreamEntry::LBMSubstreamEntry(guint64 channel, guint32 substream_id, const address * source_address, guint16 source_port, const address * destination_address, guint16 destination_port) :
83     m_channel(channel),
84     m_substream_id(substream_id),
85     m_first_frame((guint32)(~0)),
86     m_flast_frame(0),
87     m_messages(0),
88     m_bytes(0),
89     m_item(NULL)
90 {
91     m_endpoint_a = QString("%1:%2")
92         .arg(address_to_qstring(source_address))
93         .arg(source_port);
94     m_endpoint_b = QString("%1:%2")
95         .arg(address_to_qstring(destination_address))
96         .arg(destination_port);
97 }
98
99 LBMSubstreamEntry::~LBMSubstreamEntry(void)
100 {
101 }
102
103 void LBMSubstreamEntry::processPacket(guint32 frame, guint32 bytes)
104 {
105     if (m_first_frame > frame)
106     {
107         m_first_frame = frame;
108     }
109     if (m_flast_frame < frame)
110     {
111         m_flast_frame = frame;
112     }
113     m_bytes += bytes;
114     m_messages++;
115     fillItem();
116 }
117
118 void LBMSubstreamEntry::setItem(QTreeWidgetItem * item)
119 {
120     m_item = item;
121     fillItem(FALSE);
122 }
123
124 void LBMSubstreamEntry::fillItem(gboolean update_only)
125 {
126     if (update_only == FALSE)
127     {
128         m_item->setText(Stream_Column, QString("%1.%2").arg(m_channel).arg(m_substream_id));
129         m_item->setText(EndpointA_Column, m_endpoint_a);
130         m_item->setText(EndpointB_Column, m_endpoint_b);
131     }
132     m_item->setText(Messages_Column, QString("%1").arg(m_messages));
133     m_item->setText(Bytes_Column, QString("%1").arg(m_bytes));
134     m_item->setText(FirstFrame_Column, QString("%1").arg(m_first_frame));
135     m_item->setText(LastFrame_Column, QString("%1").arg(m_flast_frame));
136 }
137
138 typedef QMap<guint32, LBMSubstreamEntry *> LBMSubstreamMap;
139 typedef QMap<guint32, LBMSubstreamEntry *>::iterator LBMSubstreamMapIterator;
140
141 class LBMStreamEntry
142 {
143     public:
144         LBMStreamEntry(const packet_info * pinfo, guint64 channel, const lbm_uim_stream_endpoint_t * endpoint_a, const lbm_uim_stream_endpoint_t * endpoint_b);
145         ~LBMStreamEntry(void);
146         void processPacket(const packet_info * pinfo, const lbm_uim_stream_tap_info_t * stream_info);
147         void setItem(QTreeWidgetItem * item);
148         QTreeWidgetItem * getItem(void)
149         {
150             return (m_item);
151         }
152
153     private:
154         LBMStreamEntry(void) { }
155         void fillItem(gboolean update_only = TRUE);
156         QString formatEndpoint(const packet_info * pinfo, const lbm_uim_stream_endpoint_t * endpoint);
157         guint64 m_channel;
158         QString m_endpoint_a;
159         QString m_endpoint_b;
160         guint32 m_first_frame;
161         guint32 m_flast_frame;
162         guint32 m_messages;
163         guint32 m_bytes;
164         QTreeWidgetItem * m_item;
165         LBMSubstreamMap m_substreams;
166 };
167
168 LBMStreamEntry::LBMStreamEntry(const packet_info * pinfo, guint64 channel, const lbm_uim_stream_endpoint_t * endpoint_a, const lbm_uim_stream_endpoint_t * endpoint_b) :
169     m_channel(channel),
170     m_first_frame((guint32)(~0)),
171     m_flast_frame(0),
172     m_messages(0),
173     m_bytes(0),
174     m_item(NULL),
175     m_substreams()
176 {
177     m_endpoint_a = formatEndpoint(pinfo, endpoint_a);
178     m_endpoint_b = formatEndpoint(pinfo, endpoint_b);
179 }
180
181 LBMStreamEntry::~LBMStreamEntry(void)
182 {
183     LBMSubstreamMapIterator it;
184
185     for (it = m_substreams.begin(); it != m_substreams.end(); ++it)
186     {
187         delete *it;
188     }
189     m_substreams.clear();
190 }
191
192 QString LBMStreamEntry::formatEndpoint(const packet_info * pinfo, const lbm_uim_stream_endpoint_t * endpoint)
193 {
194     if (endpoint->type == lbm_uim_instance_stream)
195     {
196         return QString(bytes_to_str(pinfo->pool, endpoint->stream_info.ctxinst.ctxinst, sizeof(endpoint->stream_info.ctxinst.ctxinst)));
197     }
198     else
199     {
200         return QString("%1:%2:%3")
201                .arg(endpoint->stream_info.dest.domain)
202                .arg(address_to_str(pinfo->pool, &(endpoint->stream_info.dest.addr)))
203                .arg(endpoint->stream_info.dest.port);
204     }
205 }
206
207 void LBMStreamEntry::processPacket(const packet_info * pinfo, const lbm_uim_stream_tap_info_t * stream_info)
208 {
209     LBMSubstreamEntry * substream = NULL;
210     LBMSubstreamMapIterator it;
211
212     if (m_first_frame > pinfo->num)
213     {
214         m_first_frame = pinfo->num;
215     }
216     if (m_flast_frame < pinfo->num)
217     {
218         m_flast_frame = pinfo->num;
219     }
220     m_bytes += stream_info->bytes;
221     m_messages++;
222     it = m_substreams.find(stream_info->substream_id);
223     if (m_substreams.end() == it)
224     {
225         QTreeWidgetItem * item = NULL;
226
227         substream = new LBMSubstreamEntry(m_channel, stream_info->substream_id, &(pinfo->src), pinfo->srcport, &(pinfo->dst), pinfo->destport);
228         m_substreams.insert(stream_info->substream_id, substream);
229         item = new QTreeWidgetItem();
230         substream->setItem(item);
231         m_item->addChild(item);
232         m_item->sortChildren(Stream_Column, Qt::AscendingOrder);
233     }
234     else
235     {
236         substream = it.value();
237     }
238     fillItem();
239     substream->processPacket(pinfo->num, stream_info->bytes);
240 }
241
242 void LBMStreamEntry::setItem(QTreeWidgetItem * item)
243 {
244     m_item = item;
245     fillItem(FALSE);
246 }
247
248 void LBMStreamEntry::fillItem(gboolean update_only)
249 {
250     if (update_only == FALSE)
251     {
252         m_item->setData(Stream_Column, Qt::DisplayRole, QVariant((qulonglong)m_channel));
253         m_item->setText(EndpointA_Column, m_endpoint_a);
254         m_item->setText(EndpointB_Column, m_endpoint_b);
255     }
256     m_item->setText(Messages_Column, QString("%1").arg(m_messages));
257     m_item->setText(Bytes_Column, QString("%1").arg(m_bytes));
258     m_item->setText(FirstFrame_Column, QString("%1").arg(m_first_frame));
259     m_item->setText(LastFrame_Column, QString("%1").arg(m_flast_frame));
260 }
261
262 typedef QMap<guint64, LBMStreamEntry *> LBMStreamMap;
263 typedef QMap<guint64, LBMStreamEntry *>::iterator LBMStreamMapIterator;
264
265 class LBMStreamDialogInfo
266 {
267     public:
268         LBMStreamDialogInfo(void);
269         ~LBMStreamDialogInfo(void);
270         void setDialog(LBMStreamDialog * dialog);
271         LBMStreamDialog * getDialog(void);
272         void processPacket(const packet_info * pinfo, const lbm_uim_stream_tap_info_t * stream_info);
273         void resetStreams(void);
274
275     private:
276         LBMStreamDialog * m_dialog;
277         LBMStreamMap m_streams;
278 };
279
280 LBMStreamDialogInfo::LBMStreamDialogInfo(void) :
281     m_dialog(NULL),
282     m_streams()
283 {
284 }
285
286 LBMStreamDialogInfo::~LBMStreamDialogInfo(void)
287 {
288     resetStreams();
289 }
290
291 void LBMStreamDialogInfo::setDialog(LBMStreamDialog * dialog)
292 {
293     m_dialog = dialog;
294 }
295
296 LBMStreamDialog * LBMStreamDialogInfo::getDialog(void)
297 {
298     return (m_dialog);
299 }
300
301 void LBMStreamDialogInfo::processPacket(const packet_info * pinfo, const lbm_uim_stream_tap_info_t * stream_info)
302 {
303     LBMStreamEntry * stream = NULL;
304     LBMStreamMapIterator it;
305
306     it = m_streams.find(stream_info->channel);
307     if (m_streams.end() == it)
308     {
309         QTreeWidgetItem * item = NULL;
310         QTreeWidgetItem * parent = NULL;
311         Ui::LBMStreamDialog * ui = NULL;
312
313         stream = new LBMStreamEntry(pinfo, stream_info->channel, &(stream_info->endpoint_a), &(stream_info->endpoint_b));
314         it = m_streams.insert(stream_info->channel, stream);
315         item = new QTreeWidgetItem();
316         stream->setItem(item);
317         ui = m_dialog->getUI();
318         ui->lbm_stream_TreeWidget->addTopLevelItem(item);
319         parent = ui->lbm_stream_TreeWidget->invisibleRootItem();
320         parent->sortChildren(Stream_Column, Qt::AscendingOrder);
321     }
322     else
323     {
324         stream = it.value();
325     }
326     stream->processPacket(pinfo, stream_info);
327 }
328
329 void LBMStreamDialogInfo::resetStreams(void)
330 {
331     LBMStreamMapIterator it = m_streams.begin();
332
333     while (it != m_streams.end())
334     {
335         delete *it;
336         ++it;
337     }
338     m_streams.clear();
339 }
340
341 LBMStreamDialog::LBMStreamDialog(QWidget * parent, capture_file * cfile) :
342     QDialog(parent),
343     m_ui(new Ui::LBMStreamDialog),
344     m_dialog_info(NULL),
345     m_capture_file(cfile)
346 {
347     m_ui->setupUi(this);
348     m_dialog_info = new LBMStreamDialogInfo();
349     connect(this, SIGNAL(accepted()), this, SLOT(closeDialog()));
350     connect(this, SIGNAL(rejected()), this, SLOT(closeDialog()));
351     fillTree();
352 }
353
354 LBMStreamDialog::~LBMStreamDialog(void)
355 {
356     delete m_ui;
357     if (m_dialog_info != NULL)
358     {
359         delete m_dialog_info;
360     }
361 }
362
363 void LBMStreamDialog::setCaptureFile(capture_file * cfile)
364 {
365     if (cfile == NULL) // We only want to know when the file closes.
366     {
367         m_capture_file = NULL;
368         m_ui->displayFilterLineEdit->setEnabled(false);
369         m_ui->applyFilterButton->setEnabled(false);
370     }
371 }
372
373 void LBMStreamDialog::fillTree(void)
374 {
375     gchar * error_string;
376
377     if (m_capture_file == NULL)
378     {
379         return;
380     }
381     m_dialog_info->setDialog(this);
382
383     error_string = register_tap_listener("lbm_stream",
384         (void *)m_dialog_info,
385         m_ui->displayFilterLineEdit->text().toUtf8().constData(),
386         TL_REQUIRES_COLUMNS,
387         resetTap,
388         tapPacket,
389         drawTreeItems);
390     if (error_string)
391     {
392         QMessageBox::critical(this, tr("LBM Stream failed to attach to tap"),
393             error_string);
394         wmem_free(NULL, error_string);
395         reject();
396     }
397
398     cf_retap_packets(m_capture_file);
399     drawTreeItems(&m_dialog_info);
400     remove_tap_listener((void *)m_dialog_info);
401 }
402
403 void LBMStreamDialog::resetTap(void * tap_data)
404 {
405     LBMStreamDialogInfo * info = (LBMStreamDialogInfo *)tap_data;
406     LBMStreamDialog * dialog = info->getDialog();
407     if (dialog == NULL)
408     {
409         return;
410     }
411     info->resetStreams();
412     dialog->m_ui->lbm_stream_TreeWidget->clear();
413 }
414
415 gboolean LBMStreamDialog::tapPacket(void * tap_data, packet_info * pinfo, epan_dissect_t *, const void * stream_info)
416 {
417     if (pinfo->fd->flags.passed_dfilter == 1)
418     {
419         const lbm_uim_stream_tap_info_t * tapinfo = (const lbm_uim_stream_tap_info_t *)stream_info;
420         LBMStreamDialogInfo * info = (LBMStreamDialogInfo *)tap_data;
421
422         info->processPacket(pinfo, tapinfo);
423     }
424     return (TRUE);
425 }
426
427 void LBMStreamDialog::drawTreeItems(void *)
428 {
429 }
430
431 void LBMStreamDialog::on_applyFilterButton_clicked(void)
432 {
433     fillTree();
434 }
435
436 void LBMStreamDialog::closeDialog(void)
437 {
438     delete this;
439 }
440
441 /*
442  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
443  *
444  * Local variables:
445  * c-basic-offset: 4
446  * tab-width: 8
447  * indent-tabs-mode: nil
448  * End:
449  *
450  * vi: set shiftwidth=4 tabstop=8 expandtab:
451  * :indentSize=4:tabSize=8:noTabs=true:
452  */