X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Socket%2FSocketPolicy.hh;h=8784edd921e3ad0ae180eea65e120e390e61c1a8;hb=9a988902090d28007578e93bffd809f6bd913155;hp=e821d925ea72133c379f02f8bd9f640ee551ad83;hpb=ac6a813d9d99f7add4e13aff7a4bcd314d5604a6;p=senf.git diff --git a/Socket/SocketPolicy.hh b/Socket/SocketPolicy.hh index e821d92..8784edd 100644 --- a/Socket/SocketPolicy.hh +++ b/Socket/SocketPolicy.hh @@ -1,6 +1,6 @@ // $Id$ // -// Copyright (C) 2006 +// Copyright (C) 2006 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS) // Kompetenzzentrum fuer Satelitenkommunikation (SatCom) // Stefan Bund @@ -20,30 +20,386 @@ // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +/** \file + \brief Policy Framework 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? + + \idea Creating a new Socket will create 4 (!) new instances (The handle, the body, the policy + and the protocol) of which 3 (argh) (body, policy and protocol) live on the heap. This is + expensive. We should convert all the policy classes to singletons and assign the same + instance to all socket bodies with the same policy. This would reduce the number of heap + allocations per socket handle to two. + */ + +/** \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 + +
addressingPolicy
configures, whether a socket is addressable and if + so, configures the address type
+ +
framingPolicy
configures the type of framing the socket provides: either + no framing providing a simple i/o stream or packet framing
+ +
communicationPolicy
configures,if and how the communication partner is + selected
+ +
readPolicy
configures the readability of the socket
+ +
writePolicy
configures the writability of the socket
+ +
bufferingPolicy
configures, if and how buffering is configured for a + socket
+ + The template senf::SocketPolicy combines these policy axis to form a concrete socket policy. In + a concrete policy, each of these policy axis is assigned a value, the policy value. This value + is identified by a class type, a policy class. E.g. possible values for framingPolicy + are DatagramFramingPolicy or StreamFramingPolicy which are classes derived + from the axis base class FramingPolicyBase. This base class also doubles as + UnspecifiedFramingPolicy (which is just a typedef alias). If a policy axis is assigned + this Unspecified type, the axis is left unspecified, the concrete policy will be incomplete. + + The senf::SocketPolicy template defines the behavior of a socket handle. The socket handle + instances do not implement any socket functionality themselves instead deferring 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 senf::SocketPolicy instance can be incomplete. In this case it does \e not completely specify + the socket interface, it leaves some aspects open by assigning the Unspecified value to one or + more of the policy axis. A senf::SocketHandle based on such a policy will have a reduced + interface: It will only support those members for which the corresponding policies are defined. + + To build a senf::SocketPolicy instance the senf::MakeSocketPolicy helper is provided. This + helper template takes any number (it is really limited to 6 Arguments but more arguments don't + make sense) of policy classes as it's argument. The MakeSocketPolicy helper will take the + arguments in the order they are specified and for each argument will check to which axis the + policy class belongs (by checking the base classes of that class) and assign it to the correct + policy axis in the senf::SocketPolicy template. If any policy axis are not specified, they are + defaulted to their corresponding Unspecified value. This helper frees you to specify the policy + classes in any order. An additional feature is, that you may specify a complete policy as a + first argument. This policy will then be used to provide default values for unspecified axis. + + Two senf::SocketHandle's with different policies can be \e compatible. If they are, the more + specific SocketHandle can be converted (assigned to) the more basic SocketHandle. A SocketHandle + is more specific then another SocketHandle if the policy of the former is more specific then + that of the latter which means, that for each policy axis separately, the value of that axis of + the more specific policy is derived from or the same as the value of that axis in the more basic + policy. This is like converting a derived class pointer to a base class pointer, only it happens + separately but at the same time for each policy axis: + + \code + // This defines an incomplete policy where addressingPolicy, writePolicy and bufferingPolicy + // are unspecified + typedef senf::MakeSocketPolicy< + senf::StreamFramingPolicy, + senf::ConnectedCommunicationPolicy, + senf::ReadablePolicy + >::policy MyReadableSocketPolicy + + typedef senf::ClientSocketHandle MyReadableHandle; + + // TCPv4ClientSocketHandle is a socket handle with the policy equivalent to + // senf::MakeSocketPolicy< + // INet4AddressingPolicy, + // StreamFramingPolicy, + // ConnectedCommunicationPolicy, + // ReadablePolicy, + // WritablePolicy, + // SocketBufferingPolicy>::policy + senf::TCPv4ClientSocketHandle tcpHandle (...); + + MyReadableHandle myHandle (tcpHandle); // Conversion to more basic socket handle + \endcode + + \section policy_group_details The Policy Framework Classes + + In the following discussion, deeper insight into C++ and especially the concepts of template + meta-programming are needed. However, this information is only needed if you want to write new + policy classes or want to use the policy framework explicitly for your own involved + optimizations ... or if you are just plain curious :-) + + In the following discussion we will use the following conventions: + \li \e Axis 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): + +
\e Axis \c Base (ex: AddressingPolicyBase)
Baseclass of all policies in this + axis
+ +
\c Unspecified \e Axis (ex: \ref UnspecifiedAddressingPolicy)
An alias (typedef) + for \e Axis \c Base
+ +
\e Axis \c Is < \e socketPolicy, \e trait > (ex: AddressingPolicyIs)
A template + metafunction returning \c boost::true_type, if \e trait (any class derived from \e Axis \c + Base) is a compatible policy value of the given \e socketPolicy
+ +
\c If \e Axis \c Is < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIs)
This + is a combination of \e Axis \c Is and \c boost::enable_if
+ +
\c If \e Axis \c IsNot < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIsNot)
+
The inverse of above
+ + These classes form the basis of the policy framework. To bind the policy axis together, there + are some more classes and templates. + +
\c class \c SocketPolicyBase
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 checking the template directly).
+ +
\c template \c SocketPolicy < \e addressingPolicy, \e framingPolicy, \e communicationPolicy, + \e readPolicy, \e writePolicy, \e bufferingPolicy >
This is the central SocketPolicy + template. It combines a complete set of policy classes, one for each axis.
+ +
\c template \c MakeSocketPolicy < \e args >
\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 Axis. Additionally, the first Argument may optionally be ab + arbitrary SocketPolicy. It will provide default values for unspecified axis
+ +
\c template \c SocketPolicyIsBaseOf < \e base, \e derived >
This template + metafunction will check, whether 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.
+ + \implementation All these classes are created automatically. The \c SENF_SOCKET_POLICIES macro + 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 + axes. 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 + IfSomePolicyIs and + IfSomePolicyIsNot templates to dynamically enable/disable the + member depending on some other policy: + + \code + struct ExampleAddressingPolicy + { + template + void connect(senf::SocketHandle 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 Boost.Enable_If for a discussion of + the third argument (\c senf::ConnectedCommunicationPolicyIs is based on the \c boost::enable_if + template). + + \see \ref extend_policy \n + The Boost enable_if utility \n + The Boost.MPL library \n + The Boost.Preprocessor library + + \idea We could combine all the \e Axis \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 template functor's name. We could even combine this with \c + SocketPolicyIsBaseOf. + */ + +/** \defgroup policy_impl_group Policy Implementation classes + \ingroup policy_group + + Here you will find all policy classes. Also included are some supporting classes which are used + as base classes to build other policy classes. + */ + #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) - // 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 ... + /** \brief List all policy axis -# define SATLIB_SOCKET_POLICIES \ - (AddressingPolicy) \ + \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) - + (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. + + + + + + + +
typedef Address Address type
method void local(FileHandle, Address &) Get local socket address
method void peer(FileHandle, Address &) Get remote socket address
method void bind(FileHandle, Address const &) Bind socket to local address
method
void connect(FileHandle, Address const &) Connect to remote address
+ + \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 states: StreamFramingPolicy and + DatagramFramingPolicy. + + \see policy_group + */ + struct FramingPolicyBase + { + virtual ~FramingPolicyBase() {} + }; + + /** \brief Policy defining, how peers are selected + + The CommunicationPolicy may define two members: + + + + +
method void listen(FileHandle, unsigned backlog) Switch socket into listening state
method int accept(FileHandle, Address &) Accept a new connection
+ + 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, whether the socket is readable. It may define two members: + + + + +
method unsigned read(FileHandle, char * buffer, unsigned size) read data from socket
method unsigned readfrom(FileHandle, char * buffer, unsigned size, Address &) read data from unconnected socket
+ + 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, whether the socket is writable. It may define two members: + + + + +
method unsigned write(FileHandle, char * buffer, unsigned size) read data from socket
method unsigned writeto(FileHandle, char * buffer, unsigned size, Address &) read data from unconnected socket
+ + 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 following + 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 +415,132 @@ 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 \e Axis \c Is family of template metafunctions. It will + check, whether \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 + struct AddressingPolicyIs + {}; + + /** \brief Enable template overload depending on policy value + + This template is an example of the \c If \e Axis \c Is family of templates. It is used like + Boost.enable_if to enable a + templated overload only, if the AddressingPolicy of \e Axis is compatible with \c Trait + (that is the AddressingPolicy of \c Policy is derived from \c Trait). + + \see policy_group + */ + template + struct IfAddressingPolicyIs + {}; + + /** \brief Inversion of \c IfAddressingPolicyIs + \see policy_group + */ + template + struct IfAddressingPolicyIsNot + {}; + + /** \brief Baseclass of all SocketPolicies + + \internal + + This class provides the baseclass of all socket policies (bundles). It serves two purposes: + \li It allows us to easily identify a socket policy bundle by checking a classes baseclass. + \li It provides an abstract (virtual) interface to access the policy axes + + \see policy_group + */ + struct SocketPolicyBase + { + /** \brief Polymorphic access to policy axes + + This is an example of a policy axes accessor. It returns a reference to the policy axes + used by the concrete protocol bundle. This reference can then be checked using RTTI + information. + */ + AddressingPolicyBase const & theAddressingPolicy() const = 0; + }; + + /** \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. This template takes one policy from each + axis as it's template arguments (this example implementation only has AddressingPolicy as an + argument). + + A SocketPolicy can be complete or incomplete. An incomplete SocketPolicy will have at least + one axis set to \c Undefined \e Axis (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 > + struct SocketPolicy + { + /** \brief Check dynamic policy compatibility + + This method will check the socket policy \a other against this policy. It will check, + whether \a other is a base policy (or the same) of this policy. This check is done + against the \e dynamic type of \a other using RTTI. It will throw \c std::bad_cast, if + the policy is not compatible. + + \param[in] other SocketPolicy to check + \throws std::bad_cast if \a other is not a compatible policy + */ + static void checkBaseOf(SocketPolicyBase const & other); + }; + + /** \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 \e Axis. + + \see policy_group + */ + template + struct MakeSocketPolicy + {}; + + /** \brief Check policy compatibility + + This template metafunction checks, whether 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 Boost.MPL 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 + struct SocketPolicyIsBaseOf + {}; + +# endif + + /// @} } //////////////////////////////hh.e//////////////////////////////////////// @@ -71,5 +553,8 @@ namespace senf { // Local Variables: // mode: c++ +// fill-column: 100 // c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" // End: