From: g0dil Date: Tue, 24 Jul 2007 11:55:16 +0000 (+0000) Subject: Packets: Add additional packet parser clarifications X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=32573fc81844083b2aa02d3d224e4cb327de0d9d;p=senf.git Packets: Add additional packet parser clarifications Packets: Adapt to use ccide-all-includes-guard feature Packets: Remove ancient doc files (TODO, FUTURE) git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@345 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Packets/.dir.el b/Packets/.dir.el new file mode 100644 index 0000000..77d54f9 --- /dev/null +++ b/Packets/.dir.el @@ -0,0 +1 @@ +(set (make-local-variable 'ccide-all-includes-guard) "SENF_PACKETS_DECL_ONLY") diff --git a/Packets/FUTURE b/Packets/FUTURE deleted file mode 100644 index 65d4484..0000000 --- a/Packets/FUTURE +++ /dev/null @@ -1,71 +0,0 @@ -Optimize the PacketRegistry using a vtable like approach. This vtable -approach should be implemented as a generic vtable library: - -Every class which shall be extensible needs to inheriv from the vtable -base class. This base class adds an integer member to the class. This -baseclass uses the CRTP pattern to initialize this integer to a type -specific value. - -To get theese values, we use a typeid registry. The typeid-registry is -a tempalte struct with the class as template arg and a single static -member fn. This fn has a member variable of type 'typeid sequence -value'. The constructor of this type will automatically allocate the -next free typeid integer. This can then efficiently be returned by the -static retrieval function: - - template - struct senf::vtable::impl::TypeRegistry - { - static unsigned id() { - static senf::vtable::impl::AutoTypeId typeid; - return typeid.id(); - } - }; - - struct senf::vtable::impl::AutoTypeId - { - AutoTypeId() : id(nextAutoTypeId()) {} - unsigned id; - }; - - unsigned nextAutoTypeId() - { - static unsigned id(0); - return id++; - } - -This setup will assign id's uniquely. The Id's will be ordered by the -first TypeRegistry::id() call. To get the Type id of a type, just call -senf::vtable::impl::TypeRegistry::id(). - -The above is bogus ... we don't register the extensible types, we -register the extensions which are arbitrary types. - -The typeid assigned to the extension type is used as an index into a -vtable. This vtable is in the simplest case, just an std::vector of -void*. To assign an extension to a specific type, we just add some -instance of the registered extension type to the vtable of the -to-be-extended type using the slot given by the typeid of the -extension type. To get the extension, we just look up the id of the -extension type and cast the value from the vtable vector to the -appropriate type. All this is O(1) and does not depend on the number -of extensions or on the number of extended classes. - -The extension vtables are created inside a static method of a -templated class (template arg is the extensible class). Additionally, -the extensible class must CRTP-wise inherit the vtable baseclass, -which will add a vtable pointer to the extensible class and initialize -it automatically to point to the correct vtable. - -To make this even more efficient, all vtables should be kept in a -list. This allows to keep all vtables to the same size. Then no range -checking must be done on accessing the vtable, since all vtables are -all as long as the largest extension id. This of course makes the -Operation of registering a new extension type O(n), but that should -not be a problem since extensions are registered once during program -startup. As a reward, the lookup performance is increased: it is only -a memory access to find the extension-type id(the address is fixed at -compile time) followed by an indexed access to the vtable, where the -vtable address is fetched using another memory access. This differs -from a compiler-generated vtable access only by a single memory -access. diff --git a/Packets/Mainpage.dox b/Packets/Mainpage.dox index f412bfa..f541660 100644 --- a/Packets/Mainpage.dox +++ b/Packets/Mainpage.dox @@ -137,6 +137,16 @@ default protocols: Ethernet, Ip, TCP, UDP \li MPEGDVBBundle: MPEG and DVB protocols + + There are two ways to link with a bundle + + \li If you only work with known packets which you explicitly reference you may just link with + the corresponding library. + \li If you need to parse unknown packets and want those to be parsed as complete as possible + without explicitly referencing the packet type, you will need to link against the combined + object file built for every bundle. This way, all packets defined in the bundle will be + included whether they are explicitly referenced or not (and they will all automatically be + registered). */ diff --git a/Packets/PacketParser.hh b/Packets/PacketParser.hh index 98fdbb2..9a3305b 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,18 +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. - - Every parser is derived from senf::PacketParserBase. This class provides the necessary - housekeeping information and provides the parsers with access to the data. + 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. 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_ diff --git a/Packets/TODO b/Packets/TODO deleted file mode 100644 index 8749617..0000000 --- a/Packets/TODO +++ /dev/null @@ -1,15 +0,0 @@ -Klasse für IPv6 (v4?) Adressen als Parser und als value type - -Bessere check implementierung ? -check umbauen: check() static machen und vor dem DerivedPacket() constructor -aufrufen. DerivedPacket() constructor darf dann keine exception mehr -auslösen - -ParseListS wrapper implementieren. - ---------------------------------------------------------------------------- -Obsolete: - -reference-counting: Packet's mit 0 refcount erstellen und dann in -create hochzählen. Was spricht eigentlich dagegen ??? - --> Hrmpf .. doch ziemlich kompliziert, ich glaube, das lasse ich