Howtos/NewPacket: Small fixes
[senf.git] / PPI / Connectors.hh
index fe6d5f7..68a0ea4 100644 (file)
@@ -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 <g0dil@berlios.de>
 //
 // This program is free software; you can redistribute it and/or modify
@@ -28,7 +30,7 @@
 #include <deque>
 #include <boost/utility.hpp>
 #include <boost/scoped_ptr.hpp>
-#include "../Utils/SafeBool.hh"
+#include "../Utils/safe_bool.hh"
 #include "../Packets/Packets.hh"
 #include "predecl.hh"
 #include "detail/Callback.hh"
@@ -42,12 +44,12 @@ namespace ppi {
 namespace connector {
 
     /** \namespace senf::ppi::connector
-        \brief Connector classes 
+        \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
-    
+        - it may be \e active or \e passive
+        - 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.
@@ -55,8 +57,46 @@ namespace connector {
         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.
+        We therefore have 4 connector types:
+        - senf::ppi::connector::ActiveInput
+        - senf::ppi::connector::ActiveOutput
+        - senf::ppi::connector::PassiveInput
+        - 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
@@ -94,16 +134,16 @@ namespace connector {
         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:
@@ -116,17 +156,17 @@ 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() 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:
@@ -149,7 +189,7 @@ namespace connector {
         // 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_;
@@ -171,10 +211,10 @@ 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 detail::Callback<>::type Callback;
+        typedef ppi::detail::Callback<>::type Callback;
     public:
         template <class Handler>
         void onThrottle(Handler handler); ///< Register throttle notification handler
@@ -198,7 +238,7 @@ 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
 
@@ -247,7 +287,7 @@ namespace connector {
             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;
@@ -255,6 +295,7 @@ namespace connector {
         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
@@ -265,6 +306,8 @@ namespace connector {
                                              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)
@@ -276,10 +319,10 @@ namespace connector {
 
     protected:
         InputConnector();
-        
+
     private:
         void enqueue(Packet p);
-        
+
         virtual void v_requestEvent();
         virtual void v_enqueueEvent();
         virtual void v_dequeueEvent();
@@ -288,42 +331,42 @@ namespace connector {
 
         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();
     };
-    
+
     /** \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()
 
@@ -331,9 +374,12 @@ namespace connector {
         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();
@@ -344,51 +390,171 @@ namespace connector {
 
     /** \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(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 ;                                                 \
+        private:                                                                                  \
+             friend class detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType>;    \
+        };                                                                                        \
+        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::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
+
+        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=Packet>
+    class ActiveOutput : public GenericActiveOutput
+    {
+    public:
+        operator()(PacketType packet);  ///< Send out a packet
+        write(PacketType packet);       ///< Alias for operator()
+    };
+
+    /** \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=Packet>
+    class PassiveOutput : public GenericPassiveOutput
+    {
+    public:
+        operator()(PacketType packet);  ///< Send out a packet
+        write(PacketType packet);       ///< Alias for operator()
+    };
+
+#endif
+
 }}}
 
 ///////////////////////////////hh.e////////////////////////////////////////