/* conversation_dialog.cpp * * Wireshark - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "conversation_dialog.h" #include #include #include #include "ui/recent.h" #include "ui/tap-tcp-stream.h" #include "wsutil/str_util.h" #include #include #include #include #include #include "main_application.h" #include #include #include #include #include // To do: // - https://gitlab.com/wireshark/wireshark/-/issues/6727 // - Wide last column? // - Improper wildcard handling https://gitlab.com/wireshark/wireshark/-/issues/8010 // - TShark consolidation https://gitlab.com/wireshark/wireshark/-/issues/6310 // - Display filter entry? // - Add follow, copy & graph actions to context menu. // Bugs: // - Slow for large numbers of items. // - Name resolution doesn't do anything if its preference is disabled. // Fixed bugs: // - Friendly unit displays https://gitlab.com/wireshark/wireshark/-/issues/9231 // - Misleading bps calculation https://gitlab.com/wireshark/wireshark/-/issues/8703 // - Show Absolute time in conversation tables https://gitlab.com/wireshark/wireshark/-/issues/11618 // - The value of 'Rel start' and 'Duration' in "Conversations" no need too precise https://gitlab.com/wireshark/wireshark/-/issues/12803 typedef enum { CONV_COLUMN_SRC_ADDR, CONV_COLUMN_SRC_PORT, CONV_COLUMN_DST_ADDR, CONV_COLUMN_DST_PORT, CONV_COLUMN_PACKETS, CONV_COLUMN_BYTES, CONV_COLUMN_PKT_AB, CONV_COLUMN_BYTES_AB, CONV_COLUMN_PKT_BA, CONV_COLUMN_BYTES_BA, CONV_COLUMN_START, CONV_COLUMN_DURATION, CONV_COLUMN_BPS_AB, CONV_COLUMN_BPS_BA, CONV_NUM_COLUMNS, CONV_INDEX_COLUMN = CONV_NUM_COLUMNS } conversation_column_type_e; static const QString table_name_ = QObject::tr("Conversation"); static ATapDataModel * createModel(int protoId, QString filter) { return new ConversationDataModel(protoId, filter); } static QAbstractItemDelegate * createDelegate(QWidget * parent) { TimelineDelegate * delegate = new TimelineDelegate(parent); delegate->setDataRole(ATapDataModel::TIMELINE_DATA); return delegate; } ConversationDialog::ConversationDialog(QWidget &parent, CaptureFile &cf) : TrafficTableDialog(parent, cf, table_name_), tcp_graph_requested_(false) { trafficList()->setProtocolInfo(table_name_, &(recent.conversation_tabs)); trafficTab()->setProtocolInfo(table_name_, trafficList(), &(recent.conversation_tabs_columns), &createModel); trafficTab()->setDelegate(CONV_COLUMN_START, &createDelegate); trafficTab()->setDelegate(CONV_COLUMN_DURATION, &createDelegate); trafficTab()->setFilter(cf.displayFilter()); connect(trafficTab(), &TrafficTab::filterAction, this, &ConversationDialog::filterAction); connect(trafficTab()->tabBar(), &QTabBar::currentChanged, this, &ConversationDialog::tabChanged); connect(trafficTab(), &TrafficTab::tabDataChanged, this, &ConversationDialog::tabChanged); follow_bt_ = buttonBox()->addButton(tr("Follow Stream…"), QDialogButtonBox::ActionRole); follow_bt_->setToolTip(tr("Follow a TCP or UDP stream.")); connect(follow_bt_, SIGNAL(clicked()), this, SLOT(followStream())); graph_bt_ = buttonBox()->addButton(tr("Graph…"), QDialogButtonBox::ActionRole); graph_bt_->setToolTip(tr("Graph a TCP conversation.")); connect(graph_bt_, SIGNAL(clicked()), this, SLOT(graphTcp())); connect(mainApp->mainWindow(), SIGNAL(displayFilterSuccess(bool)), this, SLOT(displayFilterSuccess(bool))); absoluteTimeCheckBox()->show(); updateWidgets(); } void ConversationDialog::captureFileClosing() { trafficTab()->disableTap(); displayFilterCheckBox()->setEnabled(false); follow_bt_->setEnabled(false); graph_bt_->setEnabled(false); TrafficTableDialog::captureFileClosing(); } void ConversationDialog::followStream() { if (file_closed_) return; int endpointType = trafficTab()->currentItemData(ATapDataModel::ENDPOINT_DATATYPE).toInt(); if (endpointType != CONVERSATION_TCP && endpointType != CONVERSATION_UDP) return; follow_type_t ftype = FOLLOW_TCP; if (endpointType == CONVERSATION_UDP) ftype = FOLLOW_UDP; int convId = trafficTab()->currentItemData(ATapDataModel::CONVERSATION_ID).toInt(); // Will set the display filter too. // TCP and UDP do not have a "sub-stream", so set a dummy value. emit openFollowStreamDialog(ftype, convId, 0); } void ConversationDialog::graphTcp() { if (file_closed_) return; int endpointType = trafficTab()->currentItemData(ATapDataModel::ENDPOINT_DATATYPE).toInt(); if (endpointType != CONVERSATION_TCP) return; int convId = trafficTab()->currentItemData(ATapDataModel::CONVERSATION_ID).toInt(); // XXX The GTK+ code opens the TCP Stream dialog. We might want // to open the I/O Graphs dialog instead. QString filter = QString("tcp.stream eq %1").arg(convId); tcp_graph_requested_ = true; // Apply the filter for this conversation. When the filter is active, we // can draw the TCP graph. emit filterAction(filter, FilterAction::ActionApply, FilterAction::ActionTypePlain); } void ConversationDialog::tabChanged(int) { bool follow = false; bool graph = false; if (!file_closed_) { int endpointType = trafficTab()->currentItemData(ATapDataModel::ENDPOINT_DATATYPE).toInt(); switch(endpointType) { case CONVERSATION_TCP: graph = true; // Fall through case CONVERSATION_UDP: follow = true; break; } } follow_bt_->setEnabled(follow); graph_bt_->setEnabled(graph); TrafficTableDialog::currentTabChanged(); } void ConversationDialog::on_buttonBox_helpRequested() { mainApp->helpTopicAction(HELP_STATS_CONVERSATIONS_DIALOG); } void ConversationDialog::displayFilterSuccess(bool success) { if (tcp_graph_requested_) { if (success) { // The display filter was applied successfully, i.e. the current // packet is now part of our selected tcp conversation. openTcpStreamGraph(GRAPH_TSEQ_TCPTRACE); } tcp_graph_requested_ = false; } } void init_conversation_table(struct register_ct* ct, const char *filter) { mainApp->emitStatCommandSignal("Conversations", filter, GINT_TO_POINTER(get_conversation_proto_id(ct))); }