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 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 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 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:
// This defines an incomplete policy where addressingPolicy and writePolicy // are unspecified typedef senf::MakeSocketPolicy< senf::StreamFramingPolicy, senf::ConnectedCommunicationPolicy, senf::ReadablePolicy >::policy MyReadableSocketPolicy typedef senf::ClientSocketHandle<MyReadableSocketPolicy> MyReadableHandle; // TCPv4ClientSocketHandle is a socket handle with the policy equivalent to // senf::MakeSocketPolicy< // INet4AddressingPolicy, // StreamFramingPolicy, // ConnectedCommunicationPolicy, // ReadablePolicy, // WritablePolicy>::policy senf::TCPv4ClientSocketHandle tcpHandle (...); MyReadableHandle myHandle (tcpHandle); // Conversion to more basic socket handle
In the following discussion we will use the following conventions:
AddressingPolicy
, FramingPolicy
, CommunicationPolicy
, ReadPolicy
or WritePolicy
Base
(ex: AddressingPolicyBase)Unspecified
Axis (ex: UnspecifiedAddressingPolicy)Base
Is
< socketPolicy, trait > (ex: AddressingPolicyIs)boost::true_type
, if trait (any class derived from Axis Base
) is a compatible policy value of the given socketPolicy
If
Axis Is
< socketPolicy, trait > (ex: IfAddressingPolicyIs)Is
and boost::enable_if
If
Axis IsNot
< socketPolicy, trait > (ex: IfAddressingPolicyIsNot)These classes form the basis of the policy framework. To bind the policy axis together, there are some more classes and templates.
class
SocketPolicyBase
template
SocketPolicy
< addressingPolicy, framingPolicy, communicationPolicy, readPolicy, writePolicy >template
MakeSocketPolicy
< args >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 Unspecified
Axis. Additionally, the first Argument may optionally be an arbitrary SocketPolicy. It will provide default values for unspecified axistemplate
SocketPolicyIsBaseOf
< base, derived >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.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:
struct ExampleAddressingPolicy { template <class SPolicy> void connect(senf::SocketHandle<SPolicy> handle, Address & addr, typename senf::IfCommmunicationPolicyIs< SPolicy, senf::ConnectedCommunicationPolicy>::type * = 0); };
The 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 (senf::ConnectedCommunicationPolicyIs
is based on the boost::enable_if
template).
Is
templates into a single template. Since the 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 SocketPolicyIsBaseOf
.#define | ||||
SENF_SOCKET_POLICIES | ||||
Value:
(AddressingPolicy) \ (FramingPolicy) \ (CommunicationPolicy) \ (ReadPolicy) \ (WritePolicy)
For internal use only.
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.
Definition at line 266 of file SocketPolicy.hh.
typedef AddressingPolicyBase senf:: | ||||
UnspecifiedAddressingPolicy | ||||
Alias of AddressingPolicyBase for better readability.
Definition at line 409 of file SocketPolicy.hh.