From: g0dil Date: Fri, 18 Jan 2008 21:35:21 +0000 (+0000) Subject: PPI: Made 'Generic' connector constructors protected X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=69255c0f1669fc80b0e4a2bf524715f336b127ad;p=senf.git PPI: Made 'Generic' connector constructors protected PPI: Added/updated new connector documentation Packets: Updated packet navigation documentation git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@630 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/PPI/Connectors.cci b/PPI/Connectors.cci index 9e0f832..74270ec 100644 --- a/PPI/Connectors.cci +++ b/PPI/Connectors.cci @@ -317,6 +317,9 @@ prefix_ void senf::ppi::connector::GenericPassiveOutput::connect(GenericActiveIn Connector::connect(target); } +prefix_ senf::ppi::connector::GenericPassiveOutput::GenericPassiveOutput() +{} + /////////////////////////////////////////////////////////////////////////// // senf::ppi::connector::GenericActiveInput @@ -337,6 +340,9 @@ prefix_ void senf::ppi::connector::GenericActiveInput::request() peer().emit(); } +prefix_ senf::ppi::connector::GenericActiveInput::GenericActiveInput() +{} + /////////////////////////////////////////////////////////////////////////// // senf::ppi::connector::GenericActiveOutput @@ -357,6 +363,9 @@ prefix_ void senf::ppi::connector::GenericActiveOutput::connect(GenericPassiveIn Connector::connect(target); } +prefix_ senf::ppi::connector::GenericActiveOutput::GenericActiveOutput() +{} + ///////////////////////////////cci.e/////////////////////////////////////// #undef prefix_ diff --git a/PPI/Connectors.hh b/PPI/Connectors.hh index 1a20891..52663cc 100644 --- a/PPI/Connectors.hh +++ b/PPI/Connectors.hh @@ -66,9 +66,36 @@ namespace connector { 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 + \see senf::ppi::module::Module \n - senf::ppi::connect() + senf::ppi::connect() \n \ref ppi_connectors */ @@ -327,9 +354,9 @@ namespace connector { /** \brief Combination of PassiveConnector and InputConnector - 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 + 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. @@ -339,8 +366,6 @@ namespace connector { public safe_bool { public: - GenericPassiveInput(); - GenericActiveOutput & peer() const; bool boolean_test() const; ///< \c true, if ! empty() @@ -352,6 +377,9 @@ namespace connector { \param[in] disc New queueing discipline */ + protected: + GenericPassiveInput(); + private: void v_enqueueEvent(); void v_dequeueEvent(); @@ -374,6 +402,10 @@ namespace connector { void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead friend class GenericActiveInput; + + protected: + GenericPassiveOutput(); + }; /** \brief Combination of ActiveConnector and InputConnector @@ -389,6 +421,9 @@ namespace connector { void request(); ///< request more packets without dequeuing any packet + protected: + GenericActiveInput(); + private: void v_requestEvent(); }; @@ -405,29 +440,118 @@ namespace connector { bool boolean_test() const; ///< \c true if peer() is ! throttled() void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead + + protected: + GenericActiveOutput(); + }; -# define TypedConnector(Name, Mixin, dir) \ +#ifndef DOXYGEN + +# define TypedConnector_Input read +# define TypedConnector_Output write +# define TypedConnector(type, dir) \ template \ - class Name \ - : public Generic ## Name, detail::TypedInputMixin, PacketType> \ + class type ## dir \ + : public Generic ## type ## dir, \ + private detail::Typed ## dir ## Mixin, PacketType> \ { \ - typedef detail::TypedInputMixin, PacketType> mixin; \ + typedef detail::Typed ## dir ## Mixin, PacketType> mixin; \ public: \ using mixin::operator(); \ - using mixin:: dir ; \ + using mixin::TypedConnector_ ## dir ; \ }; \ template <> \ - class Name \ - : public Generic ## Name \ + class type ## dir : public Generic ## type ## dir \ {} - TypedConnector(PassiveInput, TypedInputMixin, read); - TypedConnector(PassiveOutput, TypedOutputMixin, write); - TypedConnector(ActiveInput, TypedInputMixin, read); - TypedConnector(ActiveOutput, TypedOutputMixin, write); + 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 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 + + 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 + + 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: + 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 PassiveOutput : public GenericPassiveOutput + { + public: + PacketType operator()(); + PacketType write(); + }; + +#endif }}} diff --git a/PPI/Connectors.test.cc b/PPI/Connectors.test.cc index 9a8b93b..16c76ea 100644 --- a/PPI/Connectors.test.cc +++ b/PPI/Connectors.test.cc @@ -158,17 +158,17 @@ BOOST_AUTO_UNIT_TEST(outputConnector) namespace { - class GenericPassiveInputTest + class PassiveInputTest : public ppi::module::Module { - SENF_PPI_MODULE(GenericPassiveInputTest); + SENF_PPI_MODULE(PassiveInputTest); public: - ppi::connector::GenericPassiveInput input; + ppi::connector::PassiveInput<> input; - GenericPassiveInputTest() : counter() { + PassiveInputTest() : counter() { noroute(input); - input.onRequest(&GenericPassiveInputTest::request); + input.onRequest(&PassiveInputTest::request); } void request() { @@ -182,7 +182,7 @@ namespace { BOOST_AUTO_UNIT_TEST(passiveInput) { debug::ActiveSource source; - GenericPassiveInputTest target; + PassiveInputTest target; ppi::connect(source,target); ppi::init(); diff --git a/PPI/Joins.cc b/PPI/Joins.cc index fb8defd..3f15955 100644 --- a/PPI/Joins.cc +++ b/PPI/Joins.cc @@ -42,10 +42,10 @@ //////////////////////////////////////// // private members -prefix_ senf::ppi::connector::GenericPassiveInput & senf::ppi::module::PassiveJoin::newInput() +prefix_ senf::ppi::connector::PassiveInput<> & senf::ppi::module::PassiveJoin::newInput() { - inputs_.push_back(new connector::GenericPassiveInput()); - connector::GenericPassiveInput & input (inputs_.back()); + inputs_.push_back(new connector::PassiveInput<>()); + connector::PassiveInput<> & input (inputs_.back()); noroute(input); input.onRequest(boost::bind(&PassiveJoin::request,this,boost::ref(input))); @@ -80,10 +80,10 @@ prefix_ void senf::ppi::module::PassiveJoin::onUnthrottle() //////////////////////////////////////// // private members -prefix_ senf::ppi::connector::GenericActiveInput & senf::ppi::module::PriorityJoin::newInput() +prefix_ senf::ppi::connector::ActiveInput<> & senf::ppi::module::PriorityJoin::newInput() { - inputs_.push_back(new connector::GenericActiveInput()); - connector::GenericActiveInput & input (inputs_.back()); + inputs_.push_back(new connector::ActiveInput<>()); + connector::ActiveInput<> & input (inputs_.back()); noroute(input); input.onThrottle(&PriorityJoin::onThrottle); diff --git a/PPI/Joins.hh b/PPI/Joins.hh index f7c1c3e..3f7087c 100644 --- a/PPI/Joins.hh +++ b/PPI/Joins.hh @@ -53,8 +53,8 @@ namespace module { /** \brief Join multiple packet streams with passive inputs The PassiveJoin will combine any number of packet streams. You may connect any number of - GenericActiveOutput's to the PassiveJoin instance. The combined stream is then provided on the - GenericActiveOutput \a output. + ActiveOutput<>'s to the PassiveJoin instance. The combined stream is then provided on the + ActiveOutput<> \a output. Since PassiveJoin allows any number of incoming packet streams, the input connectors are dynamically managed. A special senf::ppi::connect() overload is used to dynamically create @@ -74,12 +74,12 @@ namespace module { { SENF_PPI_MODULE(PassiveJoin); public: - connector::GenericActiveOutput output; + connector::ActiveOutput<> output; PassiveJoin(); private: - connector::GenericPassiveInput & newInput(); + connector::PassiveInput<> & newInput(); #ifndef DOXYGEN // I didn't get template friend functions to work ... @@ -93,15 +93,15 @@ namespace module { void onThrottle(); void onUnthrottle(); - typedef boost::ptr_vector Inputs; + typedef boost::ptr_vector > Inputs; Inputs inputs_; }; /** \brief Join multiple packet streams with active inputs The PriorityJoin will combine any number of packet streams. You may connect any number of - GenericPassiveInput's to the PassiveJoin instance. The combined stream is then provided on the - GenericPassiveOutput \a output. + PassiveInput<>'s to the PassiveJoin instance. The combined stream is then provided on the + PassiveOutput<> \a output. When a packet request is received on Priorityjoin's \a output, The request will be serviced from the first unthrottled input. The order, in which connectors are connected to the @@ -128,12 +128,12 @@ namespace module { { SENF_PPI_MODULE(PriorityJoin); public: - connector::GenericPassiveOutput output; + connector::PassiveOutput<> output; PriorityJoin(); private: - connector::GenericActiveInput & newInput(); + connector::ActiveInput<> & newInput(); #ifndef DOXYGEN public: @@ -146,7 +146,7 @@ namespace module { void onThrottle(); void onUnthrottle(); - typedef boost::ptr_vector Inputs; + typedef boost::ptr_vector > Inputs; Inputs inputs_; }; diff --git a/PPI/Mainpage.dox b/PPI/Mainpage.dox index 3d18f4a..f4d8be7 100644 --- a/PPI/Mainpage.dox +++ b/PPI/Mainpage.dox @@ -1,8 +1,8 @@ // $Id$ // -// Copyright (C) 2007 -// Fraunhofer Institute for Open Communication Systems (FOKUS) -// Competence Center NETwork research (NET), St. Augustin, GERMANY +// 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 @@ -26,7 +26,7 @@ PPI application is built by combining processing modules in a very flexible manner. \image html scenario.png Target Scenario - + The PPI concept is built around some key concepts \li The PPI is based on processing \ref ppi_packets. It does not handle stream oriented @@ -37,7 +37,7 @@ \li Data flow throughout the network is governed via flexible automatic or manual \ref ppi_throttling (throttle notifications). \li Modules may register additional external \ref ppi_events (file descriptor events or timers). - + The PPI thereby builds on the facilities provided by the other components of the SENF framework. The target scenario above depicts a diffserv capable UDLR/ULE router including performance optimizations for TCP traffic (PEP). This router is built by combining several @@ -73,7 +73,7 @@ The PPI interface is designed to be as simple as possible. It provides sane defaults for all configurable parameters to simplify getting started. It also automates all resource management. The throttling infrastructure handles blocking conditions (like input exhaustion) - automatically. + automatically. \section ppi_packets Packets @@ -103,8 +103,8 @@ Of these modules, normally only the application modules need to be implemented since the library provides an extensive set of reusable modules. - - The following example module declares three \ref ppi_connectors "Connectors": \c payload, + + The following example module declares three \ref ppi_connectors "Connectors": \c payload, \c stuffing and \c output. These connectors are defined as \e public data members so they can be accessed from the outside. This is important as we will see below. @@ -117,9 +117,9 @@ senf::ppi::IntervalTimer timer_; public: - senf::ppi::connector::GenericActiveInput payload; - senf::ppi::connector::GenericActiveInput stuffing; - senf::ppi::connector::GenericActiveOutput output; + senf::ppi::connector::ActiveInput<> payload; + senf::ppi::connector::ActiveInput<> stuffing; + senf::ppi::connector::ActiveOutput<> output; RateStuffer(unsigned packetsPerSecond) : timer_(1000u, packetsPerSecond) @@ -148,10 +148,10 @@ The module processing is very simple: Whenever a timer tick arrives a packet is sent. If the \c payload input is ready (see \ref ppi_throttling), a payload packet is sent, otherwise a stuffing packet is sent. The module will therefore provide a constant stream of packets at a fixed rate - on \c output (see the - RateStuffer example application + on \c output (see the + RateStuffer example application for a slightly different approach) - + An example module to generate the stuffing packets could be \code @@ -160,7 +160,7 @@ { SENF_PPI_MODULE(CopyPacketGenerator); public: - senf::ppi::connector::GenericPassiveOutput output; + senf::ppi::connector::PassiveOutput<> output; CopyPacketGenerator(Packet template) : template_ (template) @@ -184,14 +184,14 @@ \see senf::ppi::module::Module \section ppi_connectors Connectors - + The input and output attachment points of a module are called connectors. Each connector may be active or passive. This gives us 4 types of connectors: - \li senf::ppi::connector::GenericActiveInput - \li senf::ppi::connector::GenericActiveOutput - \li senf::ppi::connector::GenericPassiveInput - \li senf::ppi::connector::GenericPassiveOutput + \li senf::ppi::connector::ActiveInput + \li senf::ppi::connector::ActiveOutput + \li senf::ppi::connector::PassiveInput + \li senf::ppi::connector::PassiveOutput An \e active connector (input or output) is activated by the module to send data or to poll for available packets. This means, the modules processing routine will call the connector @@ -221,7 +221,7 @@ To make use of the modules, they have to be instantiated and connections have to be created between its connectors. It is possible to connect any pair of input/output connectors as long as one of them is active and the other is passive. - + It is possible to connect two active or passive connectors with each other using a special adaptor module (senf::ppi::module::PassiveQueue or senf::ppi::module::ActiveFeeder respectively). @@ -232,7 +232,7 @@ \code RateStuffer rateStuffer (10); - senf::Packet stuffingPacket = senf::DataPacket::create(...); + senf::Packet stuffingPacket = senf::DataPacket::create(...); CopyPacketGenerator generator (stuffingPacket); senf::UDPv4ClientSocketHandle inputSocket (1111); @@ -254,7 +254,7 @@ This application will read udp-packets coming in on port 1111 and will forward them to port 2222 on host 2.3.4.5 with a fixed rate of 10 packets / second. - + We start out by instantiating the necessary modules. Then the connections between these modules are set up by successively connecting each output connector to an input connector. As can be seen, the name of the connector can be left of if it is named \c output or \c input @@ -306,15 +306,15 @@ disabled, see \ref senf::ppi::connector::ActiveConnector) to be called when a throttle notification is received. The callback may then handle the notification however it sees fit, for example by manually throttling some passive connector (see \ref - senf::ppi::connector::PassiveConnector). + senf::ppi::connector::PassiveConnector). - To enable/disable automatic throttling, the \ref senf::ppi::module::Module::route() command + To enable/disable automatic throttling, the \ref senf::ppi::module::Module::route() command returns a reference to a \ref senf::ppi::Route instance. If this route is \e forwarding route, - (that is, of the connectors is passive and the other is active), the return value will be + (that is, of the connectors is passive and the other is active), the return value will be derived from \ref senf::ppi::ForwardingRoute which provides members to control the throttle notification forwarding. - - \see + + \see senf::ppi::module::Module \n senf::ppi::Route @@ -331,11 +331,11 @@ perform the call. This is handled by the Scheduler, which is wrapped by the event classes. - + All events are derived from senf::ppi::EventDescriptor. The base class allows to enable and disable the event. Each type of event will take descriptor specific constructor arguments to describe the event to be generated. Events are declared as (private) data members of the - module and are then registered using senf::ppi::module::Module::registerEvent(). + module and are then registered using senf::ppi::module::Module::registerEvent(). Each event when signaled is described by an instance of the descriptor specific \e descriptorType \c ::Event class. This instance will hold the event specific information (like @@ -384,7 +384,7 @@ \section ppi_flows Information Flow The above description conceptually introduces three different flow levels: - + \li The data flow is, where the packets are flowing. This flow always goes from output to input connector. \li The execution flow describes the flow of execution from one module to another. This @@ -397,7 +397,7 @@ Within a module, the different flow levels are defined differently depending on the type of flow: - + \li The data flow is defined by how data is processed. The different event and connector callbacks will pass packets around and thereby define the data flow \li Likewise, the execution flow is defined parallel to the data flow (however possible @@ -414,7 +414,7 @@ */ /** \page ppi_implementation Implementation Notes - + \section processing Data Processing The processing in the PPI is driven by events. Without events nothing will happen. When @@ -448,7 +448,7 @@ Every module manages a collection of all it's connectors and every connector has a reference to it's containing module. In addition, every connector maintains a collection of all it's routing - targets. + targets. All this data is initialized via the routing statements. This is, why \e every connector must appear in at least one routing statement: These statements will as a side effect initialize the @@ -459,9 +459,9 @@ instance. This simplifies the PPI usage considerably. The same is true for the connectors: Since they know the containing module, they can explicitly bind unbound member function pointers to the instance. - + \section ppi_random_notes Random implementation notes - + Generation of throttle notifications: Backward throttling notifications are automatically generated (if this is not disabled) whenever the input queue is non-empty \e after the event handler has finished processing. Forward throttling notifications are not generated @@ -473,7 +473,7 @@ \image html classes.png */ - + // Local Variables: // mode: c++ // fill-column: 100 diff --git a/PPI/PassiveQueue.hh b/PPI/PassiveQueue.hh index c5adc20..20734b6 100644 --- a/PPI/PassiveQueue.hh +++ b/PPI/PassiveQueue.hh @@ -45,8 +45,9 @@ namespace module { requested from the passive output, a packet is dequeued. The PassiveQueue will automatically throttle in both directions. Throttling on the input - connector is the standard throttling as implemented in connector::GenericPassiveInput. Additional, - forward throttling notifications are sent out whenever the queue is empty. + connector is the standard throttling as implemented in + connector::PassiveInput<>. Additional forward throttling notifications are sent out + whenever the queue is empty. \ingroup adapter_modules */ diff --git a/Packets/Packet.hh b/Packets/Packet.hh index 4fc2e1e..33f6317 100644 --- a/Packets/Packet.hh +++ b/Packets/Packet.hh @@ -186,64 +186,64 @@ namespace senf { Packet next() const; ///< Get next packet in chain - /**< \returns in - valid() packet, if no next packet + /**< \throws InvalidPacketChainException if no next packet exists */ Packet next(NoThrow_t) const; ///< Get next packet in chain - /**< \returns in - valid() packet, if no next packet + /**< \returns in - valid() packet if no next packet exists */ template OtherPacket next() const; ///< Get next packet in chain and cast to \a OtherPacket /**< \throws std::bad_cast if the next() packet is not of type \a OtherPacket - \returns in - valid() packet, if no next packet + \throws InvalidPacketChainException if no next packet exists */ template OtherPacket next(NoThrow_t) const; ///< Get next packet in chain and cast to \a OtherPacket /**< \throws std::bad_cast if the next() packet is not of type \a OtherPacket - \returns in - valid() packet, if no next packet + \returns in - valid() packet if no next packet exists */ template OtherPacket find() const; ///< Search chain forward for packet of type \a OtherPacket /**< The search will start with the current packet. - \returns in - valid() packet, if no packet of type \a - OtherPacket can be found. */ + \throws InvalidPacketChainException if no packet of + type \a OtherPacket can be found. */ template OtherPacket find(NoThrow_t) const; ///< Search chain forward for packet of type \a OtherPacket /**< The search will start with the current packet. - \returns in - valid() packet, if no packet of type \a + \returns in - valid() packet if no packet of type \a OtherPacket can be found. */ Packet prev() const; ///< Get previous packet in chain - /**< \returns in - valid() packet, if no previous packet - exists */ + /**< \throws InvalidPacketChainException if no previous + packet exists */ Packet prev(NoThrow_t) const; ///< Get previous packet in chain - /**< \returns in - valid() packet, if no previous packet + /**< \returns in - valid() packet if no previous packet exists */ template OtherPacket prev() const; ///< Get previous packet in chain and cast to \a OtherPacket /**< \throws std::bad_cast, if the previous packet is not of type \a OtherPacket - \returns in - valid() packet, if no previous packet - exists */ + \throws InvalidPacketChainException if no previous + packet exists */ template OtherPacket prev(NoThrow_t) const; ///< Get previous packet in chain and cast to \a OtherPacket /**< \throws std::bad_cast, if the previous packet is not of type \a OtherPacket - \returns in - valid() packet, if no previous packet + \returns in - valid() packet if no previous packet exists */ template OtherPacket rfind() const; ///< Search chain backwards for packet of type \a OtherPacket /**< The search will start with the current packet. - \returns in - valid() packet, if no packet of type \a - OtherPacket can be found. */ + \throws InvalidPacketChainException if no packet of + type \a OtherPacket can be found. */ template OtherPacket rfind(NoThrow_t) const; ///< Search chain backwards for packet of type \a OtherPacket /**< The search will start with the current packet. - \returns in - valid() packet, if no packet of type \a + \returns in - valid() packet if no packet of type \a OtherPacket can be found. */