diff --git a/common/abstractprotocolconfig.h b/common/abstractprotocolconfig.h index a65c959..3e87aeb 100644 --- a/common/abstractprotocolconfig.h +++ b/common/abstractprotocolconfig.h @@ -63,7 +63,8 @@ public: /*! Loads data from the protocol using it's fieldData() method into this - widget + widget. Any conversion to user friendly display/editing formats (e.g. + hex format) SHOULD be done by this method. Subclasses MUST implement this function. See the SampleProtocol for an example @@ -75,7 +76,9 @@ public: /*! Stores data from this widget into the protocol using the protocol's - setFieldData() method + setFieldData() method. Field values MUST be converted from any + user friendly display/editing formats (e.g. hex format) to simple + Qt-style integers/strings before passing to setFieldData() Subclasses MUST implement this function. See the SampleProtocol for an example diff --git a/common/ostprotogui.pro b/common/ostprotogui.pro index 0bf1c3f..b075046 100644 --- a/common/ostprotogui.pro +++ b/common/ostprotogui.pro @@ -121,7 +121,8 @@ SOURCES += \ mldpdml.cpp \ tcppdml.cpp \ udppdml.cpp \ - textprotopdml.cpp + textprotopdml.cpp \ + samplepdml.cpp QMAKE_DISTCLEAN += object_script.* diff --git a/common/pdmlprotocol.cpp b/common/pdmlprotocol.cpp index 2be78ab..a682aeb 100644 --- a/common/pdmlprotocol.cpp +++ b/common/pdmlprotocol.cpp @@ -19,35 +19,97 @@ along with this program. If not, see #include "pdmlprotocol.h" +/*! + \class PdmlProtocol + + PdmlProtocol is the base class which provides the interface for all + PDML decode helper protocols + + All Pdml helper classes derived from PdmlProtocol MUST register + themselves with PdmlReader. When PdmlReader encounters a 'proto' tag + in the PDML during parsing, it instantiates the corresponding helper + PdmlProtocol class and calls its methods to decode the protocol. + + A subclass MUST initialize the following inherited protected variables + in its constructor - + - ostProtoId_ + - fieldMap_ + + A subclass typically needs to reimplement the following methods - + - createInstance() + + Depending on certain conditions, subclasses may need to reimplement + the following additional methods - + - unknownFieldHandler() + - preProtocolHandler() + - postProtocolHandler() + + See the description of the methods for more information. + + Use the SamplePdmlProtocol implementation as boilerplate code and + for guidelines and tips +*/ + +/*! + Constructs the PdmlProtocol +*/ PdmlProtocol::PdmlProtocol() { ostProtoId_ = -1; } +/*! + Destroys the PdmlProtocol +*/ PdmlProtocol::~PdmlProtocol() { } +/*! + Allocates and returns a new instance of the class + + Caller is responsible for freeing up after use. Subclasses MUST implement + this function and register it with PdmlReader +*/ PdmlProtocol* PdmlProtocol::createInstance() { return new PdmlProtocol(); } +/*! + Returns the protocol's field number as defined in message 'Protocol', enum 'k' + (file: protocol.proto) +*/ int PdmlProtocol::ostProtoId() const { return ostProtoId_; } +/*! + Returns true if name is a 'known' field that can be directly mapped + to the protobuf field +*/ bool PdmlProtocol::hasField(QString name) const { return fieldMap_.contains(name); } +/*! + Returns the protocol's protobuf field number corresponding to name +*/ int PdmlProtocol::fieldId(QString name) const { return fieldMap_.value(name); } +/*! + This method is called by PdmlReader before any fields within the protocol + are processed. All attributes associated with the 'proto' tag in the PDML + are passed to this method + + Use this method to do any special handling that may be required for + preprocessing +*/ void PdmlProtocol::preProtocolHandler(QString /*name*/, const QXmlStreamAttributes& /*attributes*/, int /*expectedPos*/, OstProto::Protocol* /*pbProto*/, @@ -56,18 +118,41 @@ void PdmlProtocol::preProtocolHandler(QString /*name*/, return; // do nothing! } +/*! + This method is called by PdmlReader when it encounters a nested + protocol in the PDML i.e. a protocol within a protocol or a protocol + within a field + + This is a notification to the protocol that protocol processing will + be ending prematurely. postProtocolHandler() will still be called in + such cases. +*/ void PdmlProtocol::prematureEndHandler(int /*pos*/, OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) { return; // do nothing! } +/*! + This method is called by PdmlReader after all fields within the protocol + are processed. + + Use this method to do any special handling that may be required for + postprocessing +*/ void PdmlProtocol::postProtocolHandler(OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) { return; // do nothing! } + +/*! + This method is called by PdmlReader for each field in the protocol + + Depending on whether it is a known or unknown field, the virtual methods + knownFieldHandler() and unknownFieldHandler() are invoked +*/ void PdmlProtocol::fieldHandler(QString name, const QXmlStreamAttributes &attributes, OstProto::Protocol *pbProto, OstProto::Stream *stream) @@ -99,6 +184,12 @@ void PdmlProtocol::fieldHandler(QString name, } } +/*! + Handles a 'known' field + + Uses protobuf reflection interface to set the protobuf field name to + valueHexStr as per the field's datatype +*/ void PdmlProtocol::knownFieldHandler(QString name, QString valueHexStr, OstProto::Protocol *pbProto) { @@ -143,6 +234,12 @@ void PdmlProtocol::knownFieldHandler(QString name, QString valueHexStr, } } +/*! + Handles a 'unknown' field + + The default implementation does nothing. Subclasses may need to implement + this if the protocol contains 'unknown' fields. +*/ void PdmlProtocol::unknownFieldHandler(QString /*name*/, int /*pos*/, int /*size*/, const QXmlStreamAttributes& /*attributes*/, OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) diff --git a/common/pdmlprotocol.h b/common/pdmlprotocol.h index 7f23524..011fcb6 100644 --- a/common/pdmlprotocol.h +++ b/common/pdmlprotocol.h @@ -59,7 +59,9 @@ public: protected: PdmlProtocol(); + //!< Protocol's field number as defined in message 'Protocol', enum 'k' int ostProtoId_; + //!< Map of PDML field names to protobuf field numbers for 'known' fields QMap fieldMap_; }; diff --git a/common/samplepdml.cpp b/common/samplepdml.cpp new file mode 100644 index 0000000..99b671b --- /dev/null +++ b/common/samplepdml.cpp @@ -0,0 +1,118 @@ +/* +Copyright (C) 2014 Srivats P. + +This file is part of "Ostinato" + +This 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 3 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, see +*/ + +#include "samplepdml.h" + +#include "sample.pb.h" + +/*! + TODO : Initialize the following inherited protected members - + - ostProtoId_ + - fieldMap_ + + ostProtoId_ is the protocol's protobuf field number as defined in + message 'Protocol' enum 'k' in file protocol.proto + + fieldMap_ is a mapping of the protocol's field names as they appear + in the PDML to the protobuf field numbers for the protocol. All such + fields are classified as 'known' fields and the base class will take care + of decoding these without any help from the subclass. + + Note that the PDML field names are same as the field names used in Wireshark + display filters. The full reference for these is available at - + http://www.wireshark.org/docs/dfref/ +*/ +PdmlSampleProtocol::PdmlSampleProtocol() +{ + ostProtoId_ = OstProto::Protocol::kSampleFieldNumber; + + fieldMap_.insert("sample.checksum", OstProto::Sample::kChecksumFieldNumber); + fieldMap_.insert("sample.x", OstProto::Sample::kXFieldNumber); + fieldMap_.insert("sample.y", OstProto::Sample::kYFieldNumber); +} + +PdmlSampleProtocol::~PdmlSampleProtocol() +{ +} + +PdmlSampleProtocol* PdmlSampleProtocol::createInstance() +{ + return new PdmlSampleProtocol(); +} + +/*! + TODO: Use this method to do any special handling that may be required for + preprocessing a protocol before parsing/decoding the protocol's fields +*/ +void PdmlSampleProtocol::preProtocolHandler(QString /*name*/, + const QXmlStreamAttributes& /*attributes*/, + int /*expectedPos*/, OstProto::Protocol* /*pbProto*/, + OstProto::Stream* /*stream*/) +{ + return; +} + +/*! + TODO: Use this method to do any special handling or cleanup that may be + required when a protocol decode is ending prematurely +*/ +void PdmlSampleProtocol::prematureEndHandler(int /*pos*/, + OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) +{ + return; +} + +/*! + TODO: Use this method to do any special handling that may be required for + postprocessing a protocol after parsing/decoding all the protocol fields + + If your protocol's protobuf has some meta-fields that should be set to + their non default values, this is a good place to do that. e.g. derived + fields such as length, checksum etc. may be correct or incorrect in the + PCAP/PDML - to retain the same value as in the PCAP/PDML and not let + Ostinato recalculate these, you can set the is_override_length, + is_override_cksum meta-fields to true here +*/ +void PdmlSampleProtocol::postProtocolHandler(OstProto::Protocol* /*pbProto*/, + OstProto::Stream* /*stream*/) +{ + return; +} + +/*! + TODO: Handle all 'unknown' fields using this method + + You need to typically only handle frame fields or fields actually present + in the protocol on the wire. So you can safely ignore meta-fields such as + Good/Bad Checksum. + + Some fields may not have a 'name' attribute, so cannot be classified as + a 'known' field. Use this method to identify such fields using other + attributes such as 'show' or 'showname' and populate the corresponding + protobuf field. + + If the PDML protocol contains some fields that are not supported by Ostinato, + use a HexDump protocol as a replacement to store these bytes +*/ +void PdmlSampleProtocol::unknownFieldHandler(QString /*name*/, + int /*pos*/, int /*size*/, const QXmlStreamAttributes& /*attributes*/, + OstProto::Protocol* /*pbProto*/, OstProto::Stream* /*stream*/) +{ + return; +} diff --git a/common/samplepdml.h b/common/samplepdml.h new file mode 100644 index 0000000..a07965b --- /dev/null +++ b/common/samplepdml.h @@ -0,0 +1,50 @@ +/* +Copyright (C) 2014 Srivats P. + +This file is part of "Ostinato" + +This 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 3 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, see +*/ + +#ifndef _SAMPLE_PDML_H +#define _SAMPLE_PDML_H + +#include "pdmlprotocol.h" + +class PdmlSampleProtocol : public PdmlProtocol +{ +public: + virtual ~PdmlSampleProtocol(); + + static PdmlSampleProtocol* createInstance(); + + virtual void preProtocolHandler(QString name, + const QXmlStreamAttributes &attributes, int expectedPos, + OstProto::Protocol *pbProto, OstProto::Stream *stream); + virtual void prematureEndHandler(int pos, OstProto::Protocol *pbProto, + OstProto::Stream *stream); + virtual void postProtocolHandler(OstProto::Protocol *pbProto, + OstProto::Stream *stream); + + void fieldHandler(QString name, const QXmlStreamAttributes &attributes, + OstProto::Protocol *pbProto, OstProto::Stream *stream); + virtual void unknownFieldHandler(QString name, int pos, int size, + const QXmlStreamAttributes &attributes, + OstProto::Protocol *pbProto, OstProto::Stream *stream); + +protected: + PdmlSampleProtocol(); +}; + +#endif