PPI: Remove disconnected connectors from MultiConnectorMixin modules
[senf.git] / senf / PPI / Connectors.hh
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Connectors public header */
25
26 #ifndef HH_SENF_PPI_Connectors_
27 #define HH_SENF_PPI_Connectors_ 1
28
29 // Custom includes
30 #include <deque>
31 #include <boost/utility.hpp>
32 #include <boost/scoped_ptr.hpp>
33 #include <senf/Utils/safe_bool.hh>
34 #include <senf/Utils/Exception.hh>
35 #include <senf/Packets/Packets.hh>
36 #include "predecl.hh"
37 #include "detail/Callback.hh"
38 #include "Queueing.hh"
39 #include "ModuleManager.hh"
40
41 //#include "Connectors.mpp"
42 ///////////////////////////////hh.p////////////////////////////////////////
43
44 namespace senf {
45 namespace ppi {
46 namespace connector {
47
48     /** \namespace senf::ppi::connector
49         \brief Connector classes
50
51         A connector has three independent properties
52         \li it may be \e active or \e passive
53         \li it may be an \e input or an \e output
54         \li it has an (optional) packet type
55
56         \e Active connectors are activated from within the module, \e passive connectors are
57         signaled by the external framework. \e Input connectors receive packets, \e output
58         connectors send packets.
59
60         All passive connectors call some onRequest callback whenever I/O needs to be performed. All
61         input connectors possess a packet queue.
62
63         We therefore have 4 connector types each of which is parameterized by the type of packet
64         traversing the connector:
65         \li senf::ppi::connector::ActiveInput
66         \li senf::ppi::connector::ActiveOutput 
67         \li senf::ppi::connector::PassiveInput 
68         \li senf::ppi::connector::PassiveOutput.
69
70         Connectors are declared as module data members and are then externally connected to other
71         modules.
72
73         The connectors each take an optional template argument. If this argument is specified, it
74         must be the type of packet expected or sent on this connector. If it is not specified,
75         packets will be passed using the generic Packet handle.
76
77         \code
78         class IpFilter : public senf::ppi::module::Module
79         {
80             SENF_PPI_MODULE(SomeModule);
81
82         public:
83             senf::ppi::connector::ActiveInput<senf::EthernetPacket> input;
84             senf::ppi::connector::PassiveOutput<senf::IpPacket> output;
85
86             IpFilter() {
87                 route(input, output);
88                 input.onRequest(&IpFilter::onRequest);
89             }
90
91         private:
92             void onRequest() {
93                 // 'input()' will return a senf::EthernetPacket packet handle
94                 try { output( input().find<senf::IpPacket>() ); }
95                 catch (senf::InvalidPacketChainException & ex) { ; }
96             }
97         };
98         \endcode
99
100
101         \section ppi_jacks Jacks
102
103         A Jack is a packet type aware and possibly packet type converting reference to an arbitrary
104         connector of the same type. Jacks are used in groups to indirectly declare the input's and
105         output's
106
107         \code
108         class MyGroup
109         {
110         private:
111             senf::ppi::module::PassiveQueue queue;
112             senf::ppi::module::RateAnalyzer analyzer;
113
114         public:
115             senf::ppi::connector::ActiveInputJack<senf::EthernetPacket> input;
116             senf::ppi::connector::ActiveOutputJack<senf::EthernetPacket> output;
117
118             MyGroup() 
119                 : queue (), analyzer (), input (queue.input), output (analyzer.output)
120             {
121                 senf::ppi::connect(queue, analyzer);
122             }
123         };
124         \endcode
125
126         The jacks are initialized by passing an arbitrary compatible connector to the jack
127         constructor. A connector is compatible, if
128         \li It has the same input/output active/passive specification
129         \li Either the Jack or the Connector are generic (senf::Packet) or Jack and Connector have
130             the same packet type
131
132         Jacks can be used wherever connectors may be used. Jacks may be defined anywhere, not only
133         in modules. It is however important to ensure that the lifetime of the jack does not exceed
134         the lifetime of the referenced connector.
135
136         \see
137             senf::ppi::module::Module \n
138             senf::ppi::connect() \n
139             \ref ppi_connectors
140      */
141
142     /** \brief Incompatible connectors connected
143
144         This exception is thrown, when two incompatible connectors are connected. This happens if
145         both connectors of a senf::ppi::connect() statement declare a packet type (the connector
146         template argument) but they don't declare the same packet type.
147
148         You need to ensure, that both connectors use the same packet type.
149
150         \see senf::ppi::connect()
151      */
152     struct IncompatibleConnectorsException : public senf::Exception
153     { IncompatibleConnectorsException() : senf::Exception("Incompatible connectors") {} };
154
155     /** \brief Connector base-class
156
157         This connector provides access to the generic connector facilities. This includes the
158         connection management (access to the connected peer) and the containment management (access
159         to the containing module)
160      */
161     class Connector
162         : ModuleManager::Initializable, boost::noncopyable
163     {
164         SENF_LOG_CLASS_AREA();
165         SENF_LOG_DEFAULT_LEVEL(senf::log::NOTICE);
166     public:
167         Connector & peer() const;       ///< Get peer connected to this connector
168         module::Module & module() const; ///< Get this connectors containing module
169
170         bool connected() const;         ///< \c true, if connector connected, \c false otherwise
171
172         void disconnect();              ///< Disconnect connector from peer
173
174         enum TraceState { NO_TRACING, TRACE_IDS, TRACE_CONTENTS };
175
176         static void tracing(TraceState state);
177         static TraceState tracing();
178
179     protected:
180         Connector();
181         virtual ~Connector();
182
183         void connect(Connector & target);
184
185         void trace(Packet const & p, char const * label);
186         void throttleTrace(char const * label, char const * type);
187         
188     private:
189         virtual std::type_info const & packetTypeID();
190         
191         virtual void v_disconnected() const;
192
193         void setModule(module::Module & module);
194
195         Connector * peer_;
196         module::Module * module_;
197
198         static TraceState traceState_;
199
200         friend class module::Module;
201     };
202
203     /** \brief Passive connector base-class
204
205         A passive connector is a connector which is activated externally whenever an I/O request
206         occurs. Passive connectors are the origin of throttling notifications. Depending on the type
207         of connector (output or input) the respective throttling is called forward or backward
208         throttling.
209
210         Passive connectors always handle two throttling states:
211
212         - The \e native throttling state is set manually by the module. It is the throttling state
213             originating in the current module
214         - The \e forwarded throttling state is the state as it is received by throttling
215             notifications
216
217         The accumulative throttling state is generated by combining all sub-states.
218      */
219     class PassiveConnector
220         : public virtual Connector
221     {
222     public:
223         template <class Handler>
224         void onRequest(Handler handler);///< Register I/O event handler
225                                         /**< The registered handler will be called, whenever packets
226                                              arrive or should be generated by the module depending
227                                              on the connector type (input or output). The \a handler
228                                              argument is either an arbitrary callable object or it
229                                              is a pointer-to-member to a member of the class which
230                                              holds this input. In the second case, the pointer will
231                                              automatically be bound to the containing instance.
232
233                                              \param[in] handler Handler to call, whenever an I/O
234                                                  operation is to be performed. */
235
236
237         bool throttled() const;         ///< Get accumulative throttling state
238         bool nativeThrottled() const;   ///< Get native throttling state
239
240         void throttle();                ///< Set native throttling
241         void unthrottle();              ///< Revoke native throttling
242
243         ActiveConnector & peer() const;
244
245     protected:
246         PassiveConnector();
247
248         void emit();
249
250     private:
251         virtual void v_init();
252
253         // Called by the routing to change the throttling state from forwarding routes
254         void notifyThrottle();          ///< Forward a throttle notification to this connector
255         void notifyUnthrottle();        ///< Forward an unthrottle notification to this connector
256
257         // Internal members to emit throttling notifications to the connected peer
258         void emitThrottle();
259         void emitUnthrottle();
260
261         // Called after unthrottling the connector
262         virtual void v_unthrottleEvent();
263
264         // called by ForwardingRoute to register a new route
265         void registerRoute(ForwardingRoute & route);
266
267         typedef ppi::detail::Callback<>::type Callback;
268         Callback callback_;
269
270         bool remoteThrottled_;
271         bool nativeThrottled_;
272
273         typedef std::vector<ForwardingRoute*> Routes;
274         Routes routes_;
275
276         friend class senf::ppi::ForwardingRoute;
277     };
278
279     /** \brief Active connector base-class
280
281         An active connector is a connector which emits I/O requests. Active connectors receive
282         throttling notifications. Depending on the type of connector (input or output) the
283         respective throttling is called forward or backward throttling.
284
285         Active connectors do not handle any throttling state, they just receive the
286         notifications. These notifications should then either be processed by the module or be
287         forwarded to other connectors.
288      */
289     class ActiveConnector
290         : public virtual Connector
291     {
292         typedef ppi::detail::Callback<>::type Callback;
293     public:
294         template <class Handler>
295         void onThrottle(Handler handler); ///< Register throttle notification handler
296                                         /**< The handler register here will be called, whenever a
297                                              throttle notification comes in. The \a handler argument
298                                              is either an arbitrary callable object or it is a
299                                              pointer-to-member to a member of the class which holds
300                                              this input. In the second case, the pointer will
301                                              automatically be bound to the containing instance.
302
303                                              \param[in] handler Handler to call on throttle
304                                                  notifications. */
305         void onThrottle();              ///< Clear throttle notification handler
306
307         template <class Handler>
308         void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
309                                         /**< The handler register here will be called, whenever an
310                                              unthrottle notification comes in. The \a handler
311                                              argument is either an arbitrary callable object or it
312                                              is a pointer-to-member to a member of the class which
313                                              holds this input. In the second case, the pointer will
314                                              automatically be bound to the containing instance.
315
316                                              \param[in] handler Handler to call on unthrottle
317                                                  notifications. */
318         void onUnthrottle();            ///< Clear unthrottle notification handler
319
320         bool throttled() const;         ///< \c true, if peer() is throttled
321
322         PassiveConnector & peer() const;
323
324     protected:
325         ActiveConnector();
326
327     private:
328         virtual void v_init();
329
330         // called by the peer() to forward throttling notifications
331         void notifyThrottle();
332         void notifyUnthrottle();
333
334         // called by ForwardingRoute to register a new route
335         void registerRoute(ForwardingRoute & route);
336
337         Callback throttleCallback_;
338         Callback unthrottleCallback_;
339
340         typedef std::vector<ForwardingRoute*> NotifyRoutes;
341         NotifyRoutes notifyRoutes_;
342
343         bool throttled_;        
344
345         friend class senf::ppi::ForwardingRoute;
346         friend class PassiveConnector;
347     };
348
349     /** \brief Input connector base-class
350
351         An input connector receives packets. It may be either an ActiveConnector or a
352         PassiveConnector. An input connector contains a packet queue. This queue enables processing
353         packets in batches or generating multiple output packets from a single input packet. The
354         queues have the potential to greatly simplify the module implementations.
355
356         \implementation Which container to use?
357             \li list has good insertion and deletion properties on both ends but it costs a dynamic
358                 memory allocation for every insertion. A very good property is, that iterators stay
359                 valid across insertions/deletions
360             \li vector is fast and has good amortized dynamic allocation properties. However, it is
361                 quite unusable as a queue
362             \li deque has comparable dynamic allocation properties as vector but also has good
363                 insertion/removal properties on both ends.
364
365             So probably we will use a deque. I'd like a container which keeps iterators intact on
366             insertion/deletion but I believe that list is just to expensive since every packet will
367             be added to the queue before it can be processed.
368      */
369     class InputConnector
370         : public virtual Connector
371     {
372         typedef std::deque<Packet> Queue;
373     public:
374         typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
375         typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
376
377
378         Packet operator()();            ///< Get a packet
379                                         /**< This member is the primary method to access received
380                                              data. On passive connectors, this operator will just
381                                              dequeue a packet from the packet queue. If the
382                                              connector is active, the connector will request new
383                                              packets from the connected module. If the packet
384                                              request cannot be fulfilled, this is considered to be a
385                                              logic error in the module implementation and an
386                                              exception is raised. */
387
388         Packet read();                  ///< Alias for operator()()
389
390         OutputConnector & peer() const;
391
392         queue_iterator begin() const;   ///< Access queue begin (head)
393         queue_iterator end() const;     ///< Access queue past-the-end (tail)
394         Packet peek() const;            ///< Return head element from the queue
395
396         size_type queueSize() const;    ///< Return number of elements in the queue
397         bool empty() const;             ///< Return queueSize() == 0
398
399     protected:
400         InputConnector();
401
402     private:
403         void enqueue(Packet const & p);
404
405         virtual void v_requestEvent();
406         virtual void v_enqueueEvent();
407         virtual void v_dequeueEvent();
408
409         Queue queue_;
410
411         friend class OutputConnector;
412     };
413
414     /** \brief Output connector base-class
415
416         An output connector sends out packets. It may be either an ActiveConnector or a
417         PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
418         the queueing of the connected input.
419      */
420     class OutputConnector
421         : public virtual Connector
422     {
423     public:
424         void operator()(Packet const & p);      ///< Send out a packet
425
426         void write(Packet const & p);           ///< Alias for operator()(Packet p)
427
428         InputConnector & peer() const;
429
430     protected:
431         OutputConnector();
432     };
433
434     /** \brief Combination of PassiveConnector and InputConnector
435
436         The GenericPassiveInput automatically controls the connectors throttling state using a
437         queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
438         the connection whenever the queue length reaches the high threshold and unthrottles the
439         connection when the queue reaches the low threshold. The default queueing discipline is
440         <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
441         non-empty.
442      */
443     class GenericPassiveInput
444         : public PassiveConnector, public InputConnector,
445           public safe_bool<GenericPassiveInput>
446     {
447     public:
448         GenericActiveOutput & peer() const;
449
450         bool boolean_test() const;      ///< \c true, if ! empty()
451
452         template <class QDisc>
453         void qdisc(QDisc const & disc); ///< Change the queueing discipline
454                                         /**< The queueing discipline is a class which provides the
455                                              QueueingDiscipline interface.
456
457                                              \param[in] disc New queueing discipline */
458
459     protected:
460         GenericPassiveInput();
461
462     private:
463         void v_enqueueEvent();
464         void v_dequeueEvent();
465         void v_unthrottleEvent();
466
467         boost::scoped_ptr<QueueingDiscipline> qdisc_;
468     };
469
470     /** \brief Combination of PassiveConnector and OutputConnector
471      */
472     class GenericPassiveOutput
473         : public PassiveConnector, public OutputConnector,
474           public safe_bool<GenericPassiveOutput>
475     {
476     public:
477         GenericActiveInput & peer() const;
478
479         bool boolean_test() const;      ///< Always \c true
480
481         void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
482
483         friend class GenericActiveInput;
484
485     protected:
486         GenericPassiveOutput();
487
488     };
489
490     /** \brief Combination of ActiveConnector and InputConnector
491      */
492     class GenericActiveInput
493         : public ActiveConnector, public InputConnector,
494           public safe_bool<GenericActiveInput>
495     {
496     public:
497         GenericPassiveOutput & peer() const;
498
499         bool boolean_test() const;      ///< \c true, if ! empty() or ! throttled()
500
501         void request();                 ///< request more packets without dequeuing any packet
502
503     protected:
504         GenericActiveInput();
505
506     private:
507         void v_requestEvent();
508     };
509
510     /** \brief Combination of ActiveConnector and OutputConnector
511      */
512     class GenericActiveOutput
513         : public ActiveConnector, public OutputConnector,
514           public safe_bool<GenericActiveOutput>
515     {
516     public:
517         GenericPassiveInput & peer() const;
518
519         bool boolean_test() const;      ///< \c true if peer() is ! throttled()
520
521         void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
522
523     protected:
524         GenericActiveOutput();
525
526     };
527
528 #ifndef DOXYGEN
529
530 #   define TypedConnector_Input read
531 #   define TypedConnector_Output write
532 #   define TypedConnector(pType, dir)                                                             \
533         template <class PacketType>                                                               \
534         class pType ## dir                                                                        \
535             : public Generic ## pType ## dir,                                                     \
536               private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>        \
537         {                                                                                         \
538             typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin;   \
539         public:                                                                                   \
540             using mixin::operator();                                                              \
541             using mixin::TypedConnector_ ## dir ;                                                 \
542         private:                                                                                  \
543             virtual std::type_info const & packetTypeID()                                         \
544                 { return typeid(typename PacketType::type); }                                     \
545             friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>;    \
546         };                                                                                        \
547         template <>                                                                               \
548         class pType ## dir <Packet> : public Generic ## pType ## dir                              \
549         {}
550
551     TypedConnector( Passive, Input  );
552     TypedConnector( Passive, Output );
553     TypedConnector( Active,  Input  );
554     TypedConnector( Active,  Output );
555
556 #   undef TypedConnector
557 #   undef TypedConnector_Input
558 #   undef TypedConnector_Output
559
560 #else
561
562     /** \brief Connector actively reading packets
563         
564         \tparam PacketType Type of packet to read. Defaults to senf::Packet
565
566         The %ActiveInput %connector template reads data actively from a connected %module. This
567         class is completely implemented via it's base-class, GenericActiveInput, the only 
568         difference is that read packets are returned as \a PacketType instead of generic 
569         senf::Packet references.
570
571         \see GenericActiveInput \n
572             senf::ppi::connector
573      */
574     template <class PacketType=Packet>
575     class ActiveInput : public GenericActiveInput
576     {
577     public:
578         PacketType operator()();        ///< Read packet
579                                         /**< \throws std::bad_cast if the %connector receives a
580                                              Packet which is not of type \a PacketType.
581                                              \returns newly read packet reference. */
582         PacketType read();              ///< Alias for operator()
583     };
584
585     /** \brief Connector passively receiving packets
586
587         \tparam PacketType Type of packet to read. Defaults to senf::Packet
588
589         The %PassiveInput %connector template receives packets sent to it from a connected
590         %module. This class is completely implemented via it's base-class, GenericPassiveInput, 
591         the only difference is that read packets are returned as \a PacketType instead of generic
592         senf::Packet references.
593
594         \see GenericPassiveInput \n
595             senf::ppi::connector
596      */
597     template <class PacketType=Packet>
598     class PassiveInput : public GenericPassiveInput
599     {
600     public:
601         PacketType operator()();        ///< Read packet
602                                         /**< \throws std::bad_cast if the %connector receives a
603                                              Packet which is not of type \a PacketType.
604                                              \returns newly read packet reference. */
605         PacketType read();              ///< Alias for operator()
606     };
607
608     /** \brief Connector actively sending packets
609
610         \tparam PacketType Type of packet to send. Defaults to senf::Packet
611
612         The %ActiveOutput %connector template sends data actively to a connected %module. This 
613         class is completely implemented via it's base-class, GenericActiveOutput, the only
614         difference is that it only sends packets of type \a PacketType.
615
616         \see GenericActiveOutput \n
617             senf::ppi::connector
618      */
619     template <class PacketType=Packet>
620     class ActiveOutput : public GenericActiveOutput
621     {
622     public:
623         operator()(PacketType packet);  ///< Send out a packet
624         void write(PacketType packet);  ///< Alias for operator()
625     };
626
627     /** \brief Connector passively providing packets
628
629         \tparam PacketType Type of packet to send. Defaults to senf::Packet
630
631         The %PassiveOutput %connector template provides data passively to a connected %module 
632         whenever signaled. This class is completely implemented via it's base-class, 
633         GenericPassiveOutput, the only difference is that it only sends packets of type 
634         \a PacketType.
635
636         \see GenericPassiveOutput \n
637             senf::ppi::connector
638      */
639     template <class PacketType=Packet>
640     class PassiveOutput : public GenericPassiveOutput
641     {
642     public:
643         operator()(PacketType packet);  ///< Send out a packet
644         void write(PacketType packet);  ///< Alias for operator()
645     };
646
647 #endif
648
649 }}}
650
651 ///////////////////////////////hh.e////////////////////////////////////////
652 #include "Connectors.cci"
653 //#include "Connectors.ct"
654 #include "Connectors.cti"
655 #endif
656
657 \f
658 // Local Variables:
659 // mode: c++
660 // fill-column: 100
661 // c-file-style: "senf"
662 // indent-tabs-mode: nil
663 // ispell-local-dictionary: "american"
664 // compile-command: "scons -u test"
665 // comment-column: 40
666 // End: