Add TCP sequence number (Stevens-style) graphs.

Add the QCustomPlot widget. Thanks to Emanuel Eichhammer for granting a
license change. Move some common code from ui/gtk/tcp_graph.c to
ui/tap-tcp-stream.[ch]. Get rid of tcp_graph_selected_packet_enabled().
It was only used in the menu code and didn't match what we were doing
elsewhere.

Still quite a bit of work to do but it's a promising start.

svn path=/trunk/; revision=51538
This commit is contained in:
Gerald Combs 2013-08-27 18:13:20 +00:00
parent 77f1ed0f93
commit 6d731a3e79
19 changed files with 22784 additions and 592 deletions

View File

@ -159,7 +159,10 @@ HTTP request statistics?
- Preferences are complete, and are arguably more useful than the GTK+ version.
An "Advanced" preference pane exists, which lets you edit everything. They use
the proper menu placement and keyboard shortcut on OS X.
the proper menu placement and keyboard shortcut on OS X.
- Some dialogs (file sets, profiles, and UATs) provide a link to filesystem paths
where appropriate.
3. Translations (i18n)
For make your own translation of QtShark ! it is easy !

View File

@ -38,6 +38,7 @@ set(COMMON_UI_SRC
software_update.c
tap-megaco-common.c
tap-rtp-common.c
tap-tcp-stream.c
text_import.c
time_shift.c
util.c

View File

@ -59,6 +59,7 @@ WIRESHARK_UI_SRC = \
ssl_key_export.c \
tap-megaco-common.c \
tap-rtp-common.c \
tap-tcp-stream.c \
text_import.c \
time_shift.c \
util.c
@ -83,6 +84,7 @@ noinst_HEADERS = \
ssl_key_export.h \
tap-megaco-common.h \
tap-rtp-common.h \
tap-tcp-stream.h \
text_import.h \
text_import_scanner.h \
time_shift.h \

View File

@ -154,7 +154,6 @@ void rlc_lte_graph_known_channel_launch(guint16 ueid, guint8 rlcMode,
void gtk_stats_tree_cb(GtkAction *action, gpointer user_data);
void tcp_graph_cb(GtkAction *action, gpointer user_data);
gboolean tcp_graph_selected_packet_enabled(frame_data *current_frame, epan_dissect_t *edt, gpointer callback_data _U_);
void tcp_graph_known_stream_launch(address *src_address, guint16 src_port,
address *dst_address, guint16 dst_port);

View File

@ -4903,6 +4903,11 @@ set_menus_for_selected_packet(capture_file *cf)
than one time reference frame or the current frame isn't a
time reference frame). (XXX - why check frame_selected?) */
gboolean tcp_packet_selected = FALSE;
if (cf) {
tcp_packet_selected = frame_selected && (cf->edt->pi.ipproto == IP_PROTO_TCP);
}
if (cfile.edt && cfile.edt->tree) {
GPtrArray *ga;
header_field_info *hfinfo;
@ -4997,9 +5002,9 @@ set_menus_for_selected_packet(capture_file *cf)
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/SCTP",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_SCTP) : FALSE);
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/FollowTCPStream",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
tcp_packet_selected);
set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/FollowTCPStream",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
tcp_packet_selected);
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/FollowUDPStream",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_UDP) : FALSE);
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/FollowSSLStream",
@ -5013,7 +5018,7 @@ set_menus_for_selected_packet(capture_file *cf)
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/ConversationFilter/IP",
frame_selected ? ((cf->edt->pi.ethertype == ETHERTYPE_IP)||(cf->edt->pi.ethertype == ETHERTYPE_IPv6)) : FALSE);
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/ConversationFilter/TCP",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
tcp_packet_selected);
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/ConversationFilter/UDP",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_UDP) : FALSE);
set_menu_sensitivity(ui_manager_tree_view_menu, "/TreeViewPopup/FollowUDPStream",
@ -5027,7 +5032,7 @@ set_menus_for_selected_packet(capture_file *cf)
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/ColorizeConversation/IP",
frame_selected ? ((cf->edt->pi.ethertype == ETHERTYPE_IP)||(cf->edt->pi.ethertype == ETHERTYPE_IPv6)) : FALSE);
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/ColorizeConversation/TCP",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
tcp_packet_selected);
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/ColorizeConversation/UDP",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_UDP) : FALSE);
set_menu_sensitivity(ui_manager_packet_list_menu, "/PacketListMenuPopup/ColorizeConversation/PN-CBA",
@ -5061,7 +5066,7 @@ set_menus_for_selected_packet(capture_file *cf)
frame_selected && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns));
set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/AnalyzeMenu/FollowTCPStream",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_TCP) : FALSE);
tcp_packet_selected);
set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/AnalyzeMenu/FollowUDPStream",
frame_selected ? (cf->edt->pi.ipproto == IP_PROTO_UDP) : FALSE);
set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/AnalyzeMenu/FollowSSLStream",
@ -5074,7 +5079,7 @@ set_menus_for_selected_packet(capture_file *cf)
set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ToolsMenu/FirewallACLRules",
frame_selected);
set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/TCPStreamGraphMenu",
tcp_graph_selected_packet_enabled(cf->current_frame,cf->edt, NULL));
tcp_packet_selected);
while (list_entry != NULL) {
dissector_filter_t *filter_entry;

File diff suppressed because it is too large Load Diff

View File

@ -70,6 +70,7 @@ set(QTSHARK_H_SRC
splash_overlay.h
summary_dialog.h
syntax_line_edit.h
tcp_stream_dialog.h
time_shift_dialog.h
uat_dialog.h
wireshark_application.h
@ -133,6 +134,7 @@ set(CLEAN_FILES
sparkline_delegate.cpp
summary_dialog.cpp
syntax_line_edit.cpp
tcp_stream_dialog.cpp
time_shift_dialog.cpp
uat_dialog.cpp
wireshark_application.cpp
@ -164,6 +166,7 @@ set(QTSHARK_UI
search_frame.ui
splash_overlay.ui
summary_dialog.ui
tcp_stream_dialog.ui
time_shift_dialog.ui
uat_dialog.ui
)

View File

@ -52,6 +52,7 @@ NODIST_GENERATED_HEADER_FILES = \
ui_search_frame.h \
ui_summary_dialog.h \
ui_splash_overlay.h \
ui_tcp_stream_dialog.h \
ui_time_shift_dialog.h \
ui_uat_dialog.h
@ -136,6 +137,7 @@ MOC_HDRS = \
sparkline_delegate.h \
splash_overlay.h \
syntax_line_edit.h \
tcp_stream_dialog.h \
time_shift_dialog.h \
uat_dialog.h \
wireshark_application.h
@ -166,6 +168,7 @@ UI_FILES = \
search_frame.ui \
summary_dialog.ui \
splash_overlay.ui \
tcp_stream_dialog.ui \
time_shift_dialog.ui \
uat_dialog.ui
@ -265,6 +268,7 @@ WIRESHARK_QT_SRC = \
summary_dialog.cpp \
splash_overlay.cpp \
syntax_line_edit.cpp \
tcp_stream_dialog.cpp \
time_shift_dialog.cpp \
uat_dialog.cpp \
wireshark_application.cpp

View File

@ -227,7 +227,8 @@ FORMS += \
splash_overlay.ui \
summary_dialog.ui \
time_shift_dialog.ui \
uat_dialog.ui
uat_dialog.ui \
tcp_stream_dialog.ui
win32 { ## These should be in config.pri ??
@ -273,7 +274,8 @@ HEADERS += $$HEADERS_WS_C \
summary_dialog.h \
tango_colors.h \
uat_dialog.h \
elided_label.h
elided_label.h \
tcp_stream_dialog.h
win32 {
@ -498,6 +500,7 @@ HEADERS += \
proto_tree.h \
qt_ui_utils.h \
qt_ui_utils.h \
qcustomplot.h \
recent_file_status.h \
related_packet_delegate.h \
simple_dialog_qt.h \
@ -552,6 +555,7 @@ SOURCES += \
progress_bar.cpp \
proto_tree.cpp \
qt_ui_utils.cpp \
qcustomplot.cpp \
recent_file_status.cpp \
related_packet_delegate.cpp \
search_frame.cpp \
@ -562,4 +566,5 @@ SOURCES += \
syntax_line_edit.cpp \
time_shift_dialog.cpp \
uat_dialog.cpp \
wireshark_application.cpp
wireshark_application.cpp \
tcp_stream_dialog.cpp

View File

@ -290,6 +290,7 @@ private slots:
void on_actionStopCapture_triggered();
void on_actionSummary_triggered();
void on_actionStatisticsTcpStreamStevens_triggered();
};

View File

@ -28,7 +28,16 @@
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
@ -59,7 +68,7 @@
<item>
<widget class="QLineEdit" name="goToLineEdit">
<property name="inputMask">
<string>900000000; </string>
<string>900000000</string>
</property>
</widget>
</item>
@ -97,7 +106,7 @@
<x>0</x>
<y>0</y>
<width>960</width>
<height>25</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -306,8 +315,15 @@
<property name="title">
<string>Statistics</string>
</property>
<widget class="QMenu" name="menuTcpStreamGraphs">
<property name="title">
<string>TCP Stream Graphs</string>
</property>
<addaction name="actionStatisticsTcpStreamStevens"/>
</widget>
<addaction name="actionSummary"/>
<addaction name="actionProtocol_Hierarchy"/>
<addaction name="menuTcpStreamGraphs"/>
</widget>
<widget class="QMenu" name="menuTelephony">
<property name="title">
@ -1232,6 +1248,14 @@
<string>Reordercap</string>
</property>
</action>
<action name="actionStatisticsTcpStreamStevens">
<property name="text">
<string>Time Sequence (Stevens)</string>
</property>
<property name="toolTip">
<string>TCP time sequence graph (Stevens)</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

View File

@ -54,7 +54,10 @@
#include "wsutil/file_util.h"
#include "epan/column.h"
#include <epan/epan_dissect.h>
#include "epan/filter_expressions.h"
#include <epan/value_string.h>
#include <epan/ipproto.h>
#include "ui/alert_box.h"
#include "ui/ui_util.h"
@ -70,12 +73,13 @@
#include "capture_file_dialog.h"
#include "export_object_dialog.h"
#include "time_shift_dialog.h"
#include "packet_comment_dialog.h"
#include "preferences_dialog.h"
#include "print_dialog.h"
#include "profile_dialog.h"
#include "qt_ui_utils.h"
#include "tcp_stream_dialog.h"
#include "time_shift_dialog.h"
#include "wireshark_application.h"
#include <QClipboard>
@ -641,6 +645,7 @@ void MainWindow::setMenusForSelectedPacket()
than one time reference frame or the current frame isn't a
time reference frame). (XXX - why check frame_selected?) */
gboolean another_is_time_ref = FALSE;
gboolean tcp_packet_selected = FALSE;
if (cap_file_) {
frame_selected = cap_file_->current_frame != NULL;
@ -653,6 +658,7 @@ void MainWindow::setMenusForSelectedPacket()
have_time_ref = cap_file_->ref_time_count > 0;
another_is_time_ref = frame_selected && have_time_ref &&
!(cap_file_->ref_time_count == 1 && cap_file_->current_frame->flags.ref_time);
tcp_packet_selected = frame_selected && (cap_file_->edt->pi.ipproto == IP_PROTO_TCP);
}
// if (cfile.edt && cfile.edt->tree) {
// GPtrArray *ga;
@ -805,8 +811,7 @@ void MainWindow::setMenusForSelectedPacket()
// gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns));
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/ToolsMenu/FirewallACLRules",
// frame_selected);
// set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/TCPStreamGraphMenu",
// tcp_graph_selected_packet_enabled(cf->current_frame,cf->edt, NULL));
main_ui_->menuTcpStreamGraphs->setEnabled(tcp_packet_selected);
// while (list_entry != NULL) {
// dissector_filter_t *filter_entry;
@ -1588,9 +1593,17 @@ void MainWindow::on_actionAnalyzePAFOrNotSelected_triggered()
matchSelectedFilter(MatchSelectedOrNot, false, false);
}
// Next / previous / first / last slots in packet_list
// Statistics Menu
void MainWindow::on_actionStatisticsTcpStreamStevens_triggered()
{
TCPStreamDialog stream_dialog(this, cap_file_, GRAPH_TSEQ_STEVENS);
stream_dialog.exec();
}
// Help Menu
void MainWindow::on_actionHelpContents_triggered() {

18675
ui/qt/qcustomplot.cpp Normal file

File diff suppressed because it is too large Load Diff

3039
ui/qt/qcustomplot.h Normal file

File diff suppressed because it is too large Load Diff

102
ui/qt/tcp_stream_dialog.cpp Normal file
View File

@ -0,0 +1,102 @@
/* tcp_stream_dialog.cpp
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "tcp_stream_dialog.h"
#include "ui_tcp_stream_dialog.h"
#include "tango_colors.h"
#include <QDebug>
TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_type graph_type) :
QDialog(parent),
ui(new Ui::TCPStreamDialog),
cap_file_(cf)
{
struct segment current;
ui->setupUi(this);
if (!select_tcpip_session(cap_file_, &current)) {
done(QDialog::Rejected);
}
memset (&graph_, 0, sizeof(graph_));
graph_.type = graph_type;
graph_segment_list_get(cap_file_, &graph_, FALSE);
QVector<double> rel_time, seq;
double rel_time_min = DBL_MAX, rel_time_max = DBL_MIN;
double seq_min = DBL_MAX, seq_max = DBL_MIN;
for (struct segment *cur = graph_.segments; cur != NULL; cur = cur->next) {
if (!compare_headers(&graph_.src_address, &graph_.dst_address,
graph_.src_port, graph_.dst_port,
&cur->ip_src, &cur->ip_dst,
cur->th_sport, cur->th_dport,
COMPARE_CURR_DIR)) {
continue;
}
double rt_val = cur->rel_secs + cur->rel_usecs / 1000000.0;
rel_time.append(rt_val);
if (rel_time_min > rt_val) rel_time_min = rt_val;
if (rel_time_max < rt_val) rel_time_max = rt_val;
seq.append(cur->th_seq);
if (seq_min > cur->th_seq) seq_min = cur->th_seq;
if (seq_max < cur->th_seq) seq_max = cur->th_seq;
}
ui->streamPlot->addGraph();
ui->streamPlot->graph(0)->setData(rel_time, seq);
// True Stevens-style graphs don't have lines but I like them - gcc
ui->streamPlot->graph(0)->setPen(QPen(QBrush(tango_sky_blue_5), 0.5));
ui->streamPlot->graph(0)->setLineStyle(QCPGraph::lsStepLeft);
ui->streamPlot->graph(0)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 5));
ui->streamPlot->xAxis->setLabel(tr("Time (s)"));
double range_pad = (rel_time_max - rel_time_min) * 0.05;
ui->streamPlot->xAxis->setRange(rel_time_min - range_pad, rel_time_max + range_pad);
ui->streamPlot->yAxis->setLabel(tr("Sequence number (B)"));
range_pad = (seq_max - seq_min) * 0.05;
ui->streamPlot->yAxis->setRange(seq_min - range_pad, seq_max + range_pad);
}
TCPStreamDialog::~TCPStreamDialog()
{
delete ui;
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

70
ui/qt/tcp_stream_dialog.h Normal file
View File

@ -0,0 +1,70 @@
/* tcp_stream_dialog.h
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef TCP_STREAM_DIALOG_H
#define TCP_STREAM_DIALOG_H
#include "config.h"
#include <glib.h>
#include <file.h>
#include <epan/dissectors/packet-tcp.h>
#include "ui/tap-tcp-stream.h"
#include <QDialog>
namespace Ui {
class TCPStreamDialog;
}
class TCPStreamDialog : public QDialog
{
Q_OBJECT
public:
explicit TCPStreamDialog(QWidget *parent = 0, capture_file *cf = NULL, tcp_graph_type graph_type = GRAPH_TSEQ_STEVENS);
~TCPStreamDialog();
private:
Ui::TCPStreamDialog *ui;
capture_file *cap_file_;
struct tcp_graph graph_;
};
#endif // TCP_STREAM_DIALOG_H
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

127
ui/qt/tcp_stream_dialog.ui Normal file
View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TCPStreamDialog</class>
<widget class="QDialog" name="TCPStreamDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>850</width>
<height>640</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCustomPlot" name="streamPlot" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="ElidedLabel" name="hintLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="graphTypeComboBox">
<item>
<property name="text">
<string>Time / Sequence (Stevens)</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QCustomPlot</class>
<extends>QWidget</extends>
<header>qcustomplot.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ElidedLabel</class>
<extends>QLabel</extends>
<header>elided_label.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>TCPStreamDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>TCPStreamDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

320
ui/tap-tcp-stream.c Normal file
View File

@ -0,0 +1,320 @@
/* tap-tcp-stream.c
* TCP stream statistics
* Originally from tcp_graph.c by Pavel Mores <pvl@uh.cz>
* Win32 port: rwh@unifiedtech.com
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include <file.h>
#include <frame_tvbuff.h>
#include <epan/address.h>
#include <epan/epan_dissect.h>
#include <epan/packet.h>
#include <epan/tap.h>
#include <epan/dissectors/packet-tcp.h>
#include "ui/simple_dialog.h"
#include "tap-tcp-stream.h"
typedef struct _tcp_scan_t {
struct segment *current;
int direction;
struct tcp_graph *tg;
struct segment *last;
} tcp_scan_t;
static int
tapall_tcpip_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
{
tcp_scan_t *ts = (tcp_scan_t *)pct;
struct tcp_graph *tg = ts->tg;
const struct tcpheader *tcphdr = (const struct tcpheader *)vip;
if (compare_headers(&tg->src_address, &tg->dst_address,
tg->src_port, tg->dst_port,
&tcphdr->ip_src, &tcphdr->ip_dst,
tcphdr->th_sport, tcphdr->th_dport,
ts->direction))
{
struct segment *segment = (struct segment *)g_malloc(sizeof(struct segment));
segment->next = NULL;
segment->num = pinfo->fd->num;
segment->rel_secs = (guint32)pinfo->rel_ts.secs;
segment->rel_usecs = pinfo->rel_ts.nsecs/1000;
segment->abs_secs = (guint32)pinfo->fd->abs_ts.secs;
segment->abs_usecs = pinfo->fd->abs_ts.nsecs/1000;
segment->th_seq = tcphdr->th_seq;
segment->th_ack = tcphdr->th_ack;
segment->th_win = tcphdr->th_win;
segment->th_flags = tcphdr->th_flags;
segment->th_sport = tcphdr->th_sport;
segment->th_dport = tcphdr->th_dport;
segment->th_seglen = tcphdr->th_seglen;
COPY_ADDRESS(&segment->ip_src, &tcphdr->ip_src);
COPY_ADDRESS(&segment->ip_dst, &tcphdr->ip_dst);
segment->num_sack_ranges = MIN(MAX_TCP_SACK_RANGES, tcphdr->num_sack_ranges);
if (segment->num_sack_ranges > 0) {
/* Copy entries in the order they happen */
memcpy(&segment->sack_left_edge, &tcphdr->sack_left_edge, sizeof(segment->sack_left_edge));
memcpy(&segment->sack_right_edge, &tcphdr->sack_right_edge, sizeof(segment->sack_right_edge));
}
if (ts->tg->segments) {
ts->last->next = segment;
} else {
ts->tg->segments = segment;
}
ts->last = segment;
}
return 0;
}
/* here we collect all the external data we will ever need */
void
graph_segment_list_get(capture_file *cf, struct tcp_graph *tg, gboolean stream_known)
{
struct segment current;
GString *error_string;
tcp_scan_t ts;
g_log(NULL, G_LOG_LEVEL_DEBUG, "graph_segment_list_get()");
if (!cf || !tg) return;
if (!stream_known) {
select_tcpip_session(cf, &current);
if (tg->type == GRAPH_THROUGHPUT)
ts.direction = COMPARE_CURR_DIR;
else
ts.direction = COMPARE_ANY_DIR;
/* Remember stream info in graph */
COPY_ADDRESS(&tg->src_address, &current.ip_src);
tg->src_port = current.th_sport;
COPY_ADDRESS(&tg->dst_address, &current.ip_dst);
tg->dst_port = current.th_dport;
}
/* rescan all the packets and pick up all interesting tcp headers.
* we only filter for TCP here for speed and do the actual compare
* in the tap listener
*/
ts.current = &current;
ts.tg = tg;
ts.last = NULL;
error_string = register_tap_listener("tcp", &ts, "tcp", 0, NULL, tapall_tcpip_packet, NULL);
if (error_string) {
fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
error_string->str);
g_string_free(error_string, TRUE);
exit(1); /* XXX: fix this */
}
cf_retap_packets(cf);
remove_tap_listener(&ts);
}
void
graph_segment_list_free(struct tcp_graph *tg)
{
struct segment *segment;
while (tg->segments) {
segment = tg->segments->next;
g_free(tg->segments);
tg->segments = segment;
}
tg->segments = NULL;
}
int
compare_headers(address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, const address *saddr2, const address *daddr2, guint16 sport2, guint16 dport2, int dir)
{
int dir1, dir2;
dir1 = ((!(CMP_ADDRESS(saddr1, saddr2))) &&
(!(CMP_ADDRESS(daddr1, daddr2))) &&
(sport1==sport2) &&
(dport1==dport2));
if (dir == COMPARE_CURR_DIR) {
return dir1;
} else {
dir2 = ((!(CMP_ADDRESS(saddr1, daddr2))) &&
(!(CMP_ADDRESS(daddr1, saddr2))) &&
(sport1 == dport2) &&
(dport1 == sport2));
return dir1 || dir2;
}
}
typedef struct _th_t {
int num_hdrs;
#define MAX_SUPPORTED_TCP_HEADERS 8
struct tcpheader *tcphdrs[MAX_SUPPORTED_TCP_HEADERS];
} th_t;
static int
tap_tcpip_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip)
{
int n;
gboolean is_unique = TRUE;
th_t *th = (th_t *)pct;
const struct tcpheader *header = (const struct tcpheader *)vip;
/* Check new header details against any/all stored ones */
for (n=0; n < th->num_hdrs; n++) {
struct tcpheader *stored = th->tcphdrs[n];
if (compare_headers(&stored->ip_src, &stored->ip_dst,
stored->th_sport, stored->th_dport,
&header->ip_src, &header->ip_dst,
header->th_sport, stored->th_dport,
COMPARE_CURR_DIR))
{
is_unique = FALSE;
break;
}
}
/* Add address if unique and have space for it */
if (is_unique && (th->num_hdrs < MAX_SUPPORTED_TCP_HEADERS)) {
/* Need to take a deep copy of the tap struct, it may not be valid
to read after this function returns? */
th->tcphdrs[th->num_hdrs] = (struct tcpheader *)g_malloc(sizeof(struct tcpheader));
*(th->tcphdrs[th->num_hdrs]) = *header;
COPY_ADDRESS(&th->tcphdrs[th->num_hdrs]->ip_src, &header->ip_src);
COPY_ADDRESS(&th->tcphdrs[th->num_hdrs]->ip_dst, &header->ip_dst);
th->num_hdrs++;
}
return 0;
}
/* XXX should be enhanced so that if we have multiple TCP layers in the trace
* then present the user with a dialog where the user can select WHICH tcp
* session to graph.
*/
struct tcpheader *
select_tcpip_session(capture_file *cf, struct segment *hdrs)
{
frame_data *fdata;
epan_dissect_t edt;
dfilter_t *sfcode;
GString *error_string;
nstime_t rel_ts;
th_t th = {0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
if (!cf || !hdrs)
return NULL;
fdata = cf->current_frame;
/* no real filter yet */
if (!dfilter_compile("tcp", &sfcode)) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", dfilter_error_msg);
return NULL;
}
/* dissect the current frame */
if (!cf_read_frame(cf, fdata))
return NULL; /* error reading the frame */
error_string=register_tap_listener("tcp", &th, NULL, 0, NULL, tap_tcpip_packet, NULL);
if (error_string) {
fprintf(stderr, "wireshark: Couldn't register tcp_graph tap: %s\n",
error_string->str);
g_string_free(error_string, TRUE);
exit(1);
}
epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
epan_dissect_prime_dfilter(&edt, sfcode);
epan_dissect_run_with_taps(&edt, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL);
rel_ts = edt.pi.rel_ts;
epan_dissect_cleanup(&edt);
remove_tap_listener(&th);
if (th.num_hdrs == 0) {
/* This "shouldn't happen", as our menu items shouldn't
* even be enabled if the selected packet isn't a TCP
* segment, as tcp_graph_selected_packet_enabled() is used
* to determine whether to enable any of our menu items. */
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"Selected packet isn't a TCP segment");
return NULL;
}
/* XXX fix this later, we should show a dialog allowing the user
to select which session he wants here
*/
if (th.num_hdrs > 1) {
/* can only handle a single tcp layer yet */
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"The selected packet has more than one TCP unique conversation "
"in it.");
return NULL;
}
/* For now, still always choose the first/only one */
hdrs->num = fdata->num;
hdrs->rel_secs = (guint32) rel_ts.secs;
hdrs->rel_usecs = rel_ts.nsecs/1000;
hdrs->abs_secs = (guint32) fdata->abs_ts.secs;
hdrs->abs_usecs = fdata->abs_ts.nsecs/1000;
hdrs->th_seq = th.tcphdrs[0]->th_seq;
hdrs->th_ack = th.tcphdrs[0]->th_ack;
hdrs->th_win = th.tcphdrs[0]->th_win;
hdrs->th_flags = th.tcphdrs[0]->th_flags;
hdrs->th_sport = th.tcphdrs[0]->th_sport;
hdrs->th_dport = th.tcphdrs[0]->th_dport;
hdrs->th_seglen = th.tcphdrs[0]->th_seglen;
COPY_ADDRESS(&hdrs->ip_src, &th.tcphdrs[0]->ip_src);
COPY_ADDRESS(&hdrs->ip_dst, &th.tcphdrs[0]->ip_dst);
return th.tcphdrs[0];
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

105
ui/tap-tcp-stream.h Normal file
View File

@ -0,0 +1,105 @@
/* tap-tcp-stream.h
* TCP stream statistics
* Originally from tcp_graph.c by Pavel Mores <pvl@uh.cz>
* Win32 port: rwh@unifiedtech.com
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __TAP_TCP_STREAM_H__
#define __TAP_TCP_STREAM_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef enum tcp_graph_type_ {
GRAPH_TSEQ_STEVENS,
GRAPH_TSEQ_TCPTRACE,
GRAPH_THROUGHPUT,
GRAPH_RTT,
GRAPH_WSCALE
} tcp_graph_type;
struct segment {
struct segment *next;
guint32 num;
guint32 rel_secs;
guint32 rel_usecs;
guint32 abs_secs;
guint32 abs_usecs;
guint32 th_seq;
guint32 th_ack;
guint16 th_flags;
guint32 th_win; /* make it 32 bits so we can handle some scaling */
guint32 th_seglen;
guint16 th_sport;
guint16 th_dport;
address ip_src;
address ip_dst;
guint8 num_sack_ranges;
guint32 sack_left_edge[MAX_TCP_SACK_RANGES];
guint32 sack_right_edge[MAX_TCP_SACK_RANGES];
};
struct tcp_graph {
tcp_graph_type type;
/* The stream this graph will show */
address src_address;
guint16 src_port;
address dst_address;
guint16 dst_port;
struct segment *segments;
};
void graph_segment_list_get(capture_file *, struct tcp_graph *, gboolean stream_known );
void graph_segment_list_free(struct tcp_graph * );
/* for compare_headers() */
/* segment went the same direction as the currently selected one */
#define COMPARE_CURR_DIR 0
#define COMPARE_ANY_DIR 1
int compare_headers(address *saddr1, address *daddr1, guint16 sport1, guint16 dport1, const address *saddr2, const address *daddr2, guint16 sport2, guint16 dport2, int dir);
struct tcpheader *select_tcpip_session(capture_file *, struct segment * );
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __TAP_TCP_STREAM_H__ */
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/