From: g0dil Date: Fri, 20 Jun 2008 14:27:37 +0000 (+0000) Subject: Packets: Restructure documentation X-Git-Url: http://g0dil.de/git?p=senf.git;a=commitdiff_plain;h=7baaacae27c02c86ceda5c7ee41d3172d1e23ffa Packets: Restructure documentation 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 --- diff --git a/Console/Mainpage.dox b/Console/Mainpage.dox index 72ed0de..07c55d4 100644 --- a/Console/Mainpage.dox +++ b/Console/Mainpage.dox @@ -118,7 +118,7 @@ \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 @@ -138,7 +138,7 @@ \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 @@ -366,7 +366,7 @@ \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"); diff --git a/Console/Node.hh b/Console/Node.hh index 939113b..e284998 100644 --- a/Console/Node.hh +++ b/Console/Node.hh @@ -100,6 +100,8 @@ \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. @@ -119,6 +121,7 @@ \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. diff --git a/Doxyfile b/Doxyfile index b556d23..2183692 100644 --- 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" diff --git a/Examples/Sniffer/Doxyfile b/Examples/Sniffer/Doxyfile index b091ca8..c0880ed 100644 --- a/Examples/Sniffer/Doxyfile +++ b/Examples/Sniffer/Doxyfile @@ -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" diff --git a/Glossary.dox b/Glossary.dox index 668338f..40b7258 100644 --- a/Glossary.dox +++ b/Glossary.dox @@ -24,12 +24,25 @@ + + + + + + + + @@ -54,8 +67,14 @@ senf::ProtocolClientSocketHandle::protocol()/senf::ProtocolServerSocketHandle::protocol() member + + + +
collection parser libPackets 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.
complete policy libSocket socket policy where each axis is specified completely
composite parser libPackets A packet parser providing access to named + sub-fields which are parsers themselves.
incomplete policy libSocket socket policy, where at least one axis is not fully specified
packet interpreter libPackets Internal datastructure which represents + one protocol or header in the chain of interpreters representing a complete packet
packet parser libPackets lightweight class to convert between byte + representation and interpreted value. Derived from senf::PacketParserBase
policy axis libSocket one aspect defined in the socket policy, typedef and member of the senf::SocketPolicy template
protocol parser libPackets A composite parser which defines a network + protocol.
socket policy libSocket another name for 'policy'
value parser libPackets A packet parser which parses a simple value + like a number or network address.
*/ @@ -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: diff --git a/HowTos/Doxyfile b/HowTos/Doxyfile index 16ea5d4..b742612 100644 --- a/HowTos/Doxyfile +++ b/HowTos/Doxyfile @@ -1,3 +1,4 @@ @INCLUDE = "$(TOPDIR)/doclib/Doxyfile.global" +INPUT = . PROJECT_NAME = "HowTos" diff --git a/HowTos/NewPacket/Doxyfile b/HowTos/NewPacket/Doxyfile index ea46e15..30a9e97 100644 --- a/HowTos/NewPacket/Doxyfile +++ b/HowTos/NewPacket/Doxyfile @@ -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" diff --git a/HowTos/NewPacket/Mainpage.dox b/HowTos/NewPacket/Mainpage.dox index 3894806..28403e0 100644 --- a/HowTos/NewPacket/Mainpage.dox +++ b/HowTos/NewPacket/Mainpage.dox @@ -276,18 +276,15 @@ 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 index 56fde27..0000000 --- a/Packets/DefaultBundle/Doxyfile +++ /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" diff --git a/Packets/DefaultBundle/IPv4Packet.cc b/Packets/DefaultBundle/IPv4Packet.cc index 6dcc1db..2a9fa1a 100644 --- a/Packets/DefaultBundle/IPv4Packet.cc +++ b/Packets/DefaultBundle/IPv4Packet.cc @@ -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(); } diff --git a/Packets/DefaultBundle/IPv4Packet.hh b/Packets/DefaultBundle/IPv4Packet.hh index b97d3ab..496c9b8 100644 --- a/Packets/DefaultBundle/IPv4Packet.hh +++ b/Packets/DefaultBundle/IPv4Packet.hh @@ -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; } }; diff --git a/Packets/DefaultBundle/IPv6Packet.hh b/Packets/DefaultBundle/IPv6Packet.hh index 3ac278b..4006918 100644 --- a/Packets/DefaultBundle/IPv6Packet.hh +++ b/Packets/DefaultBundle/IPv6Packet.hh @@ -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; } }; diff --git a/Packets/DefaultBundle/Mainpage.dox b/Packets/DefaultBundle/Mainpage.dox index 24f9c9d..6e336b9 100644 --- a/Packets/DefaultBundle/Mainpage.dox +++ b/Packets/DefaultBundle/Mainpage.dox @@ -20,13 +20,7 @@ // 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 diff --git a/Packets/DefaultBundle/SConscript b/Packets/DefaultBundle/SConscript index 310d9c8..ca95750 100644 --- a/Packets/DefaultBundle/SConscript +++ b/Packets/DefaultBundle/SConscript @@ -20,5 +20,3 @@ SENFSCons.Lib(env, no_includes = 1) SConscript(glob.glob("*/SConscript")) - -SENFSCons.Doxygen(env) diff --git a/Packets/Doxyfile b/Packets/Doxyfile index e6c18b9..cb3d08e 100644 --- a/Packets/Doxyfile +++ b/Packets/Doxyfile @@ -3,6 +3,7 @@ PROJECT_NAME = libPackets GENERATE_TAGFILE = doc/Packets.tag INPUT = . +RECURSIVE = YES EXAMPLE_PATH = . DefaultBundle TAGFILES = \ diff --git a/Packets/ListParser.hh b/Packets/ListParser.hh index 18bc1d6..0382caa 100644 --- a/Packets/ListParser.hh +++ b/Packets/ListParser.hh @@ -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: diff --git a/Packets/MPEGDVBBundle/DTCPPacket.cc b/Packets/MPEGDVBBundle/DTCPPacket.cc index 596f6fe..48cb334 100644 --- a/Packets/MPEGDVBBundle/DTCPPacket.cc +++ b/Packets/MPEGDVBBundle/DTCPPacket.cc @@ -20,27 +20,75 @@ // 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 #include #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_ + + +// 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.hh b/Packets/MPEGDVBBundle/DTCPPacket.hh index 5166c63..e619c11 100644 --- a/Packets/MPEGDVBBundle/DTCPPacket.hh +++ b/Packets/MPEGDVBBundle/DTCPPacket.hh @@ -20,103 +20,122 @@ // 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 + public PacketTypeMixin { - typedef PacketTypeMixin mixin; - typedef ConcretePacket packet; - typedef DTCPPacketParser parser; + typedef PacketTypeMixin mixin; + typedef ConcretePacket 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 + + +// 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 index 0000000..9f71db8 --- /dev/null +++ b/Packets/MPEGDVBBundle/DTCPPacket.test.cc @@ -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 +// +// 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 + +#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(hello->v4fbipList()[0]), "101.102.103.104" ); + BOOST_CHECK_EQUAL( boost::lexical_cast(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_ + + +// 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 index 02bc421..0000000 --- a/Packets/MPEGDVBBundle/Doxyfile +++ /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" - diff --git a/Packets/MPEGDVBBundle/MPEGDVBBundle.dox b/Packets/MPEGDVBBundle/MPEGDVBBundle.dox index 4ac7950..5f02f49 100644 --- a/Packets/MPEGDVBBundle/MPEGDVBBundle.dox +++ b/Packets/MPEGDVBBundle/MPEGDVBBundle.dox @@ -20,12 +20,7 @@ // 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 diff --git a/Packets/MPEGDVBBundle/SConscript b/Packets/MPEGDVBBundle/SConscript index c219242..8bb2942 100644 --- a/Packets/MPEGDVBBundle/SConscript +++ b/Packets/MPEGDVBBundle/SConscript @@ -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") -]) diff --git a/Packets/Mainpage.dox b/Packets/Mainpage.dox index 889aa5f..9eaad45 100644 --- a/Packets/Mainpage.dox +++ b/Packets/Mainpage.dox @@ -22,7 +22,13 @@ /** \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: @@ -36,26 +42,210 @@ 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 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() // true + eth.next().next() == udp // true + eth.next().is() // false + eth.find() == udp // true + + udp.find() // throws InvalidPacketChainException + udp.find(senf::nothrow) // An in-valid() senf::Packet which tests as 'false' + udp.find == udp // true + udp.first() // throws InvalidPacketChainException + + udp.prev() == ip // true + udp.prev() // 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 + eth.data() whereas payload.data() 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)); @@ -72,8 +262,8 @@ 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; @@ -89,7 +279,7 @@ As seen above, packet fields are accessed using the -> 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 @@ -98,29 +288,10 @@ 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(); // true - eth.next().next() == udp; // true - eth.next().is(); // false - eth.find() == udp; // true - - udp.find(); // throws InvalidPacketChainException - udp.find(senf::nothrow); // An in-valid() senf::Packet which tests as 'false' - udp.find == udp; // true - udp.first(); // throws InvalidPacketChainException - - udp.prev() == ip; // true - udp.prev(); // 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 @@ -150,29 +321,403 @@ 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 of the + same type 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 RFC 3810). + + \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 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 RFC 3077) + + \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 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 DefaultBundle: Some basic - default protocols: Ethernet, Ip, TCP, UDP - \li MPEGDVBBundle: 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 NewPacket HowTo + + \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 + { + typedef PacketTypeMixin mixin; + typedef ConcretePacket 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 */ diff --git a/Packets/PacketParser.hh b/Packets/PacketParser.hh index 9be6b29..59124e3 100644 --- a/Packets/PacketParser.hh +++ b/Packets/PacketParser.hh @@ -136,16 +136,16 @@ 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).
*/ diff --git a/Packets/ParseHelpers.ih b/Packets/ParseHelpers.ih index 02520f5..9422811 100644 --- a/Packets/ParseHelpers.ih +++ b/Packets/ParseHelpers.ih @@ -150,10 +150,12 @@ size_type BOOST_PP_CAT(name,_offset)() const { \ return field_offset_(static_cast*>(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_* @@ -287,12 +289,12 @@ return field_offset_(static_cast*>(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 diff --git a/Packets/SConscript b/Packets/SConscript index 10c6a89..c3b6dc1 100644 --- a/Packets/SConscript +++ b/Packets/SConscript @@ -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")) diff --git a/Packets/VariantParser.hh b/Packets/VariantParser.hh index 8722e95..a76900e 100644 --- a/Packets/VariantParser.hh +++ b/Packets/VariantParser.hh @@ -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
(\a type) (\a type) ...
diff --git a/Packets/VectorParser.hh b/Packets/VectorParser.hh index e9378a5..b1254db 100644 --- a/Packets/VectorParser.hh +++ b/Packets/VectorParser.hh @@ -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: diff --git a/Socket/Mainpage.dox b/Socket/Mainpage.dox index 1776880..0a379c7 100644 --- a/Socket/Mainpage.dox +++ b/Socket/Mainpage.dox @@ -366,4 +366,5 @@ namespace senf { // ispell-local-dictionary: "american" // mode: flyspell // mode: auto-fill +// compile-command: "scons -u doc" // End: diff --git a/Socket/Protocols/BSDSocketAddress.hh b/Socket/Protocols/BSDSocketAddress.hh index 61cb220..1e7d1e7 100644 --- a/Socket/Protocols/BSDSocketAddress.hh +++ b/Socket/Protocols/BSDSocketAddress.hh @@ -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(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. diff --git a/Utils/auto_unit_test.hh b/Utils/auto_unit_test.hh index b2e60ae..402dd63 100644 --- a/Utils/auto_unit_test.hh +++ b/Utils/auto_unit_test.hh @@ -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//////////////////////////////////////// diff --git a/doclib/Doxyfile.global b/doclib/Doxyfile.global index bb26ef7..f589bbf 100644 --- a/doclib/Doxyfile.global +++ b/doclib/Doxyfile.global @@ -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 diff --git a/senfscons/SENFSCons.py b/senfscons/SENFSCons.py index 94b1b1c..c8ff57c 100644 --- a/senfscons/SENFSCons.py +++ b/senfscons/SENFSCons.py @@ -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)[:]