From: g0dil Date: Fri, 25 Jan 2008 11:10:58 +0000 (+0000) Subject: Packets: Add PacketParserBase::i(size_type) utility X-Git-Url: http://g0dil.de/git?p=senf.git;a=commitdiff_plain;h=844ac7af0a15ed6c487bc9928148ac38a2ce4025 Packets: Add PacketParserBase::i(size_type) utility Packets: Renamed PacketParserMixin::registry_key_t to key_t Packets: Add PacketParserMixin::lookup helper git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@638 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/HowTos/NewPacket/Mainpage.dox b/HowTos/NewPacket/Mainpage.dox index ef7a92d..1395147 100644 --- a/HowTos/NewPacket/Mainpage.dox +++ b/HowTos/NewPacket/Mainpage.dox @@ -74,6 +74,8 @@ \subsection howto_newpacket_parser_skeleton The PacketParser skeleton \code + #include + struct GREPacketParser : public senf::PacketParser { # include SENF_PARSER() @@ -270,16 +272,18 @@ which does just that: It calculates the checksum of the GRE packet. \code + #include + checksum_t::value_type calculateChecksum() const { if (!checksumEnabled()) return 0; senf::IpChecksum cs; - cs.feed( i(), i()+4 ); + cs.feed( i(), i(4) ); // Skip even number of 0 bytes (the 2 bytes checksum field) // cs.feed(0); cs.feed(0); - cs.feed( i()+6, data().end() ); + cs.feed( i(6), data().end() ); return cs.sum() } @@ -289,6 +293,11 @@ packet including it's header with the checksum field temporarily set to 0. Instead of really changing the checksum field we manually pass the correct data to \a cs. + We use the special i(offset) helper to get iterators \a offset number + of bytes into the data. This helper has the additional benefit of range-checking the returned + iterator and thereby safe os from errors due to truncated packets: If the offset is out of + range, a TruncatedPacketException will be thrown. + In this code we utilize some additional information provided by senf::PacketParserBase. The \a i() member returns an iterator to the first byte the parser is interpreting whereas \a data() returns a reference to the packet data container for the packet being parsed. Access to \a @@ -303,7 +312,6 @@ \code #include - #include struct GREPacketParser_OptFields : public senf::PacketParser { @@ -340,12 +348,17 @@ checksum_t::value_type calculateChecksum() const; }; + + // In the implementation (.cc) file: + + #include GREPacketParser::checksum_t::value_type GREPacketParser::calculateChecksum() const { if (!checksumEnabled()) return 0; + validate(6); senf::IpChecksum cs; cs.feed( i(), i()+4 ); // Skip even number of 0 bytes (the 2 bytes checksum field) @@ -370,6 +383,8 @@ utilizes a registry and is not hopelessly complex, the packet type will almost always look like this: \code + #include + struct GREPacketType : public senf::PacketTypeBase, public senf::PacketTypeMixin @@ -446,6 +461,8 @@ \c .cc file): \code + #include + SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket ); \endcode @@ -459,6 +476,8 @@ GRE has been assigned the value 47: \code + #include + SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket ); \endcode @@ -477,7 +496,7 @@ { if (p->checksumPresent()) p->checksum() << p->calculateChecksum(); - p->protocolType() << key(p->next(senf::nothrow)); + p->protocolType() << key(p.next(senf::nothrow)); } \endcode @@ -491,11 +510,418 @@ assign parsers to each other efficiently and it supports 'optional values' (as provided by Boost.Optional and as returned by \c key()). + + + \subsection howto_newpacket_type_dump Writing out a complete packet: The 'dump()' member + + For diagnostic purposes, every packet should provide a meaningful \a dump() member which writes + out the complete packet. This member is simple to implement and is often very helpful when + tracking down problems. + + \code + #include + + static void dump(packet p, std::ostream & os) + { + boost::io::ios_all_saver ias(os); + os << "General Routing Encapsulation:\n" + << " checksum present : " << p->checksumPresent() ? "true" : "false" << "\n" + << " version : " << p->version() << "\n" + << " protocol type : 0x" << std::hex << std::setw(4) << std::setfill('0') + << p->protocolType() << "\n"; + if (p->checksumPresent()) + os << " checksum : 0x" << std::hex << std::setw(4) + << std::setfill('0') << p->checksum() << "\n"; + } + \endcode + + This member is quite straight forward. We should try to adhere to the formating standard shown + above: The first line should be the type of packet/header being dumped followed by one line for + each protocol field. The colon's should be aligned at column 33 with the field name indented by + 2 spaces. + + The \c boost::ios_all_saver is just used to ensure, that the stream formatting state is restored + correctly at the end of the method. An instance of this type will save the stream state when + constructed and will restore that state when destructed. + + \subsection howto_newpacket_type_final Final touches + + The \c GREPacket implementation is now almost complete. The only thing missing is the \c + GREPacket itself. \c GREPacket is just a typedef for a specific senf::ConcretePacket template + instantiation. Here the complete GREPacket definition: + + \code + #include + + struct GREPacketType + : public senf::PacketTypeBase, + public senf::PacketTypeMixin + { + typedef senf::PacketTypeMixin mixin; + typedef senf::ConcretePacket packet; + typedef senf::GREPacketParser parser; + + using mixin::nextPacketRange; + using mixin::nextPacketType; + using mixin::init; + using mixin::initSize; + + static key_t nextPacketKey(packet p) { return p->protocolType(); } + + static void finalize(packet p) { + if (p->checksumPresent()) p->checksum() << p->calculateChecksum(); + p->protocolType() << key(p.next(senf::nothrow)); + } + + static void dump(packet p, std::ostream & os); + }; + + typedef GREPacketType::packet GREPacket; + + // In the implementation (.cc) file: + + #include + #include + + SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket ); + SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket ); + + void GREPacketType::dump(packet p, std::ostream & os) + { + boost::io::ios_all_saver ias(os); + os << "General Routing Encapsulation:\n" + << " checksum present : " << p->checksumPresent() ? "true" : "false" << "\n" + << " version : " << p->version() << "\n" + << " protocol type : 0x" << std::hex << std::setw(4) << std::setfill('0') + << p->protocolType() << "\n"; + if (p->checksumPresent()) + os << " checksum : 0x" << std::hex << std::setw(4) + << std::setfill('0') << p->checksum() << "\n"; + } + \endcode + + + \section howto_newpacket_advanced Going further + + \subsection howto_newpacket_advanced_valid Checking the GRE packet for validity + + We have implemented the \c GREPacket completely by now. There is however still room for + improvement. Reading the RFC, there are some restrictions which a packet needs to obey to be + considered valid. If the packet is not valid it cannot be parsed and should be dropped. There + are two conditions which lead to this: If one of the \a reserved0 fields first 5 bits is set or + if the version is not 0. We will add a \a valid() check to the parser and utilize this check in + the packet type. + + So first lets update the parser. We will need to change the fields a little bit so we have + access to the first 5 bits of \a reserved0. We therefore replace the first three field + statements with + + \code + SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool ); + SENF_PARSER_PRIVATE_BITFIELD ( reserved0_5bits_, 5, unsigned ); + SENF_PARSER_SKIP_BITS ( 7 ); + SENF_PARSER_PRIVATE_BITFIELD ( version_, 3, unsigned ); + \endcode + + We have added an additional private bitfield \a reserved0_5bits_() and we made the \a version_() + field private since we do not want the user to change the value. We could have used a read-only + field in this special case (since the valid value is 0) but generally in a case like this since + the field will be initialized by the parser (see next section on how). the field should be + private with an additional public read-only accessor. + + We will now add two additional simple members to the parser + + \code + typedef version__t version_t; + version_t::value_type version() const { return version_(); } + + bool valid() const { return version() == 0 && reserved0_5bits_() == 0; } + \endcode + + I think, both are quite straight forward: \a version() will allow the user to read out the value + of the version field. However, since it does \e not return a parser but a numeric value, the + access is read-only. The \a valid() member will just check the restrictions as defined in the RFC. + + Now to the packet type. We want to refrain from parsing the payload if the packet is + invalid. This is important: If the packet is not valid, we have no idea, whether the payload is + what we surmise it to be (if any of the \a reserved0_5bits_() are set, the packet is from an + older GRE RFC and the header is quite a bit longer so the payload will be incorrect). + + So we need to change the logic which is used by the packet library to find the type of the next + packet. We have two ways to do this: We keep using the default \c nextPacketType() + implementation as provided by the senf::PacketTypeMixin and have our \a nextPacketKey() + implementation return a key value which is guaranteed never to be registered in the registry. + + The more flexible possibility is implementing \c nextPacketType() ourselves. In this case, the + first method would suffice, but we will choose to go the second route to show how to write the + \c nextPacketType() member. We therefore remove the \c using declaration of \c nextPacketType() + and also remove the \a nextPacketKey() implementation. Instead we add the following to the + packet type + + \code + // disabled: using Min::nextPacketType; + + factory_t nextPacketType(packet p) { return p->valid() ? lookup(p->protocolType()) : no_factory(); } + \endcode + + As we see, this is still quite simple. \c factory_t is provided by senf::PacketTypeBase. For our + purpose it is an opaque type which somehow enables the packet library to create a new packet of + a specified packet type. The \c factory_t has a special value, \c no_factory() which stands for + the absence of any concrete factory. In a boolean context this (and only this) \c factory_t + value tests \c false. + + The \c lookup() member is provided by the senf::PacketTypeMixin. It looks up the key passed as + argument in the registry and returns the factory or \c no_factory(), if the key was not found in + the registry. + + In this case this is all. We can however return the factory for some specific type easily as in + the following example: + + \code + factory_t nextPacketType(packet p) { + if (p->valid()) { + if (p->protocolType() == 0x6558) return senf::EthernetPacket::factory(); + else return lookup(p->protocolType()); + } + else return no_factory(); + } + \endcode + + Of course, this example is academic since senf::EthernetPacket is correctly registered in the + senf::EtherTypes registry but you get the picture. + + + \subsection howto_newpacket_advanced_init Non-trivial packet initialization + + When we create a new GRE packet using the packet library, the library will initialize the packet + with all 0 bytes. It just happens, that this is correct for our GRE packet. Lets just for the + sake of experiment assume, the GRE packet would have to set \a version() to 1 not 0. In this + case, the default initialization would not suffice. It is however very simple to explicitly + initialize the packet. The initialization happens within the parser. We just add + + \code + SENF_PARSER_INIT() { version_() << 1u; } + \endcode + + to \c GREPacketParser. Here we see, why we have defined \a version_() as a private and not a + read-only field. + + + \section howto_newpacket_final The ultimate GRE packet implementation completed + + So here we now have \c GREPacket finally complete in all it's glory. First the header file \c + GREPacket.hh: + + \code + #ifndef GRE_PACKET_HH + #define GRE_PACKET_HH + + #include + + struct GREPacketParser_OptFields : public senf::PacketParser + { + # include SENF_FIXED_PARSER() + + SENF_PARSER_FIELD ( checksum, senf::UInt16Parser ); + SENF_PARSER_SKIP ( 2 ); + + SENF_PARSER_FINALIZE(GREPacketParser_OptFields); + }; + + struct GREPacketParser : public senf::PacketParser + { + # include SENF_PARSER() + + SENF_PARSER_BITFIELD_RO ( checksumPresent, 1, bool ); + SENF_PARSER_PRIVATE_BITFIELD ( reserved0_5bits_, 5, unsigned ); + SENF_PARSER_SKIP_BITS ( 7 ); + SENF_PARSER_PRIVATE_BITFIELD ( version_, 3, unsigned ); + + SENF_PARSER_FIELD ( protocolType, senf::UInt16Parser ); + + SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent, + (senf::VoidPacketParser) + (GREPacketParser_OptFields) ); + + typedef version__t version_t; + version_t::value_type version() const { return version_(); } + + bool valid() const { return version() == 0 && reserved0_5bits_() == 0; } + + typedef GREPacketParser_OptFields::checksum_t checksum_t; + checksum_t checksum() const + { return optionalFields_().get<1>().checksum(); } + + void enableChecksum() const { optionalFields_().init<1>(); } + void disableChecksum() const { optionalFields_().init<0>(); } + + SENF_PARSER_FINALIZE(GREPacketParser); + + checksum_t::value_type calculateChecksum() const; + }; + + struct GREPacketType + : public senf::PacketTypeBase, + public senf::PacketTypeMixin + { + typedef senf::PacketTypeMixin mixin; + typedef senf::ConcretePacket packet; + typedef senf::GREPacketParser parser; + + using mixin::nextPacketRange; + using mixin::init; + using mixin::initSize; + + factory_t nextPacketType(packet p) + { return p->valid() ? lookup(p->protocolType()) : no_factory(); } + + static void finalize(packet p) { + if (p->checksumPresent()) p->checksum() << p->calculateChecksum(); + p->protocolType() << key(p.next(senf::nothrow)); + } + + static void dump(packet p, std::ostream & os); + }; + + typedef GREPacketType::packet GREPacket; - \fixme Document the needed \c \#include files - \fixme Provide an advanced section with additional info: How to ensure, that the first 5 bits in - reserver0 are not set. How to enforce version == 0 (that is, make version() read-only and - return no_factory for the next packet type if any of the conditions is violated) + #endif + \endcode + + And the implementation file \c GREPacket.cc: + + \code + #include "GREPacket.hh" + #include + #include + #include + + SENF_PACKET_REGISTRY_REGISTER( senf::EtherTypes, 0x6558, senf::EthernetPacket ); + SENF_PACKET_REGISTRY_REGISTER( senf::IpTypes, 47, GREPacket ); + + GREPacketParser::checksum_t::value_type GREPacketParser::calculateChecksum() const + { + if (!checksumEnabled()) + return 0; + + validate(6); + senf::IpChecksum cs; + cs.feed( i(), i()+4 ); + // Skip even number of 0 bytes (the 2 bytes checksum field) + // cs.feed(0); cs.feed(0); + cs.feed( i()+6, data().end() ); + + return cs.sum() + } + + void GREPacketType::dump(packet p, std::ostream & os) + { + boost::io::ios_all_saver ias(os); + os << "General Routing Encapsulation:\n" + << " checksum present : " << p->checksumPresent() ? "true" : "false" << "\n" + << " version : " << p->version() << "\n" + << " protocol type : 0x" << std::hex << std::setw(4) << std::setfill('0') + << p->protocolType() << "\n"; + if (p->checksumPresent()) + os << " checksum : 0x" << std::hex << std::setw(4) + << std::setfill('0') << p->checksum() << "\n"; + } + \endcode + + + \section howto_newpacket_using Using the newly created GRE packet type + + The GRE packet is now fully integrated into the packet library framework. For example, we can + read GRE packets from a raw INet socket and forward decapsulated Ethernet frames to a packet + socket. + + \code + #include + #include + #include + #include + #include + #include "GREPacket.hh" + + int main(int, char const **) + { + senf::RawV6ClientSocketHandle isock (47u); // 47 = Read GRE packets + senf::PacketSocketHandle osock; + + while (1) { + try { + GREPacket gre (GREPacket::create(senf::noinit)); + isock.read(gre.data(),0u); + if (gre->checksumPresent() && gre->checksum() != gre->calculateChecksum()) + throw InvalidPacketChainException(); + osock.write(gre.next().data()) + } + catch (senf::TruncatedPacketException & ex) { + std::cerr << "Malformed packet dropped\n"; + } + catch (senf::InvalidPacketChainException & ex) { + std::cerr << "Invalid GRE packet dropped\n"; + } + } + } + \endcode + + Or we can do the opposite: Read ethernet packets from a \c tap device and send them out GRE + encapsulated. + + \code + #include + #include + #include + #include + #include + #include "GREPacket.hh" + + int main(int argc, char const ** argv) + { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + senf::TapSocketHandle tap ("tap0"); + senf::ConnectedRawV6ClientSocketHandle osock (47u, senf::INet6SocketAddress(argv[1])); + + while (1) { + senf::EthernetPacket eth (senf::EthernetPacket::create(senf::noinit)); + isock.read(eth.data(),0u); + GREPacket gre (senf::GREPacket::createBefore(eth)); + gre.finalize(); + osock.write(gre.data()); + } + } + \endcode + + + \section howto_newpacket_further Further reading + + Lets start with references to the important API's (Use the 'Show all members' link to get the + complete API of one of the classes and templates): + + \li senf::ConcretePacket : this is the API provided by the packet handles. + \li senf::PacketData : this API provides raw data access accessible via the handles 'data' + member. + \li senf::PacketParserBase : this is the generic parser API. This API is accessible via the + packets \c -> operator or via the sub-parsers returned by the field accessors. + + When implementing new packet's, the following information will be helpful: + + \li senf::PacketTypeBase : here you find a description of the members which need to be + implemented to provide a 'packet type'. Most of these members will normally be provided by + the mixin helper. + \li senf::PacketTypeMixin : here you find all about the packet type mixin and how to use it. + \li \ref packetparser : This section describes the packet parser facility. + \li \ref packetparsermacros : A complete list and documentation of all the packet parser macros. + \li There are several lists of available reusable packet parsers: \ref parseint, \ref + parsecollection. However, this list is not complete as there are other protocol specific + reusable parsers (without claiming to be exhaustive: senf::INet4AddressParser, + senf::INet6AddressParser, senf::MACAddressParser) + */ diff --git a/Packets/DefaultBundle/EthernetPacket.cc b/Packets/DefaultBundle/EthernetPacket.cc index 9926efc..328db04 100644 --- a/Packets/DefaultBundle/EthernetPacket.cc +++ b/Packets/DefaultBundle/EthernetPacket.cc @@ -60,24 +60,18 @@ prefix_ void senf::EthernetPacketType::dump(packet p, std::ostream & os) prefix_ senf::PacketInterpreterBase::factory_t senf::EthernetPacketType::nextPacketType(packet p) { - if (p->type_length() >= 1536) { - PkReg_Entry const * e; - e = PacketRegistry::lookup( p->type_length(), nothrow ); - return e ? e->factory() : no_factory(); - } - if (p->type_length() <= 1500) - return LlcSnapPacket::factory(); - return no_factory(); + if (p->type_length() >= 1536) return lookup(p->type_length()); + else if (p->type_length() <= 1500) return LlcSnapPacket::factory(); + else return no_factory(); } prefix_ void senf::EthernetPacketType::finalize(packet p) { - optional_registry_key_t k = key(p.next(nothrow)); + optional_key_t k (key(p.next(nothrow))); if (k) p->type_length() << k; - else - if (p.next().is()) - p->type_length() << p.next().data().size(); + else if (p.next().is()) + p->type_length() << p.next().data().size(); // Do NOT reset type_length if the type is not known ... doing this will destroy read packets } diff --git a/Packets/DefaultBundle/EthernetPacket.hh b/Packets/DefaultBundle/EthernetPacket.hh index 6991f9d..ad9c1f9 100644 --- a/Packets/DefaultBundle/EthernetPacket.hh +++ b/Packets/DefaultBundle/EthernetPacket.hh @@ -177,7 +177,7 @@ namespace senf { /** \todo Add LLC/SNAP support -> only use the registry for type() values >=1536, otherwise expect an LLC header */ - static registry_key_t nextPacketKey(packet p) + static key_t nextPacketKey(packet p) { return p->type(); } static void dump(packet p, std::ostream & os); diff --git a/Packets/DefaultBundle/IPv4Packet.hh b/Packets/DefaultBundle/IPv4Packet.hh index 1a27b27..3da21e0 100644 --- a/Packets/DefaultBundle/IPv4Packet.hh +++ b/Packets/DefaultBundle/IPv4Packet.hh @@ -174,7 +174,7 @@ namespace senf { using mixin::initSize; using mixin::init; - static registry_key_t nextPacketKey(packet p) + static key_t nextPacketKey(packet p) { return p->protocol(); } static void dump(packet p, std::ostream & os); diff --git a/Packets/DefaultBundle/IPv6Extensions.hh b/Packets/DefaultBundle/IPv6Extensions.hh index 7f1bcbc..54b18e1 100644 --- a/Packets/DefaultBundle/IPv6Extensions.hh +++ b/Packets/DefaultBundle/IPv6Extensions.hh @@ -87,7 +87,7 @@ namespace senf { using mixin::initSize; using mixin::init; - static registry_key_t nextPacketKey(packet p) + static key_t nextPacketKey(packet p) { return p->nextHeader(); } static void dump(packet p, std::ostream & os); diff --git a/Packets/DefaultBundle/IPv6Packet.hh b/Packets/DefaultBundle/IPv6Packet.hh index 05ce061..935bcea 100644 --- a/Packets/DefaultBundle/IPv6Packet.hh +++ b/Packets/DefaultBundle/IPv6Packet.hh @@ -114,7 +114,7 @@ namespace senf { using mixin::initSize; using mixin::init; - static registry_key_t nextPacketKey(packet p) + static key_t nextPacketKey(packet p) { return p->nextHeader(); } static void dump(packet p, std::ostream & os); diff --git a/Packets/DefaultBundle/LlcSnapPacket.cc b/Packets/DefaultBundle/LlcSnapPacket.cc index 99461bb..d6ced6a 100644 --- a/Packets/DefaultBundle/LlcSnapPacket.cc +++ b/Packets/DefaultBundle/LlcSnapPacket.cc @@ -61,14 +61,14 @@ prefix_ senf::PacketInterpreterBase::factory_t senf::LlcSnapPacketType::nextPack prefix_ void senf::LlcSnapPacketType::finalize(packet p) { - optional_registry_key_t k = key(p.next(nothrow)); + optional_key_t k (key(p.next(nothrow))); if (k) p->type_length() << k; + else if (p.next().is()) + p->type_length() << p.next().data().size(); else - if (p.next().is()) - p->type_length() << p.next().data().size(); - else - p->type_length() << 0; + ///\fixme Is this correct ?? + p->type_length() << 0; } diff --git a/Packets/MPEGDVBBundle/SNDUPacket.cc b/Packets/MPEGDVBBundle/SNDUPacket.cc index b969752..58dfda8 100644 --- a/Packets/MPEGDVBBundle/SNDUPacket.cc +++ b/Packets/MPEGDVBBundle/SNDUPacket.cc @@ -50,7 +50,7 @@ prefix_ boost::uint32_t senf::SNDUPacketParser::calcCrc() ule_crc32() ).checksum(); } -//prefix_ senf::SNDUPacketType::registry_key_t senf::SNDUPacketType::nextPacketKey(packet p) +//prefix_ senf::SNDUPacketType::key_t senf::SNDUPacketType::nextPacketKey(packet p) //{ // return p->type(); //} diff --git a/Packets/MPEGDVBBundle/SNDUPacket.hh b/Packets/MPEGDVBBundle/SNDUPacket.hh index 2ac0c9f..34e83b8 100644 --- a/Packets/MPEGDVBBundle/SNDUPacket.hh +++ b/Packets/MPEGDVBBundle/SNDUPacket.hh @@ -103,7 +103,7 @@ namespace senf { // using mixin::nextPacketType; // using mixin::init; -// static registry_key_t nextPacketKey(packet p); +// static key_t nextPacketKey(packet p); static void init(packet p); diff --git a/Packets/Packet.test.cc b/Packets/Packet.test.cc index e79f172..fe949cb 100644 --- a/Packets/Packet.test.cc +++ b/Packets/Packet.test.cc @@ -93,7 +93,7 @@ namespace { else p->type() = -1; } - static registry_key_t nextPacketKey(packet p) { + static key_t nextPacketKey(packet p) { return p->type(); } }; diff --git a/Packets/PacketParser.cci b/Packets/PacketParser.cci index 9266ce8..8449145 100644 --- a/Packets/PacketParser.cci +++ b/Packets/PacketParser.cci @@ -39,6 +39,13 @@ prefix_ senf::PacketParserBase::data_iterator senf::PacketParserBase::i() return i_; } +prefix_ data_iterator senf::PacketParserBase::i(size_type offset) + const +{ + validate(offset); + return boost::next(i_, offset); +} + prefix_ senf::PacketParserBase::state_type senf::PacketParserBase::state() const { diff --git a/Packets/PacketParser.hh b/Packets/PacketParser.hh index a00da0d..5248296 100644 --- a/Packets/PacketParser.hh +++ b/Packets/PacketParser.hh @@ -264,10 +264,23 @@ namespace senf { here. The size of the interpreted is given by senf::bytes(parser instance). */ + + data_iterator i(size_type offset) const; ///< Return iterator \a offset bytes from the start + /**< The return value is the same as i() + \a + offset. However, the parser checks, that the iterator is + still within range of the raw data + container. Otherwise a TruncatedPacketException is + thrown. + + \throws TruncatedPacketException if the raw data + container does not hold at least \a offset bytes + starting at i(). */ + state_type state() const; ///< Return state of this parser /**< The value returned should be interpreted as an opaque value provided just to be forwarded to other parsers. */ + PacketData & data() const; ///< Access the packets raw data container /**< This member will return the raw data container holding the data which is parsed by \c this parser. */ @@ -282,6 +295,7 @@ namespace senf { /**< This is the constructor used by most parsers. The parameters are just forwarded from the derived classes constructor parameters. */ + PacketParserBase(data_iterator i, state_type s, size_type size); ///< Size checking constructor /**< In addition to the standard constructor, this @@ -303,6 +317,7 @@ namespace senf { bool check(size_type size) const; ///< Check size of data container /**< \returns \c true, if the data container holds at least \a size beginning at i(), \c false otherwise. */ + void validate(size_type size) const; ///< Validate size of data container /**< \throws TruncatedPacketException if the raw data container does not hold at least \a size bytes @@ -312,6 +327,7 @@ namespace senf { /**< Creates a new instance of \a Parser to parse data beginning at \a i. Automatically passes \a state() to the new parser. */ + template Parser parse(size_type n) const; ///< Create sub-parser /**< Creates a new instance of \a Parser to parse data * beginning at i() + \a n. Automatically passes \a diff --git a/Packets/PacketType.cti b/Packets/PacketType.cti index 843e83a..34f15dc 100644 --- a/Packets/PacketType.cti +++ b/Packets/PacketType.cti @@ -58,9 +58,7 @@ senf::PacketTypeMixin::nextPacketType(Packet p) { if (p.data().size() < Self::initSize()) return Self::no_factory(); - PkReg_Entry const * e (PacketRegistry::lookup( - Self::nextPacketKey(p.as< ConcretePacket >()), nothrow)); - return e ? e->factory() : PacketTypeBase::no_factory(); + return lookup( Self::nextPacketKey(p.as< ConcretePacket >()) ); } template @@ -76,10 +74,17 @@ prefix_ void senf::PacketTypeMixin::init(Packet p) } template -prefix_ typename senf::PacketTypeMixin::optional_registry_key_t +prefix_ typename senf::PacketTypeMixin::optional_key_t senf::PacketTypeMixin::key(Packet p) { - return p ? PacketRegistry::key(p, nothrow) : optional_registry_key_t(); + return p ? PacketRegistry::key(p, nothrow) : optional_key_t(); +} + +template +prefix_ senf::PacketTypeBase::factory_t senf::PacketTypeMixin::lookup(key_t key) +{ + PkReg_Entry const * entry (PacketRegistry::lookup( key, senf::nothrow )); + return entry ? entry->factory() : PacketTypeBase::no_factory(); } /////////////////////////////////////////////////////////////////////////// diff --git a/Packets/PacketType.hh b/Packets/PacketType.hh index e23ef09..e9d0d30 100644 --- a/Packets/PacketType.hh +++ b/Packets/PacketType.hh @@ -263,7 +263,7 @@ namespace senf { // member. } - static registry_key_t nextPacketKey(packet p) + static key_t nextPacketKey(packet p) { // Return the key in the registry under which the next packet // header is to be found. This member must be given if a Registry argument is @@ -306,7 +306,7 @@ namespace senf { using mixin::initSize; using mixin::init; - static registry_key_t nextPacketKey(packet p) + static key_t nextPacketKey(packet p) { return p->typeField(); } }; \endcode @@ -320,10 +320,10 @@ namespace senf { class PacketTypeMixin { public: - typedef typename Registry::key_t registry_key_t; - typedef boost::optional optional_registry_key_t; + typedef typename Registry::key_t key_t; + typedef boost::optional optional_key_t; - static optional_registry_key_t key (Packet p); ///< Find key of packet from registry + static optional_key_t key (Packet p); ///< Find key of packet from registry /**< key() will query the registry to find the key of the given packet. Whereas \c nextPacketKey() as implemented by the mixin user will provide the registry key of the @@ -336,6 +336,11 @@ namespace senf { type is not found in the registry, the returned optional value will be empty. */ + static PacketTypeBase::factory_t lookup (key_t key); ///< Lookup the key in the registry + /**< lookup() will query the registry and find the factory + for the given key. If the key cannot be found, + no_factory() will be returned. */ + ///\name PacketType interface implementation ///@{ diff --git a/senf.dict b/senf.dict index 8a155b1..ec75335 100644 --- a/senf.dict +++ b/senf.dict @@ -12,11 +12,16 @@ ActiveSource addr AddressingPolicy AddressingPolicyBase +AddressParser addtogroup aListCollection alloc +API +API's arg +argc args +argv async Augustin autoThrottling @@ -36,6 +41,7 @@ cc cd cerr cfi +checksumEnabled checksumPresent CIDR ClientSocketHandle @@ -46,6 +52,7 @@ ConcretePacket conf CONFIG ConnectedCommunicationPolicy +ConnectedRawV ConnectedUDPv const createAfter @@ -55,6 +62,7 @@ DataPacket dd de DebugModules +decapsulated DefaultArea DefaultBundle defaultInit @@ -71,6 +79,7 @@ dt ElementParser enableChecksum endcode +endif enum eof EPIPE @@ -114,10 +123,11 @@ ForwardingRoute fraunhofer FroblizerArea GlobalScope -GRE +gre GREPacket GREPacketParser GREPacketType +GREPackeType GREParser hangup HangupException @@ -128,13 +138,16 @@ hostname hostnames howto HowTo +hpp href htm html http iana +ias IdleEvent ietf +ifndef ih impl INet @@ -146,17 +159,23 @@ inline InputConnector inputSocket Institut -Int +int IntervalTimer IntField InvalidPacketChainException +io IOEvent IOEventInfo +ios +iostream ip +IpChecksum IpTypes IpV ipv +IPv IPX +isock iterator join key @@ -171,6 +190,7 @@ localhost loopback mac MACAddress +MACAddressParser mainpage mixin MPEGDVBBundle @@ -204,6 +224,7 @@ OptFields optionalFields org os +osock ostream OtherPacket OtherPacketType @@ -266,6 +287,8 @@ rateFilter ratefilter RateStuffer ratestuffer +RawINetProtocol +RawV refcount registerEvent registerPacket @@ -287,12 +310,15 @@ senf ServerSocketHandle setBegin setEnd +setfill setFromPosition +setw SimplePacketType SimpleVectorSizer SiteScope SizeParser skipline +SocketAddress SocketHandle SocketProtocol SomeEvent @@ -316,6 +342,7 @@ struct structors SyntaxException SystemException +TapSocketHandle td templated ThresholdQueueing @@ -325,6 +352,7 @@ tr TruncatedPacketException tt ttl +TunTapSocketHandle TypeA TypeB typeField @@ -341,6 +369,7 @@ unthrottle unthrottled unthrottles unthrottling +Utils VectorN Ver vlanId