// 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
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
-
-
+
+ /// \addtogroup handle_group
+ /// @{
+
template <class Policy> class ServerSocketHandle;
/** \brief
friend class senf::ServerSocketHandle<Policy>;
};
+ /// @}
}
///////////////////////////////hh.e////////////////////////////////////////
\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
#include "FileHandle.ih"
namespace senf {
-
+
+ /// \addtogroup handle_group
+ /// @{
/** \brief Basic file handle wrapper
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////////////////////////////////////////
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
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
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
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
namespace senf {
+ /// \addtogroup handle_group
+ /// @{
template <class Protocol> class ProtocolServerSocketHandle;
friend class ProtocolServerSocketHandle<Protocol>;
};
+ /// @}
}
///////////////////////////////hh.e////////////////////////////////////////
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
-
-
+
+ /// \addtogroup handle_group
+ /// @{
+
template <class Protocol> class ProtocolClientSocketHandle;
/** \brief
};
+ /// @}
}
///////////////////////////////hh.e////////////////////////////////////////
namespace senf {
+ /// \addtogroup handle_group
+ /// @{
template <class Policy> class ClientSocketHandle;
};
+ /// @}
}
///////////////////////////////hh.e////////////////////////////////////////
{
// 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);
}
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);
}
namespace senf {
+ /// \addtogroup handle_group
+ /// @{
/** \brief basic SocketHandle supporting protocol and policy abstraction
\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);
*/
template <class Target, class Source>
bool check_socket_cast(Source handle);
+
+ /// @}
}
///////////////////////////////hh.e////////////////////////////////////////
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
"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////////////////////////////////////////
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
//
// 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
// 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):
// 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////////////////////////////////////////
#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) \
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()
# 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
}
+/// \endcond
+
///////////////////////////////ih.e////////////////////////////////////////
#endif
// 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
namespace senf {
+ /// \addtogroup protocol_group
+ /// @{
class SocketPolicyBase;
};
+ /// @}
}
///////////////////////////////hh.e////////////////////////////////////////
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
EXTRACT_STATIC = YES
INTERNAL_DOCS = YES
SOURCE_BROWSER = YES
-STRIP_CODE_COMMENTS = NO
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 3
--- /dev/null
+#!/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