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  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 // Adapted from stats_tree_packet.cpp
13 
14 #include "lbm_stream_dialog.h"
15 #include <ui_lbm_stream_dialog.h>
16 
17 #include "file.h"
18 
19 #include <ui/qt/utils/qt_ui_utils.h>
20 #include "wireshark_application.h"
21 
22 #include <QClipboard>
23 #include <QMessageBox>
24 #include <QTreeWidget>
25 #include <QTreeWidgetItemIterator>
26 #include <epan/packet_info.h>
27 #include <epan/to_str.h>
28 #include <epan/tap.h>
29 #include <epan/dissectors/packet-lbm.h>
30 
31 #include <QDebug>
32 
33 namespace
34 {
35     static const int Stream_Column = 0;
36     static const int EndpointA_Column = 1;
37     static const int EndpointB_Column = 2;
38     static const int Messages_Column = 3;
39     static const int Bytes_Column = 4;
40     static const int FirstFrame_Column = 5;
41     static const int LastFrame_Column = 6;
42 }
43 
44 class LBMSubstreamEntry
45 {
46     public:
47         LBMSubstreamEntry(guint64 channel, guint32 substream_id, const address * source_address, guint16 source_port, const address * destination_address, guint16 destination_port);
48         ~LBMSubstreamEntry(void);
49         void processPacket(guint32 frame, guint32 bytes);
50         void setItem(QTreeWidgetItem * item);
getItem(void)51         QTreeWidgetItem * getItem(void)
52         {
53             return (m_item);
54         }
55 
56     private:
57         void fillItem(gboolean update_only = TRUE);
58         guint64 m_channel;
59         guint32 m_substream_id;
60         QString m_endpoint_a;
61         QString m_endpoint_b;
62         guint32 m_first_frame;
63         guint32 m_flast_frame;
64         guint32 m_messages;
65         guint32 m_bytes;
66         QTreeWidgetItem * m_item;
67 };
68 
LBMSubstreamEntry(guint64 channel,guint32 substream_id,const address * source_address,guint16 source_port,const address * destination_address,guint16 destination_port)69 LBMSubstreamEntry::LBMSubstreamEntry(guint64 channel, guint32 substream_id, const address * source_address, guint16 source_port, const address * destination_address, guint16 destination_port) :
70     m_channel(channel),
71     m_substream_id(substream_id),
72     m_first_frame((guint32)(~0)),
73     m_flast_frame(0),
74     m_messages(0),
75     m_bytes(0),
76     m_item(NULL)
77 {
78     m_endpoint_a = QString("%1:%2")
79         .arg(address_to_qstring(source_address))
80         .arg(source_port);
81     m_endpoint_b = QString("%1:%2")
82         .arg(address_to_qstring(destination_address))
83         .arg(destination_port);
84 }
85 
~LBMSubstreamEntry(void)86 LBMSubstreamEntry::~LBMSubstreamEntry(void)
87 {
88 }
89 
processPacket(guint32 frame,guint32 bytes)90 void LBMSubstreamEntry::processPacket(guint32 frame, guint32 bytes)
91 {
92     if (m_first_frame > frame)
93     {
94         m_first_frame = frame;
95     }
96     if (m_flast_frame < frame)
97     {
98         m_flast_frame = frame;
99     }
100     m_bytes += bytes;
101     m_messages++;
102     fillItem();
103 }
104 
setItem(QTreeWidgetItem * item)105 void LBMSubstreamEntry::setItem(QTreeWidgetItem * item)
106 {
107     m_item = item;
108     fillItem(FALSE);
109 }
110 
fillItem(gboolean update_only)111 void LBMSubstreamEntry::fillItem(gboolean update_only)
112 {
113     if (update_only == FALSE)
114     {
115         m_item->setText(Stream_Column, QString("%1.%2").arg(m_channel).arg(m_substream_id));
116         m_item->setText(EndpointA_Column, m_endpoint_a);
117         m_item->setText(EndpointB_Column, m_endpoint_b);
118     }
119     m_item->setText(Messages_Column, QString("%1").arg(m_messages));
120     m_item->setText(Bytes_Column, QString("%1").arg(m_bytes));
121     m_item->setText(FirstFrame_Column, QString("%1").arg(m_first_frame));
122     m_item->setText(LastFrame_Column, QString("%1").arg(m_flast_frame));
123 }
124 
125 typedef QMap<guint32, LBMSubstreamEntry *> LBMSubstreamMap;
126 typedef QMap<guint32, LBMSubstreamEntry *>::iterator LBMSubstreamMapIterator;
127 
128 class LBMStreamEntry
129 {
130     public:
131         LBMStreamEntry(const packet_info * pinfo, guint64 channel, const lbm_uim_stream_endpoint_t * endpoint_a, const lbm_uim_stream_endpoint_t * endpoint_b);
132         ~LBMStreamEntry(void);
133         void processPacket(const packet_info * pinfo, const lbm_uim_stream_tap_info_t * stream_info);
134         void setItem(QTreeWidgetItem * item);
getItem(void)135         QTreeWidgetItem * getItem(void)
136         {
137             return (m_item);
138         }
139 
140     private:
141         void fillItem(gboolean update_only = TRUE);
142         QString formatEndpoint(const packet_info * pinfo, const lbm_uim_stream_endpoint_t * endpoint);
143         guint64 m_channel;
144         QString m_endpoint_a;
145         QString m_endpoint_b;
146         guint32 m_first_frame;
147         guint32 m_flast_frame;
148         guint32 m_messages;
149         guint32 m_bytes;
150         QTreeWidgetItem * m_item;
151         LBMSubstreamMap m_substreams;
152 };
153 
LBMStreamEntry(const packet_info * pinfo,guint64 channel,const lbm_uim_stream_endpoint_t * endpoint_a,const lbm_uim_stream_endpoint_t * endpoint_b)154 LBMStreamEntry::LBMStreamEntry(const packet_info * pinfo, guint64 channel, const lbm_uim_stream_endpoint_t * endpoint_a, const lbm_uim_stream_endpoint_t * endpoint_b) :
155     m_channel(channel),
156     m_first_frame((guint32)(~0)),
157     m_flast_frame(0),
158     m_messages(0),
159     m_bytes(0),
160     m_item(NULL),
161     m_substreams()
162 {
163     m_endpoint_a = formatEndpoint(pinfo, endpoint_a);
164     m_endpoint_b = formatEndpoint(pinfo, endpoint_b);
165 }
166 
~LBMStreamEntry(void)167 LBMStreamEntry::~LBMStreamEntry(void)
168 {
169     LBMSubstreamMapIterator it;
170 
171     for (it = m_substreams.begin(); it != m_substreams.end(); ++it)
172     {
173         delete *it;
174     }
175     m_substreams.clear();
176 }
177 
formatEndpoint(const packet_info * pinfo,const lbm_uim_stream_endpoint_t * endpoint)178 QString LBMStreamEntry::formatEndpoint(const packet_info * pinfo, const lbm_uim_stream_endpoint_t * endpoint)
179 {
180     if (endpoint->type == lbm_uim_instance_stream)
181     {
182         return QString(bytes_to_str(pinfo->pool, endpoint->stream_info.ctxinst.ctxinst, sizeof(endpoint->stream_info.ctxinst.ctxinst)));
183     }
184     else
185     {
186         return QString("%1:%2:%3")
187                .arg(endpoint->stream_info.dest.domain)
188                .arg(address_to_str(pinfo->pool, &(endpoint->stream_info.dest.addr)))
189                .arg(endpoint->stream_info.dest.port);
190     }
191 }
192 
processPacket(const packet_info * pinfo,const lbm_uim_stream_tap_info_t * stream_info)193 void LBMStreamEntry::processPacket(const packet_info * pinfo, const lbm_uim_stream_tap_info_t * stream_info)
194 {
195     LBMSubstreamEntry * substream = NULL;
196     LBMSubstreamMapIterator it;
197 
198     if (m_first_frame > pinfo->num)
199     {
200         m_first_frame = pinfo->num;
201     }
202     if (m_flast_frame < pinfo->num)
203     {
204         m_flast_frame = pinfo->num;
205     }
206     m_bytes += stream_info->bytes;
207     m_messages++;
208     it = m_substreams.find(stream_info->substream_id);
209     if (m_substreams.end() == it)
210     {
211         QTreeWidgetItem * item = NULL;
212 
213         substream = new LBMSubstreamEntry(m_channel, stream_info->substream_id, &(pinfo->src), pinfo->srcport, &(pinfo->dst), pinfo->destport);
214         m_substreams.insert(stream_info->substream_id, substream);
215         item = new QTreeWidgetItem();
216         substream->setItem(item);
217         m_item->addChild(item);
218         m_item->sortChildren(Stream_Column, Qt::AscendingOrder);
219     }
220     else
221     {
222         substream = it.value();
223     }
224     fillItem();
225     substream->processPacket(pinfo->num, stream_info->bytes);
226 }
227 
setItem(QTreeWidgetItem * item)228 void LBMStreamEntry::setItem(QTreeWidgetItem * item)
229 {
230     m_item = item;
231     fillItem(FALSE);
232 }
233 
fillItem(gboolean update_only)234 void LBMStreamEntry::fillItem(gboolean update_only)
235 {
236     if (update_only == FALSE)
237     {
238         m_item->setData(Stream_Column, Qt::DisplayRole, QVariant((qulonglong)m_channel));
239         m_item->setText(EndpointA_Column, m_endpoint_a);
240         m_item->setText(EndpointB_Column, m_endpoint_b);
241     }
242     m_item->setText(Messages_Column, QString("%1").arg(m_messages));
243     m_item->setText(Bytes_Column, QString("%1").arg(m_bytes));
244     m_item->setText(FirstFrame_Column, QString("%1").arg(m_first_frame));
245     m_item->setText(LastFrame_Column, QString("%1").arg(m_flast_frame));
246 }
247 
248 typedef QMap<guint64, LBMStreamEntry *> LBMStreamMap;
249 typedef QMap<guint64, LBMStreamEntry *>::iterator LBMStreamMapIterator;
250 
251 class LBMStreamDialogInfo
252 {
253     public:
254         LBMStreamDialogInfo(void);
255         ~LBMStreamDialogInfo(void);
256         void setDialog(LBMStreamDialog * dialog);
257         LBMStreamDialog * getDialog(void);
258         void processPacket(const packet_info * pinfo, const lbm_uim_stream_tap_info_t * stream_info);
259         void resetStreams(void);
260 
261     private:
262         LBMStreamDialog * m_dialog;
263         LBMStreamMap m_streams;
264 };
265 
LBMStreamDialogInfo(void)266 LBMStreamDialogInfo::LBMStreamDialogInfo(void) :
267     m_dialog(NULL),
268     m_streams()
269 {
270 }
271 
~LBMStreamDialogInfo(void)272 LBMStreamDialogInfo::~LBMStreamDialogInfo(void)
273 {
274     resetStreams();
275 }
276 
setDialog(LBMStreamDialog * dialog)277 void LBMStreamDialogInfo::setDialog(LBMStreamDialog * dialog)
278 {
279     m_dialog = dialog;
280 }
281 
getDialog(void)282 LBMStreamDialog * LBMStreamDialogInfo::getDialog(void)
283 {
284     return (m_dialog);
285 }
286 
processPacket(const packet_info * pinfo,const lbm_uim_stream_tap_info_t * stream_info)287 void LBMStreamDialogInfo::processPacket(const packet_info * pinfo, const lbm_uim_stream_tap_info_t * stream_info)
288 {
289     LBMStreamEntry * stream = NULL;
290     LBMStreamMapIterator it;
291 
292     it = m_streams.find(stream_info->channel);
293     if (m_streams.end() == it)
294     {
295         QTreeWidgetItem * item = NULL;
296         QTreeWidgetItem * parent = NULL;
297         Ui::LBMStreamDialog * ui = NULL;
298 
299         stream = new LBMStreamEntry(pinfo, stream_info->channel, &(stream_info->endpoint_a), &(stream_info->endpoint_b));
300         it = m_streams.insert(stream_info->channel, stream);
301         item = new QTreeWidgetItem();
302         stream->setItem(item);
303         ui = m_dialog->getUI();
304         ui->lbm_stream_TreeWidget->addTopLevelItem(item);
305         parent = ui->lbm_stream_TreeWidget->invisibleRootItem();
306         parent->sortChildren(Stream_Column, Qt::AscendingOrder);
307     }
308     else
309     {
310         stream = it.value();
311     }
312     stream->processPacket(pinfo, stream_info);
313 }
314 
resetStreams(void)315 void LBMStreamDialogInfo::resetStreams(void)
316 {
317     LBMStreamMapIterator it = m_streams.begin();
318 
319     while (it != m_streams.end())
320     {
321         delete *it;
322         ++it;
323     }
324     m_streams.clear();
325 }
326 
LBMStreamDialog(QWidget * parent,capture_file * cfile)327 LBMStreamDialog::LBMStreamDialog(QWidget * parent, capture_file * cfile) :
328     QDialog(parent),
329     m_ui(new Ui::LBMStreamDialog),
330     m_dialog_info(NULL),
331     m_capture_file(cfile)
332 {
333     m_ui->setupUi(this);
334     m_dialog_info = new LBMStreamDialogInfo();
335     connect(this, SIGNAL(accepted()), this, SLOT(closeDialog()));
336     connect(this, SIGNAL(rejected()), this, SLOT(closeDialog()));
337     fillTree();
338 }
339 
~LBMStreamDialog(void)340 LBMStreamDialog::~LBMStreamDialog(void)
341 {
342     delete m_ui;
343     if (m_dialog_info != NULL)
344     {
345         delete m_dialog_info;
346     }
347 }
348 
setCaptureFile(capture_file * cfile)349 void LBMStreamDialog::setCaptureFile(capture_file * cfile)
350 {
351     if (cfile == NULL) // We only want to know when the file closes.
352     {
353         m_capture_file = NULL;
354         m_ui->displayFilterLineEdit->setEnabled(false);
355         m_ui->applyFilterButton->setEnabled(false);
356     }
357 }
358 
fillTree(void)359 void LBMStreamDialog::fillTree(void)
360 {
361     GString * error_string;
362 
363     if (m_capture_file == NULL)
364     {
365         return;
366     }
367     m_dialog_info->setDialog(this);
368 
369     error_string = register_tap_listener("lbm_stream",
370         (void *)m_dialog_info,
371         m_ui->displayFilterLineEdit->text().toUtf8().constData(),
372         TL_REQUIRES_COLUMNS,
373         resetTap,
374         tapPacket,
375         drawTreeItems,
376         NULL);
377     if (error_string)
378     {
379         QMessageBox::critical(this, tr("LBM Stream failed to attach to tap"),
380             error_string->str);
381         g_string_free(error_string, TRUE);
382         reject();
383     }
384 
385     cf_retap_packets(m_capture_file);
386     drawTreeItems(&m_dialog_info);
387     remove_tap_listener((void *)m_dialog_info);
388 }
389 
resetTap(void * tap_data)390 void LBMStreamDialog::resetTap(void * tap_data)
391 {
392     LBMStreamDialogInfo * info = (LBMStreamDialogInfo *)tap_data;
393     LBMStreamDialog * dialog = info->getDialog();
394     if (dialog == NULL)
395     {
396         return;
397     }
398     info->resetStreams();
399     dialog->m_ui->lbm_stream_TreeWidget->clear();
400 }
401 
tapPacket(void * tap_data,packet_info * pinfo,epan_dissect_t *,const void * stream_info)402 tap_packet_status LBMStreamDialog::tapPacket(void * tap_data, packet_info * pinfo, epan_dissect_t *, const void * stream_info)
403 {
404     if (pinfo->fd->passed_dfilter == 1)
405     {
406         const lbm_uim_stream_tap_info_t * tapinfo = (const lbm_uim_stream_tap_info_t *)stream_info;
407         LBMStreamDialogInfo * info = (LBMStreamDialogInfo *)tap_data;
408 
409         info->processPacket(pinfo, tapinfo);
410     }
411     return (TAP_PACKET_REDRAW);
412 }
413 
drawTreeItems(void *)414 void LBMStreamDialog::drawTreeItems(void *)
415 {
416 }
417 
on_applyFilterButton_clicked(void)418 void LBMStreamDialog::on_applyFilterButton_clicked(void)
419 {
420     fillTree();
421 }
422 
closeDialog(void)423 void LBMStreamDialog::closeDialog(void)
424 {
425     delete this;
426 }
427