X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Packets%2FPacketParser.hh;h=2b73860b2c32f9385fe8ffcc0dd1685b23f1638c;hb=81ffa1c459b96dd44472bcef37e1e373934ee138;hp=a52c888a63ddfc917d535c399f908ff2484fa195;hpb=ef0a3583fc76292d631de6a4a5cad4a432351ac8;p=senf.git diff --git a/Packets/PacketParser.hh b/Packets/PacketParser.hh index a52c888..2b73860 100644 --- a/Packets/PacketParser.hh +++ b/Packets/PacketParser.hh @@ -28,6 +28,11 @@ by value, they can be understood as pointers into the packet data with added type information providing parsing functions. + Packet parsers are \e only used within the packet framework. You should never allocate a new + parser instance directly, you should the Packet library let that do for you (either by having + the parser as a packet parser in a packet type or by having a member in the packet parser which + allocates the parser as a sub-parser). + Parsers are built hierarchically. A high-level parser will return other parsers when accessing an element (Example: Asking an EthernetParser for the ethertype field by calling the parsers \c type() member will return an \c UInt16 parser). The lowest level building blocks then return the @@ -56,13 +61,86 @@ complex parsers provide type specific access members. Assigning a value to a parser will change the underlying representation (the packet data). - More complex parsers (especially those representing a collection of values) provide an - additional wrapper class for mutating access (e.g. Parse_Vector provides a container wrapper - with am STL compatible random-access sequence interface). See the documentation of the specific - parser for the wrapper specification. + Parsers can be grouped into several categories. These categories are not all defined rigorously + but are nevertheless helpful when working with the parsers: + \li Value parsers provide the lowest level parsers (e.g. senf::Parse_UInt16 which + returns an integer value). + \li Collection parsers are parsers which model a collection of sub-elements like + senf::Parse_List or senf::Parse_Vector. + \li Composite parsers collect several fields of arbitrary type into a new + parser. Parsers defined using the \ref packetparsermacros fall under this category. + \li Packet parsers are used to define a packet type. + + \warning Parsers are like iterators: They are invalidated whenever the size of the packet's + data is changed. You should not store a parser anywhere. If you want to keep a parser + reference, use the senf::SafePacketParser wrapper. You still will need to take extra care to + ensure the parser is not invalidated. + + \section parserimpl Packet parser categories Every parser is derived from senf::PacketParserBase. This class provides the necessary - housekeeping information and provides the parsers with access to the data. + housekeeping information and provides the parsers with access to the data. You may in principle + define arbitrary methods as parser members (e.g. methods to calculate a checksum, methods + processing fields in some way and so on). You should however be very wary to access data outside + the range assigned to the packet (the range starting at \c i() and with a size of senf::bytes() + bytes). + + Each parser type has specific features + + \subsection parserimpl_value Value parsers + + For a parser \a SomeParser to be a value parser, the following expressions must be valid: + \code + // SomeParser must have a 'value_type', The 'value_type' must be default constructible, copy + // constructible and assignable + SomeParser::value_type v; + + // An instance of 'SomeParser' must have a 'value' member which returns a value which may be + // assigned to a variable of type 'value_type' + v = p.someParserField().value() + + // It must be possible to assign a new value using the 'value' member + p.someParserField().value(v) + \endcode + + If at all possible, the 'value_type' should not reference the packet data using iterators or + pointers, it should hold a copy of the value (it's Ok for \c value() to return such a reference + as long as assigning it to a \c value_type variable will copy the value). + + \subsection parserimpl_collection Collection parsers + + A collection parser \a SomeParser should model STL containers. The parsers themselves will + probably only // provide a reduced interface, but the collection parser should have a \c + collection member which is a wrapper providing the full interface. + \code + SomeParser::container c (p.someParserField()); + \endcode + + You will probably only very seldom need to implement a completely new collection + parser. Instead, you can rely on senf::Parse_Vector or senf::Parse_List and implement new + polcies. + + \subsection parserimpl_composite Composite parsers + + If possible, composite parsers should be implemented using the \ref packetparsermacros. In + addition to the normal parser requirements, these macros ensure, that for each field, + fieldname_t is a typedef for the fields parser and + fieldname_offset is the offset of the field in bytes from the beginning of the + parser (either a constant for fixed size parsers or a member function for dynamically sized + parsers). When defining composite parsers without the help of the \ref packetparsermacros, you + should provide those same members. + + \subsection parserimpl_packet Packet parsers + + Packet parsers are composite parsers with relaxed requirements. Since a packet parser will never + be used as a sub-parser (it will not be used within another composite parser or as value type in + a collection parser), the value returned by senf::bytes for this parser must not necessarily + cover the complete packet (e.g. if the packet has a trailer, the trailer will live outside the + range given by senf::bytes). You may define any member you want to have in your packets field + interface. These members may access the packet data in any way. You just need to ensure, that + the integration into the packet-type is correct (the senf::PacketTypeMixin will by default use + senf::bytes() to find the end of the header). + */ #ifndef HH_PacketParser_ @@ -74,9 +152,7 @@ #include #include "Utils/SafeBool.hh" #include "PacketTypes.hh" -#define HH_PacketData_DeclOnly #include "PacketData.hh" -#undef HH_PacketData_DeclOnly #include "PacketParser.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -85,7 +161,7 @@ namespace senf { /** \brief Parser Base class - Parsers come in two favors: fixed and dynamically sized parsers. A fixed size + Parsers come in two flavors: fixed and dynamically sized parsers. A fixed size parser has a constant size, it will always parse a fixed number of bytes. The low-level 'final' parsers (like the integer parsers) are fixed size parsers as are composite parsers built up only of fixed-size fields. @@ -284,6 +360,13 @@ namespace senf { struct init_bytes : public detail::ParserInitBytes {}; +# ifndef DOXYGEN + template + typename boost::enable_if< + boost::is_base_of, + Parser >::type + operator<<(Parser target, Parser source); +# else /** \brief Generic parser copying This operator allows to copy the values of identical parsers. This operation does \e not @@ -297,11 +380,17 @@ namespace senf { \ingroup packetparser */ template - typename boost::enable_if< - boost::is_base_of, - Parser >::type - operator<<(Parser target, Parser source); + Parser operator<<(Parser target, Parser source); +# endif +# ifndef DOXYGEN + template + typename boost::enable_if_c < + boost::is_base_of::value + && ! boost::is_base_of::value, + Parser >::type + operator<<(Parser target, Value const & value); +# else /** \brief Generic parser value assignment This operator allows to assign a value to parsers which implement a value(\a @@ -311,11 +400,8 @@ namespace senf { \ingroup packetparser */ template - typename boost::enable_if_c < - boost::is_base_of::value - && ! boost::is_base_of::value, - Parser >::type - operator<<(Parser target, Value const & value); + Parser operator<<(Parser target, Value const & value); +# endif /** \defgroup packetparsermacros Helper macros for defining new packet parsers @@ -325,28 +411,26 @@ namespace senf { These macros simplify providing the above defined interface. A typical packet declaration using these macros has the following form (This is a concrete example from the definition of - the ethernet packet in DefaultBundle//EthernetPacket.hh) + the ethernet packet in DefaultBundle/EthernetPacket.hh) + \code - struct Parse_EthVLan : public senf::PacketParserBase - { - SENF_PACKET_PARSER_INIT(Parse_EthVLan); - - // //////////////////////////////////////////////////////////////////////// - - typedef senf::Parse_UIntField < 0, 3 > Parse_Priority; - typedef senf::Parse_Flag < 3 > Parse_CFI; - typedef senf::Parse_UIntField < 4, 16 > Parse_VLanId; - typedef senf::Parse_UInt16 Parse_Type; - - SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS( - ((OverlayField)( priority, Parse_Priority )) - ((OverlayField)( cfi, Parse_CFI )) - ((Field )( vlanId, Parse_VLanId )) - ((Field )( type, Parse_Type )) - ); - }; + struct Parse_EthVLan : public PacketParserBase + { + typedef Parse_UIntField < 0, 3 > Parse_Priority; + typedef Parse_Flag < 3 > Parse_CFI; + typedef Parse_UIntField < 4, 16 > Parse_VLanId; + typedef Parse_UInt16 Parse_Type; + + SENF_PACKET_PARSER_INIT(Parse_EthVLan); + + SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS( + ((OverlayField)( priority, Parse_Priority )) + ((OverlayField)( cfi, Parse_CFI )) + ((Field )( vlanId, Parse_VLanId )) + ((Field )( type, Parse_Type )) ); + }; \endcode - + The macros take care of the following: \li They define the accessor functions returning parsers of the given type. \li They automatically calculate the offset of the fields from the preceding fields. @@ -463,8 +547,37 @@ namespace senf { \hideinitializer */ # define SENF_PACKET_PARSER_DEFINE_FIELDS(fields) \ - SENF_PACKET_PARSER_I_DEFINE_FIELDS(fields) + SENF_PACKET_PARSER_I_DEFINE_FIELDS(0,fields) + + /** \brief Define fields for a dynamically sized parser (with offset) + + Define the fields as specified in \a fields. This macro supports dynamically sized + subfields, the resulting parser will be dynamically sized. + + The \a offset argument gives the byte offset at which to start parsing the fields. This + helps defining extended parser deriving from a base parser: + \code + struct ExtendedParser : public BaseParser + { + ExtendedParser(data_iterator i, state_type s) : BaseParser(i,s) {} + SENF_PACKET_PARSER_DEFINE_FIELDS_OFFSET(senf::bytes(BaseParser(*this)), + ( ... fields ... ) ); + + void init() { + BaseParser::init(); + defaultInit(); + // other init code + } + } + \endcode + + \ingroup packetparsermacros + \hideinitializer + */ +# define SENF_PACKET_PARSER_DEFINE_FIELDS_OFFSET(offset,fields) \ + SENF_PACKET_PARSER_I_DEFINE_FIELDS(offset,fields) + /** \brief Define fields for a fixed size parser Define the fields as specified in \a fields. This macro only supports fixed size @@ -474,8 +587,39 @@ namespace senf { \hideinitializer */ # define SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS(fields) \ - SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(fields) + SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(0,fields) + + /** \brief Define fields for a fixed size parser + + Define the fields as specified in \a fields. This macro only supports fixed size + subfields, the resulting parser will also be a fixed size parser. + + The \a offset argument gives the byte offset at which to start parsing the fields. This + helps defining extended parser deriving from a base parser: + \code + struct ExtendedParser : public BaseParser + { + ExtendedParser(data_iterator i, state_type s) : BaseParser(i,s) {} + + SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS_OFFSET(BaseParser::fixed_bytes, + ( ... fields ... ) ); + + void init() { + BaseParser::init(); + defaultInit(); + // other init code + } + } + \endcode + \ingroup packetparsermacros + \hideinitializer + */ +# define SENF_PACKET_PARSER_DEFINE_FIXED_FIELDS_OFFSET(offset,fields) \ + SENF_PACKET_PARSER_I_DEFINE_FIXED_FIELDS(offset,fields) + + /** \brief Default parser parsing nothing + */ struct VoidPacketParser : public PacketParserBase { @@ -494,8 +638,10 @@ namespace senf { location will \e not be updated accordingly and therefore the parser will be invalid. - Additionally a SafePacketparser has an uninitialized state. The only allowed operations in + Additionally a SafePacketParser has an uninitialized state. The only allowed operations in this state are the boolean test for validity and assigning another parser. + + \ingroup packetparser */ template class SafePacketParser @@ -540,6 +686,9 @@ namespace senf { } ///////////////////////////////hh.e//////////////////////////////////////// +#endif +#if !defined(SENF_PACKETS_DECL_ONLY) && !defined(HH_PacketParser_i_) +#define HH_PacketParser_i_ #include "PacketParser.cci" #include "PacketParser.ct" #include "PacketParser.cti" @@ -556,13 +705,3 @@ namespace senf { // comment-column: 40 // End: -// LocalWords: templated PacketParser defgroup packetparser PacketParsers li -// LocalWords: EthernetParser ethertype UInt senf PacketParserBase tt -// LocalWords: struct FooParser const init endcode ingroup param SomeParser -// LocalWords: ethernet DefaultBundle EthernetPacket hh EthVLan UIntField CFI -// LocalWords: VLanId OverlayField cfi vlanId accessor defaultInit bitfield -// LocalWords: SomePacket SimpleVectorSizer packetparsermacros Fraunhofer std -// LocalWords: hideinitializer Institut fuer offene Kommunikationssysteme STL -// LocalWords: FOKUS Kompetenzzentrum Satelitenkommunikation SatCom Bund cerr -// LocalWords: berlios dil Structors someField someVector someOtherField -// LocalWords: TruncatedPacketException