diff --git a/Packets/ParseListS.hh b/Packets/ParseListS.hh index a480be6afeaf4a36c31f2f86d43fad904ecf8e23..87b708253adf3e88cf1982aebbff6e7c9a4a361b 100644 --- a/Packets/ParseListS.hh +++ b/Packets/ParseListS.hh @@ -20,6 +20,36 @@ // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/** \file + + \idea Add an optional state to the sentinel and an optional + transition function. See ParseListS.hh for more. + + We should write a baseclass for sentinels which has no \c check() + member, en empty \c next() member and \c void as the state + type. This simplifies writing simple sentinels. + + The parse_listS iterator will have to pass the state in addition + to the current list element to \c check(). The \c next() member + will be invoked to advance the iterator. It is passer the current + element and a (non-const) reference to the state which it may + update. The Parse_ListS constructor must take an arbitrary number + of additional arguments which are forwarded to the state + initialization. + + This structure makes it simple to optimize away the overhead if + the state type is void. If we would always instantiate the + sentinel, this will always take up space. + + Another possibility would be to always instantiate the sentinel + and make the baseclass mandatory. The baseclass would then hold + the current raw iterator. The iterator itself would ONLY include a + single sentinel instance .. I think, this is the best solution, + sentinel members then have intrinsic access to the + state. Arguments are forwarded from the list constructor to the + Sentinel constructor. + */ + #ifndef HH_ParseListS_ #define HH_ParseListS_ 1 diff --git a/Socket/ClientSocketHandle.hh b/Socket/ClientSocketHandle.hh index 1a120b763f0e1deadc5cbc850dd7dd050be8159d..a1f3b9243654b2eae18b8c40c60ee992be6ad263 100644 --- a/Socket/ClientSocketHandle.hh +++ b/Socket/ClientSocketHandle.hh @@ -31,8 +31,10 @@ ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { - - + + /// \addtogroup handle_group + /// @{ + template <class Policy> class ServerSocketHandle; /** \brief @@ -141,6 +143,7 @@ namespace senf { friend class senf::ServerSocketHandle<Policy>; }; + /// @} } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Socket/FileHandle.hh b/Socket/FileHandle.hh index d2c93b61c63bcfa04b94043b7c19a99cb286a397..5f82eaf103c5bb175999b8a842017dab3ef3b3a2 100644 --- a/Socket/FileHandle.hh +++ b/Socket/FileHandle.hh @@ -24,6 +24,46 @@ \brief senf::FileHandle public header */ +/** \defgroup handle_group The Handle Hierarchy + + \image html FhHierarchy.png + + The senf::FileHandle class is the base of a hierarchy of socket + handle classes (realized as templates). These classes provide an + interface to the complete socket API. While going down the + inheritance hierarchy, the interface will be more and more + complete. + + The most complete interface is provided by + senf::ProtocolClientSocketHandle and + senf::ProtocolServerSocketHandle. The template Arguments specifies + the Protocol class of the underlying socket type. These are the + \e only classes having public constructors and are therefore the + only classes, which may be created by the library user. You will + normally use these classes by naming a specific socket typedef + (e.g. senf::TCPv4ClientSocketHandle). + + However, to aid writing flexible and generic code, the socket + library provides the senf::ClientSocketHandle and + senf::ServerSocketHandle class templates. These templates + implement a family of closely related classes based on the + specification of the socket policy. This policy specification may + be \e incomplete (see below). Instances of + senf::ClientSocketHandle/senf::ServerSocketHandle can be assigned + and converted to different ClientSocketHandle/ServerSocketHandle + types as long as the policy specifications are compatible. + + \attention It is very important, to (almost) always pass the socket + handle <em>by value</em>. The socket handle is a very lightweight + class and designed to be used like an ordinary built-in type. This + is very important in combination with the policy interface. + + \note The FileHandle hierarchy below the SocketHandle template is + \e not meant to be user extensible. To add new socket types, you + should introduce new protocol and/or policy classes, the + SocketHandle classes should not be changed. + */ + #ifndef HH_FileHandle_ #define HH_FileHandle_ 1 @@ -36,7 +76,9 @@ #include "FileHandle.ih" namespace senf { - + + /// \addtogroup handle_group + /// @{ /** \brief Basic file handle wrapper @@ -151,8 +193,18 @@ namespace senf { FileBody::ptr body_; }; + /** \brief Adapt FileHandle to senf::Scheduler + \related senf::FileHandle + + \internal + + This function will be called by the Scheduler to retrieve the file descriptor of the + FileHandle. + */ int retrieve_filehandle(FileHandle handle); + /// @} + } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Socket/Mainpage.dox b/Socket/Mainpage.dox index 2721d3696778685f2e6d12b66b802baf87efeabb..a7279fcd8bf117a43d76dafc1649df135052b048 100644 --- a/Socket/Mainpage.dox +++ b/Socket/Mainpage.dox @@ -4,12 +4,13 @@ abstraction of the BSD socket API. The abstraction is based on several concepts: - \li The basic visible interface is a handle object - (senf::FileHandle and it's derived classes) - \li The socket interface relies on a policy framework to configure - it's functionality + \li The basic visible interface is a \link handle_group handle + object \endlink + \li The socket interface relies on a \link policy_group policy + framework \endlink to configure it's functionality \li The rest of the socket API is accessible using a classic - inheritance hierarchy of protocol classes + inheritance hierarchy of \link protocol_group protocol classes + \endlink The handle/body architecture provides automatic reference counted management of socket instances, the policy framework provides @@ -19,136 +20,65 @@ dependent options. \see \ref usage \n - \ref extend \n + \ref handle_group \n + \ref policy_group \n + \ref protocol_group \n + \ref extend \n \ref implementation */ /** \page usage Using the Socket Library - \section socket_handle The socket handle - Whenever you use the socket library, what you will be dealing with are senf::FileHandle derived instances. The socket library relies on reference counting to automatically manage the underlying socket representation. This frees you of having to manage the socket lifetime explicitly. - - \section socket_hierarchy The FileHandle hierarchy - - \image html FhHierarchy.png - - The senf::FileHandle class is the base of a hierarchy of socket - handle classes (realized as templates). These classes provide an - interface to the complete socket API. While going down the - inheritance hierarchy, the interface will be more and more - complete. - - The most complete interface is provided by - senf::ProtocolClientSocketHandle and - senf::ProtocolServerSocketHandle. The template Arguments specifies - the Protocol class of the underlying socket type. These are the - \e only classes having public constructors and are therefore the - only classes, which may be created by the library user. You will - normally use these classes by naming a specific socket typedef - (e.g. senf::TCPv4ClientSocketHandle). - - However, to aid writing flexible and generic code, the socket - library provides the senf::ClientSocketHandle and - senf::ServerSocketHandle class templates. These templates - implement a family of closely related classes based on the - specification of the socket policy. This policy specification may - be \e incomplete (see below). Instances of - senf::ClientSocketHandle/senf::ServerSocketHandle can be assigned - and converted to different ClientSocketHandle/ServerSocketHandle - types as long as the policy specifications are compatible. - \attention It is very important, to (almost) always pass the socket - handle <em>by value</em>. The socket handle is a very lightweight - class and designed to be used like an ordinary built-in type. This - is very important in combination with the policy interface. - - \section policy_framework The policy framework - - \image html SocketPolicy.png - - The policy framework conceptually implements a list of parallel - inheritance hierarchies each covering a specific interface aspect - of the socket handle. The socket handle itself only provides - minimal functionality. All further functionality is relayed to a - policy class, or more precisely, to a group of policy classes, one - for each policy axis. The policy axis are - - <dl> - <dt><em>addressingPolicy</em></dt> - <dd>configures, whether a socket is - addressable and if so, configures the address type</dd> - - <dt><em>framingPolicy</em></dt> - <dd>configures the type of framing the socket provides: either no - framing providing a simple i/o stream or packet framing</dd> - - <dt><em>communicationPolicy</em></dt> - <dd>configures,if and how the communication partner is - selected</dd> - - <dt><em>readPolicy</em></dt> - <dd>configures the readability of the socket</dd> - - <dt><em>writePolicy</em></dt> - <dd>configures the writability of the socket</dd> + \section usage_create Creating a Socket Handle + + To create a new socket handle (opening a socket), you will need to + use senf::ProtocolClientSocketHandle or + senf::ProtocolServerSocketHandle. You will probably not use these + templates as is but use proper typedefs (for example + senf::TCPv4ClientSocketHandle or senf::PacketSocketHandle). The + documentation for these socket handles are found in the protocol + class (for example senf::TCPv4SocketProtocol or + senf::PacketProtocol). + + \section usage_reusable Writing Reusable Components + + To make your code more flexible, you should not pass around your + socket in this form. Most of your code will be using only a small + subset of the senf::ProtocolClientSocketHandle or + senf::ProtocolServerSocketHandle API. If instead of using the + fully specified handle type you use a more incomplete type, you + allow your code to be used with all socket which fulfill the + minimal requirements of your code. + + This works, by defining a special reduced policy or handle for + your code: + + \code + typedef senf::ClientSocketHandle< + senf::MakeSocketPolicy< + senf::ReadablePolicy, + senf::StreamFramingPolicy, + senf::ConnectedCommunicationPolicy > > MyReadableHandle; + + \endcode + + This defines \c MyReadableHandle as a senf::ClientSocketHandle + which will have only read functionality. Your code expects a + stream interface (in contrast to a packet or datagram based + interface). You will not have \c write or \c readfrom members. \c + write will be disabled since the WritePolicy is unknown, \c + readfrom will be disabled since a socket with the + senf::ConnectedCommunicationPolicy does not have a \c readfrom + member. + */ - <dt><em>bufferingPolicy</em></dt> - <dd>configures, if and how buffering is configured for a socket</dd> - </dl> - - Every Policy value is identified by a class type. The policy types - themselves built an inheritance hierarchy for each policy - axis. For each policy axis, the root of this tree is the class - named '<tt>(axis name)Base</tt>' (e.g. \p FramingPolicyBase or \p - CommunicationPolicyBase) which is aliased to '<tt>Unspecified(axis - name)</tt>' (e.g. \p UnspecifiedFramingPolicy or \p - UnspecifiedCommunicationPolicy). - - The senf::SocketPolicy template combines a set of policy classes, - one for each policy axis. Together, they define the behavior of a - socket handle. The socket handle instances do net implement any - socket functionality themselves, instead defering the - implementation to the socket classes. The interface is therefore - \e not implemented using virtual members, all important socket - functions can be inlined by the compiler to create highly - efficient code. - - Two SocketPolicy instances are considered compatible, if all - policy axis are compatible. A policy axis is compatible, if one - policy class is either the same as the other or derived from - it. Two SocketHandle instances can be converted into each other, - as long as the SocketPolicies are compatible. - \section protocol_interface The protocol interface - - \image html Protocols.png - - The socket handle classes and templates only implement the most - important socket API methods using the policy framework. To access - the complete API, the protocol interface is provided. Access to - the protocol interface is only possible via - senf::ProtocolClientSocketHandle and - senf::ProtocolServerSocketHandle which have the necessary \c - protocol() member. This member returns a reference to the protocol - class instance which contains members covering all the API - function (mostly setsockopt/getsockopt related calls) not found in - the SocketHandle interface. The protocol interface is specific to - the protocol. It's implementation is quite free. The standard - protocols are implemented using a simple multiple-inheritance - hierarchy as shown above. - - Since the protocol class is protocol specific (how intelligent - ...), the protocol class also defines the complete socket policy - to be used with it's protocol. Complete meaning, that every policy - axis must be assigned it's the most specific (that is derived) - policy class to be used with the protocol. - - */ /** \page extend Extending the Library @@ -157,7 +87,7 @@ the protocol layer is quite simple and works as long as the desired protocol does use the same BSD API used by the standard internet protocols as implemented in the standard policies - (i.e. it uses ordinere read() and write() or rcvfrom() or sendto() + (i.e. it uses ordinary read() and write() or rcvfrom() or sendto() calls and so on). If however the implementation of a policy feature needs to be @@ -241,6 +171,8 @@ members additionally depend on other policy axis (example: AddressingPolicy::connect is only defined if the communication policy is ConnectedCommunication). + + \see policy_group */ /** \page implementation Implementation notes diff --git a/Socket/ProtocolClientSocketHandle.hh b/Socket/ProtocolClientSocketHandle.hh index cf230441f580c0cf1a17265a0c6865e4468ff86a..54a32d0d7052e82603150ab8e88e3a0f6e06d062 100644 --- a/Socket/ProtocolClientSocketHandle.hh +++ b/Socket/ProtocolClientSocketHandle.hh @@ -31,6 +31,8 @@ namespace senf { + /// \addtogroup handle_group + /// @{ template <class Protocol> class ProtocolServerSocketHandle; @@ -73,6 +75,7 @@ namespace senf { friend class ProtocolServerSocketHandle<Protocol>; }; + /// @} } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Socket/ProtocolServerSocketHandle.hh b/Socket/ProtocolServerSocketHandle.hh index 26865101346a295941562bac7fe8322f7d274897..002e2097006d64e524ad3f6146d01f3a5a23a9a2 100644 --- a/Socket/ProtocolServerSocketHandle.hh +++ b/Socket/ProtocolServerSocketHandle.hh @@ -30,8 +30,10 @@ ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { - - + + /// \addtogroup handle_group + /// @{ + template <class Protocol> class ProtocolClientSocketHandle; /** \brief @@ -75,6 +77,7 @@ namespace senf { }; + /// @} } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Socket/ServerSocketHandle.hh b/Socket/ServerSocketHandle.hh index a62636012a86b695627adade3f06eaa73f649eff..d1032b49589d3b3172198a777991d9d984befb20 100644 --- a/Socket/ServerSocketHandle.hh +++ b/Socket/ServerSocketHandle.hh @@ -35,6 +35,8 @@ namespace senf { + /// \addtogroup handle_group + /// @{ template <class Policy> class ClientSocketHandle; @@ -110,6 +112,7 @@ namespace senf { }; + /// @} } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Socket/SocketHandle.cti b/Socket/SocketHandle.cti index e93ec630b939fec3d6dd2b5fb08d93fcc5754a2d..08a3e4db5b00c563dd94a9b6f7ca944131bb67f0 100644 --- a/Socket/SocketHandle.cti +++ b/Socket/SocketHandle.cti @@ -106,7 +106,7 @@ senf::SocketHandle<SocketPolicy>::cast_dynamic(FileHandle handle) { // throws bad_cast if the body is not a SocketBody SocketBody & body (dynamic_cast<SocketBody&>(FileHandle::body(handle))); - // throws bad_cast if the poplicy is not compatible + // throws bad_cast if the policy is not compatible SocketPolicy::checkBaseOf(body.protocol().policy()); return cast_static(handle); } @@ -160,6 +160,11 @@ prefix_ bool senf::check_socket_cast(Source handle) template <class SocketPolicy> prefix_ void senf::SocketHandle<SocketPolicy>::state(SocketStateMap & map, unsigned lod) { + // We use typeid here even though the type of *this is static + // (SocketHandle is not polymorphic and has no vtable). This will + // automatically include the SocketPolicy template parameter in + // the type name and therefore show the \e static policy of the + // socket handle. map["handle"] = prettyName(typeid(*this)); body().state(map,lod); } diff --git a/Socket/SocketHandle.hh b/Socket/SocketHandle.hh index 8f10b4a83877023b6d4399f3b650c3d7f71a8b21..25225c71b91501ea8a09ba330920df999437666d 100644 --- a/Socket/SocketHandle.hh +++ b/Socket/SocketHandle.hh @@ -39,6 +39,8 @@ namespace senf { + /// \addtogroup handle_group + /// @{ /** \brief basic SocketHandle supporting protocol and policy abstraction @@ -121,11 +123,20 @@ namespace senf { \param map string to string mapping to be filled with state information \param lod level of detail requesten. The interpretation - of this value is protocol specific */ + of this value is protocol specific + + \implementation This member will be re-implemented in + every derived class. This is very important since state() + is \e not a virtual function (which we don't want since + we don't want to add a vtable pointer to every handle + instance). */ std::string dumpState(unsigned lod=0); ///< Format complete state information as string /**< Formats the complete state map value and returns it as - a single multi-line string. */ + a single multi-line string. + + \implementation This member will be re-implemented in + every derived class. See the state() documentation. */ protected: explicit SocketHandle(std::auto_ptr<SocketProtocol> protocol, bool isServer); @@ -225,6 +236,8 @@ namespace senf { */ template <class Target, class Source> bool check_socket_cast(Source handle); + + /// @} } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/Socket/SocketHandle.ih b/Socket/SocketHandle.ih index c72b54ddd8981b540fa8e882e1e8905161e64ca8..4c52c6597acc0ce7df1fde2f9ee356d6a09f3042 100644 --- a/Socket/SocketHandle.ih +++ b/Socket/SocketHandle.ih @@ -153,10 +153,6 @@ namespace senf { otherwise */ void state(SocketStateMap & map, unsigned lod); - /**< \todo Move state into a virtual body member (which is - ok, since SocketBody already has virtual members). This - makes in unnecessary to reimplement dumpState and state - in every SocketHandle derived class */ private: virtual void v_close(); ///< Close socket diff --git a/Socket/SocketHandle.test.cc b/Socket/SocketHandle.test.cc index 8a3f6cdcdc82b736cd1222a9794adc65ad7cd61e..a8a50cc4093d04b6930b21754224143f51779d9b 100644 --- a/Socket/SocketHandle.test.cc +++ b/Socket/SocketHandle.test.cc @@ -94,7 +94,6 @@ BOOST_AUTO_UNIT_TEST(socketHandle) "socket.policy: senf::SocketPolicy<senf::test::SomeAddressingPolicy, senf::test::SomeFramingPolicy, senf::test::SomeCommunicationPolicy, senf::test::SomeReadPolicy, senf::test::SomeWritePolicy, senf::test::SomeBufferingPolicy>\n" "socket.protocol: senf::test::SomeProtocol\n" "socket.server: false\n" ); - } ///////////////////////////////cc.e//////////////////////////////////////// diff --git a/Socket/SocketPolicy.ct b/Socket/SocketPolicy.ct index cbcfd30842a4f91502a53e51271dc8ac7166285c..3f07f25c841601d8cc673be12d2a7a193c9c4272 100644 --- a/Socket/SocketPolicy.ct +++ b/Socket/SocketPolicy.ct @@ -36,6 +36,9 @@ template < BOOST_PP_SEQ_FOR_EACH_I( SP_TemplateArgs, , SENF_SOCKET_POLICIES ) > prefix_ void senf::SocketPolicy< BOOST_PP_SEQ_FOR_EACH_I( SP_TemplateParams, , SENF_SOCKET_POLICIES ) >:: checkBaseOf(SocketPolicyBase const & other) { + // check, wether each policy of other is (dynamically!) convertible + // to the corresponding (static) policy of this class. Throws + // std::bad_cast on failure # define SP_CheckPolicy(x1,x2,SomePolicy) (void) dynamic_cast<SomePolicy const &>(other.BOOST_PP_CAT(the,SomePolicy)()); BOOST_PP_SEQ_FOR_EACH( SP_CheckPolicy, , SENF_SOCKET_POLICIES ) # undef SP_CheckPolicy diff --git a/Socket/SocketPolicy.hh b/Socket/SocketPolicy.hh index 91ee1bf5c8dd83919ea0670cede44cb92afafc8d..297a469aafc156e691f2ac5ea069d0696797b901 100644 --- a/Socket/SocketPolicy.hh +++ b/Socket/SocketPolicy.hh @@ -12,7 +12,7 @@ // // 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 +// 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 @@ -20,29 +20,380 @@ // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/** \file + \brief SocketPolicy public header + + \todo We should probably remove BufferingPolicy from the + interface, it does not make much sense (how did I come to include + it ??) + + \todo Do we want to support separate read and write policies. This + allows to treat pipes within this framework however, is this worth + the effort? + */ + +/** \defgroup policy_group The Policy Framework + + \image html SocketPolicy.png + + \section policy_group_introduction Introduction to the Policy Framework + + The policy framework conceptually implements a list of parallel + inheritance hierarchies each covering a specific interface aspect + of the socket handle. The socket handle itself only provides + minimal functionality. All further functionality is relayed to a + policy class, or more precisely, to a group of policy classes, one + for each policy axis. The policy axis are + + <dl> + <dt><em>addressingPolicy</em></dt> + <dd>configures, whether a socket is + addressable and if so, configures the address type</dd> + + <dt><em>framingPolicy</em></dt> + <dd>configures the type of framing the socket provides: either no + framing providing a simple i/o stream or packet framing</dd> + + <dt><em>communicationPolicy</em></dt> + <dd>configures,if and how the communication partner is + selected</dd> + + <dt><em>readPolicy</em></dt> + <dd>configures the readability of the socket</dd> + + <dt><em>writePolicy</em></dt> + <dd>configures the writability of the socket</dd> + + <dt><em>bufferingPolicy</em></dt> + <dd>configures, if and how buffering is configured for a socket</dd> + </dl> + + Every Policy value is identified by a class type. The policy + classes themselves built an inheritance hierarchy for each policy + axis. For each policy axis, the root of this tree is the class + named \i Policy \c Base (e.g. \p AddressingPolicyBase). + + The senf::SocketPolicy defines the complete policy of a socket. It + combines a set of policy classes, one for each policy + axis. Together, they define the behavior of a socket handle. The + socket handle instances do not implement any socket functionality + themselves instead defering the implementation to the policy + classes. The SocketHandle interface is therefore \e not + implemented using virtual members, all important socket functions + can be inlined by the compiler to create highly efficient code. + + A SocketPolicy can be incomplete. In this case it does \e not + completely specify the socket interface, it leaves some aspects + open. A SocketHandle based on such a policy will have a reduced + interface: It will only support those members for wich the + corresponding policies are defined. + + Two SocketHandle's with different policies can be \e + compatible. If they are, the more derived SocketHandle can be + converted (assigned to) the more basic SocketHandle. + + \section policy_group_details The Policy Framework Classes + + In the following discussion we will use the following conventions: + \li \e Policy is one or \c AddressingPolicy, \c FramingPolicy, \c + CommunicationPolicy, \c ReadPolicy, \c WritePolicy or \c + BufferingPolicy + \li \e socketPolicy is any socket policy (that is, an + instantiation of the SocketPolicy template) + \li \e trait is an any policy class (that is, any class derived + from one of the axis base classes) + + Each axis is comprised of a number of classes and templates (all + in namespace senf of course): + + <dl> + <dt>\e Policy \c Base (ex: AddressingPolicyBase)</dt> + <dd>Baseclass of all policies in this axis</dd> + + <dt>\c Unspecified \e Policy (ex: \ref UnspecifiedAddressingPolicy)</dt> + <dd>An alias (typedef) for \e Policy \c Base</dd> + + <dt>\e Policy \c Is < \e socketPolicy, \e trait > (ex: AddressingPolicyIs)</dt> + <dd>A template metafunction returning \c boost::true_type, if \e + trait (any class derived from \e Policy \c Base) is a compatible + policy value of the given \e socketPolicy</dd> + + <dt>\c If \e Policy \c Is < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIs)</dt> + <dd>This is a combination of \e Policy \c Is and \c boost::enable_if</dd> + + <dt>\c If \e Policy \c IsNot < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIsNot)</dt> + <dd>The inverse of above</dd> + </dl> + + These classes form the basis of the policy framework. To bind the + policy axis together, there are some more classes and templates. + + <dl> + <dt>\c class \c SocketPolicyBase</dt> + <dd>This class is the base class of the SocketPolicy template. It + is used to validate, that a class is really a SocketPolicy (by + checking, that it derives from SocketPolicyBase. This is simpler + than chacking the template directly).</dd> + + <dt>\c template \c SocketPolicy < \e addressingPolicy, \e framingPolicy, \e communicationPolicy, \e readPolicy, \e writePolicy, \e bufferingPolicy ></dt> + <dd>This is the central SocketPolicy template. It combines a + complete set of policy classes, one for each axis.</dd> + + <dt>\c template \c MakeSocketPolicy < \e args ></dt> + <dd>\c MakeSocketPolicy is a template metafunction which + simplifies building SocketPolicy instantiations. It takes any + number (ok, up to a maximum of 6) of policy classes as an + argument (in any order). It will sort these arguments into the + SocketPolicy template arguments. If for some axis no class is + specified, it's slot will be filled with \c Unspecified \e + Policy. Additionally, the first Argument may optionally be ab + arbitrary SocketPolicy. It will provide default values for + unspecified axis</dd> + + <dt>\c template \c SocketPolicyIsBaseOf < \e base, \e derived ></dt> + <dd>This template metafunction will check, wether the socket + policy \e derived is convertible to \e base. This means, that for + each axis, the corresponding policy class in \e derived must be + derived or be the same as the one on \e base.</dd> + </dl> + + \implementation All these classes are created automatically. The + \c SENF_SOCKET_POLICIES makro is a Boost.Preprocessor style + sequence listing all policy axis. The Boost.Preprocessor library + is then used to generate the respective classes. + + \section policy_implement Implementing Policy Classes + + To define a new policy class, derive from the corresponding base + class for your policy axies. The only policy axis which might + possibly need to be extended are the addressing policy + (AddressingPolicyBase) and the buffering policy + (BufferingPolicyBase). See the Documentation of these classes for + more information on which members can be implemented. + + All members you define must be static. For any of the policy + classes, you must only define those members which are supported by + your implementation. If you leave out a member you automatically + disable the corresponding functionality in the + ClientSocketHandle/ServerSocketHandle interface. + + The member prototypes given in the base class documentation only + specify the call signature not the way, the member must be defined + (FileHandle really is not a FileHandle but an arbitrary + SocketHandle). + + If the existence of a member depends on other policies, you should + use the <code>If</code><i>SomePolicy</i><code>Is</code> and + <code>If</code><i>SomePolicy</i><code>IsNot</code> templates to + dynamically enable/disable the member depending on some other + policy: + + \code + struct ExampleAddressingPolicy + { + template <class Policy> + void connect(senf::SocketHandle<Policy> handle, Address & addr, + typename senf::IfCommmunicationPolicyIs< + Policy, senf::ConnectedCommunicationPolicy>::type * = 0); + }; + \endcode + + The \c connect member in this example will only be enabled, it + the communication policy of the socket handle is + ConnectedCommunicationPolicy (or a derived type). See <a + href="http://www.boost.org/libs/utility/enable_if.html">Boost.Enable_If</a> + for a discussion of the third argument (\c + senf::ConnectedCommunicationPolicyIs is based on the \c + boost::enable_if template). + + \see \ref policy_framework \n + \ref extend_policy \n + <a class="ext" href="http://www.boost.org/libs/utility/enable_if.html">The Boost enable_if utility</a> \n + <a class="ext" href="http://www.boost.org/libs/mpl/doc/index.html">The Boost.MPL library</a> \n + <a class="ext" href="http://www.boost.org/libs/preprocessor/doc/index.html">The Boost.Preprocessor library</a> + + \idea We could combine all the \e Policy \c Is templates into a + single template. Since the \e trait argument will automatically + specify the axis to be used, it is not necessary to specify that + axis in the tempalte functor's name. We could even combine this + with \c SocketPolicyIsBaseOf. + */ + #ifndef HH_SocketPolicy_ #define HH_SocketPolicy_ 1 // Custom includes +#include "GenericSockAddr.hh" + //#include "SocketPolicy.mpp" ///////////////////////////////hh.p//////////////////////////////////////// namespace senf { + /// \addtogroup policy_group + /// @{ // This may be adapted to change the supported policies (however, // ClientSocketHandle and ServerSocketHandle will probably have to - // be adjusted accordingly). However, AddressingPolicy MUST always - // be the first Policy member ... - -# define SENF_SOCKET_POLICIES \ - (AddressingPolicy) \ - (FramingPolicy) \ - (CommunicationPolicy) \ - (ReadPolicy) \ - (WritePolicy) \ + // be adjusted accordingly) + + /** \brief List all policy axis + + \internal + + This define symbol is used to configure the policy axis. The + base class for each of these axis must be defined explicitly + (e.g. AddressingPolicyBase). The implementation files will + then automatically generate all the other classes from this + list. + + \see policy_group + */ +# define SENF_SOCKET_POLICIES \ + (AddressingPolicy) \ + (FramingPolicy) \ + (CommunicationPolicy) \ + (ReadPolicy) \ + (WritePolicy) \ (BufferingPolicy) + + // Wer define these classes explicitly (and not with some macro + // magic) because + // a) AddressingPolicyBase is different from all the others + // b) We want to document each one explicitly + + /** \brief Policy defining socket addressing + + AddressingPolicyBase is the baseclass of all addressing policy + classes. When defining a new addressing policy, the following + members can be defined. All methods must be static. + + <table class="senf"> + <tr><td>typedef</td> <td><tt>Address</tt></td> <td>Address type</td></tr> + <tr><td>method</td> <td><tt>void local(FileHandle, Address &)</tt></td> <td>Get local socket address</td></tr> + <tr><td>method</td> <td><tt>void peer(FileHandle, Address &)</tt></td> <td>Get remote socket address</td></tr> + <tr><td>method</td> <td><tt>void bind(FileHandle, Address const &)</tt></td> <td>Bind socket to local address</td></tr> + <tr><td>method</tr> <td><tt>void connect(FileHandle, Address const &)</tt></td> <td>Connect to remote address</td></tr> + </table> + + \see policy_group + */ + struct AddressingPolicyBase + { + virtual ~AddressingPolicyBase() {} + + typedef GenericSockAddr Address; + }; + + /** \brief Policy defining the framing format + + This policy does not define any operations since it does have + no influence on any method signature. It does however affect + the semantics of the \c read() and \c write() operations. + + \note This policy axis probably only has two sensible statess: + StreamFramingPolicy and DatagramFramingPolicy. + + \see policy_group + */ + struct FramingPolicyBase + { + virtual ~FramingPolicyBase() {} + }; + + /** \brief Policy defining, how peers are selected + + The CommunicationPolicy may define two members: + + <table class="senf"> + <tr><td>method</td> <td><tt>void listen(FileHandle, unsigned backlog)</tt></td> <td>Switch socket into listening state</td></tr> + <tr><td>method</td> <td><tt>int accept(FileHandle, Address &)</tt></td> <td>Accept a new connection</td></tr> + </table> + + The \c listen member is straight forward. The \c accept() member + must return a new file descriptor (which will be used to + create a new SocketHandle of the correct type). Additionally, + accept() should only be defined, if the Addressing policy is + not \c NoAddressingPolicy (which together with + ConnectedCommunicationPolicy would identify a point-to-point + link with fixed communication partners). + + \note This Policy only has two meaningful states: + ConnectedCommunicationPolicy and + UnconnectedCommunicationPolicy. It is probably not sensible to + define a new CommunicationPolicy type. + + \see policy_group + */ + struct CommunicationPolicyBase + { + virtual ~CommunicationPolicyBase() {} + }; + + /** \brief Policy defining the readability + + The ReadPolicy defines, wether the socket is readable. It + may define two members: + + <table class="senf"> + <tr><td>method</td> <td><tt>unsigned read(FileHandle, char * buffer, unsigned size)</tt></td> <td>read data from socket</td></tr> + <tr><td>method</td> <td><tt>unsigned readfrom(FileHandle, char * buffer, unsigned size, Address &)</tt></td> <td>read data from unconnected socket</td></tr> + </table> + + The second member should only be enabled if the communication + policy is UnconnectedCommunication (otherwise it does not make + sense since the communication partner is fixed) (see + AddressingPolicyBase on how to do this). + + \note This Policy only has two meaningful states: + ReadablePolicy and NotReadablePolicy. It probably does not + make sense to define new read policy types. + + \see policy_group + */ + struct ReadPolicyBase + { + virtual ~ReadPolicyBase() {} + }; + + /** \brief Policy defining the writability + + The WritePolicy defines, wether the socket is writable. It may + define two members: + + <table class="senf"> + <tr><td>method</td> <td><tt>unsigned write(FileHandle, char * buffer, unsigned size)</tt></td> <td>read data from socket</td></tr> + <tr><td>method</td> <td><tt>unsigned writeto(FileHandle, char * buffer, unsigned size, Address &)</tt></td> <td>read data from unconnected socket</td></tr> + </table> + + The second member should only be enabled if the communication + policy is UnconnectedCommunication (otherwise it does not make + sense since the communication partner is fixed) (see + AddressingPolicyBase on how to do this). + + \note This Policy only has two meaningful states: + WritablePolicy and NotWritablePolicy. It probably does not + make sense to define new write policy types. + + \see policy_group + */ + struct WritePolicyBase + { + virtual ~WritePolicyBase() {} + }; + + /** \brief Policy defining the buffering interface + + The BufferingPolicy defines the buffer handling of the + socket. It may provide the follogin members: + + \see policy_group + */ + struct BufferingPolicyBase + { + virtual ~BufferingPolicyBase() {} + }; // The implementation file will for each Policy declared above // define the following (SomePolicy is one of the above): @@ -59,6 +410,126 @@ namespace senf { // template SocketPolicy< ..policies.. > // template MakeSocketPolicy< ..args.. > // template SocketPolicyIsBaseOf< Base, Derived > + +# ifdef DOXYGEN + + // The following stub definitions are only visible to doxygen + + /** \brief Alias of AddressingPolicyBase for better readability + \see \ref policy_group + */ + typedef AddressingPolicyBase UnspecifiedAddressingPolicy; + + /** \brief Check single policy axis + + This template is an example of the \i Policy \c Is family of + tempalte metafunctions. It will check, wether \c Trait is a + valid compatible Policy class of \c SocketPolicy. \c Trait + must be derived from AddressingPolicyBase (respectively \i + Policy \c Base). + + \see \ref policy_group + */ + template <class SocketPolicy, class Trait> + struct AddressingPolicyIs + {}; + + /** \brief Enable template overload depending on policy value + + This template is an exmaple of the \c If \i Policy \c Is + family of templates. It is used like <a class="ext" + href="http://www.boost.org/libs/utility/enable_if.html">Boost.enable_if</a> + to enable a templated overload only, if the AddressingPolicy + of \i Policy is compatible with \c Trait (that is the + AddressingPolicy of \c Policy is derived from \c Trait). + + \see policy_group + */ + template <class SocketPolicy, class Trait> + struct IfAddressingPolicyIs + {}; + + /** \brief Inversion of \c IfAddressingPolicyIs + \see policy_group + */ + template <class SocketPolicy, class Trait> + struct IfAddressingPolicyIsNot + {}; + + /** \brief Baseclass of all SocketPolicies + + \internal + + This class is used to + + \see policy_group + */ + struct SocketPolicyBase + {}; + + /** \brief Collection of policy classes + + The SocketPolicy template defines the complete Policy used by + the socket library. It contains one policy class for each + policy axis. + + A SocketPolicy can be complete or incomplete. An incomplete + SocketPolicy will have at least one axis set to \c Undefined + \i Policy (or a generic derived class which is used to group + some other policies but does not (completely) define the + policy behavior). A complete SocketPolicy will have a + concrete definition of the desired behavior for each policy + axis. + + \see policy_group + */ + template < + class AddressingPolicy, + class FramingPolicy, + class CommunicationPolicy, + class ReadPolicy, + class WritePolicy, + class BufferingPolicy > + struct SocketPolicy + {}; + + /** \brief Metafunction to create SocketPolicy + + This template metafunction simplifies the creation of a + SocketPolicy instantiation. It takes any number (that is up to + 6) of Policy classes as arguments in any Order. It will create + a SocketPolicy from these policy classes. Any axis not + specified will be left as \c Unspecified \i Policy. + + \see policy_group + */ + template <class Arg1, class Arg2, class ArgN> + struct MakeSocketPolicy + {}; + + /** \brief Check policy compatibility + + This tempalte metafunction checks, wether the SocketPolicy \c + Derived is more specialized than \c Base (and therefore a + SocketHandle with policy \c Derived is convertible to a + SocketHandle with policy \c Base). + + The metafunction will return true (that is inherits from \c + boost::true_type, see the <a class="ext" + href="http://www.boost.org/libs/mpl/doc/index.html">Boost.MPL</a> + library documentation for more information) if each policy + class in \c Base is a baseclass of (or the same as) the + corresponding policy class in \c Derived. + + \see policy_group + */ + template <class Base, class Derived> + struct SocketPolicyIsBaseOf + {}; + +# endif + + /// @} } //////////////////////////////hh.e//////////////////////////////////////// diff --git a/Socket/SocketPolicy.ih b/Socket/SocketPolicy.ih index dabdf26b67cb45954a02f938fd0b1acf92d66e36..fac273ad16657abdbeb8cd23c9d0acf7f923dbcb 100644 --- a/Socket/SocketPolicy.ih +++ b/Socket/SocketPolicy.ih @@ -46,49 +46,32 @@ #include <boost/mpl/and.hpp> #include <boost/utility.hpp> // for enable_if -#include "GenericSockAddr.hh" - ///////////////////////////////ih.p//////////////////////////////////////// -namespace senf { +/// \cond disabled +// Hide this code from doxygen +namespace senf { # define SENF_SOCKET_POLICIES_N BOOST_PP_SEQ_SIZE( SENF_SOCKET_POLICIES ) - // This REALLY is bad ... but we just need an Address member in - // AddressingPolicyBase as long as ClientSocketHandle / - // ServerSocketHandle don't make use of enable_if for each and - // every member they define ... - - struct AddressingPolicyBase - { - virtual ~ AddressingPolicyBase() {} - - typedef GenericSockAddr Address; - }; - -# define SP_DeclareBase(x1,x2,SomePolicy) \ - struct BOOST_PP_CAT(SomePolicy,Base) \ - { virtual ~ BOOST_PP_CAT(SomePolicy,Base) () {} }; \ +# define SP_DeclareAlias(x1,x2,SomePolicy) \ typedef BOOST_PP_CAT(SomePolicy,Base) BOOST_PP_CAT(Unspecified,SomePolicy); - BOOST_PP_SEQ_FOR_EACH( SP_DeclareBase, , BOOST_PP_SEQ_POP_FRONT( SENF_SOCKET_POLICIES ) ) + BOOST_PP_SEQ_FOR_EACH( SP_DeclareAlias, , SENF_SOCKET_POLICIES ) -# undef SP_DeclareBase +# undef SP_DeclareAlias struct SocketPolicyBase { virtual ~SocketPolicyBase() {} -# define SP_DeclareTypedef(x1,x2,SomePolicy) \ - typedef BOOST_PP_CAT(SomePolicy,Base) SomePolicy; \ - BOOST_PP_CAT(SomePolicy,Base) BOOST_PP_CAT(BOOST_PP_CAT(the,SomePolicy),_); \ - virtual BOOST_PP_CAT(SomePolicy,Base) const & BOOST_PP_CAT(the,SomePolicy) () const \ - { return BOOST_PP_CAT(BOOST_PP_CAT(the,SomePolicy),_); } +# define SP_Declare(x1,x2,SomePolicy) \ + virtual BOOST_PP_CAT(SomePolicy,Base) const & BOOST_PP_CAT(the,SomePolicy) () const = 0; - BOOST_PP_SEQ_FOR_EACH( SP_DeclareTypedef, , SENF_SOCKET_POLICIES ) + BOOST_PP_SEQ_FOR_EACH( SP_Declare, , SENF_SOCKET_POLICIES ) -# undef SP_DeclareTypedef +# undef SP_Declare }; # define SP_TemplateArgs(x1,x2,n,SomePolicy) \ @@ -130,15 +113,15 @@ namespace impl { BOOST_PP_IIF( BOOST_PP_EQUAL(n,m), Policy, typename Base::SomePolicy ) # define BOOST_PP_LOCAL_LIMITS (0, BOOST_PP_DEC( SENF_SOCKET_POLICIES_N ) ) -# define BOOST_PP_LOCAL_MACRO(n) \ - SocketPolicy_rv<n> MakeSocketPolicy_merge_(BOOST_PP_CAT( BOOST_PP_SEQ_ELEM( n, SENF_SOCKET_POLICIES ),Base)*); \ - \ - template <class Base, class Policy> \ - struct MakeSocketPolicy_merge<Base,Policy,sizeof(SocketPolicy_rv<n>)> \ - { \ - typedef SocketPolicy< \ - BOOST_PP_SEQ_FOR_EACH_I( SP_DeclareMakeSocketPolicy_merge_member, n, SENF_SOCKET_POLICIES ) \ - > type; \ +# define BOOST_PP_LOCAL_MACRO(n) \ + SocketPolicy_rv<n> MakeSocketPolicy_merge_(BOOST_PP_CAT( BOOST_PP_SEQ_ELEM( n, SENF_SOCKET_POLICIES ),Base)*); \ + \ + template <class Base, class Policy> \ + struct MakeSocketPolicy_merge<Base,Policy,sizeof(SocketPolicy_rv<n>)> \ + { \ + typedef SocketPolicy< \ + BOOST_PP_SEQ_FOR_EACH_I( SP_DeclareMakeSocketPolicy_merge_member, n, SENF_SOCKET_POLICIES ) \ + > type; \ }; # include BOOST_PP_LOCAL_ITERATE() @@ -178,8 +161,7 @@ namespace impl { # undef SP_DeclareArguments template <class Base> - SocketPolicy_rv<2> SocketPolicy_checkcompat_( - BOOST_PP_ENUM_PARAMS( SENF_SOCKET_POLICIES_N, void * BOOST_PP_INTERCEPT ) ); + SocketPolicy_rv<2> SocketPolicy_checkcompat_( ... ); template <int Size> struct SocketPolicy_checkcompat @@ -243,6 +225,8 @@ namespace impl { } +/// \endcond + ///////////////////////////////ih.e//////////////////////////////////////// #endif diff --git a/Socket/SocketProtocol.hh b/Socket/SocketProtocol.hh index fe42ee805093ec3caff9d5fb6428f6f2af6ccb17..0335412b41cfd504de9b7318c40733554ebb87f6 100644 --- a/Socket/SocketProtocol.hh +++ b/Socket/SocketProtocol.hh @@ -20,6 +20,36 @@ // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/** \file + */ + +/** \defgroup protocol_group The Protocol Classes + + \image html Protocols.png + + The socket handle classes and templates only implement the most + important socket API methods using the policy framework. To access + the complete API, the protocol interface is provided. Access to + the protocol interface is only possible via + senf::ProtocolClientSocketHandle and + senf::ProtocolServerSocketHandle which have the necessary \c + protocol() member. This member returns a reference to the protocol + class instance which contains members covering all the API + functions (mostly setsockopt/getsockopt related calls but there + may be more, this is completely up to the implementor of the + protocol class) not found in the SocketHandle interface. The + protocol interface is specific to the protocol. It's + implementation is quite free. The standard protocols are + implemented using a simple multiple-inheritance hierarchy as shown + above. + + Since the protocol class is protocol specific (how intelligent + ...), the protocol class also defines the complete socket policy + to be used with it's protocol. Complete meaning, that every policy + axis must be assigned it's the most specific (that is derived) + policy class to be used with the protocol. + */ + #ifndef HH_SocketProtocol_ #define HH_SocketProtocol_ 1 @@ -33,6 +63,8 @@ namespace senf { + /// \addtogroup protocol_group + /// @{ class SocketPolicyBase; @@ -107,6 +139,7 @@ namespace senf { }; + /// @} } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/doclib/Doxyfile.global b/doclib/Doxyfile.global index ac07ee1f8fab9344ac1771c751a3ff6a3b5db07a..d2b544d2a7704291417f18a6dbba00c4f72d4c89 100644 --- a/doclib/Doxyfile.global +++ b/doclib/Doxyfile.global @@ -1,11 +1,12 @@ OUTPUT_DIRECTORY = doc INPUT = . FILE_PATTERNS = *.c *.cc *.cci *.ct *.cti *.h *.hh *.ih *.mmc *.dox -EXCLUDE_PATTERNS = *.test.cc .* +EXCLUDE_PATTERNS = *.test.cc *.test.hh .* IMAGE_PATH = . ALIASES = "fixme=\xrefitem fixme \"Fix\" \"Fixmes\"" \ - "idea=\xrefitem idea \"Idea\" \"Ideas\"" + "idea=\xrefitem idea \"Idea\" \"Ideas\"" \ + "implementation=\par \"Implementation note:\"" REPEAT_BRIEF = YES ALWAYS_DETAILED_SEC = YES MULTILINE_CPP_IS_BRIEF = YES @@ -16,7 +17,6 @@ EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES INTERNAL_DOCS = YES SOURCE_BROWSER = YES -STRIP_CODE_COMMENTS = NO ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 3 diff --git a/run-test-gdb.sh b/run-test-gdb.sh new file mode 100755 index 0000000000000000000000000000000000000000..34dc2ba112dc8262a7f5a4824ced48dee0b2d6d9 --- /dev/null +++ b/run-test-gdb.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +# This script helps finding the origin of unhandled exceptions in the +# unit tests. The unit test framework will tell, that an exception has +# been caught by the test driver but will not tell, where in the code +# it has occured. +# +# This script will run the .test.bin test driver within gdb and will +# create a backtrace for every exception caught by the test driver. +# +# NOTE: If your unit test (excplicitly) writes output to stderr, this +# output will be lost +# +# NOTE: This works by setting a breakpoint in the std::exception +# constructor. This is, where the backtrace is created from. If you do +# some funky manipulations with your exceptions, the backtrace might +# not point to the throw statement, however this is very unusual. Of +# course, this only works, if all your exceptions are derived from +# std::exception but that should always be the case. + +trap 'rm -f .run-test-gdb.cmd' 0 1 2 15 + +# This gdb script will set the breakpoint and will then run the test +# driver. Whenever the execution stops, it will print a backtrace and +# will then continue execution. This will produce superflous +# backtraces for exceptions which are handled correctly. These will be +# filtered out later. +cat >.run-test-gdb.cmd <<EOF +break std::exception::exception() +run --build_info=yes --log_level=test_suite +while 1 + bt + c +end +EOF + +# The perl script will filter out exceptions which are handled +# correctly (cought before the reach the unit test driver). It will +# also truncate the backtrace at the first stackframe within the unit +# test subsystem since we are only interested in the user code. +gdb -batch -x .run-test-gdb.cmd ./.test.bin 2>/dev/null | perl -e ' + while (<STDIN>) { + if (/^$/) { + $_=<STDIN>; + if (/^Breakpoint 1, exception/) { + @l=(); + while (<STDIN>) { + last unless /^#?[0-9]|^ /; + push @l,$_ if /^#/; + $l[$#l] .= $_ if /^ /; + } + if (/: fatal error in /) { + for (@l[1..$#l]) { + last if /^#[0-9]+ +0x[0-9a-f]+ in boost::unit_test/; + print; + } + } + } + else { print "\n"; } + } + print; + } +' \ No newline at end of file