Packets: Restructure documentation
g0dil [Fri, 20 Jun 2008 14:27:37 +0000 (14:27 +0000)]
senfscons: Speed up non-documentation builds (doesn't help much)
Socket/Protocols: Add documentation for sockaddr_cast

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@881 270642c3-0616-0410-b53a-bc976706d245

33 files changed:
Console/Mainpage.dox
Console/Node.hh
Doxyfile
Examples/Sniffer/Doxyfile
Glossary.dox
HowTos/Doxyfile
HowTos/NewPacket/Doxyfile
HowTos/NewPacket/Mainpage.dox
Packets/DefaultBundle/Doxyfile [deleted file]
Packets/DefaultBundle/IPv4Packet.cc
Packets/DefaultBundle/IPv4Packet.hh
Packets/DefaultBundle/IPv6Packet.hh
Packets/DefaultBundle/Mainpage.dox
Packets/DefaultBundle/SConscript
Packets/Doxyfile
Packets/ListParser.hh
Packets/MPEGDVBBundle/DTCPPacket.cc
Packets/MPEGDVBBundle/DTCPPacket.hh
Packets/MPEGDVBBundle/DTCPPacket.test.cc [new file with mode: 0644]
Packets/MPEGDVBBundle/Doxyfile [deleted file]
Packets/MPEGDVBBundle/MPEGDVBBundle.dox
Packets/MPEGDVBBundle/SConscript
Packets/Mainpage.dox
Packets/PacketParser.hh
Packets/ParseHelpers.ih
Packets/SConscript
Packets/VariantParser.hh
Packets/VectorParser.hh
Socket/Mainpage.dox
Socket/Protocols/BSDSocketAddress.hh
Utils/auto_unit_test.hh
doclib/Doxyfile.global
senfscons/SENFSCons.py

index 72ed0de..07c55d4 100644 (file)
     \see \ref console_testserver for a complete example application
 
 
-    \section intro_usage Access: Configuration files, Network console, ...
+    \section intro_usage Using the Console: Configuration files, Network console, ...
 
     There are several ways to access the node tree:
     \li By parsing configuration files
     \see \ref node_tree
 
 
-    \section intro_commands Registering console/config commands
+    \section intro_commands Implementing console/config commands
 
     The console/config language does not define, how arguments are passed to the commands, it just
     tokenizes the input and passes the tokens to the commands which then handle the
     \code
     // Create a console/config aware object and place it into the node tree
     FooObject foo;
-    senf::console::add("foo", foo.dir);
+    senf::console::root().add("foo", foo.dir);
 
     // Open configuration file
     senf::console::ConfigFile cf ("/etc/myserver.conf");
index 939113b..e284998 100644 (file)
     
     \li senf::console::DirectoryNode provides internal nodes with an arbitrary number of children
     \li senf::console::CommandNode describes a command entry in the tree
+    \li senf::console::LinkNode is a link to another node. It works much like a symlink on POSIX
+        systems.
 
     senf::console::CommandNode is the base-class of all command nodes of which there are several,
     depending on the type of command.
     \li A senf::console::CommandNode is normally added to the tree by directly adding a callback
         using one of the overloaded senf::console::DirectoryNode::add() members. See \ref
         console_commands.
+    \li A senf::console::LinkNode is created by senf::console::DirectoryNode::link()
 
     When directly adding a node callback, the type of node added depends on the type of
     callback. The callback types which can be added are listed at \ref console_callbacks.
index b556d23..2183692 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -11,7 +11,6 @@ TAGFILES = \
     "$(TOPDIR)/PPI/doc/PPI.tag" \
     "$(TOPDIR)/Scheduler/doc/Scheduler.tag" \
     "$(TOPDIR)/Packets/doc/Packets.tag" \
-    "$(TOPDIR)/Packets/DefaultBundle/doc/DefaultBundle.tag" \
     "$(TOPDIR)/Socket/doc/Socket.tag" \
     "$(TOPDIR)/Utils/doc/Utils.tag" \
     "$(TOPDIR)/senfscons/doc/senfscons.tag"
index b091ca8..c0880ed 100644 (file)
@@ -6,7 +6,6 @@ EXAMPLE_PATH = .
 TAGFILES = \
     "$(TOPDIR)/Scheduler/doc/Scheduler.tag" \
     "$(TOPDIR)/Packets/doc/Packets.tag" \
-    "$(TOPDIR)/Packets/DefaultBundle/doc/DefaultBundle.tag" \
     "$(TOPDIR)/Socket/doc/Socket.tag" \
     "$(TOPDIR)/Utils/doc/Utils.tag" \
     "$(TOPDIR)/doc/overview.tag"
index 668338f..40b7258 100644 (file)
 
     <table class="glossary">
 
+    <tr><td>collection parser</td> <td>libPackets</td> <td>A packet parser which allows to repeat
+    another parser or which uses some additional information to decide on the type or number of
+    sub-parsers.</td></tr>
+
     <tr><td>complete policy</td> <td>libSocket</td> <td>socket policy where each axis is specified
     completely</td></tr>
 
+    <tr><td>composite parser</td> <td>libPackets</td> <td>A packet parser providing access to named
+    sub-fields which are parsers themselves.</td></tr>
+
     <tr><td>incomplete policy</td> <td>libSocket</td> <td>socket policy, where at least one axis is
     not fully specified</td></tr>
 
+    <tr><td>packet interpreter</td> <td>libPackets</td> <td>Internal datastructure which represents
+    one protocol or header in the chain of interpreters representing a complete packet</td></tr>
+
+    <tr><td>packet parser</td> <td>libPackets</td> <td>lightweight class to convert between byte
+    representation and interpreted value. Derived from senf::PacketParserBase</td></tr>
+
     <tr><td>policy axis</td> <td>libSocket</td> <td>one aspect defined in the socket policy, typedef
     and member of the senf::SocketPolicy template</td></tr>
 
     senf::ProtocolClientSocketHandle::protocol()/senf::ProtocolServerSocketHandle::protocol()
     member</td></tr>
 
+    <tr><td>protocol parser</td> <td>libPackets</td> <td>A composite parser which defines a network
+    protocol.</td></tr>
+
     <tr><td>socket policy</td> <td>libSocket</td> <td>another name for 'policy'</td></tr>
 
+    <tr><td>value parser</td> <td>libPackets</td> <td>A packet parser which parses a simple value
+    like a number or network address.</td></tr>
+
     </table>
  */
 
@@ -67,7 +86,7 @@
 // c-file-style: "senf"
 // indent-tabs-mode: nil
 // ispell-local-dictionary: "american"
-// compile-command: "scons -u test"
+// compile-command: "scons -u doc"
 // mode: flyspell
 // mode: auto-fill
 // End:
index 16ea5d4..b742612 100644 (file)
@@ -1,3 +1,4 @@
 @INCLUDE = "$(TOPDIR)/doclib/Doxyfile.global"
 
+INPUT = .
 PROJECT_NAME = "HowTos"
index ea46e15..30a9e97 100644 (file)
@@ -1,5 +1,6 @@
 @INCLUDE = "$(TOPDIR)/doclib/Doxyfile.global"
 
+INPUT = .
 PROJECT_NAME = NewPacket
 EXAMPLE_PATH = .
 
@@ -7,6 +8,5 @@ TAGFILES = \
     "$(TOPDIR)/PPI/doc/PPI.tag" \
     "$(TOPDIR)/Scheduler/doc/Scheduler.tag" \
     "$(TOPDIR)/Packets/doc/Packets.tag" \
-    "$(TOPDIR)/Packets/DefaultBundle/doc/DefaultBundle.tag" \
     "$(TOPDIR)/Socket/doc/Socket.tag" \
     "$(TOPDIR)/Utils/doc/Utils.tag"
index 3894806..28403e0 100644 (file)
     definition to generate a more usable interface:
 
     \code
-    SENF_PARSER_PRIVATE_VARIANT ( optionalFields_, checksumPresent,
-                                      (novalue(disable_checksum, senf::VoidPacketParser))
-                                      (     id(checksum,         GREPacketParser_OptFields)) );
+    SENF_PARSER_VARIANT ( optionalFields_, checksumPresent,
+                                  (novalue(disable_checksum, senf::VoidPacketParser))
+                                  (     id(checksum,         GREPacketParser_OptFields)) );
     \endcode
 
-    Here, we changed to things:
-    \li We made the variant private
-    \li We added some optional information to the variants type list
+    Here, we added some optional information to the variants type list.
 
-    With this information, \ref SENF_PARSER_PRIVATE_VARIANT() will create some additional \e public
-    accessor members (those are public, only the variant itself is private). The members generated
-    work like:
+    With this information, \ref SENF_PARSER_VARIANT() will create some additional \e public accessor
+    members and will automatically make the variant itself private. The members generated work like:
     \code
     void disable_checksum() const { optionalFields_().init<0>; }
 
diff --git a/Packets/DefaultBundle/Doxyfile b/Packets/DefaultBundle/Doxyfile
deleted file mode 100644 (file)
index 56fde27..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-@INCLUDE = "$(TOPDIR)/doclib/Doxyfile.global"
-
-PROJECT_NAME= DefaultBundle
-GENERATE_TAGFILE = doc/DefaultBundle.tag
-INPUT = .
-ALPHABETICAL_INDEX = NO
-
-TAGFILES = \
-    "$(TOPDIR)/Packets/doc/Packets.tag" \
-    "$(TOPDIR)/Socket/doc/Socket.tag" \
-    "$(TOPDIR)/Utils/doc/Utils.tag" 
index 6dcc1db..2a9fa1a 100644 (file)
@@ -55,9 +55,6 @@ prefix_ boost::uint16_t senf::IPv4PacketParser::calcChecksum()
     validate(bytes(*this));
     IpChecksum summer;
     summer.feed( i(),                   i()+checksum_offset );
-    // Not needed since the number of 0-bytes is even
-    // summer.feed( 0u );
-    // summer.feed( 0u );
     summer.feed( i()+checksum_offset+2, i()+bytes(*this)    );
     return summer.sum();
 }
index b97d3ab..496c9b8 100644 (file)
@@ -50,8 +50,8 @@ namespace senf {
 
         value_type value() const { return value_type::from_data(i()); }
         void value(value_type const & v) { std::copy(v.begin(), v.end(), i()); }
-        operator value_type() { return value(); }
-        byte & operator[](size_type index) { return *boost::next(i(),index); }
+        operator value_type() const { return value(); }
+        byte & operator[](size_type index) const { return *boost::next(i(),index); }
         INet4AddressParser const & operator= (value_type const & other) 
             { value(other); return *this; }
     };
index 3ac278b..4006918 100644 (file)
@@ -51,8 +51,8 @@ namespace senf {
 
         value_type value() const { return value_type::from_data(i()); }
         void value(value_type const & v) { std::copy(v.begin(), v.end(), i()); }
-        operator value_type() { return value(); }
-        byte & operator[](size_type index) { return *boost::next(i(),index); }
+        operator value_type() const { return value(); }
+        byte & operator[](size_type index) const { return *boost::next(i(),index); }
         INet6AddressParser const & operator= (value_type const & other) 
             { value(other); return *this; }
     };
index 24f9c9d..6e336b9 100644 (file)
 // Free Software Foundation, Inc.,
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
-/** \mainpage The Default Bundle
-
-    The default bundle combines a set of basic low level protocols like Ethernet or IP. Find the
-    list of protocols implemented at \ref protocolbundle_default
- */
-
-/** \defgroup protocolbundle_default Protocols contained in the DefaultBundle
+/** \defgroup protocolbundle_default The DefaultBundle
 
     Each protocol consists of several objects
 
index 310d9c8..ca95750 100644 (file)
@@ -20,5 +20,3 @@ SENFSCons.Lib(env,
     no_includes = 1)
                  
 SConscript(glob.glob("*/SConscript"))
-
-SENFSCons.Doxygen(env)
index e6c18b9..cb3d08e 100644 (file)
@@ -3,6 +3,7 @@
 PROJECT_NAME = libPackets
 GENERATE_TAGFILE = doc/Packets.tag
 INPUT = .
+RECURSIVE = YES
 EXAMPLE_PATH = . DefaultBundle
 
 TAGFILES = \
index 18bc1d6..0382caa 100644 (file)
@@ -234,6 +234,10 @@ namespace senf {
         
         Here \c EltParser can be an arbitrary parser and need not have a fixed size.
 
+        \warning Realize, that the \a size field is controlled by the list parser. This field
+            should therefore be declared either read-only or private and must be changed only via
+            the list parser.
+
         Further additional tags are supported which modify the type of list created:
 
         <table class="senf fixedcolumn">
index 596f6fe..48cb334 100644 (file)
 // Free Software Foundation, Inc.,
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
+/** \file
+    \brief DTCPPacket non-inline non-template implementation */
 
+//#include "DTCPPacket.hh"
+//#include "DTCPPacket.ih"
+
+// Custom includes
 #include "DTCPPacket.hh"
 #include <boost/io/ios_state.hpp>
 #include <iomanip>
 
 #define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
 
-prefix_ void senf::DTCPPacketType::dump(packet p, std::ostream & os)
+prefix_ void senf::DTCPHelloPacketType::dump(packet p, std::ostream & os)
 {
+    static char const * COMMANDS[] = { "0", "JOIN", "LEAVE", "3", "4", "5", "6", "7",
+                                       "8", "9", "10", "11", "12", "13", "14", "15" };
     boost::io::ios_all_saver ias(os);
-    os << "DTCPPacket" << std::endl
-       << "  version              : " << p->version_number()              << std::endl
-       << "  command              : " << p->command()                     << std::endl
-       << "  interval             : " << p->interval()                    << std::endl
-       << "  sequence_number      : " << p->sequence_number()             << std::endl
-       << "  receive_capable_feed : " << p->receive_capable_feed()        << std::endl
-       << "  ip_version           : " << p->ip_version()                  << std::endl
-       << "  tunnel_protocol      : " << p->tunnel_protocol()             << std::endl
-       ;
-       
-        //TODO: print included IPs
+    os << "DTCP HELLO Packet:" << std::endl
+       << "  version              : " << p->versionNumber()                       << std::endl
+       << "  command              : " << COMMANDS[p->command()]                   << std::endl
+       << "  interval             : " << unsigned(p->interval())                  << std::endl
+       << "  sequence number      : " << p->sequenceNumber()                      << std::endl
+       << "  receive capable feed : " << (p->receiveCapableFeed() ? "yes" : "no") << std::endl
+       << "  ip version           : " << p->ipVersion()                           << std::endl
+       << "  tunnel protocol      : " << unsigned(p->tunnelProtocol())            << std::endl
+       << "  number of BDL ips    : " << unsigned(p->fbipCount())                 << std::endl
+       << "  feed BDL ips         : ";
+    
+    switch (p->ipVersion()) {
+    case 4 : {
+        typedef DTCPHelloPacket::Parser::v4fbipList_t FBIPList;
+        FBIPList::container fbips (p->v4fbipList());
+        FBIPList::container::iterator i (fbips.begin());
+        FBIPList::container::iterator const i_end (fbips.end());
+        for (; i != i_end; ++i)
+            os << "\n    " << *i;
+        break;
+    }
+    case 6 : {
+        typedef DTCPHelloPacket::Parser::v6fbipList_t FBIPList;
+        FBIPList::container fbips (p->v6fbipList());
+        FBIPList::container::iterator i (fbips.begin());
+        FBIPList::container::iterator const i_end (fbips.end());
+        for (; i != i_end; ++i)
+            os << "\n    " << *i;
+        break;
+    }
+    default:
+        os << "unknown ip version";
+    }
+    
+    os << std::endl;
 }
 
 #undef prefix_
+
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
index 5166c63..e619c11 100644 (file)
 // Free Software Foundation, Inc.,
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
+/** \file
+    \brief DTCPPacket public header */
 
-#ifndef DTCPPACKET_HH_
-#define DTCPPACKET_HH_
+#ifndef HH_DTCPPacket_
+#define HH_DTCPPacket_ 1
 
+// Custom includes
 #include "../../Packets/Packets.hh"
 #include "../../Packets/DefaultBundle/IPv4Packet.hh"
 #include "../../Packets/DefaultBundle/IPv6Packet.hh"
 
-#define DTCP_V4_MCADDRESS "224.0.0.36"
-#define DTCP_V6_MCADDRESS "FF02:0:0:0:0:0:1:4"
-#define DTCP_UDP_PORT 652
+//#include "DTCPPacket.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf {
-    
-    //first we have to define some helpers
-    struct DTCPIPv4AddressListParser : public PacketParserBase {
+
+#   define DTCP_V4_MCADDRESS "224.0.0.36"
+#   define DTCP_V6_MCADDRESS "FF02:0:0:0:0:0:1:4"
+#   define DTCP_UDP_PORT 652
+
+    struct DTCPIPv4AddressListParser : public PacketParserBase 
+    {
 #       include SENF_PARSER()        
-        SENF_PARSER_PRIVATE_FIELD ( num_of_fbips, UInt8Parser );
-        SENF_PARSER_PRIVATE_FIELD ( reserved ,    UInt8Parser );   //must be zero 
-        SENF_PARSER_VECTOR        ( fbiplist,     num_of_fbips, INet4AddressParser );
+
+        SENF_PARSER_PRIVATE_FIELD( fbipCount_, UInt8Parser );
+        SENF_PARSER_PRIVATE_FIELD( reserved_, UInt8Parser );
+
+        SENF_PARSER_VECTOR( fbips, fbipCount_, INet4AddressParser );
+
+        // Needed since we do NOT want to init fbipCount_ or reseverd_. And since
+        // INet4AddressParser::init() is a no-op, we can just as well disable init completely
+        SENF_PARSER_INIT() {}
 
         SENF_PARSER_FINALIZE(DTCPIPv4AddressListParser);
     };
         
-    struct DTCPIPv6AddressListParser : public PacketParserBase {
+    struct DTCPIPv6AddressListParser : public PacketParserBase 
+    {
 #       include SENF_PARSER()        
-        SENF_PARSER_PRIVATE_FIELD ( num_of_fbips, UInt8Parser );
-        SENF_PARSER_PRIVATE_FIELD ( reserved,     UInt8Parser );   //must be zero 
-        SENF_PARSER_VECTOR        ( fbiplist,     num_of_fbips, INet6AddressParser );
+
+        SENF_PARSER_PRIVATE_FIELD( fbipCount_, UInt8Parser );
+        SENF_PARSER_PRIVATE_FIELD( reserved_, UInt8Parser );
+
+        SENF_PARSER_VECTOR( fbips, fbipCount_, INet6AddressParser );
+
+        // Needed since we do NOT want to init fbipCount_ or reseverd_. And since
+        // INet4AddressParser::init() is a no-op, we can just as well disable init completely
+        SENF_PARSER_INIT() {}
 
         SENF_PARSER_FINALIZE(DTCPIPv6AddressListParser);
     };
 
-    /** \brief Parse a DTCP packet
+    /** \brief Parse a DTCP HELLO packet
 
         Parser implementing the DTCP packet according to RFC 3077
         
         \see DTCPPacketType
      */
-    struct DTCPPacketParser : public PacketParserBase
+    struct DTCPHelloPacketParser : public PacketParserBase
     {
 #       include SENF_PARSER()
 
-        SENF_PARSER_BITFIELD         ( version_number,       4, unsigned );  // =1 according to rfc3077
-        SENF_PARSER_BITFIELD         ( command,              4, unsigned );  // 1=JOIN 2=LEAVE
-        SENF_PARSER_FIELD            ( interval,             UInt8Parser );  // 5 according to rfc3077
-        SENF_PARSER_FIELD            ( sequence_number,      UInt16Parser );
-        SENF_PARSER_PRIVATE_BITFIELD ( reserved,             3, unsigned );
-        SENF_PARSER_BITFIELD         ( receive_capable_feed, 1, bool );      // 0=send only, 1=receive_capable_feed
-        SENF_PARSER_BITFIELD_RO      ( ip_version,           4, unsigned );  // 4=IPv4, 6=IPv6
-        SENF_PARSER_FIELD    ( tunnel_protocol,      UInt8Parser ); 
-        /* Please consider the following comments on the implementation given in this class: 
-         * 1. you could think of simply using SENF_PARSER_PRIVATE_VARIANT and List / Vectorparser like this:
-         * SENF_PARSER_PRIVATE_VARIANT  ( fbiplist,             ip_version,
-         *                                                       (senf::VoidPacketParser) //ip_version=0
-         *                                                       (senf::VoidPacketParser) //1
-         *                                                       (senf::VoidPacketParser) //2
-         *                                                       (senf::VoidPacketParser) //3
-         *                                                       (senf::ListBParser< IPv4Packet, num_of_fbips>) //4 
-         *                                                       (senf::VoidPacketParser) //5
-         *                                                       (senf::ListBParser< IPv6Packet, num_of_fbips>) ); //6
-         * This can't work for two reasons: 
-         *      -SENF_PARSER_PRIVATE_VARIANT only accepts 6 templates in types but you have to start from 0.
-         *      -you NEVER can use templated Parsers in these macros since the macro-preprocessor won't recognize the <> brackets and will
-         *      interpret the ","
-         * 
-         * The first problem is solved by using key()
-         * The second problem is solved by introducing Helper-Parser which cover both the list and the number field. By that no 
-         *      templates have to be used. 
-         */
-
-        SENF_PARSER_VARIANT( fbiplist, ip_version,
-                                        ( ids(getIpv4AddressList, na, setIpVersion4, 
-                                      key(4, senf::DTCPIPv4AddressListParser)) )    //IPv4 
-                                ( ids(getIpv6AddressList, na, setIpVersion6,
-                                      key(6, senf::DTCPIPv6AddressListParser)) ) ); //IPv6
+        SENF_PARSER_BITFIELD         ( versionNumber,        4, unsigned );  // must be 1
+        SENF_PARSER_BITFIELD         ( command,              4, unsigned );
+
+       enum Command { JOIN=1, LEAVE=2 };
+
+        SENF_PARSER_FIELD            ( interval,             UInt8Parser );  // should be 5
+        SENF_PARSER_FIELD            ( sequenceNumber,       UInt16Parser );
+
+        SENF_PARSER_PRIVATE_BITFIELD ( reserved0_,           3, unsigned );
+        SENF_PARSER_BITFIELD         ( receiveCapableFeed,   1, bool );
+        SENF_PARSER_BITFIELD_RO      ( ipVersion,            4, unsigned );  // 4=IPv4, 6=IPv6
+
+        SENF_PARSER_FIELD            ( tunnelProtocol,       UInt8Parser ); 
+        SENF_PARSER_FIELD_RO         ( fbipCount,            UInt8Parser );
+        SENF_PARSER_PRIVATE_FIELD    ( reserved1_,           UInt8Parser );  //must be zero 
+
+        // Go back to fbipCount so the variant has access to that field
+        SENF_PARSER_GOTO( fbipCount );
+
+        SENF_PARSER_VARIANT          ( fbipList_,            ipVersion,
+                                          ( ids(na, has_v4fbipList, init_v4fbipList,
+                                                 key(4, DTCPIPv4AddressListParser)) ) 
+                                          ( ids(na, has_v6fbipList, init_v6fbipList,
+                                                 key(6, DTCPIPv6AddressListParser)) ) );
+
+        // We define the two variant accessors ourselves so we can directly return the vector and
+        // not the collection parser which contains the vector ...
+
+        typedef DTCPIPv4AddressListParser::fbips_t v4fbipList_t;
+        v4fbipList_t v4fbipList() { return fbipList_().get<0>().fbips(); }
+
+        typedef DTCPIPv6AddressListParser::fbips_t v6fbipList_t;
+        v6fbipList_t v6fbipList() { return fbipList_().get<1>().fbips(); }
                                                                  
-        SENF_PARSER_FINALIZE(DTCPPacketParser);
+        SENF_PARSER_FINALIZE(DTCPHelloPacketParser);
     };
     
-    /** \brief DTCP packet
+    /** \brief DTCP HELLO packet
         
         \par Packet type (typedef):
-            \ref DTCPPacket
+            \ref DTCPHelloPacket
 
         \par Fields:
-            \ref DTCPPacketParser
+            \ref DTCPHelloPacketParser
 
         \ingroup protocolbundle_mpegdvb
      */
-    struct DTCPPacketType
+    struct DTCPHelloPacketType
         : public PacketTypeBase,
-          public PacketTypeMixin<DTCPPacketType>
+          public PacketTypeMixin<DTCPHelloPacketType>
     {
-        typedef PacketTypeMixin<DTCPPacketType> mixin;
-        typedef ConcretePacket<DTCPPacketType> packet;
-        typedef DTCPPacketParser parser;
+        typedef PacketTypeMixin<DTCPHelloPacketType> mixin;
+        typedef ConcretePacket<DTCPHelloPacketType> packet;
+        typedef DTCPHelloPacketParser parser;
     
         using mixin::nextPacketRange;
         using mixin::init;
@@ -126,7 +145,22 @@ namespace senf {
     };
     
     /** \brief DTCP packet typedef */
-    typedef DTCPPacketType::packet DTCPPacket;
+    typedef DTCPHelloPacketType::packet DTCPHelloPacket;
 }
 
-#endif /*DTCPPACKET_HH_*/
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "DTCPPacket.cci"
+//#include "DTCPPacket.ct"
+//#include "DTCPPacket.cti"
+#endif
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Packets/MPEGDVBBundle/DTCPPacket.test.cc b/Packets/MPEGDVBBundle/DTCPPacket.test.cc
new file mode 100644 (file)
index 0000000..9f71db8
--- /dev/null
@@ -0,0 +1,115 @@
+// $Id$
+//
+// Copyright (C) 2008 
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
+//     Stefan Bund <g0dil@berlios.de>
+//
+// This program 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 2 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, write to the
+// Free Software Foundation, Inc.,
+// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+/** \file
+    \brief DTCPPacket.test unit tests */
+
+//#include "DTCPPacket.test.hh"
+//#include "DTCPPacket.test.ih"
+
+// Custom includes
+#include "DTCPPacket.hh"
+
+#include "../../Utils/auto_unit_test.hh"
+#include <boost/test/test_tools.hpp>
+
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+BOOST_AUTO_UNIT_TEST(dtcpPacket)
+{
+    unsigned char data[] = { 0x11,                 // versionNumber = 1, command = JOIN
+                             5,                    // interval
+                             0x0A, 0x0B,           // sequence number
+                             0x14,                 // receiveCapable = true, ipVersion = 4
+                             23,                   // tunnelProtocol
+                             2,                    // fbipCount
+                             0x00,
+                             101, 102, 103, 104,   // fbip1
+                             201, 202, 203, 204 }; // fbip2
+
+    senf::DTCPHelloPacket hello (senf::DTCPHelloPacket::create(
+                                     boost::make_iterator_range(data, data+sizeof(data))));
+
+    BOOST_CHECK_EQUAL_COLLECTIONS( data, data+sizeof(data),
+                                   hello.data().begin(), hello.data().end() );
+
+    BOOST_CHECK_EQUAL( senf::bytes(hello.parser()), 16u );
+
+    BOOST_CHECK_EQUAL( hello->versionNumber(), 1u );
+    BOOST_CHECK_EQUAL( hello->command(), unsigned(senf::DTCPHelloPacket::Parser::JOIN) );
+    BOOST_CHECK_EQUAL( hello->interval(), 5u );
+    BOOST_CHECK_EQUAL( hello->sequenceNumber(), 0x0A0Bu );
+    BOOST_CHECK_EQUAL( hello->receiveCapableFeed(), true );
+    BOOST_CHECK_EQUAL( hello->ipVersion(), 4u );
+    BOOST_CHECK_EQUAL( hello->tunnelProtocol(), 23u );
+    BOOST_CHECK_EQUAL( hello->fbipCount(), 2u );
+    BOOST_CHECK( hello->has_v4fbipList() );
+    BOOST_CHECK_EQUAL( boost::lexical_cast<std::string>(hello->v4fbipList()[0]), "101.102.103.104" );
+    BOOST_CHECK_EQUAL( boost::lexical_cast<std::string>(hello->v4fbipList()[1]), "201.202.203.204" );
+
+    std::stringstream ss;
+    hello.dump(ss);
+    BOOST_CHECK_EQUAL( ss.str(), 
+                       "DTCP HELLO Packet:\n"
+                       "  version              : 1\n"
+                       "  command              : JOIN\n"
+                       "  interval             : 5\n"
+                       "  sequence number      : 2571\n"
+                       "  receive capable feed : yes\n"
+                       "  ip version           : 4\n"
+                       "  tunnel protocol      : 23\n"
+                       "  number of BDL ips    : 2\n"
+                       "  feed BDL ips         : \n"
+                       "    101.102.103.104\n"
+                       "    201.202.203.204\n" );
+
+    senf::DTCPHelloPacket hello2 (senf::DTCPHelloPacket::create());
+
+    SENF_CHECK_NO_THROW( hello2->versionNumber() = 1u );
+    SENF_CHECK_NO_THROW( hello2->command() = senf::DTCPHelloPacket::Parser::JOIN );
+    SENF_CHECK_NO_THROW( hello2->interval() = 5u );
+    SENF_CHECK_NO_THROW( hello2->sequenceNumber() = 0x0A0B );
+    SENF_CHECK_NO_THROW( hello2->receiveCapableFeed() = true );
+    SENF_CHECK_NO_THROW( hello2->tunnelProtocol() = 23u );
+    SENF_CHECK_NO_THROW( hello2->init_v4fbipList() );
+    SENF_CHECK_NO_THROW( hello2->v4fbipList().push_back( senf::INet4Address(0x65666768u) ) );
+    SENF_CHECK_NO_THROW( hello2->v4fbipList().push_back( senf::INet4Address(0xC9CACBCCu) ) );
+
+    BOOST_CHECK_EQUAL( senf::bytes(hello2.parser()), 16u );
+    BOOST_CHECK_EQUAL_COLLECTIONS( data, data+sizeof(data),
+                                   hello2.data().begin(), hello2.data().end() );
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+
+\f
+// Local Variables:
+// mode: c++
+// fill-column: 100
+// comment-column: 40
+// c-file-style: "senf"
+// indent-tabs-mode: nil
+// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// End:
diff --git a/Packets/MPEGDVBBundle/Doxyfile b/Packets/MPEGDVBBundle/Doxyfile
deleted file mode 100644 (file)
index 02bc421..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-@INCLUDE = "$(TOPDIR)/doclib/Doxyfile.global"
-
-PROJECT_NAME = MPEGDVBBundle
-GENERATE_TAGFILE = doc/MPEGDVBBundle.tag
-INPUT = .
-ALPHABETICAL_INDEX = NO
-
-TAGFILES = \
-    "$(TOPDIR)/Packets/doc/Packets.tag" \
-    "$(TOPDIR)/Packets/DefaultBundle/doc/DefaultBundle.tag" \
-    "$(TOPDIR)/Socket/doc/Socket.tag" \
-    "$(TOPDIR)/Utils/doc/Utils.tag"
-
index 4ac7950..5f02f49 100644 (file)
 // Free Software Foundation, Inc.,
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
-/** \mainpage The MPEG/DVB Bundle
-
-    \ref protocolbundle_mpegdvb
- */
-
-/** \defgroup protocolbundle_mpegdvb Protocols of the MPEG/DVB bundle
+/** \defgroup protocolbundle_mpegdvb The MPEG/DVB bundle
 
     Each protocol consists of several objects
 
index c219242..8bb2942 100644 (file)
@@ -18,7 +18,3 @@ SENFSCons.Lib(env,
     library = 'Packets_MPEGDVBBundle', 
     sources = sources[0],
     no_includes = 1)
-
-SENFSCons.Doxygen(env, extra_sources = [
-    env.Dia2Png("TLV.dia")
-])
index 889aa5f..9eaad45 100644 (file)
 
 /** \mainpage The SENF Packet Library
 
-    \section arch Overall Architecture
+    The SENF Packet library provides facilities to analyze, manipulate and create structured packet
+    oriented data (e.g. network packets).
+
+    \autotoc
+
+    
+    \section packet_intro_arch Overall Architecture
 
     The Packet library consists of several components:
     
     All these components work together to provide a hopefully simple and intuitive interface to
     packet parsing and creation.
 
-    \section intro Introduction
+    \see \ref packet_arch
+
+
+    \section packet_intro_usage Using the packet library
+
+    This chapter discusses the usage of the packet library from a high level view. 
+
+    \see \ref packet_usage 
+
+    
+    \section packet_intro_parser Parsing packet data
+
+    This chapter goes into more detail discussing the usage of packet parsers. 
+    
+    \li categorizing packet parsers
+    \li reading and writing values
+    \li using complex parsers
+
+    \see \ref packetparser
+
+    
+    \section protocolbundles Supported packet types (protocols)
+
+    Each protocol bundle provides a collection of related concrete packet classes for a group of
+    related protocols:
+
+    \li \ref protocolbundle_default : Some basic default protocols: Ethernet, Ip, TCP, UDP
+    \li \ref protocolbundle_mpegdvb : 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).
+
+    
+    \section packet_intro_new Defining new packet types
+
+    The packet library provides the framework which allows to define arbitrary packet types. There
+    is quite some information needed to completely specify a specific type of paceket.
+
+    \see \ref packet_new
+ */
+
+/** \page packet_arch Overall Packet library Architecture
+
+    The packet library handles network packets of a large number of protocols. We work with a packet
+    on three levels
+
+    \autotoc
+
+    
+    \section packet_arch_handle The Packet handle
+
+    Whenever we are using a Packet, we are talking about a senf::Packet (or a
+    senf::ConcretePacket). This class is a \e handle referencing an internally managed packet data
+    structure. So even though we pass senf::Packet instances around by value, they work like
+    references. The packet library automatically manages all required memory resources using
+    reference counting. 
+
+    Different Packet handles may really internally share one Packet data structure if they both
+    point to the same packet.
+
+   
+    \section packet_arch_data The Packet as a 'bunch of bytes'
+
+    From the outside, a packet is just a bunch of bytes just as it is read from (or will be
+    written to) the wire. At this low-level view, we can access the data in it's raw form but
+    have no further information about what kind of packet we have.
+
+    The packet library provides a consistent container interface for this representation.
+
+    \code
+    Packet p = ...;
+
+    // Change first byte of packet to 0
+    p.data()[0] = 1u; 
+
+    // Copy packet data into a vector
+    std::vector<char> data (p.data().size());
+    std::copy(p.data().begin(), p.data().end(), data.begin());
+    \endcode
+
+    This type of access is primarily needed when reading or writing packets (e.g. to/from the
+    network).
+
+    \see senf::Packet::data() \n
+        senf::PacketData
+
+    
+    \section packet_arch_chain The Interpreter Chain
+
+    On the next level, the packet is divided into a nested list of sub-packets (or headers) called
+    interpreters. Each senf::Packet handle internally points to an interpreter or header. This
+    allows us to access one and the same packet in different ways. 
+
+    Consider an Ethernet Packet with an IP payload holding a UDP packet. We may reference either the
+    Ethernet packet as a whole or we may reference the IP or UDP interpreters (sub-packets or
+    headers). All handles really refer to the \e same data structure but provide access to a
+    different (sub-)range of the data in the packet.
+
+    We can navigate around this chained structure using appropriate members:
+
+    \code
+    // eth, ip and udp all reference the same internal packet data albeit at different data ranges
+    Packet eth = ...;
+    Packet ip = eth.next();
+    Packet udp = ip.next();
+
+    eth.next() == ip                   // true
+    eth.next().is<IPv4Packet>()        // true
+    eth.next().next() == udp           // true
+    eth.next().is<UDPPacket>()         // false
+    eth.find<UDPPacket>() == udp       // true
+
+    udp.find<EthernetPacket>()         // throws InvalidPacketChainException
+    udp.find<EthernetPacket>(senf::nothrow) // An in-valid() senf::Packet which tests as 'false'
+    udp.find<UDPPacket> == udp         // true
+    udp.first<IPv4Packet>()            // throws InvalidPacketChainException
+
+    udp.prev() == ip                   // true
+    udp.prev<EthernetPacket>()         // throws Inv
+    \endcode
+    
+    \see \ref packet_module
+
+
+    \section packet_arch_parser Parsing specific Protocols
 
-    Whenever using the library, you will probably need to \c \#include it's header:
+    On the next level, the packet library allows us to parse the individual protocols. This gives us
+    access to the protocol specific data members of a packet and allows us to access or manipulate a
+    packet in a protocol specific way.
+
+    To access this information, we need to use a protocol specific handle, the senf::ConcretePacket
+    which takes as a template argument the specific type of packet to be interpreted. This allows us
+    to easily interpret or create packets. Here an example on how to create a new Etheret / IP / UDP
+    / Payload packet interpreter chain:
 
     \code
-    #include "Packets/Packets.hh"
+    // EthernetPacket, IPv4Packet, UDPPacket and DataPacket are typedefs for corresponding
+    // ConcretePacket instantiations
+    senf::EthernetPacket eth      (senf::EthernetPacket::create());
+    senf::IPv4Packet     ip       (senf::IPv4Packet    ::createAfter(eth));
+    senf::UDPPacket      udp      (senf::UDPPacket     ::createAfter(ip));
+    senf::DataPacket     payload  (senf::DataPacket    ::createAfter(udp, 
+                                                                     std::string("Hello, world!")));
+
+    udp->source()      = 2000u;
+    udp->destination() = 2001u;
+    ip->ttl()          = 255u;
+    ip->source()       = senf::INet4Address::from_string("192.168.0.1");
+    ip->destination()  = senf::INet4Address::from_string("192.168.0.2");
+    eth->source()      = senf::MACAddress::from_string("00:11:22:33:44:55");
+    eth->destination() = senf::MACAddress::from_string("00:11:22:33:44:66");
+    
+    eth.finalize();
     \endcode
 
-    \warning Never include any other Packets library header directly, always include \c
-    Packets/Packets.hh.
+    Again, realize, that \a eth, \a ip, \a udp and \a payload share the same internal packet
+    data structure (the respective \c data() members all provide access to the same underlying
+    container however at different byte ranges): The complete packet can be accessed at
+    <tt>eth.data()</tt> whereas <tt>payload.data()</tt> only holds UDP payload (in this case the
+    string "Hello, world!").
+
+    \see \ref packetparser \n
+        \ref protocolbundles
+ */
+
+/** \page packet_usage Using the packet library
+
+    \autotoc
+
+    \section packet_usage_intro Includes
 
-    Additionally you will have to include the header files for the packet types you use, e.g. \c
-    Packets/DefaultBundle/EthernetPacket.hh etc.
+    To use the library, you need to include the appropriate header files. This will probably happen
+    automatically when including the specific protocol headers. If needed, you may explicitly use
+
+    \code
+    #include "Packets.hh"
+    \endcode
     
+    explicitly.
+
+    \warning Never include any other Packets library header directly, only include \c
+    Packets.hh or one (or several) protocol headers from the protocol bundles.
+
     Most every use of the packet library starts with some concrete packet typedef. Some fundamental
-    packet types are provided by \ref protocolbundle_default. Building on those packet types, this
-    example will build a complex packet: This will be an Ethernet packet containing an IPv4 UDP
-    packet. We begin by building the raw packet skeleton:
+    packet types are provided by \ref protocolbundle_default. 
+
+
+    \section packet_usage_create Creating a new packet
+
+    Building on those packet types, this example will build a complex packet: This will be an
+    Ethernet packet containing an IPv4 UDP packet. We begin by building the raw packet skeleton:
 
     \code
+    #include "Packets/DefaultBundle/EthernetPacket.hh"
+    #include "Packets/DefaultBundle/IPv4Packet.hh"
+    #include "Packets/DefaultBundle/UDPPacket.hh"
+
     senf::EthernetPacket eth      (senf::EthernetPacket::create());
     senf::IPv4Packet     ip       (senf::IPv4Packet    ::createAfter(eth));
     senf::UDPPacket      udp      (senf::UDPPacket     ::createAfter(ip));
         structure. This data structure will be freed when the last reference to it goes out of
         scope.
 
-    The packet created above already has the correct payload however all protocol fields are
-    empty. We need to set those protocol fields:
+    The packet created above already has the correct UDP payload (The string "Hello, world!")
+    however all protocol fields are empty. We need to set those protocol fields:
 
     \code
     udp->source()      = 2000u;
 
     As seen above, packet fields are accessed using the <tt>-></tt> operator whereas other packet
     facilities (like \c finalize()) are directly accessed using the member operator. The field
-    values are simple set using appropriately named accessors. As a last step, the \c finalize()
+    values are simply set using appropriately named accessors. As a last step, the \c finalize()
     call will update all calculated fields (fields like next-protocol, header or payload length,
     checksums etc). Now the packet is ready. We may now send it out using a packet socket
 
     sock.write(eth.data());
     \endcode
 
-    The packet library also provides lot's of facilities to navigate the packet chain:
-
-    \code
-    eth.next() == ip;                   // true
-    eth.next().is<IPv4Packet>();        // true
-    eth.next().next() == udp;           // true
-    eth.next().is<UDPPacket>();         // false
-    eth.find<UDPPacket>() == udp;       // true
-
-    udp.find<EthernetPacket>();         // throws InvalidPacketChainException
-    udp.find<EthernetPacket>(senf::nothrow); // An in-valid() senf::Packet which tests as 'false'
-    udp.find<UDPPacket()> == udp;       // true
-    udp.first<IPv4Packet>();            // throws InvalidPacketChainException
-
-    udp.prev() == ip;                   // true
-    udp.prev<EthernetPacket>();         // throws Inv
-    \endcode
 
-    ... and so on. See the senf::Packet documentation for more. Using these members, the complete
-    chain of packet interpreters (as these sub-packets or headers are called) may be traversed from
-    any packet handle.
+    \section packet_usage_read Reading and parsing packets
 
-    These chain navigation functions are also used to parse a packet. Let's read an Ethernet packet
+    The chain navigation functions are also used to parse a packet. Let's read an Ethernet packet
     from a packet socket handle:
     
     \code
     packet). More generally, whenever a field cannot be accessed because it would be out of bounds
     of the data read, this exception is generated.
 
-    This is only a very short introduction to the library to give a feel for the implementation. For
-    a detailed discussion see the respective reference documentation.
+
+    \section packet_usage_container The raw data container
+    
+    Every packet is based internally on a raw data container holding the packet data. This container
+    is accessed via senf::Packet::data() member.
+    
+    This container is a random access container. It can be used like an ordinary STL container and
+    supports all the standard container members.
+
+    \code
+    Packet p = ...;
+
+    // Insert 5 0x01 bytes
+    p.data().insert(p.data().begin()+5, 5, 0x01);
+
+    // Insert data from another container
+    p.data().insert(p.data().end(), other.begin(), other.end());
+
+    // Erase a single byte
+    p.data().erase(p.data().begin()+5);
+
+    // XOR byte 5 with 0xAA
+    p.data()[5] ^= 0xAA;
+    \endcode
+
+    A packet consists of a list of interpreters (packet headers or protocols) which all reference
+    the same data container at different byte ranges. Each packet consists of the protocol header \e
+    plus the packets payload. This means, that the data container ranges of successive packets from
+    a single interpreter chain are nested.
+
+    Example: The packet created above (the Ethernet-IP-UDP packet with payload "Hello, world!") has
+    4 Interpreters: Ethernet, IPv4, UDP and the UDP payload data. The nested data containers lead to
+    the following structure
+
+    \code
+    // The ethernet header has a size of 14 bytes
+    eth.data().begin() + 14 == ip.data().begin()
+    eth.data().end()        == ip.data().end()
+
+    // The IP header has a size of 20 bytes and therefore
+    ip.data().begin()  + 20 == udp.data().begin()
+    ip.data().end()         == udp.data().end()
+
+    // The UDP header has a size of 8 bytes and thus
+    udp.data().begin() +  8 == payload.data().begin()
+    udp.data().end()        == payload.data().end()
+    \endcode
+
+    This nesting will (and must) always hold: The data range of a subsequent packet will always be
+    within the range of it's preceding packet.
+
+    \warning It is forbidden to change the data of a subsequent packet interpreter from the
+        preceding packet even if the data container includes this data. If you do so, you may
+        corrupt the data structure (especially when changing it's size).
+
+    Every operation on a packet is considered to be \e within this packet and \e without and
+    following packet. When inserting or erasing data, the data ranges are all adjusted
+    accordingly. So the following are \e not the same even though \c eth.end(), \c ip.end() and \c
+    udp.end() are identical.
+
+    \code
+    eth.data().insert(eth.data().end(), 5, 0x01);
+    assert(    eth.data().end() == ip.data().end() + 5 
+            && ip.data().end()  == udp.data().end() );
+
+    // Or alternatively: (You could even use eth.data().end() here ... it's the same)
+    ip.data().insert(ip.data().end(), 5, 0x01);
+    assert(    eth.data().end() == ip.data().end()
+            && ip.data().end()  == udp.data().end() + 5 );
+    \endcode
+
+    \warning When accessing the packet data via the container interface, you may easily build
+        invalid packets since the packet will not be validated against it's protocol.
+
+
+    \section packet_usage_fields Protocol fields
+
+    When working with concrete protocols, the packet library provides direct access to all the
+    protocol information.
+
+    \code
+    udp->source()      = 2000u;
+    udp->destination() = 2001u;
+    ip->ttl()          = 255u;
+    ip->source()       = senf::INet4Address::from_string("192.168.0.1");
+    ip->destination()  = senf::INet4Address::from_string("192.168.0.2");
+    eth->source()      = senf::MACAddress::from_string("00:11:22:33:44:55");
+    eth->destination() = senf::MACAddress::from_string("00:11:22:33:44:66");
+    \endcode
+
+    The protocol field members above do \e not return references, they return parser instances.
+    Protocol fields are accessed via parsers. A parser is a very lightweight class which points into
+    the raw packet data and converts between raw data bytes and it's interpreted value: For example
+    a senf::UInt16Parser accesses 2 bytes (in network byte order) and converts them to or from a 16
+    bit integer. There are a few properties about parsers which need to be understood:
+
+    \li Parsers are created only temporarily when needed. They are created when accessing a protocol
+        field and are returned by value.
+
+    \li A parser never contains a value itself, it just references a packets data container.
+
+    \li Parsers can be built using other parsers and may have members which return further parsers.
+
+    The top-level interface to a packets protocol fields is provided by a protocol parser. This
+    protocol parser is a composite parser which has members to access the protocol fields (compare
+    with the example code above). Some protocol fields may be more complex than a simple value. In
+    this case, those accessors may return other composite parsers or collection parsers. Ultimately,
+    a value parser will be returned.
+
+    The simple value parsers which return plain values (integer numbers, network addresses etc) can
+    be used like those values and can also be assigned corresponding values. More complex parsers
+    don't allow simple assignment. However, they can always be copied from another parser <em>of the
+    same type</em> using the generalized parser assignment. This type of assignment also works for
+    simple parsers and is then identical to a normal assignment.
+
+    \code
+    // Copy the complete udp parser from udp packet 2 to packet 1
+    udp1.parser() << udp2.parser();
+    \endcode
+
+    Additionally, the parsers have a parser specific API which allows to manipulate or query the
+    value. 
+
+    This is a very abstract description of the parser structure. For a more concrete description, we
+    need to differentiate between the different parser types
+
+    \subsection packet_usage_fields_value Value parsers
+
+    We have already seen value parsers: These are the lowest level building blocks witch parse
+    numbers, addresses etc. They return some type of value and can be assigned such a value. More
+    formally, they have a \c value_type typedef member which gives the type of value they accept and
+    they have an overloaded \c value() member which is used to read or set the value. Some parsers
+    have additional functionality: The numeric parser for Example provide conversion and arithmetic
+    operators so they can be used like a numeric value.
+
+    If you have a value parser \c valueParser with type \c ValueParser, the following will always be
+    valid:
+    \code
+    // You can read the value and assign it to a variable of the corresponding value_type
+    ValueParser::value_type v (valueParser.value());
+
+    // You can assign that value to the parser
+    valueParser.value(v);
+
+    // The assignment can also be done using the generic parser assignment
+    valueParser << v;
+    \endcode
+
+
+    \subsection packet_usage_fields_composite Composite and protocol parsers
+
+    A composite parser is a parser which just combines several other parsers into a structure: For
+    example, the senf::EthernetPacketParser has members \c destination(), \c source() and \c
+    type_length(). Those members return parsers again (in this case value parsers) to access the
+    protocol fields.
+
+    Composite parsers can be nested; A composite parser may be returned by another composite
+    parser. The protocol parser is a composite parser which defines the field for a specific
+    protocol header like Ethernet.
+
+    \subsection packet_usage_fields_collection Collection parsers
+
+    Besides simple composites, the packet library has support for more complex collections. 
+
+    \li The senf::ArrayParser allows to repeat an arbitrary parser a fixed number of times.
+    \li senf::VectorParser and senf::ListParser are two different types of lists with variable
+        number of elements
+    \li The senf::VariantParser is a discriminated union: It will select one of several parsers
+        depending on the value of a discriminant.
+
+
+    \subsubsection packet_usage_collection_vector Vector and List Parsers
+
+    Remember, that a parser does \e not contain any data: It only points into the raw data
+    container. This is also true for the collection parsers. VectorParser and ListParser provide an
+    interface which looks like an STL container to access the elements.
+
+    We will use an MLDv2 Query as an example (see <a
+    href="http://tools.ietf.org/html/rfc3810#section-5">RFC 3810</a>).
+
+    \code
+    MLDv2QueryPacket mld = ...;
+
+    // Instantiate a collection wrapper for the source list
+    MLDv2QueryPacket::Parser::sources_t::container sources (mld->sources());
+
+    // Iterate over all the addresses in that list
+    for (MLDv2QueryPacket::Parser::sources_t::container::iterator i (sources.begin()); 
+         i != sources.end(); ++i)
+        std::cout << *i << std::endl;
+    \endcode
+
+    Beside other fields, the MLDv2Query consists of a list of source addresses. The \c sources()
+    member returns a VectorParser for these addresses. The collection parsers can only be accessed
+    completely using a container wrapper. This is, what we do in above example.
+
+    The wrapper can also be used to manipulate that list. Here we copy a list of addresses from an
+    \c std::vector into the packet:
+
+    \code
+    std::vector<senf::INet6Address> addrs (...);
+
+    sources.resize(addrs.size());
+    std::copy(addrs.begin(), addrs.end(), sources.begin())
+    \endcode
+
+    Collection parsers may also be nested. To access a nested collection parser, such a container
+    wrapper should be allocated for each level. An MLD Report (which is a composite parser) includes
+    a list of multicast address records called \c records(). Each record is again a composite which
+    contains a list of sources called \c sources():
+
+    \code
+    MLDv2ReportPacket report = ...;
+
+    // Instantiate a collection wrapper for the list of records:
+    MLDv2ReportPacket::Parser::records_t::container records (report->records());
+
+    // Iterate over the multicast address records
+    for (MLDv2ReportPacket::Parser::records_t::container::iterator i (records.begin());
+         i != records.end(); ++i) {
+        // Allocate a collection wrapper for the multicast address record
+        typedef MLDv2ReportPackte::Parser::records_t::value_type::sources_t Sources;
+        Sources::container sources (i->sources());
+        
+        // Iterate over the sources in this record
+        for (Sources::container::iterator i (sources.begin());
+             i != sources.end(); ++i)
+            std::cout << *i << std::endl;
+    }
+    \endcode
+
+    In this example we also see how to find the type of a parser or container wrapper.
+    \li Composite parsers have typedefs for each their fields with a \c _t postfix
+    \li The vector or list parsers have a \c value_type typedef which gives the type of the
+        element.
+
+    By traversing this hierarchical structure, the types of all the fields can be found.
+
+    The container wrapper is only temporary (even though it has a longer lifetime than a
+    parser). Any change made to the packet not via the collection wrapper has the potential to
+    invalidate the wrapper if it changes the packets size.
+
+    \see 
+        senf::VectorParser_Container Interface of the vector parser container wrapper \n
+        senf::ListParser_Container Interface of the list parser container wrapper
+    
+
+    \subsubsection packet_usage_collection_variant The Variant Parser
+
+    The senf::VariantParser is a discriminated union of parsers. It is also used for optional fields
+    (using senf::VoidPacketParser as one possible variant which is a parser parsing nothing).  A
+    senf::VariantParser is not really a collection in the strict sense: It only ever contains one
+    element, the \e type of which is determined by the discriminant.
+
+    For Example, we look at the DTCP HELLO Packet as defined in the UDLR Protocol (see <a
+    href="http://tools.ietf.org/html/rfc3077">RFC 3077</a>)
+
+    \code
+    DTCPHelloPacket hello (...);
+
+    if (hello->ipVersion() == 4) {
+        typedef DTCPHelloPacket::Parser::v4fbipList_t FBIPList;
+        FBIPList::container fbips (hello->v4fbipList());
+        for (FBIPList::container::iterator i (fbips.begin()); i != fbips.end(); ++i)
+            std::cout << *i << std::endl;
+    }
+    else { // if (hello->ipVersion() == 6)
+        typedef DTCPHelloPacket::Parser::v6fbipList_t FBIPList;
+        FBIPList::container fbips (hello->v6fbipList());
+        for (FBIPList::container::iterator i (fbips.begin()); i != fbips.end(); ++i)
+            std::cout << *i << std::endl;
+    }
+    \endcode
+
+    This packet has a field \c ipVersion() which has a value of 4 or 6. Depending on the version,
+    the packet contains a list of IPv4 or IPv6 addresses. Only one of the fields \c v4fbipList() and
+    \c v6fbipList() is available at a time. Which one is decided by the value of \c
+    ipVersion(). Trying to access the wrong one will provoke undefined behavior.
+
+    Here we have used the variants discriminant (the \c ipVersion() field) to select, which field to
+    parse. More generically, every variant field should have a corresponding member to test for it's
+    existence:
+    \code
+    if (hello->has_v4fbipList()) {
+        ...
+    }
+    else { // if (hello->has_v6fbipList())
+        ...
+    }
+    \endcode
+
+    A variant can have more than 2 possible types and you can be sure, that exactly one type will be
+    accessible at any time.
+
+    It is not possible to change a variant by simply changing the discriminant:
+    \code
+    // INVALID CODE:
+    hello->ipVersion() = 6;
+    \endcode
+    Instead, for each variant field there is a special member which switches the variant to that
+    type. After switching the type, the field will be in it's initialized (that is mostly zero)
+    state.
+    \code
+    std::vector<senf::INet6Address> addrs (...);
+
+    // Initialize the IPv6 list
+    hello->init_v6fbipList();
+
+    // Copy values into that list
+    DTCPHelloPacket::Parser::v6fbipList_t::container fbips (hello->v6fbipList());
+    fbips.resize(addrs.size());
+    std::copy(addrs.begin(), addrs.end(), fbips.begin());
+    \endcode
+    
+    \note Here we have documented the default variant interface as it is preferred. It is possible
+        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.
  */
 
-/** \defgroup protocolbundles Protocol Bundles
+/** \page packet_new Defining new Packet types
 
-    Each protocol bundle provides a collection of related concrete packet classes for a group of
-    related protocols:
+    Each packet is specified by the following two components:
 
-    \li <a href="../../DefaultBundle/doc/html/index.html">DefaultBundle</a>: Some basic
-        default protocols: Ethernet, Ip, TCP, UDP
-    \li <a href="../../MPEGDVBBundle/doc/html/index.html">MPEGDVBBundle</a>: MPEG and DVB
-        protocols
+    \li A protocol parser which defines the protocol specific fields
+    \li A packet type class which is a policy class defining the packet
 
-    There are two ways to link with a bundle
+    \autotoc
+
+    \see <a href="../../../HowTos/NewPacket/doc/html/index.html">NewPacket HowTo</a>
+
+    \section packet_new_parser The protocol parser
+
+    The protocol parser is simply a composite parser. It defines all the protocol
+    fields. Additionally, the protocol parser may have additional members which will then be
+    accessible via the \c -> operator of the packet. Possibilities here are e.g. checksum
+    calculation and validation, packet validation as a whole and so on.
+
+    Defining a protocol parser is quite simple:
+    \code
+    struct EthernetPacketParser : public PacketParserBase
+    {
+    #   include SENF_FIXED_PARSER()
+
+        SENF_PARSER_FIELD( destination, MACAddressParser    );
+        SENF_PARSER_FIELD( source,      MACAddressParser    );
+        SENF_PARSER_FIELD( type_length, UInt16Parser );
+
+        SENF_PARSER_FINALIZE(EthernetPacketParser);
+    };
+    \endcode
     
-    \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).
+    There are a lot of other possibilities to define fields. See \ref packetparsermacros for a
+    detailed description of the macro language which is used to define composite parsers.
+
+    \see 
+        \ref packetparsermacros
+
+    \section packet_new_type The packet type policy class
+
+    This is a class which provides all the information needed to integrate the new packet type into
+    the packet library:
+
+    \li It provides the type of the protocol parser to use
+    \li It provides information on how the next protocol can be found and where the payload resides
+        in this packet
+    \li It provides methods to initialize a new packet and get information about the packet size
+
+    All this information is provided via static or typedef members. 
+
+    \code
+    struct EthernetPacketType
+        : public PacketTypeBase,
+          public PacketTypeMixin<EthernetPacketType, EtherTypes>
+    {
+        typedef PacketTypeMixin<EthernetPacketType, EtherTypes> mixin;
+        typedef ConcretePacket<EthernetPacketType> packet;
+        typedef EthernetPacketParser parser;
+
+        using mixin::nextPacketRange;
+        using mixin::initSize;
+        using mixin::init;
+
+        static factory_t nextPacketType(packet p);
+        static void dump(packet p, std::ostream & os);
+        static void finalize(packet p);
+    };
+
+    typedef EthernetPacketType::packet EthernetPacket;
+    \endcode
+
+    The definition of senf::EthernetPacket is quite straight forward. This template works for most
+    simple packet types.
+
+    \see \ref senf::PacletTypeMixin
+        \ref senf::PacketTypeBase
+        \ref senf::PacketRegistry
  */
 
 \f
index 9be6b29..59124e3 100644 (file)
     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).
+    \subsection parserimpl_packet Protocol parsers
+
+    Protocol parsers are composite parsers with relaxed requirements. Since a Protocol 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).
 
     <hr>
  */
index 02520f5..9422811 100644 (file)
         size_type BOOST_PP_CAT(name,_offset)() const {                                            \
             return field_offset_(static_cast<senf::mpl::rv<BOOST_PP_CAT(name,_index)-1>*>(0));    \
         }                                                                                         \
-        static size_type const BOOST_PP_CAT(name, _init_bytes) = SENF_MPL_SLOT_GET(init_bytes);
+        static size_type const BOOST_PP_CAT(name, _init_bytes) =                                  \
+            SENF_MPL_SLOT_GET(init_bytes);
 #
 # define SENF_PARSER_I_FIELD_OFS_fix(name, type, access)                                          \
-        static size_type const BOOST_PP_CAT(name, _offset) = SENF_MPL_SLOT_GET(offset);
+        static size_type const BOOST_PP_CAT(name, _offset) =                                      \
+            SENF_MPL_SLOT_GET(offset);
 #
 # ////////////////////////////////////////
 # // SENF_PARSER_I_ADVANCE_OFS_*
             return field_offset_(static_cast<senf::mpl::rv<BOOST_PP_CAT(name,_index)-1>*>(0))     \
                 - SENF_MPL_SLOT_GET(bitfield_size);                                               \
         }                                                                                         \
-        static size_type const BOOST_PP_CAT(name, _init_bytes) = SENF_MPL_SLOT_GET(init_bytes)    \
-            - SENF_MPL_SLOT_GET(bitfield_size);
+        static size_type const BOOST_PP_CAT(name, _init_bytes) =                                  \
+            SENF_MPL_SLOT_GET(init_bytes) - SENF_MPL_SLOT_GET(bitfield_size);
 #
 # define SENF_PARSER_I_BITFIELD_OFS_fix(name, type, access)                                       \
-        static size_type const BOOST_PP_CAT(name, _offset) = SENF_MPL_SLOT_GET(offset)            \
-            - SENF_MPL_SLOT_GET(bitfield_size);
+        static size_type const BOOST_PP_CAT(name, _offset) =                                      \
+            SENF_MPL_SLOT_GET(offset) - SENF_MPL_SLOT_GET(bitfield_size);
 #
 # ////////////////////////////////////////
 # // SENF_PARSER_I_BITFIELD_RESET
index 10c6a89..c3b6dc1 100644 (file)
@@ -14,7 +14,8 @@ SENFSCons.Lib(env,
               sources = SENFSCons.GlobSources(),
               LIBS = [ 'Utils' ])
 SENFSCons.Doxygen(env, extra_sources = [
-    env.Dia2Png("structure.dia")
+    env.Dia2Png("structure.dia"),
+    env.Dia2Png("MPEGDVBBundle/TLV.dia")
 ])
 
 SConscript(glob.glob("*/SConscript"))
index 8722e95..a76900e 100644 (file)
@@ -133,11 +133,11 @@ namespace senf {
         
             SENF_PARSER_PRIVATE_FIELD( type, senf::UInt8Parser );
             SENF_PARSER_VARIANT( content, type,
-                                    (novalue( disable, senf::VoidPacketParser ))
-                                    (     id( uint8,   senf::UInt8Parser      ))
-                                    (     id( uint16,  senf::UInt16Parser     ))
-                                    (     id( uint24,  senf::UInt24Parser     ))
-                                    (     id( uint32,  senf::UInt32Parser     )) );
+                                    (novalue( disable,      senf::VoidPacketParser ))
+                                    (     id( uint8value,   senf::UInt8Parser      ))
+                                    (     id( uint16value,  senf::UInt16Parser     ))
+                                    (     id( uint24value,  senf::UInt24Parser     ))
+                                    (     id( uint32value,  senf::UInt32Parser     )) );
 
             SENF_PARSER_FINALIZE(SomeParser);
         };
@@ -146,6 +146,10 @@ namespace senf {
         The variant \c content chooses one of the sub parsers depending on the \c type field. If \c
         type is 0, senf::VoidPacketParser is selected, if it is 1, senf::UInt8Parser and so on. 
 
+        \warning Realize, that the \a chooser field is controlled by the variant parser. This field
+            should therefore be declared either read-only or private and must be changed only via
+            the variant parser.
+
         The \a types parameter specifies the types of sub-objects supported by this variant
         parser. This parameter is a (Boost.Preprocessor style) sequence
         <pre>(\a type) (\a type) ...</pre>
index e9378a5..b1254db 100644 (file)
@@ -236,6 +236,10 @@ namespace senf {
         SENF_PARSER_VECTOR        ( vec,       vec_size_, senf::UInt32Parser );
         \endcode
 
+        \warning Realize, that the \a size field is controlled by the vector parser. This field
+            should therefore be declared either read-only or private and must be changed only via
+            the vector parser.
+
         Further additional tags are supported which modify the way, the \a size field is
         interpreted:
 
index 1776880..0a379c7 100644 (file)
@@ -366,4 +366,5 @@ namespace senf {
 // ispell-local-dictionary: "american"
 // mode: flyspell
 // mode: auto-fill
+// compile-command: "scons -u doc"
 // End:
index 61cb220..1e7d1e7 100644 (file)
@@ -50,6 +50,20 @@ namespace senf {
         It is \e not possible to create or store BSDSocketAddress instances: You must either store
         an address in one of the specifically typed subclasses or using GenericBSDSocketAddress.
 
+        A BSDSocketAddress or GenericBSDSocketAddress can be cast (like a downcast) to (the correct)
+        type specific cast using sockaddr_cast:
+
+        \code
+        void foo(senf::BSDSOcketAddress const & addr)
+        {
+            if (addr.family() == senf::INet4SocketAddress::addressFamily) {
+                senf::INet4SocketAddress i4addr (
+                    senf::sockaddr_cast<senf::INet4SocketAddress>(addr) );
+                ...
+            }
+        }
+        \endcode
+        
         All these classes provide a generic \c sockaddr API to interface with legacy \c sockaddr
         based code (e.g. the BSD socket API). In this base-class, this interface is read-only, the
         derived classes however provide a read-write interface.
index b2e60ae..402dd63 100644 (file)
@@ -90,7 +90,7 @@
  */
 #define SENF_CHECK_NO_THROW(expr)                                                                 \
     BOOST_CHECK_NO_THROW(                                                                         \
-        try { (void) expr ; }                                                                     \
+        try { expr ; }                                                                            \
         catch (std::exception & e) { std::cerr << e.what() << std::endl; throw; } )
 
 ///////////////////////////////hh.e////////////////////////////////////////
index bb26ef7..f589bbf 100644 (file)
@@ -517,7 +517,7 @@ WARN_FORMAT            = "$file:$line: $text"
 # directories like "/usr/src/myproject". Separate the files or directories 
 # with spaces.
 
-INPUT                  = .
+##INPUT                = .
 
 # This tag can be used to specify the character encoding of the source files 
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 
index 94b1b1c..c8ff57c 100644 (file)
@@ -25,6 +25,7 @@
 import os.path, glob
 import SCons.Options, SCons.Environment, SCons.Script.SConscript, SCons.Node.FS
 import SCons.Defaults, SCons.Action
+from SCons.Script import *
 
 ## \defgroup use Predefined Framework Configurators
 #
@@ -451,6 +452,8 @@ def InstallWithSources(env, targets, dir, sources, testSources = [], no_includes
 #
 # \ingroup target
 def Doxygen(env, doxyfile = "Doxyfile", extra_sources = []):
+    if not 'all' in BUILD_TARGETS and not 'doc' in BUILD_TARGETS and not 'all_docs' in BUILD_TARGETS:
+        return []
     # ARGHHH !!! without the [:] we are changing the target list
     #        ||| WITHIN THE DOXYGEN BUILDER
     docs = env.Doxygen(doxyfile)[:]