aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorJirka Novak <j.novak@netsystem.cz>2021-04-13 16:38:13 +0200
committerWireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2021-04-14 14:02:58 +0000
commitc7f56462490eb287a4152fb086dc8ae4ef8fcd11 (patch)
treebcb417998a807bb87209d2af263765707c380ffe /ui
parent38d279326a7b48aab44edfc58348758663b4d2ba (diff)
VoIP dialogs: Performance improvements
Retap and UI response are much faster when many RTP streams are processed. RTP Streams/Analyse 1000+, RTP Player 500+. Changes: - RTP streams are searched with hash, not by iterating over list. - UI operations do not redraw screen after every change, just after all changes. UI is locked when rereading packets. - Sample list during RTP decoding is stored in memory so wireshark uses just half of opened files for audio decoding than before. - Analysis window checkbox area is limited in height - Dialogs shows shows count of streams, count of selected streams and count of unmuted streams - Documentation extended with chapter about RTP decoding parameters - Documentation extended with performance estimates
Diffstat (limited to 'ui')
-rw-r--r--ui/cli/tap-rtp.c2
-rw-r--r--ui/qt/rtp_analysis_dialog.cpp34
-rw-r--r--ui/qt/rtp_analysis_dialog.h1
-rw-r--r--ui/qt/rtp_analysis_dialog.ui29
-rw-r--r--ui/qt/rtp_audio_stream.cpp5
-rw-r--r--ui/qt/rtp_audio_stream.h1
-rw-r--r--ui/qt/rtp_player_dialog.cpp77
-rw-r--r--ui/qt/rtp_player_dialog.h4
-rw-r--r--ui/rtp_stream.c1
-rw-r--r--ui/rtp_stream.h3
-rw-r--r--ui/rtp_stream_id.c41
-rw-r--r--ui/rtp_stream_id.h10
-rw-r--r--ui/tap-rtp-common.c92
-rw-r--r--ui/tap-rtp-common.h20
14 files changed, 275 insertions, 45 deletions
diff --git a/ui/cli/tap-rtp.c b/ui/cli/tap-rtp.c
index 1e6f5add4b..75a8bf961c 100644
--- a/ui/cli/tap-rtp.c
+++ b/ui/cli/tap-rtp.c
@@ -44,7 +44,7 @@ static void rtpstreams_stat_draw_cb(rtpstream_tapinfo_t *tapinfo);
*/
static rtpstream_tapinfo_t the_tapinfo_struct =
{ NULL, rtpstreams_stat_draw_cb, NULL,
- NULL, 0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, FALSE, FALSE
+ NULL, 0, NULL, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, FALSE, FALSE
};
static void
diff --git a/ui/qt/rtp_analysis_dialog.cpp b/ui/qt/rtp_analysis_dialog.cpp
index c57d508f98..632f0e2bef 100644
--- a/ui/qt/rtp_analysis_dialog.cpp
+++ b/ui/qt/rtp_analysis_dialog.cpp
@@ -429,7 +429,7 @@ int RtpAnalysisDialog::addTabUI(tab_info_t *new_tab)
new_tab->graphHorizontalLayout->setStretch(6, 1);
- ui->verticalLayout_2->addLayout(new_tab->graphHorizontalLayout);
+ ui->layout->addLayout(new_tab->graphHorizontalLayout);
return new_tab_no;
}
@@ -504,6 +504,7 @@ void RtpAnalysisDialog::updateWidgets()
ui->actionNextProblem->setEnabled(enable_nav);
if (enable_nav) {
+ hint.append(tr(" %1 streams, ").arg(tabs_.count() - 1));
hint.append(tr(" G: Go to packet, N: Next problem packet"));
}
@@ -653,10 +654,13 @@ tap_packet_status RtpAnalysisDialog::tapPacket(void *tapinfo_ptr, packet_info *p
return TAP_PACKET_DONT_REDRAW;
/* is it the forward direction? */
else {
- for(int i=0; i<rtp_analysis_dialog->tabs_.count(); i++) {
- tab_info_t *tab = rtp_analysis_dialog->tabs_[i];
- if (rtpstream_id_equal_pinfo_rtp_info(&(tab->stream.id),pinfo,rtpinfo)) {
+ // Search tab in hash key, if there are multiple tabs with same hash
+ QList<tab_info_t *> tabs = rtp_analysis_dialog->tab_hash_.values(pinfo_rtp_info_to_hash(pinfo, rtpinfo));
+ for (int i = 0; i < tabs.size(); i++) {
+ tab_info_t *tab = tabs.at(i);
+ if (rtpstream_id_equal_pinfo_rtp_info(&tab->stream.id, pinfo, rtpinfo)) {
rtp_analysis_dialog->addPacket(tab, pinfo, rtpinfo);
+ break;
}
}
}
@@ -930,6 +934,7 @@ void RtpAnalysisDialog::closeTab(int index)
if (index != tabs_.count()) {
QWidget *remove_tab = qobject_cast<QWidget *>(ui->tabWidget->widget(index));
tab_info_t *tab = tabs_[index];
+ tab_hash_.remove(rtpstream_to_hash(&tab->stream), tab);
ui->tabWidget->removeTab(index);
ui->streamGraph->removeGraph(tab->jitter_graph);
ui->streamGraph->removeGraph(tab->diff_graph);
@@ -1089,11 +1094,16 @@ void RtpAnalysisDialog::addRtpStreamsPrivate(QVector<rtpstream_info_t *> stream_
{
int first_tab_no = -1;
+ setUpdatesEnabled(false);
foreach(rtpstream_info_t *rtpstream, stream_infos) {
bool found = false;
- for(int i=0; i < tabs_.count(); i++) {
- if (rtpstream_id_equal(&(tabs_[i]->stream.id), &(rtpstream->id), RTPSTREAM_ID_EQUAL_SSRC)) {
+
+ QList<tab_info_t *> tabs = tab_hash_.values(rtpstream_to_hash(rtpstream));
+ for (int i = 0; i < tabs.size(); i++) {
+ tab_info_t *tab = tabs.at(i);
+ if (rtpstream_id_equal(&tab->stream.id, &rtpstream->id, RTPSTREAM_ID_EQUAL_SSRC)) {
found = true;
+ break;
}
}
@@ -1108,6 +1118,7 @@ void RtpAnalysisDialog::addRtpStreamsPrivate(QVector<rtpstream_info_t *> stream_
new_tab->delta_vals = new QVector<double>();
tabs_ << new_tab;
cur_tab_no = addTabUI(new_tab);
+ tab_hash_.insert(rtpstream_to_hash(rtpstream), new_tab);
if (first_tab_no == -1) {
first_tab_no = cur_tab_no;
}
@@ -1116,6 +1127,7 @@ void RtpAnalysisDialog::addRtpStreamsPrivate(QVector<rtpstream_info_t *> stream_
if (first_tab_no != -1) {
ui->tabWidget->setCurrentIndex(first_tab_no);
}
+ setUpdatesEnabled(true);
registerTapListener("rtp", this, NULL, 0, tapReset, tapPacket, tapDraw);
cap_file_.retapPackets();
removeTapListeners();
@@ -1125,13 +1137,17 @@ void RtpAnalysisDialog::addRtpStreamsPrivate(QVector<rtpstream_info_t *> stream_
void RtpAnalysisDialog::removeRtpStreams(QVector<rtpstream_info_t *> stream_infos _U_)
{
+ setUpdatesEnabled(false);
foreach(rtpstream_info_t *rtpstream, stream_infos) {
- for(int i=0; i < tabs_.count(); i++) {
- if (rtpstream_id_equal(&(tabs_[i]->stream.id), &(rtpstream->id), RTPSTREAM_ID_EQUAL_SSRC)) {
- closeTab(i);
+ QList<tab_info_t *> tabs = tab_hash_.values(rtpstream_to_hash(rtpstream));
+ for (int i = 0; i < tabs.size(); i++) {
+ tab_info_t *tab = tabs.at(i);
+ if (rtpstream_id_equal(&tab->stream.id, &rtpstream->id, RTPSTREAM_ID_EQUAL_SSRC)) {
+ closeTab(tabs_.indexOf(tab));
}
}
}
+ setUpdatesEnabled(true);
updateGraph();
}
diff --git a/ui/qt/rtp_analysis_dialog.h b/ui/qt/rtp_analysis_dialog.h
index b3c0cafa13..cb9016ba1e 100644
--- a/ui/qt/rtp_analysis_dialog.h
+++ b/ui/qt/rtp_analysis_dialog.h
@@ -115,6 +115,7 @@ private:
int tab_seq;
QVector<tab_info_t *> tabs_;
+ QMultiHash<guint, tab_info_t *> tab_hash_;
QPushButton *player_button_;
diff --git a/ui/qt/rtp_analysis_dialog.ui b/ui/qt/rtp_analysis_dialog.ui
index 33df9bfa11..1ce64d9c79 100644
--- a/ui/qt/rtp_analysis_dialog.ui
+++ b/ui/qt/rtp_analysis_dialog.ui
@@ -25,10 +25,37 @@
<attribute name="title">
<string>Graph</string>
</attribute>
- <layout class="QVBoxLayout" name="verticalLayout_2" stretch="1,0,0">
+ <layout class="QVBoxLayout" name="verticalLayout_2" stretch="1,0">
<item>
<widget class="QCustomPlot" name="streamGraph" native="true"/>
</item>
+ <item>
+ <widget class="QScrollArea" name="scrollarea">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>200</height>
+ </size>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="qwidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>606</width>
+ <height>298</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="layout"/>
+ </widget>
+ </widget>
+ </item>
</layout>
</widget>
</widget>
diff --git a/ui/qt/rtp_audio_stream.cpp b/ui/qt/rtp_audio_stream.cpp
index 5fc8d1c9f5..41a848ed1d 100644
--- a/ui/qt/rtp_audio_stream.cpp
+++ b/ui/qt/rtp_audio_stream.cpp
@@ -36,6 +36,7 @@
#include <QVariant>
#include <QTimer>
#include <QDebug>
+#include <QBuffer>
// To do:
// - Only allow one rtpstream_info_t per RtpAudioStream?
@@ -80,7 +81,7 @@ RtpAudioStream::RtpAudioStream(QObject *parent, rtpstream_info_t *rtpstream, boo
qWarning() << "Can't create temp file in " << tempname;
throw -1;
}
- sample_file_frame_ = new QTemporaryFile(tempname, this);
+ sample_file_frame_ = new QBuffer(this);
if (! sample_file_frame_->open(QIODevice::ReadWrite)) {
// We are out of file resources
delete sample_file_;
@@ -179,7 +180,7 @@ void RtpAudioStream::reset(double global_start_time)
if (!sample_file_->open(QIODevice::ReadWrite)) {
qWarning() << "Can't create temp file in " << tempname << " during retap";
}
- sample_file_frame_ = new QTemporaryFile(tempname, this);
+ sample_file_frame_ = new QBuffer(this);
if (!sample_file_frame_->open(QIODevice::ReadWrite)) {
qWarning() << "Can't create temp file in " << tempname << " during retap";
}
diff --git a/ui/qt/rtp_audio_stream.h b/ui/qt/rtp_audio_stream.h
index 60a5b2e4fd..5fa14ec65e 100644
--- a/ui/qt/rtp_audio_stream.h
+++ b/ui/qt/rtp_audio_stream.h
@@ -154,6 +154,7 @@ public:
qint64 getLeadSilenceSamples() { return prepend_samples_; }
qint64 getTotalSamples() { return (sample_file_->size()/(qint64)sizeof(SAMPLE)); }
bool savePayload(QIODevice *file);
+ guint getHash() { return rtpstream_id_to_hash(&id_); }
QString getIDAsQString();
signals:
diff --git a/ui/qt/rtp_player_dialog.cpp b/ui/qt/rtp_player_dialog.cpp
index d634b9a83b..19c7763cb0 100644
--- a/ui/qt/rtp_player_dialog.cpp
+++ b/ui/qt/rtp_player_dialog.cpp
@@ -8,6 +8,7 @@
*/
#include <ui/rtp_media.h>
+#include <ui/tap-rtp-common.h>
#include "rtp_player_dialog.h"
#include <ui_rtp_player_dialog.h>
@@ -149,6 +150,8 @@ RtpPlayerDialog::RtpPlayerDialog(QWidget &parent, CaptureFile &cf) :
, marker_stream_requested_out_rate_(0)
, last_ti_(0)
, listener_removed_(true)
+ , block_redraw_(false)
+ , lock_ui_(0)
{
ui->setupUi(this);
loadGeometry(parent.width(), parent.height());
@@ -414,6 +417,7 @@ void RtpPlayerDialog::retapPackets()
void RtpPlayerDialog::rescanPackets(bool rescale_axes)
{
+ lockUI();
// Show information for a user - it can last long time...
ui->hintLabel->setText("<i><small>" + tr("Decoding streams...") + "</i></small>");
wsApp->processEvents();
@@ -453,6 +457,7 @@ void RtpPlayerDialog::rescanPackets(bool rescale_axes)
createPlot(rescale_axes);
updateWidgets();
+ unlockUI();
}
void RtpPlayerDialog::createPlot(bool rescale_axes)
@@ -600,6 +605,8 @@ void RtpPlayerDialog::createPlot(bool rescale_axes)
void RtpPlayerDialog::addSingleRtpStream(rtpstream_info_t *rtpstream)
{
+ bool found = false;
+
AudioRouting audio_routing = AudioRouting(AUDIO_UNMUTED, channel_mono);
if (!rtpstream) return;
@@ -607,23 +614,24 @@ void RtpPlayerDialog::addSingleRtpStream(rtpstream_info_t *rtpstream)
// Find the RTP streams associated with this conversation.
// gtk/rtp_player.c:mark_rtp_stream_to_play does this differently.
- RtpAudioStream *audio_stream = NULL;
- int tli_count = ui->streamTreeWidget->topLevelItemCount();
- for (int row = 0; row < tli_count; row++) {
- QTreeWidgetItem *ti = ui->streamTreeWidget->topLevelItem(row);
- RtpAudioStream *row_stream = ti->data(stream_data_col_, Qt::UserRole).value<RtpAudioStream*>();
+ QList<RtpAudioStream *> streams = stream_hash_.values(rtpstream_to_hash(rtpstream));
+ for (int i = 0; i < streams.size(); i++) {
+ RtpAudioStream *row_stream = streams.at(i);
if (row_stream->isMatch(rtpstream)) {
- audio_stream = row_stream;
+ found = true;
break;
}
}
- if (!audio_stream) {
+ int tli_count = ui->streamTreeWidget->topLevelItemCount();
+
+ if (!found) {
try {
- audio_stream = new RtpAudioStream(this, rtpstream, stereo_available_);
+ RtpAudioStream *audio_stream = new RtpAudioStream(this, rtpstream, stereo_available_);
audio_stream->setColor(ColorUtils::graphColor(tli_count));
QTreeWidgetItem *ti = new RtpPlayerTreeWidgetItem(ui->streamTreeWidget);
+ stream_hash_.insert(rtpstream_to_hash(rtpstream), audio_stream);
ti->setText(src_addr_col_, address_to_qstring(&rtpstream->id.src_addr));
ti->setText(src_port_col_, QString::number(rtpstream->id.src_port));
ti->setText(dst_addr_col_, address_to_qstring(&rtpstream->id.dst_addr));
@@ -686,15 +694,19 @@ void RtpPlayerDialog::addSingleRtpStream(rtpstream_info_t *rtpstream)
void RtpPlayerDialog::lockUI()
{
- if (playing_streams_.count() > 0) {
- on_stopButton_clicked();
+ if (0 == lock_ui_++) {
+ if (playing_streams_.count() > 0) {
+ on_stopButton_clicked();
+ }
+ setEnabled(false);
}
- setEnabled(false);
}
void RtpPlayerDialog::unlockUI()
{
- setEnabled(true);
+ if (--lock_ui_ == 0) {
+ setEnabled(true);
+ }
}
void RtpPlayerDialog::replaceRtpStreams(QVector<rtpstream_info_t *> stream_infos)
@@ -1197,15 +1209,16 @@ tap_packet_status RtpPlayerDialog::tapPacket(void *tapinfo_ptr, packet_info *pin
void RtpPlayerDialog::addPacket(packet_info *pinfo, const _rtp_info *rtpinfo)
{
- for (int row = 0; row < ui->streamTreeWidget->topLevelItemCount(); row++) {
- QTreeWidgetItem *ti = ui->streamTreeWidget->topLevelItem(row);
- RtpAudioStream *row_stream = ti->data(stream_data_col_, Qt::UserRole).value<RtpAudioStream*>();
-
+ // Search stream in hash key, if there are multiple streams with same hash
+ QList<RtpAudioStream *> streams = stream_hash_.values(pinfo_rtp_info_to_hash(pinfo, rtpinfo));
+ for (int i = 0; i < streams.size(); i++) {
+ RtpAudioStream *row_stream = streams.at(i);
if (row_stream->isMatch(pinfo, rtpinfo)) {
row_stream->addRtpPacket(pinfo, rtpinfo);
- return;
+ break;
}
}
+
// qDebug() << "=ap no match!" << address_to_qstring(&pinfo->src) << address_to_qstring(&pinfo->dst);
}
@@ -1448,8 +1461,10 @@ void RtpPlayerDialog::on_streamTreeWidget_itemSelectionChanged()
ui->actionSavePayload->setEnabled(false);
}
- ui->audioPlot->replot();
- updateHintLabel();
+ if (!block_redraw_) {
+ ui->audioPlot->replot();
+ updateHintLabel();
+ }
}
// Change channel audio routing if double clicked channel column
@@ -1471,6 +1486,7 @@ void RtpPlayerDialog::removeRow(QTreeWidgetItem *ti)
{
RtpAudioStream *audio_stream = ti->data(stream_data_col_, Qt::UserRole).value<RtpAudioStream*>();
if (audio_stream) {
+ stream_hash_.remove(audio_stream->getHash(), audio_stream);
ti->setData(stream_data_col_, Qt::UserRole, QVariant());
delete audio_stream;
}
@@ -1513,13 +1529,16 @@ void RtpPlayerDialog::on_actionRemoveStream_triggered()
{
QList<QTreeWidgetItem *> items = ui->streamTreeWidget->selectedItems();
+ block_redraw_ = true;
if (last_ti_) {
highlightItem(last_ti_, false);
last_ti_ = NULL;
}
- for(int i = 0; i<items.count(); i++ ) {
+ //for(int i = 0; i<items.count(); i++ ) {
+ for(int i = items.count() - 1; i>=0; i-- ) {
removeRow(items[i]);
}
+ block_redraw_ = false;
// TODO: Recalculate legend
// - Graphs used for legend could be removed above and we must add new
// - If no legend is required, it should be removed
@@ -1551,7 +1570,9 @@ void RtpPlayerDialog::changeAudioRoutingOnItem(QTreeWidgetItem *ti, AudioRouting
audio_graph->setSelected(ti->isSelected());
audio_graph->setMuted(audio_routing.isMuted());
- ui->audioPlot->replot();
+ if (!block_redraw_) {
+ ui->audioPlot->replot();
+ }
}
}
@@ -1560,11 +1581,14 @@ void RtpPlayerDialog::changeAudioRouting(AudioRouting new_audio_routing)
{
QList<QTreeWidgetItem *> items = ui->streamTreeWidget->selectedItems();
+ block_redraw_ = true;
for(int i = 0; i<items.count(); i++ ) {
QTreeWidgetItem *ti = items[i];
changeAudioRoutingOnItem(ti, new_audio_routing);
}
+ block_redraw_ = false;
+ ui->audioPlot->replot();
updateHintLabel();
}
@@ -1621,11 +1645,14 @@ void RtpPlayerDialog::on_actionAudioRoutingMuteInvert_triggered()
{
QList<QTreeWidgetItem *> items = ui->streamTreeWidget->selectedItems();
+ block_redraw_ = true;
for(int i = 0; i<items.count(); i++ ) {
QTreeWidgetItem *ti = items[i];
invertAudioMutingOnItem(ti);
}
+ block_redraw_ = false;
+ ui->audioPlot->replot();
updateHintLabel();
}
@@ -1695,6 +1722,7 @@ void RtpPlayerDialog::cleanupMarkerStream()
void RtpPlayerDialog::on_outputDeviceComboBox_currentIndexChanged(const QString &)
{
+ lockUI();
stereo_available_ = isStereoAvailable();
for (int row = 0; row < ui->streamTreeWidget->topLevelItemCount(); row++) {
QTreeWidgetItem *ti = ui->streamTreeWidget->topLevelItem(row);
@@ -1709,10 +1737,12 @@ void RtpPlayerDialog::on_outputDeviceComboBox_currentIndexChanged(const QString
cleanupMarkerStream();
fillAudioRateMenu();
rescanPackets();
+ unlockUI();
}
void RtpPlayerDialog::on_outputAudioRate_currentIndexChanged(const QString & rate_string)
{
+ lockUI();
// Any unconvertable string is converted to 0 => used as Automatic rate
unsigned selected_rate = rate_string.toInt();
@@ -1727,6 +1757,7 @@ void RtpPlayerDialog::on_outputAudioRate_currentIndexChanged(const QString & rat
marker_stream_requested_out_rate_ = selected_rate;
cleanupMarkerStream();
rescanPackets();
+ unlockUI();
}
void RtpPlayerDialog::on_jitterSpinBox_valueChanged(double)
@@ -1844,10 +1875,14 @@ bool RtpPlayerDialog::isStereoAvailable()
void RtpPlayerDialog::invertSelection()
{
+ block_redraw_ = true;
for (int row = 0; row < ui->streamTreeWidget->topLevelItemCount(); row++) {
QTreeWidgetItem *ti = ui->streamTreeWidget->topLevelItem(row);
ti->setSelected(!ti->isSelected());
}
+ block_redraw_ = false;
+ ui->audioPlot->replot();
+ updateHintLabel();
}
void RtpPlayerDialog::on_actionSelectAll_triggered()
diff --git a/ui/qt/rtp_player_dialog.h b/ui/qt/rtp_player_dialog.h
index 21b47f6fc1..c3f0c8e659 100644
--- a/ui/qt/rtp_player_dialog.h
+++ b/ui/qt/rtp_player_dialog.h
@@ -20,6 +20,7 @@
#include "rtp_audio_stream.h"
#include <QMap>
+#include <QMultiHash>
#include <QTreeWidgetItem>
#include <QMetaType>
#include <ui/qt/widgets/qcustomplot.h>
@@ -177,6 +178,9 @@ private:
QTreeWidgetItem *last_ti_;
bool listener_removed_;
QPushButton *export_btn_;
+ QMultiHash<guint, RtpAudioStream *> stream_hash_;
+ bool block_redraw_;
+ int lock_ui_;
// const QString streamKey(const rtpstream_info_t *rtpstream);
// const QString streamKey(const packet_info *pinfo, const struct _rtp_info *rtpinfo);
diff --git a/ui/rtp_stream.c b/ui/rtp_stream.c
index 48ca001da4..ddbf514d22 100644
--- a/ui/rtp_stream.c
+++ b/ui/rtp_stream.c
@@ -138,7 +138,6 @@ void rtpstream_mark(rtpstream_tapinfo_t *tapinfo, capture_file *cap_file, rtpstr
remove_tap_listener_rtpstream(tapinfo);
}
-
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
diff --git a/ui/rtp_stream.h b/ui/rtp_stream.h
index d92af1267a..24b14b83c8 100644
--- a/ui/rtp_stream.h
+++ b/ui/rtp_stream.h
@@ -90,6 +90,9 @@ struct _rtpstream_tapinfo {
void *tap_data; /**< data for tap callbacks */
int nstreams; /**< number of streams in the list */
GList *strinfo_list; /**< list of rtpstream_info_t* */
+ GHashTable *strinfo_hash; /**< multihash of rtpstream_info_t **/
+ /* multihash means that there can be */
+ /* more values related to one hash key */
int npackets; /**< total number of rtp packets of all streams */
/* used while tapping. user shouldn't modify these */
tap_mode_t mode;
diff --git a/ui/rtp_stream_id.c b/ui/rtp_stream_id.c
index a238d900b7..9bfdd15f07 100644
--- a/ui/rtp_stream_id.c
+++ b/ui/rtp_stream_id.c
@@ -66,6 +66,26 @@ void rtpstream_id_free(rtpstream_id_t *id)
}
/****************************************************************************/
+/* convert rtpstream_id_t to hash */
+guint rtpstream_id_to_hash(const rtpstream_id_t *id)
+{
+ guint hash = 0;
+
+ if (!id) { return 0; }
+ /* XOR of: */
+ /* SRC PORT | DST_PORT */
+ /* SSRC */
+ /* SRC ADDR */
+ /* DST ADDR */
+ hash ^= id->src_port | id->dst_port << 16;
+ hash ^= id->ssrc;
+ add_address_to_hash(hash, &id->src_addr);
+ add_address_to_hash(hash, &id->dst_addr);
+
+ return hash;
+}
+
+/****************************************************************************/
/* compare two ids by flags */
gboolean rtpstream_id_equal(const rtpstream_id_t *id1, const rtpstream_id_t *id2, guint flags)
{
@@ -104,6 +124,27 @@ gboolean rtpstream_id_equal_pinfo_rtp_info(const rtpstream_id_t *id, const packe
return FALSE;
}
+/****************************************************************************/
+/* convert packet_info and _rtp_info to hash */
+guint pinfo_rtp_info_to_hash(const packet_info *pinfo, const struct _rtp_info *rtp_info)
+{
+ guint hash = 0;
+
+ if (!pinfo || !rtp_info) { return 0; }
+ /* XOR of: */
+ /* SRC PORT | DST_PORT */
+ /* SSRC */
+ /* SRC ADDR */
+ /* DST ADDR */
+ hash ^= pinfo->srcport | pinfo->destport << 16;
+ hash ^= rtp_info->info_sync_src;
+ add_address_to_hash(hash, &pinfo->src);
+ add_address_to_hash(hash, &pinfo->dst);
+
+ return hash;
+}
+
+
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
diff --git a/ui/rtp_stream_id.h b/ui/rtp_stream_id.h
index a9e57e5811..81d29cc482 100644
--- a/ui/rtp_stream_id.h
+++ b/ui/rtp_stream_id.h
@@ -38,6 +38,11 @@ typedef struct _rtpstream_id {
} rtpstream_id_t;
/**
+ * Get hash of rtpstream_id
+ */
+guint rtpstream_id_to_hash(const rtpstream_id_t *id);
+
+/**
* Copy rtpstream_id_t structure
*/
void rtpstream_id_copy(const rtpstream_id_t *src, rtpstream_id_t *dest);
@@ -70,6 +75,11 @@ gboolean rtpstream_id_equal(const rtpstream_id_t *id1, const rtpstream_id_t *id2
*/
gboolean rtpstream_id_equal_pinfo_rtp_info(const rtpstream_id_t *id, const packet_info *pinfo, const struct _rtp_info *rtp_info);
+/**
+ * Get hash of rtpstream_id extracted from packet_info and _rtp_info
+ */
+guint pinfo_rtp_info_to_hash(const packet_info *pinfo, const struct _rtp_info *rtp_info);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/ui/tap-rtp-common.c b/ui/tap-rtp-common.c
index baa3a6c9cc..ba6fb45501 100644
--- a/ui/tap-rtp-common.c
+++ b/ui/tap-rtp-common.c
@@ -147,6 +147,10 @@ void rtpstream_reset(rtpstream_tapinfo_t *tapinfo)
if (tapinfo->mode == TAP_ANALYSE) {
/* free the data items first */
+ if (tapinfo->strinfo_hash) {
+ g_hash_table_foreach(tapinfo->strinfo_hash, rtpstream_info_multihash_destroy_value, NULL);
+ g_hash_table_destroy(tapinfo->strinfo_hash);
+ }
list = g_list_first(tapinfo->strinfo_list);
while (list)
{
@@ -157,6 +161,7 @@ void rtpstream_reset(rtpstream_tapinfo_t *tapinfo)
}
g_list_free(tapinfo->strinfo_list);
tapinfo->strinfo_list = NULL;
+ tapinfo->strinfo_hash = NULL;
tapinfo->nstreams = 0;
tapinfo->npackets = 0;
}
@@ -366,7 +371,6 @@ tap_packet_status rtpstream_packet_cb(void *arg, packet_info *pinfo, epan_dissec
const struct _rtp_info *rtpinfo = (const struct _rtp_info *)arg2;
rtpstream_info_t new_stream_info;
rtpstream_info_t *stream_info = NULL;
- GList* list;
rtpdump_info_t rtpdump_info;
struct _rtp_conversation_info *p_conv_data = NULL;
@@ -386,15 +390,8 @@ tap_packet_status rtpstream_packet_cb(void *arg, packet_info *pinfo, epan_dissec
}
/* check whether we already have a stream with these parameters in the list */
- list = g_list_first(tapinfo->strinfo_list);
- while (list)
- {
- if (rtpstream_info_cmp(&new_stream_info, (rtpstream_info_t *)(list->data))==0)
- {
- stream_info = (rtpstream_info_t *)(list->data); /*found!*/
- break;
- }
- list = g_list_next(list);
+ if (tapinfo->strinfo_hash) {
+ stream_info = rtpstream_info_multihash_lookup(tapinfo->strinfo_hash, &new_stream_info);
}
/* not in the list? then create a new entry */
@@ -419,6 +416,10 @@ tap_packet_status rtpstream_packet_cb(void *arg, packet_info *pinfo, epan_dissec
stream_info = rtpstream_info_malloc_and_init();
rtpstream_info_copy_deep(stream_info, &new_stream_info);
tapinfo->strinfo_list = g_list_prepend(tapinfo->strinfo_list, stream_info);
+ if (!tapinfo->strinfo_hash) {
+ tapinfo->strinfo_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
+ }
+ rtpstream_info_multihash_insert(tapinfo->strinfo_hash, stream_info);
}
/* get RTP stats for the packet */
@@ -535,6 +536,77 @@ void rtpstream_info_calc_free(rtpstream_info_calc_t *calc)
wmem_free(NULL, calc->all_payload_type_names);
}
+/****************************************************************************/
+/* Get hash for rtpstream_info_t */
+guint rtpstream_to_hash(gconstpointer key)
+{
+ if (key) {
+ return rtpstream_id_to_hash(&((rtpstream_info_t *)key)->id);
+ } else {
+ return 0;
+ }
+}
+
+/****************************************************************************/
+/* Inserts new_stream_info to multihash if its not there */
+
+void rtpstream_info_multihash_insert(GHashTable *multihash, rtpstream_info_t *new_stream_info)
+{
+ GList *hlist = (GList *)g_hash_table_lookup(multihash, GINT_TO_POINTER(rtpstream_to_hash(new_stream_info)));
+ gboolean found = FALSE;
+ if (hlist) {
+ // Key exists in hash
+ GList *list = g_list_first(hlist);
+ while (list)
+ {
+ if (rtpstream_info_cmp(new_stream_info, (rtpstream_info_t *)(list->data))==0) {
+ found = TRUE;
+ break;
+ }
+ list = g_list_next(list);
+ }
+ if (!found) {
+ // stream_info is not in list yet, add it
+ hlist = g_list_prepend(hlist, new_stream_info);
+ }
+ } else {
+ // No key in hash, init new list
+ hlist = g_list_prepend(hlist, new_stream_info);
+ }
+ g_hash_table_insert(multihash, GINT_TO_POINTER(rtpstream_to_hash(new_stream_info)), hlist);
+}
+
+/****************************************************************************/
+/* Lookup stream_info in multihash */
+
+rtpstream_info_t *rtpstream_info_multihash_lookup(GHashTable *multihash, rtpstream_info_t *stream_info)
+{
+ GList *hlist = (GList *)g_hash_table_lookup(multihash, GINT_TO_POINTER(rtpstream_to_hash(stream_info)));
+ if (hlist) {
+ // Key exists in hash
+ GList *list = g_list_first(hlist);
+ while (list)
+ {
+ if (rtpstream_info_cmp(stream_info, (rtpstream_info_t *)(list->data))==0) {
+ return (rtpstream_info_t *)(list->data);
+ }
+ list = g_list_next(list);
+ }
+ }
+
+ // No stream_info in hash or was not found in existing list
+ return NULL;
+}
+
+/****************************************************************************/
+/* Destroys GList used in multihash */
+
+void rtpstream_info_multihash_destroy_value(gpointer key _U_, gpointer value, gpointer user_data _U_)
+{
+ g_list_free((GList *)value);
+}
+
+
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
diff --git a/ui/tap-rtp-common.h b/ui/tap-rtp-common.h
index 651c6f6f9f..7b91784a82 100644
--- a/ui/tap-rtp-common.h
+++ b/ui/tap-rtp-common.h
@@ -138,6 +138,26 @@ void rtpstream_info_calculate(const rtpstream_info_t *strinfo, rtpstream_info_ca
*/
void rtpstream_info_calc_free(rtpstream_info_calc_t *calc);
+/**
+ * Get hash key for rtpstream_info_t
+ */
+guint rtpstream_to_hash(gconstpointer key);
+
+/**
+ * Insert new_stream_info into multihash
+ */
+void rtpstream_info_multihash_insert(GHashTable *multihash, rtpstream_info_t *new_stream_info);
+
+/**
+ * Lookup stream_info in stream_info multihash
+ */
+rtpstream_info_t *rtpstream_info_multihash_lookup(GHashTable *multihash, rtpstream_info_t *stream_info);
+
+/**
+ * GHFunc () for destroying GList in multihash
+ */
+void rtpstream_info_multihash_destroy_value(gpointer key, gpointer value, gpointer user_data);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */