+// $Id$
+//
// Copyright (C) 2007
-// Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
-// Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
+// 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
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
- \brief Conenctors 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.
- */
+ \brief Connectors public header */
-#ifndef HH_Conenctors_
-#define HH_Conenctors_ 1
+#ifndef HH_Connectors_
+#define HH_Connectors_ 1
// Custom includes
+#include <deque>
#include <boost/utility.hpp>
-
-//#include "Conenctors.mpp"
+#include <boost/scoped_ptr.hpp>
+#include "../Utils/safe_bool.hh"
+#include "../Packets/Packets.hh"
+#include "predecl.hh"
+#include "detail/Callback.hh"
+#include "Queueing.hh"
+
+//#include "Connectors.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
namespace ppi {
namespace connector {
- /** \brief Connector baseclass
+ /** \namespace senf::ppi::connector
+ \brief 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:
+ \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 Connector base-class
This connector provides access to the generic connector facilities. This includes the
connection management (access to the connected peer) and the containment management (access
: boost::noncopyable
{
public:
- Connector & peer(); ///< Get peer connected to this connector
- Module & module(); ///< Get this connectors containing module
+ Connector & peer() const; ///< Get peer connected to this connector
+ module::Module & module() const; ///< Get this connectors containing module
protected:
- // here to protect
Connector();
- ~Connector();
+ virtual ~Connector();
+
+ void connect(Connector & target);
+
+ private:
+ void setModule(module::Module & module);
+
+ Connector * peer_;
+ module::Module * module_;
+
+ friend class module::Module;
};
- /** \brief Passive connector baseclass
+ /** \brief Passive connector base-class
A passive connector is a connector which is activated externally whenever an I/O request
occurs. Passive connectors are the origin of throttling notifications. Depending on the type
operation is to be performed. */
- bool throttled(); ///< Get accumulative throttling state
- bool nativeThrottled(); ///< Get native throttling state
+ bool throttled() const; ///< Get accumulative throttling state
+ bool nativeThrottled() const; ///< Get native throttling state
void throttle(); ///< Set native throttling
void unthrottle(); ///< Revoke native throttling
- void notifyThrottle(); ///< Forward a throttling notification to this connector
- void notifyUnthrottle(); ///< Forward an unthrottling notification to this connector
-
- ActiveConnector & peer();
+ ActiveConnector & peer() const;
protected:
- // here to protect
PassiveConnector();
- ~PassiveConnector();
+
+ void emit();
+
+ private:
+ // Called by the routing to change the remote throttling state
+ void notifyThrottle(); ///< Forward a throttle notification to this connector
+ void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
+
+ // Internal members to emit throttling notifications
+ void emitThrottle();
+ void emitUnthrottle();
+
+ // Called after unthrottling the connector
+ virtual void v_unthrottleEvent();
+
+ // called by ForwardingRoute to register a new route
+ void registerRoute(ForwardingRoute & route);
+
+ typedef ppi::detail::Callback<>::type Callback;
+ Callback callback_;
+
+ bool remoteThrottled_;
+ bool nativeThrottled_;
+
+ typedef std::vector<ForwardingRoute*> Routes;
+ Routes routes_;
+
+ friend class senf::ppi::ForwardingRoute;
};
- /** \brief Active connector baseclass
+ /** \brief Active connector base-class
An active connector is a connector which emits I/O requests. Active connectors receive
throttling notifications. Depending on the type of connector (input or output) the
class ActiveConnector
: public virtual Connector
{
+ typedef ppi::detail::Callback<>::type Callback;
public:
template <class Handler>
- void onThrottle(Handler handle); ///< Register throttle notification handler
+ void onThrottle(Handler handler); ///< Register throttle notification handler
/**< The handler register here will be called, whenever a
throttle notification comes in. The \a handler argument
is either an arbitrary callable object or it is a
\param[in] handler Handler to call on throttle
notifications. */
+ void onThrottle(); ///< Clear throttle notification handler
template <class Handler>
void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
\param[in] handler Handler to call on unthrottle
notifications. */
+ void onUnthrottle(); ///< Clear unthrottle notification handler
+
+ bool throttled() const; ///< \c true, if peer() is throttled
- PassiveConnector & peer();
+ PassiveConnector & peer() const;
protected:
- // here to protect
- PassiveConnector();
- ~PassiveConnector();
+ ActiveConnector();
+
+ private:
+ // called by the peer() to forward throttling notifications
+ void notifyThrottle();
+ void notifyUnthrottle();
+
+ // called by ForwardingRoute to register a new route
+ void registerRoute(ForwardingRoute & route);
+
+ Callback throttleCallback_;
+ Callback unthrottleCallback_;
+
+ typedef std::vector<ForwardingRoute*> NotifyRoutes;
+ NotifyRoutes notifyRoutes_;
+
+ friend class senf::ppi::ForwardingRoute;
+ friend class PassiveConnector;
};
- /** \brief Input connector baseclass
+ /** \brief Input connector base-class
An input connector receives packets. It may be either an ActiveConnector or a
PassiveConnector. An input connector contains a packet queue. This queue enables processing
insertion/removal properties on both ends.
So probably we will use a deque. I'd like a container which keeps iterators intact on
- isertion/deletion but I believe that list is just to expensive since every packet will
+ 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
: public virtual Connector
{
+ typedef std::deque<Packet> Queue;
public:
- typedef unspecified queue_iterator; ///< Iterator type of the embedded queue
- typedef unspecified size_type; ///< Unsigned type representing the number of queue elements
+ 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::ptr operator(); ///< Get a packet
+
+ Packet operator()(); ///< Get a packet
/**< This member is the primary method to access received
data. On passive connectors, this operator will just
dequeue a packet from the packet queue. If the
request cannot be fulfilled, this is considered to be a
logic error in the module implementation and an
exception is raised. */
- operator unspecified_boolean_type (); ///< Check packet availability
- /**< Using any input connector in a boolean context will
- check, wether an input request can be fulfilled. This
- is always possible if the queue is non-empty. If the
- input is active, it also returns when the connected
- passive output is not throttled so new packets can be
- requested.
-
- Calling the operator() member is an error if this test
- returns \c false
- \returns \c true if operator() can be called, \c false
- otherwise */
- operator ! (); ///< Check packet availability
- /**< Inverse of the boolean conversion operator
- \returns \c false if operator() can be called, \c true
- otherwise */
+ Packet read(); ///< Alias for operator()()
- OutputConnector & peer();
+ OutputConnector & peer() const;
- queue_iterator begin(); ///< Access queue begin (head)
- queue_iterator end(); ///< Access queue past-the-end (tail)
- Packet::ptr head(); ///< Return head element from the queue
+ queue_iterator begin() const; ///< Access queue begin (head)
+ queue_iterator end() const; ///< Access queue past-the-end (tail)
+ Packet peek() const; ///< Return head element from the queue
- size_type queueSize(); ///< Return number of elements in the queue
- bool empty(); ///< Return queueSize() == 0
+ size_type queueSize() const; ///< Return number of elements in the queue
+ bool empty() const; ///< Return queueSize() == 0
protected:
- // here to protect
- PassiveConnector();
- ~PassiveConnector();
+ InputConnector();
+
+ private:
+ void enqueue(Packet p);
+
+ virtual void v_requestEvent();
+ virtual void v_enqueueEvent();
+ virtual void v_dequeueEvent();
+
+ Queue queue_;
+
+ friend class OutputConnector;
};
- /** \brief Output connector baseclass
+ /** \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
: public virtual Connector
{
public:
- void operator(Packet::ptr); ///< Send out a packet
+ void operator()(Packet p); ///< Send out a packet
+
+ void write(Packet p); ///< Alias for operator()(Packet p)
- InputConnector & peer();
+ InputConnector & peer() const;
protected:
- // here to protect
- PassiveConnector();
- ~PassiveConnector();
+ OutputConnector();
};
- ///@{
- ///\addtogroup connectors
-
/** \brief Combination of PassiveConnector and InputConnector
- In addition to the native and the forwarded throttling state, the PassiveInput manages a
- queue throttling state. This state is automatically managed by 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 discpiline is
+ 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
- : public PassiveConnector, public InputConnector
+ class GenericPassiveInput
+ : public PassiveConnector, public InputConnector,
+ public safe_bool<GenericPassiveInput>
{
public:
- ActiveOutput & peer();
+ GenericActiveOutput & peer() const;
+
+ bool boolean_test() const; ///< \c true, if ! empty()
- template <class QueueingDiscipline>
- void qdisc(QueueingDiscipline const & disc); ///< Change the queueing discipline
+ template <class QDisc>
+ 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();
+ void v_unthrottleEvent();
+
+ boost::scoped_ptr<QueueingDiscipline> qdisc_;
};
/** \brief Combination of PassiveConnector and OutputConnector
*/
- class PassiveOutput
- : public PassiveConnector, public OutputConnector
+ class GenericPassiveOutput
+ : public PassiveConnector, public OutputConnector,
+ public safe_bool<GenericPassiveOutput>
{
public:
- ActiveInput & peer();
+ GenericActiveInput & peer() const;
+
+ bool boolean_test() const; ///< Always \c true
+
+ void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
+
+ friend class GenericActiveInput;
+
+ protected:
+ GenericPassiveOutput();
+
};
/** \brief Combination of ActiveConnector and InputConnector
*/
- class ActiveInput
- : public ActiveConnector, public InputConnector
+ class GenericActiveInput
+ : public ActiveConnector, public InputConnector,
+ public safe_bool<GenericActiveInput>
{
public:
- PassiveOutput & peer();
+ GenericPassiveOutput & peer() const;
+
+ bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
+
+ void request(); ///< request more packets without dequeuing any packet
+
+ protected:
+ GenericActiveInput();
- void request(); ///< request more packets without dequeing any packet
+ private:
+ void v_requestEvent();
};
/** \brief Combination of ActiveConnector and OutputConnector
*/
- class ActiveOutput
- : public ActiveConnector, public OutputConnector
+ class GenericActiveOutput
+ : public ActiveConnector, public OutputConnector,
+ public safe_bool<GenericActiveOutput>
+ {
+ public:
+ GenericPassiveInput & peer() const;
+
+ bool boolean_test() const; ///< \c true if peer() is ! throttled()
+
+ void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
+
+ protected:
+ GenericActiveOutput();
+
+ };
+
+#ifndef DOXYGEN
+
+# define TypedConnector_Input read
+# define TypedConnector_Output write
+# define TypedConnector(type, dir) \
+ template <class PacketType> \
+ class type ## dir \
+ : public Generic ## type ## dir, \
+ private detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType> \
+ { \
+ typedef detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType> mixin; \
+ public: \
+ using mixin::operator(); \
+ using mixin::TypedConnector_ ## dir ; \
+ }; \
+ template <> \
+ class type ## dir <Packet> : public Generic ## type ## 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
+
+ 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::connectro
+ */
+ template <class PacketType>
+ class ActiveInput : public GenericActiveInput
{
public:
- ActiveInput & peer();
+ 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
+
+ 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
+
+ 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>
+ class ActiveOutput : public GenericActiveOutput
+ {
+ public:
+ PacketType operator()();
+ PacketType write();
+ };
+
+ /** \brief Connector passively providing packets
+
+ 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>
+ class PassiveOutput : public GenericPassiveOutput
+ {
+ public:
+ PacketType operator()();
+ PacketType write();
+ };
+
+#endif
}}}
///////////////////////////////hh.e////////////////////////////////////////
-//#include "Conenctors.cci"
-//#include "Conenctors.ct"
-//#include "Conenctors.cti"
+#include "Connectors.cci"
+//#include "Connectors.ct"
+#include "Connectors.cti"
#endif
\f
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// comment-column: 40
// End: