X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Socket%2FSocketPolicy.hh;h=6fd63c9a831f414301558e73f16b3de0ec26b78c;hb=245bdb920e5f8fc1150794db8d0b42a15fa2cd15;hp=91ee1bf5c8dd83919ea0670cede44cb92afafc8d;hpb=62464586315edf52fbcc613acb4a8a7e919fd8e2;p=senf.git
diff --git a/Socket/SocketPolicy.hh b/Socket/SocketPolicy.hh
index 91ee1bf..6fd63c9 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,397 @@
// 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
+
+
+ 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 \e 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):
+
+
+ - \e Policy \c Base (ex: AddressingPolicyBase)
+ - Baseclass of all policies in this axis
+
+ - \c Unspecified \e Policy (ex: \ref UnspecifiedAddressingPolicy)
+ - An alias (typedef) for \e Policy \c Base
+
+ - \e Policy \c Is < \e socketPolicy, \e trait > (ex: AddressingPolicyIs)
+ - 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
+
+ - \c If \e Policy \c Is < \e socketPolicy, \e trait > (ex: IfAddressingPolicyIs)
+ - This is a combination of \e Policy \c Is and \c boost::enable_if
+
+ - \c If \e Policy \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 chacking 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
+ Policy. 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, 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.
+
+
+ \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 If
SomePolicyIs
and
+ If
SomePolicyIsNot
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 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.
+ */
+
+/** \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). 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.
+
+
+ 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 statess:
+ 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, wether 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, wether 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 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 +427,151 @@ 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 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
+ struct AddressingPolicyIs
+ {};
+
+ /** \brief Enable template overload depending on policy value
+
+ This template is an exmaple of the \c If \e Policy \c Is
+ family of templates. It is used like Boost.enable_if
+ to enable a templated overload only, if the AddressingPolicy
+ of \e Policy 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 conrecte 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 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 >
+ struct SocketPolicy
+ {
+ /** \brief Check dynamic policy compatibility
+
+ This method will check the socket policy \a other against
+ this policy. It will check, wether \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 Policy.
+
+ \see policy_group
+ */
+ template
+ 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 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////////////////////////////////////////