diff options
-rw-r--r-- | epan/dissectors/packet-dns.c | 4 | ||||
-rw-r--r-- | epan/dissectors/packet-icmp.c | 4 | ||||
-rw-r--r-- | epan/ftypes/ftypes.h | 8 | ||||
-rw-r--r-- | epan/proto.c | 7 | ||||
-rw-r--r-- | epan/proto.h | 3 | ||||
-rwxr-xr-x | tools/checkAPIs.pl | 4 | ||||
-rw-r--r-- | ui/qt/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ui/qt/packet_list.cpp | 13 | ||||
-rw-r--r-- | ui/qt/packet_list.h | 1 | ||||
-rw-r--r-- | ui/qt/packet_list_record.cpp | 8 | ||||
-rw-r--r-- | ui/qt/packet_list_record.h | 6 | ||||
-rw-r--r-- | ui/qt/proto_tree.cpp | 7 | ||||
-rw-r--r-- | ui/qt/proto_tree.h | 4 | ||||
-rw-r--r-- | ui/qt/related_packet_delegate.cpp | 158 | ||||
-rw-r--r-- | ui/qt/related_packet_delegate.h | 22 |
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: |