X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Socket%2FSocketPolicy.hh;h=708f18a3125fb7eabe23b48e228139efc6d6b335;hb=3cde315703150449c967936e3f064fa5928a1cc2;hp=91ee1bf5c8dd83919ea0670cede44cb92afafc8d;hpb=62464586315edf52fbcc613acb4a8a7e919fd8e2;p=senf.git diff --git a/Socket/SocketPolicy.hh b/Socket/SocketPolicy.hh index 91ee1bf..708f18a 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,387 @@ // 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 three new instances (The + handle, the body and the policy) of which two (body and + policy) live on the heap. This is expensive. We should check, + wether we can make 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 allocations per socket + handle to one. + */ + +/** \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 \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): + +
+
\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 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 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. + + + + + + + +
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 +417,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 + 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 Boost.enable_if + 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 + struct IfAddressingPolicyIs + {}; + + /** \brief Inversion of \c IfAddressingPolicyIs + \see policy_group + */ + template + 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 + 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////////////////////////////////////////