aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-dns.c4
-rw-r--r--epan/dissectors/packet-icmp.c4
-rw-r--r--epan/ftypes/ftypes.h8
-rw-r--r--epan/proto.c7
-rw-r--r--epan/proto.h3
-rwxr-xr-xtools/checkAPIs.pl4
-rw-r--r--ui/qt/CMakeLists.txt2
-rw-r--r--ui/qt/packet_list.cpp13
-rw-r--r--ui/qt/packet_list.h1
-rw-r--r--ui/qt/packet_list_record.cpp8
-rw-r--r--ui/qt/packet_list_record.h6
-rw-r--r--ui/qt/proto_tree.cpp7
-rw-r--r--ui/qt/proto_tree.h4
-rw-r--r--ui/qt/related_packet_delegate.cpp158
-rw-r--r--ui/qt/related_packet_delegate.h22
15 files changed, 183 insertions, 68 deletions
diff --git a/epan/dissectors/packet-dns.c b/epan/dissectors/packet-dns.c
index 68c1d4ee59..b3789213f6 100644
--- a/epan/dissectors/packet-dns.c
+++ b/epan/dissectors/packet-dns.c
@@ -5177,12 +5177,12 @@ proto_register_dns(void)
{ &hf_dns_response_in,
{ "Response In", "dns.response_in",
- FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
"The response to this DNS query is in this frame", HFILL }},
{ &hf_dns_response_to,
{ "Request In", "dns.response_to",
- FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
"This is a response to the DNS query in this frame", HFILL }},
{ &hf_dns_time,
diff --git a/epan/dissectors/packet-icmp.c b/epan/dissectors/packet-icmp.c
index d58980db74..73c8a1c8f1 100644
--- a/epan/dissectors/packet-icmp.c
+++ b/epan/dissectors/packet-icmp.c
@@ -1872,7 +1872,7 @@ void proto_register_icmp(void)
{&hf_icmp_resp_in,
{"Response frame", "icmp.resp_in", FT_FRAMENUM, BASE_NONE,
- NULL, 0x0,
+ FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
"The frame number of the corresponding response",
HFILL}},
@@ -1884,7 +1884,7 @@ void proto_register_icmp(void)
{&hf_icmp_resp_to,
{"Request frame", "icmp.resp_to", FT_FRAMENUM, BASE_NONE,
- NULL, 0x0,
+ FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
"The frame number of the corresponding request", HFILL}},
{&hf_icmp_resptime,
diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h
index 71f6e9386c..226084449a 100644
--- a/epan/ftypes/ftypes.h
+++ b/epan/ftypes/ftypes.h
@@ -97,6 +97,14 @@ enum ftenum {
typedef enum ftenum ftenum_t;
+enum ft_framenum_type {
+ FT_FRAMENUM_NONE,
+ FT_FRAMENUM_REQUEST,
+ FT_FRAMENUM_RESPONSE
+};
+
+typedef enum ft_framenum_type ft_framenum_type_t;
+
struct _ftype_t;
typedef struct _ftype_t ftype_t;
diff --git a/epan/proto.c b/epan/proto.c
index 4c07a5e2c9..d22e41539a 100644
--- a/epan/proto.c
+++ b/epan/proto.c
@@ -5636,8 +5636,9 @@ tmp_fld_check_assert(header_field_info *hfinfo)
(hfinfo->type == FT_INT56) ||
(hfinfo->type == FT_INT64) ||
(hfinfo->type == FT_BOOLEAN) ||
- (hfinfo->type == FT_PROTOCOL) ))
- g_error("Field '%s' (%s) has a 'strings' value but is of type %s"
+ (hfinfo->type == FT_PROTOCOL) ||
+ (hfinfo->type == FT_FRAMENUM) ))
+ g_error("Field '%s' (%s) has a 'strings' value but is of type %s"
" (which is not allowed to have strings)\n",
hfinfo->name, hfinfo->abbrev, ftype_name(hfinfo->type));
@@ -6637,7 +6638,7 @@ fill_label_number(field_info *fi, gchar *label_str, gboolean is_signed)
fmtfunc(tmp, value);
label_fill(label_str, 0, hfinfo, tmp);
}
- else if (hfinfo->strings) {
+ else if (hfinfo->strings && hfinfo->type != FT_FRAMENUM) { /* Add fill_label_framenum? */
const char *val_str = hf_try_val_to_str_const(value, hfinfo, "Unknown");
out = hfinfo_number_vals_format(hfinfo, buf, value);
diff --git a/epan/proto.h b/epan/proto.h
index 5f47b53fb0..f62a1a904f 100644
--- a/epan/proto.h
+++ b/epan/proto.h
@@ -98,6 +98,9 @@ typedef void (*custom_fmt_func_64_t)(gchar *, guint64);
* header_field_info.strings */
#define RVALS(x) (const struct _range_string*)(x)
+/** Cast a ft_framenum_type_t, used to set header_field_info.strings */
+#define FRAMENUM_TYPE(x) GINT_TO_POINTER(x)
+
struct _protocol;
/** Structure for information about a protocol */
diff --git a/tools/checkAPIs.pl b/tools/checkAPIs.pl
index 679a364242..598e95a03b 100755
--- a/tools/checkAPIs.pl
+++ b/tools/checkAPIs.pl
@@ -1817,8 +1817,8 @@ sub check_hf_entries($$)
print STDERR "Error: $hf is passing the address of a pointer to RVALS in $filename\n";
$errorCount++;
}
- if ($convert !~ m/^((0[xX]0?)?0$|NULL$|VALS|VALS64|RVALS|TFS|CF_FUNC|&)/ && $display !~ /BASE_CUSTOM/) {
- print STDERR "Error: non-null $hf 'convert' field missing 'VALS|VALS64|RVALS|TFS|CF_FUNC|&' in $filename ?\n";
+ if ($convert !~ m/^((0[xX]0?)?0$|NULL$|VALS|VALS64|RVALS|TFS|CF_FUNC|FRAMENUM_TYPE|&)/ && $display !~ /BASE_CUSTOM/) {
+ print STDERR "Error: non-null $hf 'convert' field missing 'VALS|VALS64|RVALS|TFS|CF_FUNC|FRAMENUM_TYPE|&' in $filename ?\n";
$errorCount++;
}
## Benign...
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt
index 9f6f7311eb..b1c56139bf 100644
--- a/ui/qt/CMakeLists.txt
+++ b/ui/qt/CMakeLists.txt
@@ -85,6 +85,7 @@ set(WIRESHARK_QT_HEADERS
protocol_hierarchy_dialog.h
qcustomplot.h
recent_file_status.h
+ related_packet_delegate.h
rtp_stream_dialog.h
sctp_all_assocs_dialog.h
sctp_assoc_analyse_dialog.h
@@ -119,7 +120,6 @@ endif()
file(GLOB EXTRA_QT_HEADERS
packet_list_record.h
qt_ui_utils.h
- related_packet_delegate.h
sparkline_delegate.h
stock_icon.h
)
diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp
index 9f3dfcd971..fd3c509c6a 100644
--- a/ui/qt/packet_list.cpp
+++ b/ui/qt/packet_list.cpp
@@ -425,7 +425,8 @@ void PacketList::setProtoTree (ProtoTree *proto_tree) {
proto_tree_ = proto_tree;
connect(proto_tree_, SIGNAL(goToPacket(int)), this, SLOT(goToPacket(int)));
- connect(proto_tree_, SIGNAL(relatedFrame(int)), this, SLOT(addRelatedFrame(int)));
+ connect(proto_tree_, SIGNAL(relatedFrame(int,ft_framenum_type_t)),
+ &related_packet_delegate_, SLOT(addRelatedFrame(int,ft_framenum_type_t)));
}
void PacketList::setByteViewTab (ByteViewTab *byte_view_tab) {
@@ -456,12 +457,13 @@ void PacketList::selectionChanged (const QItemSelection & selected, const QItemS
if (!cap_file_->edt) return;
if (proto_tree_ && cap_file_->edt->tree) {
- proto_tree_->fillProtocolTree(cap_file_->edt->tree);
packet_info *pi = &cap_file_->edt->pi;
+ related_packet_delegate_.setCurrentFrame(pi->fd->num);
+ proto_tree_->fillProtocolTree(cap_file_->edt->tree);
conversation_t *conv = find_conversation(pi->fd->num, &pi->src, &pi->dst, pi->ptype,
pi->srcport, pi->destport, 0);
if (conv) {
- related_packet_delegate_.setConversationSpan(conv->setup_frame, conv->last_frame);
+ related_packet_delegate_.setConversation(conv);
}
viewport()->update();
}
@@ -1038,11 +1040,6 @@ void PacketList::unsetAllTimeReferences()
redrawVisiblePackets();
}
-void PacketList::addRelatedFrame(int related_frame)
-{
- related_packet_delegate_.addRelatedFrame(related_frame);
-}
-
void PacketList::showHeaderMenu(QPoint pos)
{
header_ctx_column_ = header()->logicalIndexAt(pos);
diff --git a/ui/qt/packet_list.h b/ui/qt/packet_list.h
index 357533c67b..8095fe7d2e 100644
--- a/ui/qt/packet_list.h
+++ b/ui/qt/packet_list.h
@@ -130,7 +130,6 @@ public slots:
void applyRecentColumnWidths();
private slots:
- void addRelatedFrame(int related_frame);
void showHeaderMenu(QPoint pos);
void headerMenuTriggered();
void columnVisibilityTriggered();
diff --git a/ui/qt/packet_list_record.cpp b/ui/qt/packet_list_record.cpp
index 8ded43bb1d..1bacfd66d9 100644
--- a/ui/qt/packet_list_record.cpp
+++ b/ui/qt/packet_list_record.cpp
@@ -26,6 +26,7 @@
#include <epan/epan_dissect.h>
#include <epan/column-info.h>
#include <epan/column.h>
+#include <epan/conversation.h>
#include "color.h"
#include "color_filters.h"
@@ -39,7 +40,8 @@ unsigned PacketListRecord::col_data_ver_ = 1;
PacketListRecord::PacketListRecord(frame_data *frameData) :
fdata_(frameData),
data_ver_(0),
- colorized_(false)
+ colorized_(false),
+ conv_(NULL)
{
}
@@ -159,6 +161,10 @@ void PacketListRecord::dissect(capture_file *cap_file, bool dissect_color)
}
data_ver_ = col_data_ver_;
+ packet_info *pi = &edt.pi;
+ conv_ = find_conversation(pi->fd->num, &pi->src, &pi->dst, pi->ptype,
+ pi->srcport, pi->destport, 0);
+
epan_dissect_cleanup(&edt);
ws_buffer_free(&buf);
}
diff --git a/ui/qt/packet_list_record.h b/ui/qt/packet_list_record.h
index af2b251eb4..8fea32a0de 100644
--- a/ui/qt/packet_list_record.h
+++ b/ui/qt/packet_list_record.h
@@ -35,6 +35,8 @@
#include <QList>
#include <QVariant>
+struct conversation;
+
class PacketListRecord
{
public:
@@ -44,6 +46,7 @@ public:
frame_data *frameData() const { return fdata_; }
// packet_list->col_to_text in gtk/packet_list_store.c
static int textColumn(int column) { return cinfo_column_.value(column, -1); }
+ struct conversation *conversation() { return conv_; }
int columnTextSize(const char *str);
static void resetColumns(column_info *cinfo);
@@ -63,6 +66,9 @@ private:
/** Has this record been colorized? */
bool colorized_;
+ /** Conversation. Used by RelatedPacketDelegate */
+ struct conversation *conv_;
+
void dissect(capture_file *cap_file, bool dissect_color = false);
void cacheColumnStrings(column_info *cinfo);
diff --git a/ui/qt/proto_tree.cpp b/ui/qt/proto_tree.cpp
index 992e78b5c5..c50a05fc93 100644
--- a/ui/qt/proto_tree.cpp
+++ b/ui/qt/proto_tree.cpp
@@ -107,7 +107,8 @@ proto_tree_draw_node(proto_node *node, gpointer data)
item->setData(0, Qt::FontRole, font);
if (fi->hfinfo->type == FT_FRAMENUM) {
- proto_tree->emitRelatedFrame(fi->value.value.uinteger);
+ ft_framenum_type_t framenum_type = (ft_framenum_type_t)GPOINTER_TO_INT(fi->hfinfo->strings);
+ proto_tree->emitRelatedFrame(fi->value.value.uinteger, framenum_type);
}
}
}
@@ -294,9 +295,9 @@ void ProtoTree::fillProtocolTree(proto_tree *protocol_tree) {
proto_tree_children_foreach(protocol_tree, proto_tree_draw_node, invisibleRootItem());
}
-void ProtoTree::emitRelatedFrame(int related_frame)
+void ProtoTree::emitRelatedFrame(int related_frame, ft_framenum_type_t framenum_type)
{
- emit relatedFrame(related_frame);
+ emit relatedFrame(related_frame, framenum_type);
}
void ProtoTree::updateSelectionStatus(QTreeWidgetItem* item) {
diff --git a/ui/qt/proto_tree.h b/ui/qt/proto_tree.h
index e10fa67d8d..8890cca27a 100644
--- a/ui/qt/proto_tree.h
+++ b/ui/qt/proto_tree.h
@@ -37,7 +37,7 @@ class ProtoTree : public QTreeWidget
public:
explicit ProtoTree(QWidget *parent = 0);
void fillProtocolTree(proto_tree *protocol_tree);
- void emitRelatedFrame(int related_frame);
+ void emitRelatedFrame(int related_frame, ft_framenum_type_t framenum_type = FT_FRAMENUM_NONE);
void clear();
protected:
@@ -53,7 +53,7 @@ signals:
void protoItemSelected(field_info *);
void openPacketInNewWindow(bool);
void goToPacket(int);
- void relatedFrame(int);
+ void relatedFrame(int, ft_framenum_type_t);
public slots:
void setMonospaceFont(const QFont &mono_font);
diff --git a/ui/qt/related_packet_delegate.cpp b/ui/qt/related_packet_delegate.cpp
index c7964d2e8f..83c93ee491 100644
--- a/ui/qt/related_packet_delegate.cpp
+++ b/ui/qt/related_packet_delegate.cpp
@@ -22,22 +22,45 @@
#include "related_packet_delegate.h"
#include "packet_list_record.h"
-#include <QPainter>
+#include "color_utils.h"
+
#include <QApplication>
+#include <QPainter>
+
+// To do:
+// - Add other frame types and symbols (ACKs, etc).
+// - Add tooltips. It looks like this needs to be done in
+// PacketListModel::data.
+// - Add "Go -> Next Related" and "Go -> Previous Related"?
+// - Apply as filter?
+
+RelatedPacketDelegate::RelatedPacketDelegate(QWidget *parent) :
+ QStyledItemDelegate(parent),
+ conv_(NULL),
+ current_frame_(0)
+{
+ clear();
+}
void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
- int en_w = option.fontMetrics.height() / 2;
-
QStyleOptionViewItemV4 optv4 = option;
QStyledItemDelegate::initStyleOption(&optv4, index);
+ int em_w = optv4.fontMetrics.height();
+ int en_w = (em_w + 1) / 2;
optv4.features |= QStyleOptionViewItemV4::HasDecoration;
optv4.decorationSize.setHeight(1);
- optv4.decorationSize.setWidth(en_w);
+ optv4.decorationSize.setWidth(em_w);
QStyledItemDelegate::paint(painter, optv4, index);
+ guint32 setup_frame = 0, last_frame = 0;
+ if (conv_) {
+ setup_frame = (int) conv_->setup_frame;
+ last_frame = (int) conv_->last_frame;
+ }
+
const frame_data *fd;
PacketListRecord *record = static_cast<PacketListRecord*>(index.internalPointer());
if (!record || (fd = record->frameData()) == NULL) {
@@ -62,41 +85,78 @@ void RelatedPacketDelegate::paint(QPainter *painter, const QStyleOptionViewItem
} else {
fg = optv4.palette.color(cg, QPalette::Text);
}
- qreal alpha = 0.20; // Arbitrary. Should arguably be a preference.
- // We draw in the same place more than once so we first draw on a
- // QImage at 100% opacity then draw that on our packet list item.
- QImage overlay = QImage(en_w * 2, optv4.rect.height(), QImage::Format_ARGB32_Premultiplied);
- QPainter op(&overlay);
+ fg = ColorUtils::alphaBlend(fg, optv4.palette.color(cg, QPalette::Base), 0.5);
+ QPen line_pen(fg);
+ line_pen.setWidth(optv4.fontMetrics.lineWidth());
+ line_pen.setJoinStyle(Qt::RoundJoin);
+
+ painter->setPen(line_pen);
+ painter->translate(optv4.rect.x(), optv4.rect.y());
+ painter->translate(en_w + 0.5, 0.5);
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ int height = optv4.rect.height();
- overlay.fill(Qt::transparent);
- op.setPen(fg);
- op.translate(en_w + 0.5, 0.5);
- op.setRenderHint(QPainter::Antialiasing, true);
+ // Uncomment to make the boundary visible.
+// painter->save();
+// painter->setPen(Qt::darkRed);
+// painter->drawRect(QRectF(0.5, 0.5, en_w - 1, height - 1));
+// painter->restore();
// The current decorations are based on what looked good and were easy
- // to code. W might want to improve them by drawing small dots or tick
- // marks for frames in the same conversation XOR draw a gap for unrelated
- // frames.
- if (first_frame_ > 0 && last_frame_ > 0 && first_frame_ != last_frame_) {
- int height = optv4.rect.height();
- if ((int) fd->num == first_frame_) {
- op.drawLine(0, height / 2, 0, height);
- op.drawLine(1, height / 2, en_w, height / 2);
- } else if ((int) fd->num > first_frame_ && (int) fd->num < last_frame_) {
- op.drawLine(0, 0, 0, height);
- } else if ((int) fd->num == last_frame_) {
- op.drawLine(0, 0, 0, height / 2);
- op.drawLine(1, height / 2, en_w, height / 2);
+ // to code.
+
+ // Vertical line. Lower and upper half for the start and end of the
+ // conversation respectively, solid for conversation member, dashed
+ // for other packets in the start-end range.
+ if (setup_frame > 0 && last_frame > 0 && setup_frame != last_frame) {
+ if (fd->num == setup_frame) {
+ painter->drawLine(0, height / 2, 0, height);
+ painter->drawLine(1, height / 2, en_w - 1, height / 2);
+ } else if (fd->num > setup_frame && fd->num < last_frame) {
+ painter->save();
+ if (conv_ != record->conversation()) {
+ QPen other_pen(line_pen);
+ other_pen.setStyle(Qt::DashLine);
+ painter->setPen(other_pen);
+ }
+ painter->drawLine(0, 0, 0, height);
+ painter->restore();
+ } else if (fd->num == last_frame) {
+ painter->drawLine(0, 0, 0, height / 2);
+ painter->drawLine(1, height / 2, en_w, height / 2);
}
}
+
+ // Related packet indicator. Rightward arrow for requests, leftward
+ // arrow for responses, circle for others.
if (related_frames_.contains(fd->num)) {
- op.setBrush(fg);
- op.drawEllipse(QPointF(0.0, optv4.rect.height() / 2), 2, 2);
+ painter->setBrush(fg);
+ switch (related_frames_[fd->num]) {
+ // Request and response arrows are moved forward one pixel in order to
+ // maximize white space between the heads and the conversation line.
+ case FT_FRAMENUM_REQUEST:
+ {
+ int hh = height / 2;
+ QPoint tail(2 - en_w, hh);
+ QPoint head(en_w, hh);
+ drawArrow(painter, tail, head, hh / 2);
+ break;
+ }
+ case FT_FRAMENUM_RESPONSE:
+ {
+ int hh = height / 2;
+ QPoint tail(en_w - 1, hh);
+ QPoint head(1 - en_w, hh);
+ drawArrow(painter, tail, head, hh / 2);
+ break;
+ }
+ case FT_FRAMENUM_NONE:
+ default:
+ painter->drawEllipse(QPointF(0.0, optv4.rect.height() / 2), 2, 2);
+ }
}
- painter->setOpacity(alpha);
- painter->drawImage(optv4.rect.x(), optv4.rect.y(), overlay);
painter->restore();
}
@@ -106,21 +166,47 @@ QSize RelatedPacketDelegate::sizeHint(const QStyleOptionViewItem &option,
QStyledItemDelegate::sizeHint(option, index).height());
}
+void RelatedPacketDelegate::drawArrow(QPainter *painter, QPoint tail, QPoint head, int head_size) const
+{
+ int x_mul = head.x() > tail.x() ? -1 : 1;
+ QPoint head_points[] = {
+ head,
+ QPoint(head.x() + (head_size * x_mul), head.y() + (head_size / 2)),
+ QPoint(head.x() + (head_size * x_mul), head.y() - (head_size / 2)),
+ };
+
+ painter->drawLine(tail.x(), tail.y(), head.x() + (head_size * x_mul), head.y());
+ painter->drawPolygon(head_points, 3);
+}
+
void RelatedPacketDelegate::clear()
{
related_frames_.clear();
- first_frame_ = last_frame_ = -1;
+ current_frame_ = 0;
+ conv_ = NULL;
}
-void RelatedPacketDelegate::addRelatedFrame(int frame_num)
+void RelatedPacketDelegate::addRelatedFrame(int frame_num, ft_framenum_type_t framenum_type)
{
- related_frames_ << frame_num;
+ related_frames_[frame_num] = framenum_type;
+ // Last match wins. Last match might not make sense, however.
+ if (current_frame_ > 0) {
+ switch (framenum_type) {
+ case FT_FRAMENUM_REQUEST:
+ related_frames_[current_frame_] = FT_FRAMENUM_RESPONSE;
+ break;
+ case FT_FRAMENUM_RESPONSE:
+ related_frames_[current_frame_] = FT_FRAMENUM_REQUEST;
+ break;
+ default:
+ break;
+ }
+ }
}
-void RelatedPacketDelegate::setConversationSpan(int first_frame, int last_frame)
+void RelatedPacketDelegate::setConversation(conversation *conv)
{
- first_frame_ = first_frame;
- last_frame_ = last_frame;
+ conv_ = conv;
}
/*
diff --git a/ui/qt/related_packet_delegate.h b/ui/qt/related_packet_delegate.h
index db8b1a617a..c33bbf2c72 100644
--- a/ui/qt/related_packet_delegate.h
+++ b/ui/qt/related_packet_delegate.h
@@ -26,16 +26,23 @@
#include "epan/conversation.h"
-#include <QList>
+#include <QHash>
#include <QStyledItemDelegate>
+class QPainter;
+struct conversation;
+
class RelatedPacketDelegate : public QStyledItemDelegate
{
+ Q_OBJECT
public:
- RelatedPacketDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) { clear(); }
+ RelatedPacketDelegate(QWidget *parent = 0);
void clear();
- void addRelatedFrame(int frame_num);
- void setConversationSpan(int first_frame, int last_frame);
+ void setCurrentFrame(guint32 current_frame) { current_frame_ = current_frame; }
+ void setConversation(struct conversation *conv);
+
+public slots:
+ void addRelatedFrame(int frame_num, ft_framenum_type_t framenum_type = FT_FRAMENUM_NONE);
protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option,
@@ -44,10 +51,11 @@ protected:
const QModelIndex &index) const;
private:
- QList<int> related_frames_;
- int first_frame_;
- int last_frame_;
+ QHash<int, ft_framenum_type_t> related_frames_;
+ struct conversation *conv_;
+ guint32 current_frame_;
+ void drawArrow(QPainter *painter, QPoint tail, QPoint head, int head_size) const;
signals: