Packets: More annotation documentation
g0dil [Thu, 2 Oct 2008 08:19:02 +0000 (08:19 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@922 270642c3-0616-0410-b53a-bc976706d245

Packets/Mainpage.dox
Packets/Packet.hh
senf.dict

index 817a455..a164bd1 100644 (file)
         to define variants in a different way giving other names to the special members (\c has_\e
         name or \c init_\e name etc.). This must be documented with the composite or protocol parser
         which defines the variant.
+
+    \section packet_usage_annotation Annotations
+
+    Sometimes we need to store additional data with a packet. Data, which is not part of the packet
+    itself but gives us some information about the packet: A timestamp, the interface the packet was
+    received on or other processing related information.
+
+    This type of information can be stored using the annotation interface.
+
+    \code
+    struct Timestamp {
+        senf::ClockService::clock_t value;
+    };
+
+    senf::EthernetPacket packet (senf::EthernetPacket::create(senf::noinit));
+    sock.read(packet.data(), 0u);
+    packet.annotation<Timestamp>().value = senf::ClockService::now();
+    \endcode
+
+    In the same way, the annotation can be used later
+
+    \code
+    if (senf::ClockService::now() - packet.annotation<Timestamp>().value 
+            > senf::ClockService::seconds(1)) {
+        // Ouch ... this packet is to old
+        // ...
+    }
+    \endcode
+
+    It is very important to define a specific structure (or class) type for each type of
+    annotation. \e Never directly store a fundamental type as an annotation: The name of the type is
+    used to look up the annotation, so you can store only one annotation for each built-in type. \c
+    typedef does not help since \c typedef does not introduce new type names, it only defines an
+    alias.
+
+    Of course, the annotation structure can be arbitrary. However, one very important caveat: If the
+    annotation is not a POD type, it needs to inherit from senf::ComplexAnnotation. A type is POD,
+    if it is really just a bunch of bytes: No (non-static) members, no constructor or destructor and
+    no base classes and all it's members must be POD too. So the following annotation is complex
+    since \c std::string is not POD
+
+    \code
+    struct ReadInfo : senf::ComplexAnnotation
+    {
+        std::string interface;
+        senf::ClockService::clock_t timestamp;
+    };
+
+    // ...
+
+    packet.annotation<ReadInfo>().interface = "eth0";
+    packet.annotation<ReadInfo>().timestamp = senf::ClockService::now();
+
+    // Or store a reference to the annotation for easier access
+
+    ReadInfo & info (packet.annotation<ReadInfo>());
+    
+    if (info.interface == "eth0") {
+        // ...
+    }
+    \endcode
+
+    You should use annotations economically: Every annotation type used in your program will
+    allocate an annotation slot in \e all packet data structures. So don't use hundreds of different
+    annotation types if this is not really necessary: Reuse annotation types where possible or
+    aggregate data into larger annotation structures. The best solution is to use annotations only
+    for a small number of packet specific informations. If you really need to manage a train-load of
+    data together with the packet consider some other way (e.g. place the packet into another class
+    which holds that data).
+
+    \see senf::Packet::annotation()
  */
 
 /** \page packet_new Defining new Packet types
index e2e3c3f..124e8bd 100644 (file)
@@ -358,6 +358,16 @@ namespace senf {
                                                  used). Additionally, non-complex small annotations
                                                  require no additional memory management (\c new /
                                                  \c delete).
+                                             
+                                             \idea Pool the annotation vectors: In the destructor
+                                                 swap the vector into a vector graveyard (swapping
+                                                 two vectors is an O(1) no allocation operation). In
+                                                 the constructor, if there is a vector in the
+                                                 graveyard, swap it in from there. Of course, it
+                                                 would be better to do away with the vector and just
+                                                 allocate the space together with the packet but
+                                                 that looks quite complicated to do ... especially
+                                                 considering that the packetimpl itself uses a pool.
                                           */
 
         ///@}
index 1e116ff..b34ca69 100644 (file)
--- a/senf.dict
+++ b/senf.dict
@@ -62,6 +62,7 @@ checksumPresent
 CIDR
 classsenf
 ClientSocketHandle
+ClockService
 cloneable
 CloneSource
 cmd
@@ -72,6 +73,7 @@ CommandOverload
 CommandParser
 CommunicationPolicy
 CommunicationPolicyBase
+ComplexAnnotation
 ConcretePacket
 conf
 config
@@ -435,6 +437,7 @@ ratestuffer
 RawINetProtocol
 RawV
 rdynamic
+ReadInfo
 refcount
 regex
 registerEvent