-// 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
\brief Module public header
*/
-#ifndef HH_Module_
-#define HH_Module_ 1
+#ifndef HH_SENF_PPI_Module_
+#define HH_SENF_PPI_Module_ 1
// Custom includes
+#include <vector>
#include <boost/utility.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
+#include "../Scheduler/ClockService.hh"
+#include "predecl.hh"
+#include "ModuleManager.hh"
//#include "Module.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
namespace ppi {
+namespace module {
+
+ /** \namespace senf::ppi::module
+ \brief PPI Modules
+
+ The modules build the PPI core. The PPI provides a set of general purpose infrastructure
+ modules. For concrete applications, additional application specific processing modules need
+ to be implemented.
+
+ \section module_impl Implementing Modules
+
+ All modules derive from senf::ppi::module::Module. See this class for a documentation on how
+ to write new modules.
+
+ \section infrastructure_modules General Purpose Modules
+
+ The PPI provided general purpose modules can be grouped into several categories
+
+ \li \ref io_modules receive external data or forward packets out of the PPI
+ \li \ref routing_modules forward packets within the network
+ \li \ref adapter_modules are used to connect incompatible connectors to each other
+
+ \todo Implement Spliters: PassiveSplitter, PrioritySplitter, CloneSplitter
+ */
+
+ /** \defgroup io_modules Source/Sink Modules
+
+ Source and Sink modules generate or absorb packets in some way: Reading data from a file
+ descriptor, discarding packets etc.
+ */
+
+ /** \defgroup routing_modules Routing Modules
+
+ Routing modules perform packet forwarding within the network. They do not process the packet
+ data, they just route it.
+ */
- /** \brief Module baseclass
+ /** \defgroup adapter_modules Adapter Modules
- senf::ppi::Module is the baseclass of all PPI modules. It provides the module implementation
+ Adapter modules adapt incompatible connectors to each other. They allow connection a pair of
+ active or passive connectors.
+ */
+
+ /** \brief Module base-class
+
+ senf::ppi::Module is the base-class of all PPI modules. It provides the module implementation
with interfaces to several PPI facilities:
\li Connector management
\li Event handling
To provide internal bookkeeping, most access to the PPI infrastructure is managed through
- this base class.
+ this base class. This is an example module specification:
+ \code
+ class SomeModule : public senf::ppi::module::Module
+ {
+ SENF_PPI_MODULE(SomeModule);
+
+ senf::FileHandle handle;
+
+ // If needed, define events
+ senf::ppi::IOEvent event;
+
+ public:
+ // Define connectors. Any number and type of connectors may be defined. Connectors
+ // must be public since they need to be accessed to connect modules with each other.
+ senf::ppi::connector::PassiveInput<> input;
+ senf::ppi::connector::ActiveOutput<> output;
+
+ SomeModule(senf::FileHandle h)
+ : handle ( h ),
+ event ( handle, senf::ppi::IOEvent::Read )
+ {
+ // Set up routing. If some connector is not routed you need to explicitly state this
+ // using noroute()
+ route( input, output );
+ route( event, output )
+ .autoThrottling( false );
+
+ // Register event handlers
+ registerEvent( event, &SomeModule::read );
+
+ // Register passive connector handlers
+ input.onRequest( &SomeModule::outputRequest );
+
+ // If needed, you may register throttling event handlers
+ output.onThrottle( &SomeModule::throttle );
+ output.onUnthrottle( &SomeModule::unthrottle );
+ }
+
+ void read() {
+ // Called whenever the 'handle' is readable. Read data, do processing and so
+ // on. This example reads the data, puts it into an ethernet packet and sends the
+ // packet out via the active output.
+ output(senf::EthernetPacket::create(handle.read()))
+ }
+
+ void outputRequest() {
+ // Called whenever a packet is sent into the input to. Here we just forward it to
+ // the output if it is an EthernetPacket
+ senf::EthernetPacket p (input().find<EthernetPacket>(senf::nothrow));
+ if (p)
+ output(p);
+ }
+
+ void onThrottle() {
+ // Called whenever a throttle notification comes in. Here, we just disable the
+ // event (which is stupid since we should just not have disabled autoThrottling on
+ // the route but this is only an example which tries to be simple ...)
+ event.disable();
+ }
+
+ void onUnthrottle() {
+ // and for unthrottle notifications
+ event.enable();
+ }
+
+ void v_init() {
+ // Optional. Called after before running the module but after connections have been
+ // set up. This is either directly before senf::ppi::run() or senf::ppi::init() is
+ // called or, for modules created while the PPI is already running, after returning
+ // from all event handlers but before going back to the event loop.
+ }
- Instances of this class may be allocated either statically or dynamically. Dynamic instances
- are automatically managed using the dynamicModule adaptor.
+ };
+ \endcode
+
+ If your module only has a single input connector, you should call this connector \c
+ input. If it has only a single output connector, you should call it \c output. This allows
+ to setup connections without stating the connector explicitly (see senf::ppi::connect()).
+
+ \see \ref ppi_modules
*/
class Module
- : boost::noncopyable
+ : ModuleManager::Initializable, boost::noncopyable
{
+ public:
+ virtual ~Module();
+
protected:
Module();
- ~Module();
+#ifndef DOXYGEN
template <class Source, class Target>
- Route<Source, Target> & route(Source const & source, Target const & target);
+ Route<Source, Target> & route(Source & source, Target & target);
+#else
+ Route<connector::InputConnector, connector::OutputConnector> &
+ route(connector::InputConnector & input, connector::OutputConnector & output);
///< Define flow information
/**< Using the route() and noroute() members, the
information flow within the module is defined. Routing
- may be specified either between inputs, outputs and
- events. The routing information is used to perform
- automatic throttling. The throttling behavior may
- however be controlled manually.
+ may be defined between inputs, outputs and events. The
+ routing information is used to perform automatic
+ throttling. The throttling behavior may however be
+ controlled manually.
Even if no automatic throttling is desired <em>it is
- vital to define the flow information for all inputs and
- outputs</em>. Without flow information important
+ essential to define the flow information for all inputs
+ and outputs</em>. Without flow information important
internal state of the module cannot be
initialized. This includes, explicitly defining
terminal inputs and outputs using noroute. Event
- routing however is optional.
+ routing is optional however.
The return value may be used to alter routing
parameters like throttling parameters.
-
- \param[in] source Data source, object which controlls
- incoming data
- \param[in] target Data target, object which controlls
- outgoing data
- \returns Route instance describing this route */
-
- template <class Connector>
- void noroute(Connector const & connector); ///< Define terminal connectors
+
+ \param[in] input Data source, object which controls
+ incoming data (connector or event)
+ \param[in] output Data target, object which controls
+ outgoing data (connector or event)
+ \returns Route instance describing this route
+ \see \ref ppi_throttling
+ \note The real implementation is not provided by three
+ overloads but by a single template member */
+
+ Route<connector::InputConnector, EventDescriptor> &
+ route(connector::InputConnector & input, EventDescriptor & output);
+ ///< Define flow information
+ /**< Route from a connector to an event. Routing from a
+ connector to an event defines the event as the
+ conceptual 'receiver' of the data. This means, the
+ event is controlling the processing of received data
+ packets (Example: Routing from an input to an IOEvent
+ defines, that input data will be processed whenever the
+ event is signaled.).
+
+ This event routing allows to automatically
+ enable/disable the event on throttling notifications.
+
+ \see \ref route() */
+
+ Route<EventDescriptor, connector::OutputConnector> &
+ route(EventDescriptor & input, connector::OutputConnector & output);
+ ///< Define flow information
+ /**< Route from an event to a connector. Routing from an
+ event to a connector defines the event as the
+ conceptual 'source' of the data. This means, the event
+ controls how packets are sent (Example: Routing from an
+ IOEvent to an output defines, that output data will be
+ generated whenever the event is signaled).
+
+ This event routing allows to automatically
+ enable/disable the event on throttling notifications.
+
+ \see \ref route() */
+#endif
+
+ void noroute(connector::Connector & connector); ///< Define terminal connectors
/**< The noroute() member explicitly declares, that a
connector is terminal and does not directly
receive/forward data from/to some other
\param[in] connector Terminal connector to declare */
- template <class Target, class Descriptor>
- typename Descriptor & registerEvent(Target target, Descriptor const & descriptor);
+#ifndef DOXYGEN
+ template <class Descriptor, class Target>
+ void registerEvent(Descriptor & descriptor, Target target);
+#else
+ template <class Target>
+ void registerEvent(EventDescriptor & descriptor, Target target);
///< Register an external event
/**< The \a target argument may be either an arbitrary
callable object or it may be a member function pointer
pointing to a member function of the Module derived
classed. The handler may \e optionally take an Argument
- of type <tt>typename Descriptor::Event const
- &</tt>. This object allows to access detailed
- information on the event delivered.
-
- The \a descriptor describes the event to signal. This
- may be a timer event or some type of I/O event on a
- file descriptor or socket.
-
- The return value may be used to modify the
- binding. This allows to temporarily inhibit event
- delivery or to remove the binding explicitly. Depending
- on the type of event, other operations may be
- possible. See the event descriptor documentation.
-
- \param[in] target The handler to call whenever the event
- is signaled
- \param[in] descriptor The type of event to register
- \returns An event binding instance of the appropriate
- type. */
-
- boost::posix_time::ptime eventTime(); ///< Return timestamp of the currently processing event
- };
+ of type <tt>Descriptor::Event const &</tt>. This object
+ allows to access detailed information on the event
+ delivered.
- /** \brief Automatically manage dynamic module deallocation
+ The \a descriptor describes the event to signal like a
+ timer event or some type of I/O event on a file
+ descriptor or socket.
- The dynamicModule helper will create a new dynamically managed module instance.
+ \param[in] target The handler to call whenever the
+ event is signaled
+ \param[in] descriptor The type of event to register
+ \note The real implementation has the second arguments
+ type as an additional template parameter. */
+#endif
- The \a args template parameter is only a placeholder. All arguments to dynamicModule will be
- passed to the Module constructor.
+ ClockService::clock_type time() const; ///< Time-stamp of the currently processing event
+ /**< If available, this returns the scheduled time of the
+ event. */
- \implementation dynamicModule should just register the Instance in a different way with the
- Infrastructure and return a reference to the new module.
- */
- template <class Module, class Args>
- unspecified dynamicModule(Args args);
+ ClockService::clock_type now() const; ///< Current time of the currently processing event
+#ifndef DOXYGEN
+ virtual void macro_SENF_PPI_MODULE_missing() = 0;
- /** \brief Connect compatible connectors
+ private:
+#endif
+ virtual void v_init(); ///< Called after module setup
+ /**< This member is called directly before the PPI (resumes)
+ execution. It is called after connections have been
+ setup before entering the PPI main loop.
- connect() will connect two compatible connectors: One connector must be active, the other
- passive.
- */
- template <class Source, class Target>
- void connect(Source const & source, Target const & target);
+ You may overload this member. Your overload should
+ always call the base-class implementation. */
- /** \brief Connect connectors via an adaptor module
+#ifndef DOXYGEN
+ public:
+#endif
+ void destroy();
- This connect() overload will insert an additional adaptor module into the connection. The
- Adaptor module must have two connectors, \a input and \a output. The call will setup the
- connections \a source to \a input and \a output to \a target. Each connector pair must be
- compatible.
+ private:
+ EventManager & eventManager() const;
+ ModuleManager & moduleManager() const;
+
+ void registerConnector(connector::Connector & connector);
+ RouteBase & addRoute(std::auto_ptr<RouteBase> route);
+
+ typedef std::vector<connector::Connector *> ConnectorRegistry;
+ ConnectorRegistry connectorRegistry_;
+
+ typedef boost::ptr_vector<RouteBase> RouteInfoBase;
+ RouteInfoBase routes_;
+
+ template <class Source, class Target>
+ friend class detail::RouteHelper;
+ friend class senf::ppi::ModuleManager;
+ };
+
+ /** \brief Define PPI Module
+
+ Every module must begin by using this macro.
+
+ \see senf::ppi::module::Module
*/
- template <class Source, class Target, class Adaptor)
- Adaptor const & connect(Source const & source, Target const & target,
- Adaptor const & adaptor);
+# define SENF_PPI_MODULE(name) \
+ public: \
+ ~ name() { destroy(); } \
+ void macro_SENF_PPI_MODULE_missing() {} \
+ private:
-}}
+}}}
///////////////////////////////hh.e////////////////////////////////////////
-//#include "Module.cci"
-//#include "Module.ct"
+#include "Module.cci"
+#include "Module.ct"
//#include "Module.cti"
#endif
// c-file-style: "senf"
// indent-tabs-mode: nil
// ispell-local-dictionary: "american"
+// compile-command: "scons -u test"
+// comment-column: 40
// End: