diff options
author | Jirka Novak <j.novak@netsystem.cz> | 2021-04-13 16:38:13 +0200 |
---|---|---|
committer | Wireshark GitLab Utility <gerald+gitlab-utility@wireshark.org> | 2021-04-14 14:02:58 +0000 |
commit | c7f56462490eb287a4152fb086dc8ae4ef8fcd11 (patch) | |
tree | bcb417998a807bb87209d2af263765707c380ffe /ui | |
parent | 38d279326a7b48aab44edfc58348758663b4d2ba (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.c | 2 | ||||
-rw-r--r-- | ui/qt/rtp_analysis_dialog.cpp | 34 | ||||
-rw-r--r-- | ui/qt/rtp_analysis_dialog.h | 1 | ||||
-rw-r--r-- | ui/qt/rtp_analysis_dialog.ui | 29 | ||||
-rw-r--r-- | ui/qt/rtp_audio_stream.cpp | 5 | ||||
-rw-r--r-- | ui/qt/rtp_audio_stream.h | 1 | ||||
-rw-r--r-- | ui/qt/rtp_player_dialog.cpp | 77 | ||||
-rw-r--r-- | ui/qt/rtp_player_dialog.h | 4 | ||||
-rw-r--r-- | ui/rtp_stream.c | 1 | ||||
-rw-r--r-- | ui/rtp_stream.h | 3 | ||||
-rw-r--r-- | ui/rtp_stream_id.c | 41 | ||||
-rw-r--r-- | ui/rtp_stream_id.h | 10 | ||||
-rw-r--r-- | ui/tap-rtp-common.c | 92 | ||||
-rw-r--r-- | ui/tap-rtp-common.h | 20 |
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 */ |