Packets: Fix VariantParser invalid parser access bug
[senf.git] / PPI / Connectors.hh
index 52663cc..07316b6 100644 (file)
@@ -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 <g0dil@berlios.de>
 //
 // This program is free software; you can redistribute it and/or modify
 /** \file
     \brief Connectors public header */
 
-#ifndef HH_Connectors_
-#define HH_Connectors_ 1
+#ifndef HH_SENF_PPI_Connectors_
+#define HH_SENF_PPI_Connectors_ 1
 
 // Custom includes
 #include <deque>
 #include <boost/utility.hpp>
 #include <boost/scoped_ptr.hpp>
 #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////////////////////////////////////////
@@ -44,23 +46,25 @@ namespace ppi {
 namespace connector {
 
     /** \namespace senf::ppi::connector
-        \brief Connector classes 
+        \brief Connector classes
 
-        A connector has two independent properties
+        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 modules receive packets, \e output modules send
-        packets.
+        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 modules possess a packet queue.
+        input connectors possess a packet queue.
 
-        We therefore have 4 connector types: 
+        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::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
@@ -87,18 +91,31 @@ namespace connector {
         private:
             void onRequest() {
                 // 'input()' will return a senf::EthernetPacket packet handle
-                try { output( input().find<IpPacket>() ); }
+                try { output( input().find<senf::IpPacket>() ); }
                 catch (senf::InvalidPacketChainException & ex) { ; }
             }
         };
         \endcode
 
-        \see 
+        \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
@@ -106,19 +123,25 @@ namespace connector {
         to the containing module)
      */
     class Connector
-        : boost::noncopyable
+        : ModuleManager::Initializable, boost::noncopyable
     {
     public:
         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_;
@@ -134,16 +157,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:
@@ -156,17 +179,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:
@@ -175,6 +198,8 @@ namespace connector {
         void emit();
 
     private:
+        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
@@ -211,7 +236,7 @@ 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;
@@ -250,6 +275,8 @@ namespace connector {
         ActiveConnector();
 
     private:
+        virtual void v_init();
+
         // called by the peer() to forward throttling notifications
         void notifyThrottle();
         void notifyUnthrottle();
@@ -263,6 +290,8 @@ namespace connector {
         typedef std::vector<ForwardingRoute*> NotifyRoutes;
         NotifyRoutes notifyRoutes_;
 
+        bool throttled_;        
+
         friend class senf::ppi::ForwardingRoute;
         friend class PassiveConnector;
     };
@@ -287,7 +316,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;
@@ -319,10 +348,10 @@ namespace connector {
 
     protected:
         InputConnector();
-        
+
     private:
         void enqueue(Packet p);
-        
+
         virtual void v_requestEvent();
         virtual void v_enqueueEvent();
         virtual void v_dequeueEvent();
@@ -331,14 +360,14 @@ 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:
@@ -351,7 +380,7 @@ namespace connector {
     protected:
         OutputConnector();
     };
-    
+
     /** \brief Combination of PassiveConnector and InputConnector
 
         The GenericPassiveInput automatically controls the connectors throttling state using a
@@ -361,7 +390,7 @@ namespace connector {
         <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
         non-empty.
      */
-    class GenericPassiveInput 
+    class GenericPassiveInput
         : public PassiveConnector, public InputConnector,
           public safe_bool<GenericPassiveInput>
     {
@@ -374,7 +403,7 @@ 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:
@@ -450,19 +479,23 @@ namespace connector {
 
 #   define TypedConnector_Input read
 #   define TypedConnector_Output write
-#   define TypedConnector(type, dir)                                                              \
+#   define TypedConnector(pType, dir)                                                             \
         template <class PacketType>                                                               \
-        class type ## dir                                                                         \
-            : public Generic ## type ## dir,                                                      \
-              private detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType>         \
+        class pType ## dir                                                                        \
+            : public Generic ## pType ## dir,                                                     \
+              private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>        \
         {                                                                                         \
-            typedef detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType> mixin;    \
+            typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, 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<pType ## dir <PacketType>, PacketType>;    \
         };                                                                                        \
         template <>                                                                               \
-        class type ## dir <Packet> : public Generic ## type ## dir                                \
+        class pType ## dir <Packet> : public Generic ## pType ## dir                              \
         {}
 
     TypedConnector( Passive, Input  );
@@ -477,20 +510,23 @@ namespace connector {
 #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.
+        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
+            senf::ppi::connector
      */
-    template <class PacketType>
+    template <class PacketType=Packet>
     class ActiveInput : public GenericActiveInput
     {
     public:
         PacketType operator()();        ///< Read packet
-                                        /**< \throws std::bad_cast, if the connector receives a
+                                        /**< \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()
@@ -498,9 +534,11 @@ namespace connector {
 
     /** \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
+        \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
@@ -511,7 +549,7 @@ namespace connector {
     {
     public:
         PacketType operator()();        ///< Read packet
-                                        /**< \throws std::bad_cast, if the connector receives a
+                                        /**< \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()
@@ -519,36 +557,41 @@ namespace connector {
 
     /** \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.
+        \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 PacketType>
+    template <class PacketType=Packet>
     class ActiveOutput : public GenericActiveOutput
     {
     public:
-        PacketType operator()();
-        PacketType write();
+        operator()(PacketType packet);  ///< Send out a packet
+        void 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.
+        \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 PacketType>
+    template <class PacketType=Packet>
     class PassiveOutput : public GenericPassiveOutput
     {
     public:
-        PacketType operator()();
-        PacketType write();
+        operator()(PacketType packet);  ///< Send out a packet
+        void write(PacketType packet);  ///< Alias for operator()
     };
 
 #endif