X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=PPI%2FConnectors.hh;h=78b7023f1d6cacef07bc159c710af7c0de005019;hb=bd9f9d3fd6fbcff0112a7bf48ab9284da9576b11;hp=6ca4aa5fd12e66d4c83e531cf1c5a6e2a6866e93;hpb=b356790e396900fd46a677b39f4e182822bb5c1f;p=senf.git diff --git a/PPI/Connectors.hh b/PPI/Connectors.hh index 6ca4aa5..78b7023 100644 --- a/PPI/Connectors.hh +++ b/PPI/Connectors.hh @@ -1,6 +1,8 @@ -// 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 // // This program is free software; you can redistribute it and/or modify @@ -21,34 +23,20 @@ /** \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 +#ifndef HH_SENF_PPI_Connectors_ +#define HH_SENF_PPI_Connectors_ 1 // Custom includes #include #include #include -#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" +#include "ModuleManager.hh" //#include "Connectors.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -57,26 +45,139 @@ namespace senf { namespace ppi { namespace connector { - /** \brief Connector baseclass + /** \namespace senf::ppi::connector + \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 connectors receive packets, \e output + connectors send packets. + + All passive connectors call some onRequest callback whenever I/O needs to be performed. All + input connectors 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 input; + senf::ppi::connector::PassiveOutput output; + + IpFilter() { + route(input, output); + input.onRequest(&IpFilter::onRequest); + } + + private: + void onRequest() { + // 'input()' will return a senf::EthernetPacket packet handle + try { output( input().find() ); } + catch (senf::InvalidPacketChainException & ex) { ; } + } + }; + \endcode + + + \section ppi_jacks Jacks + + A Jack is a packet type aware and possibly packet type converting reference to an arbitrary + connector of the same type. Jacks are used in groups to indirectly declare the input's and + output's + + \code + class MyGroup + { + private: + senf::ppi::module::PassiveQueue queue; + senf::ppi::module::RateAnalyzer analyzer; + + public: + senf::ppi::connector::ActiveInputJack input; + senf::ppi::connector::ActiveOutputJack output; + + MyGroup() + : queue (), analyzer (), input (queue.input), output (analyzer.output) + { + senf::ppi::connect(queue, analyzer); + } + }; + \endcode + + The jacks are initialized by passing an arbitrary compatible connector to the jack + constructor. A connector is compatible, if + \li It has the same input/output active/passive specification + \li Either the Jack or the Connector are generic (senf::Packet) or Jack and Connector have + the same packet type + + Jacks can be used wherever connectors may be used. Jacks may be defined anywhere, not only + in modules. It is however important to ensure that the lifetime of the jack does not exceed + the lifetime of the referenced connector. + + \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 This connector provides access to the generic connector facilities. This includes the connection management (access to the connected peer) and the containment management (access to the containing module) */ class Connector - : boost::noncopyable + : ModuleManager::Initializable, boost::noncopyable { public: - Connector & peer(); ///< Get peer connected to this connector - module::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 + + bool connected() const; ///< \c true, if connector connected, \c false otherwise + + void disconnect(); ///< Disconnect connector from peer protected: Connector(); virtual ~Connector(); void connect(Connector & target); - + private: + virtual std::type_info const & packetTypeID(); + void setModule(module::Module & module); Connector * peer_; @@ -85,23 +186,23 @@ namespace connector { 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 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: @@ -114,18 +215,18 @@ namespace connector { 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(); ///< 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 - - ActiveConnector & peer(); + + ActiveConnector & peer() const; protected: PassiveConnector(); @@ -133,16 +234,35 @@ namespace connector { void emit(); private: - void notifyThrottle(); ///< Forward a throttling notification to this connector - void notifyUnthrottle(); ///< Forward an unthrottling notification to this connector + virtual void v_init(); + + // 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 - typedef detail::Callback<>::type Callback; + // 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_; - - friend class ActiveConnector; + + bool remoteThrottled_; + bool nativeThrottled_; + + typedef std::vector 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 @@ -152,12 +272,13 @@ namespace connector { 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 ppi::detail::Callback<>::type Callback; public: template - 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 @@ -165,11 +286,12 @@ namespace connector { this input. In the second case, the pointer will automatically be bound to the containing instance. - \param[in] handle Handler to call on throttle + \param[in] handler Handler to call on throttle notifications. */ + void onThrottle(); ///< Clear throttle notification handler template - void onUnthrottle(Handler handle); ///< Register unthrottle notification handler + void onUnthrottle(Handler handler); ///< Register unthrottle notification handler /**< The handler register here will be called, whenever an unthrottle notification comes in. The \a handler argument is either an arbitrary callable object or it @@ -177,16 +299,40 @@ namespace connector { 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 - PassiveConnector & peer(); + bool throttled() const; ///< \c true, if peer() is throttled + + PassiveConnector & peer() const; protected: ActiveConnector(); + + private: + virtual void v_init(); + + // 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 NotifyRoutes; + NotifyRoutes notifyRoutes_; + + bool throttled_; + + 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 @@ -203,18 +349,18 @@ namespace connector { 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, - public SafeBool + class InputConnector + : public virtual Connector { typedef std::deque Queue; public: 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 @@ -224,35 +370,24 @@ namespace connector { request cannot be fulfilled, this is considered to be a logic error in the module implementation and an exception is raised. */ - bool boolean_test (); ///< Check packet availability - /**< Using any input connector in a boolean context will - check, whether 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 */ + 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 peek(); ///< 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: InputConnector(); - + private: - void enqueue(Packet p); - + void enqueue(Packet const & p); + virtual void v_requestEvent(); virtual void v_enqueueEvent(); virtual void v_dequeueEvent(); @@ -261,100 +396,241 @@ namespace connector { 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 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 const & p); ///< Send out a packet + + void write(Packet const & p); ///< Alias for operator()(Packet p) - InputConnector & peer(); + InputConnector & peer() const; protected: 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 discipline 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 ThresholdQueueing(1,0) 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 { public: - PassiveInput(); + GenericActiveOutput & peer() const; - ActiveOutput & peer(); + bool boolean_test() const; ///< \c true, if ! empty() template 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 qdisc_; - QueueingDiscipline::State qstate_; }; /** \brief Combination of PassiveConnector and OutputConnector */ - class PassiveOutput - : public PassiveConnector, public OutputConnector + class GenericPassiveOutput + : public PassiveConnector, public OutputConnector, + public safe_bool { public: - ActiveInput & peer(); + GenericActiveInput & peer() const; + + bool boolean_test() const; ///< Always \c true + + void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead - void connect(ActiveInput & target); + friend class GenericActiveInput; + + protected: + GenericPassiveOutput(); - friend class ActiveInput; }; /** \brief Combination of ActiveConnector and InputConnector */ - class ActiveInput - : public ActiveConnector, public InputConnector + class GenericActiveInput + : public ActiveConnector, public InputConnector, + public safe_bool { 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(); + 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 { public: - PassiveInput & peer(); + GenericPassiveInput & peer() const; + + bool boolean_test() const; ///< \c true if peer() is ! throttled() - void connect(PassiveInput & target); + 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 pType ## dir \ + : public Generic ## pType ## dir, \ + private detail::Typed ## dir ## Mixin, PacketType> \ + { \ + typedef detail::Typed ## dir ## Mixin, 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, PacketType>; \ + }; \ + template <> \ + class pType ## dir : 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 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 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 ActiveOutput : public GenericActiveOutput + { + public: + operator()(PacketType packet); ///< Send out a packet + void 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 PassiveOutput : public GenericPassiveOutput + { + public: + operator()(PacketType packet); ///< Send out a packet + void write(PacketType packet); ///< Alias for operator() + }; + +#endif }}}