-// Copyright (C) 2007
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// $Id$
+//
+// Copyright (C) 2007
+// Fraunhofer Institute for Open Communication Systems (FOKUS)
+// Competence Center NETwork research (NET), St. Augustin, GERMANY
// Stefan Bund <g0dil@berlios.de>
//
// This program is free software; you can redistribute it and/or modify
/** \file
\brief Connectors public header */
-/** \defgroup connectors Connector classes
-
- A connector has two independent properties
- \li it may be \e active or \e passive
- \li it may be an \e input or an \e output
-
- \e Active connectors are activated from within the module, \e passive connectors are signaled by
- the external framework. \e Input modules receive packets, \e output modules send packets.
-
- All passive connectors call some onRequest callback whenever I/O needs to be performed. All
- input modules possess a packet queue.
-
- We therefore have 4 connector types: senf::ppi::ActiveInput, senf::ppi::ActiveOutput,
- senf::ppi::PassiveInput and senf::ppi::PassiveOutput.
- */
-
#ifndef HH_Connectors_
#define HH_Connectors_ 1
#include <deque>
#include <boost/utility.hpp>
#include <boost/scoped_ptr.hpp>
-#include "Utils/SafeBool.hh"
-#include "Packets/Packets.hh"
+#include "../Utils/safe_bool.hh"
+#include "../Utils/Exception.hh"
+#include "../Packets/Packets.hh"
#include "predecl.hh"
#include "detail/Callback.hh"
#include "Queueing.hh"
namespace connector {
/** \namespace senf::ppi::connector
- \brief Connector classes
+ \brief Connector classes
+
+ A connector has three independent properties
+ \li it may be \e active or \e passive
+ \li it may be an \e input or an \e output
+ \li it has an (optional) packet type
+
+ \e Active connectors are activated from within the module, \e passive connectors are
+ signaled by the external framework. \e Input modules receive packets, \e output modules send
+ packets.
+
+ All passive connectors call some onRequest callback whenever I/O needs to be performed. All
+ input modules possess a packet queue.
+
+ We therefore have 4 connector types each of which is parameterized by the type of packet
+ traversing the connector:
+ \li senf::ppi::connector::ActiveInput
+ \li senf::ppi::connector::ActiveOutput
+ \li senf::ppi::connector::PassiveInput
+ \li senf::ppi::connector::PassiveOutput.
+
+ Connectors are declared as module data members and are then externally connected to other
+ modules.
+
+ The connectors each take an optional template argument. If this argument is specified, it
+ must be the type of packet expected or sent on this connector. If it is not specified,
+ packets will be passed using the generic Packet handle.
+
+ \code
+ class IpFilter : public senf::ppi::module::Module
+ {
+ SENF_PPI_MODULE(SomeModule);
+
+ public:
+ senf::ppi::connector::ActiveInput<senf::EthernetPacket> input;
+ senf::ppi::connector::PassiveOutput<senf::IpPacket> output;
+
+ IpFilter() {
+ route(input, output);
+ input.onRequest(&IpFilter::onRequest);
+ }
+
+ private:
+ void onRequest() {
+ // 'input()' will return a senf::EthernetPacket packet handle
+ try { output( input().find<IpPacket>() ); }
+ catch (senf::InvalidPacketChainException & ex) { ; }
+ }
+ };
+ \endcode
+
+ \see
+ senf::ppi::module::Module \n
+ senf::ppi::connect() \n
+ \ref ppi_connectors
+ */
+
+ /** \brief Incompatible connectors connected
+
+ This exception is thrown, when two incompatible connectors are connected. This happens if
+ both connectors of a senf::ppi::connect() statement declare a packet type (the connector
+ template argument) but they don't declare the same packet type.
+
+ You need to ensure, that both connectors use the same packet type.
+
+ \see senf::ppi::connect()
*/
+ struct IncompatibleConnectorsException : public senf::Exception
+ { IncompatibleConnectorsException() : senf::Exception("Incompatible connectors") {} };
/** \brief Connector base-class
void connect(Connector & target);
private:
+ virtual std::type_info const & packetTypeID();
+
void setModule(module::Module & module);
Connector * peer_;
of connector (output or input) the respective throttling is called forward or backward
throttling.
- Passive connectors always handle two throttling states:
-
- \li The \e native throttling state is set manually by the module. It is the throttling state
+ Passive connectors always handle two throttling states:
+
+ - The \e native throttling state is set manually by the module. It is the throttling state
originating in the current module
- \li The \e forwarded throttling state is the state as it is received by throttling
+ - The \e forwarded throttling state is the state as it is received by throttling
notifications
The accumulative throttling state is generated by combining all sub-states.
*/
- class PassiveConnector
+ class PassiveConnector
: public virtual Connector
{
public:
is a pointer-to-member to a member of the class which
holds this input. In the second case, the pointer will
automatically be bound to the containing instance.
-
+
\param[in] handler Handler to call, whenever an I/O
operation is to be performed. */
-
+
bool throttled() const; ///< Get accumulative throttling state
bool nativeThrottled() const; ///< Get native throttling state
void throttle(); ///< Set native throttling
void unthrottle(); ///< Revoke native throttling
-
+
ActiveConnector & peer() const;
protected:
// called by ForwardingRoute to register a new route
void registerRoute(ForwardingRoute & route);
- typedef detail::Callback<>::type Callback;
+ typedef ppi::detail::Callback<>::type Callback;
Callback callback_;
bool remoteThrottled_;
notifications. These notifications should then either be processed by the module or be
forwarded to other connectors.
*/
- class ActiveConnector
+ class ActiveConnector
: public virtual Connector
{
- typedef detail::Callback<>::type Callback;
+ typedef ppi::detail::Callback<>::type Callback;
public:
template <class Handler>
void onThrottle(Handler handler); ///< Register throttle notification handler
holds this input. In the second case, the pointer will
automatically be bound to the containing instance.
- \param[in] handle Handler to call on unthrottle
+ \param[in] handler Handler to call on unthrottle
notifications. */
void onUnthrottle(); ///< Clear unthrottle notification handler
insertion/deletion but I believe that list is just to expensive since every packet will
be added to the queue before it can be processed.
*/
- class InputConnector
+ class InputConnector
: public virtual Connector
{
typedef std::deque<Packet> Queue;
typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
+
Packet operator()(); ///< Get a packet
/**< This member is the primary method to access received
data. On passive connectors, this operator will just
logic error in the module implementation and an
exception is raised. */
+ Packet read(); ///< Alias for operator()()
+
OutputConnector & peer() const;
queue_iterator begin() const; ///< Access queue begin (head)
protected:
InputConnector();
-
+
private:
void enqueue(Packet p);
-
+
virtual void v_requestEvent();
virtual void v_enqueueEvent();
virtual void v_dequeueEvent();
friend class OutputConnector;
};
-
+
/** \brief Output connector base-class
-
+
An output connector sends out packets. It may be either an ActiveConnector or a
PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
the queueing of the connected input.
*/
- class OutputConnector
+ class OutputConnector
: public virtual Connector
{
public:
- void operator()(Packet p); ///< Send out a packet
+ void operator()(Packet p); ///< Send out a packet
+
+ void write(Packet p); ///< Alias for operator()(Packet p)
InputConnector & peer() const;
protected:
OutputConnector();
};
-
- ///@{
- ///\addtogroup connectors
/** \brief Combination of PassiveConnector and InputConnector
- The PassiveInput automatically controls the connectors throttling state using a queueing
- discipline. The standard queueing discipline is ThresholdQueueing, which throttles the
- connection whenever the queue length reaches the high threshold and unthrottles the
+ The GenericPassiveInput automatically controls the connectors throttling state using a
+ queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
+ the connection whenever the queue length reaches the high threshold and unthrottles the
connection when the queue reaches the low threshold. The default queueing discipline is
<tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
non-empty.
*/
- class PassiveInput
+ class GenericPassiveInput
: public PassiveConnector, public InputConnector,
- public SafeBool<PassiveInput>
+ public safe_bool<GenericPassiveInput>
{
public:
- PassiveInput();
-
- ActiveOutput & peer() const;
+ GenericActiveOutput & peer() const;
bool boolean_test() const; ///< \c true, if ! empty()
void qdisc(QDisc const & disc); ///< Change the queueing discipline
/**< The queueing discipline is a class which provides the
QueueingDiscipline interface.
-
+
\param[in] disc New queueing discipline */
+ protected:
+ GenericPassiveInput();
+
private:
void v_enqueueEvent();
void v_dequeueEvent();
/** \brief Combination of PassiveConnector and OutputConnector
*/
- class PassiveOutput
+ class GenericPassiveOutput
: public PassiveConnector, public OutputConnector,
- public SafeBool<PassiveOutput>
+ public safe_bool<GenericPassiveOutput>
{
public:
- ActiveInput & peer() const;
+ GenericActiveInput & peer() const;
bool boolean_test() const; ///< Always \c true
- void connect(ActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
+ void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
+
+ friend class GenericActiveInput;
+
+ protected:
+ GenericPassiveOutput();
- friend class ActiveInput;
};
/** \brief Combination of ActiveConnector and InputConnector
*/
- class ActiveInput
+ class GenericActiveInput
: public ActiveConnector, public InputConnector,
- public SafeBool<ActiveInput>
+ public safe_bool<GenericActiveInput>
{
public:
- PassiveOutput & peer() const;
+ GenericPassiveOutput & peer() const;
bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
void request(); ///< request more packets without dequeuing any packet
+ protected:
+ GenericActiveInput();
+
private:
void v_requestEvent();
};
/** \brief Combination of ActiveConnector and OutputConnector
*/
- class ActiveOutput
+ class GenericActiveOutput
: public ActiveConnector, public OutputConnector,
- public SafeBool<ActiveOutput>
+ public safe_bool<GenericActiveOutput>
{
public:
- PassiveInput & peer() const;
+ GenericPassiveInput & peer() const;
bool boolean_test() const; ///< \c true if peer() is ! throttled()
- void connect(PassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
+ void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
+
+ protected:
+ GenericActiveOutput();
+
+ };
+
+#ifndef DOXYGEN
+
+# define TypedConnector_Input read
+# define TypedConnector_Output write
+# define TypedConnector(pType, dir) \
+ template <class PacketType> \
+ class pType ## dir \
+ : public Generic ## pType ## dir, \
+ private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
+ { \
+ typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
+ public: \
+ using mixin::operator(); \
+ using mixin::TypedConnector_ ## dir ; \
+ private: \
+ virtual std::type_info const & packetTypeID() \
+ { return typeid(typename PacketType::type); } \
+ friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
+ }; \
+ template <> \
+ class pType ## dir <Packet> : public Generic ## pType ## dir \
+ {}
+
+ TypedConnector( Passive, Input );
+ TypedConnector( Passive, Output );
+ TypedConnector( Active, Input );
+ TypedConnector( Active, Output );
+
+# undef TypedConnector
+# undef TypedConnector_Input
+# undef TypedConnector_Output
+
+#else
+
+ /** \brief Connector actively reading packets
+
+ \tparam PacketType Type of packet to read. Defaults to senf::Packet
+
+ The %ActiveInput %connector template reads data actively from a connected %module. This
+ class is completely implemented via it's base-class, GenericActiveInput, the only
+ difference is that read packets are returned as \a PacketType instead of generic
+ senf::Packet references.
+
+ \see GenericActiveInput \n
+ senf::ppi::connector
+ */
+ template <class PacketType=Packet>
+ class ActiveInput : public GenericActiveInput
+ {
+ public:
+ PacketType operator()(); ///< Read packet
+ /**< \throws std::bad_cast, if the %connector receives a
+ Packet which is not of type \a PacketType.
+ \returns newly read packet reference. */
+ PacketType read(); ///< Alias for operator()
+ };
+
+ /** \brief Connector passively receiving packets
+
+ \tparam PacketType Type of packet to read. Defaults to senf::Packet
+
+ The %PassiveInput %connector template receives packets sent to it from a connected
+ %module. This class is completely implemented via it's base-class, GenericPassiveInput,
+ the only difference is that read packets are returned as \a PacketType instead of generic
+ senf::Packet references.
+
+ \see GenericPassiveInput \n
+ senf::ppi::connector
+ */
+ template <class PacketType=Packet>
+ class PassiveInput : public GenericPassiveInput
+ {
+ public:
+ PacketType operator()(); ///< Read packet
+ /**< \throws std::bad_cast, if the %connector receives a
+ Packet which is not of type \a PacketType.
+ \returns newly read packet reference. */
+ PacketType read(); ///< Alias for operator()
+ };
+
+ /** \brief Connector actively sending packets
+
+ \tparam PacketType Type of packet to send. Defaults to senf::Packet
+
+ The %ActiveOutput %connector template sends data actively to a connected %module. This
+ class is completely implemented via it's base-class, GenericActiveOutput, the only
+ difference is that it only sends packets of type \a PacketType.
+
+ \see GenericActiveOutput \n
+ senf::ppi::connector
+ */
+ template <class PacketType=Packet>
+ class ActiveOutput : public GenericActiveOutput
+ {
+ public:
+ operator()(PacketType packet); ///< Send out a packet
+ write(PacketType packet); ///< Alias for operator()
};
- ///@}
+ /** \brief Connector passively providing packets
+
+ \tparam PacketType Type of packet to send. Defaults to senf::Packet
+
+ The %PassiveOutput %connector template provides data passively to a connected %module
+ whenever signaled. This class is completely implemented via it's base-class,
+ GenericPassiveOutput, the only difference is that it only sends packets of type
+ \a PacketType.
+
+ \see GenericPassiveOutput \n
+ senf::ppi::connector
+ */
+ template <class PacketType=Packet>
+ class PassiveOutput : public GenericPassiveOutput
+ {
+ public:
+ operator()(PacketType packet); ///< Send out a packet
+ write(PacketType packet); ///< Alias for operator()
+ };
+
+#endif
}}}