Add previous/next stream navigation to the TCP stream graph dialog.

Add get_tcp_stream_count() to the TCP dissector and modify
graph_segment_list_get() to allow matching based solely on a stream.

Use text instead of icons for the mouse click behavior buttons. Remove
their PNG resources since we aren't using them any more. Fix setting the
cursor in the graph widget.

svn path=/trunk/; revision=51989
This commit is contained in:
Gerald Combs 2013-09-12 21:37:47 +00:00
parent 467f128306
commit 07c3d057b8
8 changed files with 212 additions and 73 deletions

View File

@ -448,7 +448,7 @@ static dissector_table_t subdissector_table;
static heur_dissector_list_t heur_subdissector_list;
static dissector_handle_t data_handle;
static dissector_handle_t sport_handle;
static guint32 tcp_stream_index;
static guint32 tcp_stream_count;
/* TCP structs and definitions */
@ -511,7 +511,7 @@ init_tcp_conversation_data(packet_info *pinfo)
tcpd->ts_prev.nsecs=pinfo->fd->abs_ts.nsecs;
tcpd->flow1.valid_bif = 1;
tcpd->flow2.valid_bif = 1;
tcpd->stream = tcp_stream_index++;
tcpd->stream = tcp_stream_count++;
tcpd->server_port = 0;
return tcpd;
@ -595,6 +595,11 @@ add_tcp_process_info(guint32 frame_num, address *local_addr, address *remote_add
flow->command = wmem_strdup(wmem_file_scope(), command);
}
/* Return the current stream count */
guint32 get_tcp_stream_count(void)
{
return tcp_stream_count;
}
/* Calculate the timestamps relative to this conversation */
static void
@ -4764,7 +4769,7 @@ dissect_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
static void
tcp_init(void)
{
tcp_stream_index = 0;
tcp_stream_count = 0;
reassembly_table_init(&tcp_reassembly_table,
&addresses_ports_reassembly_table_functions);
}

View File

@ -293,6 +293,12 @@ extern gboolean decode_tcp_ports(tvbuff_t *, int, packet_info *, proto_tree *, i
*/
extern void add_tcp_process_info(guint32 frame_num, address *local_addr, address *remote_addr, guint16 local_port, guint16 remote_port, guint32 uid, guint32 pid, gchar *username, gchar *command);
/** Get the current number of TCP streams
*
* @return The number of TCP streams
*/
WS_DLL_PUBLIC guint32 get_tcp_stream_count(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -15,8 +15,4 @@
<file>plus-8.png</file>
<file>copy-8.png</file>
</qresource>
<qresource prefix="/graph">
<file>openhand-16.png</file>
<file>rubberband-16.png</file>
</qresource>
</RCC>

View File

@ -96,8 +96,14 @@ TCPStreamDialog::TCPStreamDialog(QWidget *parent, capture_file *cf, tcp_graph_ty
ui->graphTypeComboBox->setCurrentIndex(-1);
ui->graphTypeComboBox->setUpdatesEnabled(true);
ui->mouseHorizontalLayout->setContentsMargins(0, 0, 0, 0);
ui->dragToolButton->setChecked(mouse_drags_);
if (QIcon::hasThemeIcon("go-previous") && QIcon::hasThemeIcon("go-next")) {
ui->prevStreamPushButton->setText(QString());
ui->prevStreamPushButton->setIcon(QIcon::fromTheme("go-previous"));
ui->nextStreamPushButton->setText(QString());
ui->nextStreamPushButton->setIcon(QIcon::fromTheme("go-next"));
}
ui->dragRadioButton->setChecked(mouse_drags_);
memset (&graph_, 0, sizeof(graph_));
graph_.type = graph_type;
@ -215,6 +221,13 @@ void TCPStreamDialog::keyPressEvent(QKeyEvent *event)
resetAxes();
break;
case Qt::Key_PageDown:
on_prevStreamPushButton_clicked();
break;
case Qt::Key_PageUp:
on_nextStreamPushButton_clicked();
break;
case Qt::Key_D:
on_otherDirectionButton_clicked();
break;
@ -233,9 +246,9 @@ void TCPStreamDialog::keyPressEvent(QKeyEvent *event)
break;
case Qt::Key_Z:
if (mouse_drags_) {
ui->selectToolButton->toggle();
ui->selectRadioButton->toggle();
} else {
ui->dragToolButton->toggle();
ui->dragRadioButton->toggle();
}
break;
@ -317,6 +330,11 @@ void TCPStreamDialog::fillGraph()
sequence_num_map_.clear();
graph_segment_list_free(&graph_);
tracer_->setGraph(NULL);
ui->streamNumberLabel->setText(QString("Stream %1").arg(graph_.stream));
ui->prevStreamPushButton->setEnabled(graph_.stream > 0);
ui->nextStreamPushButton->setEnabled(graph_.stream < get_tcp_stream_count() - 1);
// We need at least one graph, so don't bother deleting the first one.
for (int i = 0; i < sp->graphCount(); i++) {
sp->graph(i)->clearData();
@ -662,8 +680,12 @@ QRectF TCPStreamDialog::getZoomRanges(QRect zoom_rect)
void TCPStreamDialog::graphClicked(QMouseEvent *event)
{
Q_UNUSED(event)
QCustomPlot *sp = ui->streamPlot;
if (mouse_drags_) {
if (sp->axisRect()->rect().contains(event->pos())) {
sp->setCursor(QCursor(Qt::ClosedHandCursor));
}
if (tracer_->visible() && cap_file_ && packet_num_ > 0) {
emit goToPacket(packet_num_);
}
@ -717,6 +739,27 @@ void TCPStreamDialog::axisClicked(QCPAxis *axis, QCPAxis::SelectablePart part, Q
// using a QTimer instead.
void TCPStreamDialog::mouseMoved(QMouseEvent *event)
{
QCustomPlot *sp = ui->streamPlot;
Qt::CursorShape shape = Qt::ArrowCursor;
if (event) {
if (event->buttons() & Qt::LeftButton == Qt::LeftButton) {
if (mouse_drags_) {
shape = Qt::ClosedHandCursor;
} else {
shape = Qt::CrossCursor;
}
} else {
if (sp->axisRect()->rect().contains(event->pos())) {
if (mouse_drags_) {
shape = Qt::OpenHandCursor;
} else {
shape = Qt::CrossCursor;
}
}
}
}
sp->setCursor(QCursor(shape));
if (mouse_drags_) {
double tr_key = tracer_->position->key();
struct segment *packet_seg = NULL;
@ -790,6 +833,8 @@ void TCPStreamDialog::mouseReleased(QMouseEvent *event)
sp->replot();
}
}
} else if (ui->streamPlot->cursor().shape() == Qt::ClosedHandCursor) {
ui->streamPlot->setCursor(QCursor(Qt::OpenHandCursor));
}
}
@ -861,6 +906,26 @@ void TCPStreamDialog::setCaptureFile(capture_file *cf)
}
}
void TCPStreamDialog::on_prevStreamPushButton_clicked()
{
if (graph_.stream > 0) {
graph_.stream--;
graph_.src_address.type = AT_NONE;
graph_.dst_address.type = AT_NONE;
fillGraph();
}
}
void TCPStreamDialog::on_nextStreamPushButton_clicked()
{
if (graph_.stream < get_tcp_stream_count() - 1) {
graph_.stream++;
graph_.src_address.type = AT_NONE;
graph_.dst_address.type = AT_NONE;
fillGraph();
}
}
void TCPStreamDialog::on_otherDirectionButton_clicked()
{
address tmp_addr;
@ -876,21 +941,19 @@ void TCPStreamDialog::on_otherDirectionButton_clicked()
fillGraph();
}
void TCPStreamDialog::on_dragToolButton_toggled(bool checked)
void TCPStreamDialog::on_dragRadioButton_toggled(bool checked)
{
if (checked) mouse_drags_ = true;
ui->streamPlot->setInteractions(
QCP::iRangeDrag |
QCP::iRangeZoom
);
ui->streamPlot->setCursor(QCursor(Qt::OpenHandCursor));
}
void TCPStreamDialog::on_selectToolButton_toggled(bool checked)
void TCPStreamDialog::on_selectRadioButton_toggled(bool checked)
{
if (checked) mouse_drags_ = false;
ui->streamPlot->setInteractions(0);
ui->streamPlot->setCursor(QCursor(Qt::CrossCursor));
}
/*

View File

@ -104,9 +104,11 @@ private slots:
void on_buttonBox_accepted();
void on_graphTypeComboBox_currentIndexChanged(int index);
void on_resetButton_clicked();
void on_prevStreamPushButton_clicked();
void on_nextStreamPushButton_clicked();
void on_otherDirectionButton_clicked();
void on_dragToolButton_toggled(bool checked);
void on_selectToolButton_toggled(bool checked);
void on_dragRadioButton_toggled(bool checked);
void on_selectRadioButton_toggled(bool checked);
};
#endif // TCP_STREAM_DIALOG_H

View File

@ -44,6 +44,8 @@
&lt;tr&gt;&lt;th&gt;&lt;i&gt;Shift+&lt;/i&gt;←&lt;/th&gt;&lt;td&gt;Move left 10%&lt;/td&gt;&lt;/th&gt;
&lt;tr&gt;&lt;th&gt;&lt;i&gt;Shift+&lt;/i&gt;↑&lt;/th&gt;&lt;td&gt;Move up 10%&lt;/td&gt;&lt;/th&gt;
&lt;tr&gt;&lt;th&gt;&lt;i&gt;Shift+&lt;/i&gt;↓&lt;/th&gt;&lt;td&gt;Move down 10%&lt;/td&gt;&lt;/th&gt;
&lt;tr&gt;&lt;th&gt;&lt;i&gt;Pg Up&lt;/i&gt;&lt;/th&gt;&lt;td&gt;Next stream&lt;/td&gt;&lt;/th&gt;
&lt;tr&gt;&lt;th&gt;&lt;i&gt;Pg Dn&lt;/i&gt;&lt;/th&gt;&lt;td&gt;Previous stream&lt;/td&gt;&lt;/th&gt;
&lt;tr&gt;&lt;th&gt;0&lt;/th&gt;&lt;td&gt;Reset graph to its initial state&lt;/td&gt;&lt;/th&gt;
&lt;tr&gt;&lt;th&gt;d&lt;/th&gt;&lt;td&gt;Switch direction (swap TCP endpoints)&lt;/td&gt;&lt;/th&gt;
&lt;tr&gt;&lt;th&gt;g&lt;/th&gt;&lt;td&gt;Go to packet under cursor&lt;/td&gt;&lt;/th&gt;
@ -60,7 +62,7 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
@ -85,42 +87,97 @@
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="mouseHorizontalLayout">
<item>
<widget class="QToolButton" name="dragToolButton">
<property name="toolTip">
<string>Drag using the mouse button.</string>
</property>
<property name="icon">
<iconset resource="../../image/toolbar.qrc">
<normaloff>:/graph/openhand-16.png</normaloff>:/graph/openhand-16.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">mouseButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QToolButton" name="selectToolButton">
<property name="toolTip">
<string>Select using the mouse button.</string>
</property>
<property name="icon">
<iconset resource="../../image/toolbar.qrc">
<normaloff>:/graph/rubberband-16.png</normaloff>:/graph/rubberband-16.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">mouseButtonGroup</string>
</attribute>
</widget>
</item>
</layout>
<widget class="QPushButton" name="prevStreamPushButton">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Go to the previous TCP stream.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>⇦</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="streamNumberLabel">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="nextStreamPushButton">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Go to the next TCP stream.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>⇨</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="otherDirectionButton">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Switch the direction of the connection (view the opposite flow).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Switch Direction</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="mouseLabel">
<property name="text">
<string>Mouse</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="dragRadioButton">
<property name="toolTip">
<string>Drag using the mouse button.</string>
</property>
<property name="text">
<string>drags</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">mouseButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="selectRadioButton">
<property name="toolTip">
<string>Select using the mouse button.</string>
</property>
<property name="text">
<string>selects</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">mouseButtonGroup</string>
</attribute>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="resetButton">
@ -132,16 +189,6 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="otherDirectionButton">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Switch the direction of the connection (swap the TCP endpoints).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Switch Direction</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -169,9 +216,7 @@
<header>elided_label.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../image/toolbar.qrc"/>
</resources>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>

View File

@ -50,13 +50,25 @@ typedef struct _tcp_scan_t {
} tcp_scan_t;
static int
static gboolean
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 (tg->stream == tcphdr->th_stream
&& (tg->src_address.type == AT_NONE || tg->dst_address.type == AT_NONE)) {
/*
* We only know the stream number. Fill in our connection data.
* We assume that the server response is more interesting.
*/
COPY_ADDRESS(&tg->src_address, &tcphdr->ip_dst);
tg->src_port = tcphdr->th_dport;
COPY_ADDRESS(&tg->dst_address, &tcphdr->ip_src);
tg->dst_port = tcphdr->th_sport;
}
if (compare_headers(&tg->src_address, &tg->dst_address,
tg->src_port, tg->dst_port,
&tcphdr->ip_src, &tcphdr->ip_dst,
@ -98,7 +110,7 @@ tapall_tcpip_packet(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, cons
ts->last = segment;
}
return 0;
return FALSE;
}
/* here we collect all the external data we will ever need */
@ -226,7 +238,7 @@ typedef struct _th_t {
struct tcpheader *tcphdrs[MAX_SUPPORTED_TCP_HEADERS];
} th_t;
static int
static gboolean
tap_tcpip_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip)
{
int n;
@ -261,7 +273,7 @@ tap_tcpip_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, con
th->num_hdrs++;
}
return 0;
return FALSE;
}
/* XXX should be enhanced so that if we have multiple TCP layers in the trace
@ -347,7 +359,6 @@ select_tcpip_session(capture_file *cf, struct segment *hdrs)
COPY_ADDRESS(&hdrs->ip_src, &th.tcphdrs[0]->ip_src);
COPY_ADDRESS(&hdrs->ip_dst, &th.tcphdrs[0]->ip_dst);
return th.tcphdrs[0];
}
int rtt_is_retrans(struct unack *list, unsigned int seqno)

View File

@ -77,7 +77,18 @@ struct tcp_graph {
struct segment *segments;
};
void graph_segment_list_get(capture_file *, struct tcp_graph *, gboolean stream_known );
/** Fill in the segment list for a TCP graph
*
* @param cf Capture file to scan
* @param tg TCP graph. A valid stream must be set. If either the source or
* destination address types are AT_NONE the address and port
* information will be filled in using the first packet in the
* specified stream.
* @param stream_known If FALSE, session information will be filled in using
* the currently selected packet. If FALSE, session information will
* be matched against tg.
*/
void graph_segment_list_get(capture_file *cf, struct tcp_graph *tg, gboolean stream_known );
void graph_segment_list_free(struct tcp_graph * );
/* for compare_headers() */