Fix SCons 1.2.0 build failure
[senf.git] / 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 "../Utils/safe_bool.hh"
34 #include "../Utils/Exception.hh"
35 #include "../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         void setModule(module::Module & module);
192
193         Connector * peer_;
194         module::Module * module_;
195
196         static TraceState traceState_;
197
198         friend class module::Module;
199     };
200
201     /** \brief Passive connector base-class
202
203         A passive connector is a connector which is activated externally whenever an I/O request
204         occurs. Passive connectors are the origin of throttling notifications. Depending on the type
205         of connector (output or input) the respective throttling is called forward or backward
206         throttling.
207
208         Passive connectors always handle two throttling states:
209
210         - The \e native throttling state is set manually by the module. It is the throttling state
211             originating in the current module
212         - The \e forwarded throttling state is the state as it is received by throttling
213             notifications
214
215         The accumulative throttling state is generated by combining all sub-states.
216      */
217     class PassiveConnector
218         : public virtual Connector
219     {
220     public:
221         template <class Handler>
222         void onRequest(Handler handler);///< Register I/O event handler
223                                         /**< The registered handler will be called, whenever packets
224                                              arrive or should be generated by the module depending
225                                              on the connector type (input or output). The \a handler
226                                              argument is either an arbitrary callable object or it
227                                              is a pointer-to-member to a member of the class which
228                                              holds this input. In the second case, the pointer will
229                                              automatically be bound to the containing instance.
230
231                                              \param[in] handler Handler to call, whenever an I/O
232                                                  operation is to be performed. */
233
234
235         bool throttled() const;         ///< Get accumulative throttling state
236         bool nativeThrottled() const;   ///< Get native throttling state
237
238         void throttle();                ///< Set native throttling
239         void unthrottle();              ///< Revoke native throttling
240
241         ActiveConnector & peer() const;
242
243     protected:
244         PassiveConnector();
245
246         void emit();
247
248     private:
249         virtual void v_init();
250
251         // Called by the routing to change the throttling state from forwarding routes
252         void notifyThrottle();          ///< Forward a throttle notification to this connector
253         void notifyUnthrottle();        ///< Forward an unthrottle notification to this connector
254
255         // Internal members to emit throttling notifications to the connected peer
256         void emitThrottle();
257         void emitUnthrottle();
258
259         // Called after unthrottling the connector
260         virtual void v_unthrottleEvent();
261
262         // called by ForwardingRoute to register a new route
263         void registerRoute(ForwardingRoute & route);
264
265         typedef ppi::detail::Callback<>::type Callback;
266         Callback callback_;
267
268         bool remoteThrottled_;
269         bool nativeThrottled_;
270
271         typedef std::vector<ForwardingRoute*> Routes;
272         Routes routes_;
273
274         friend class senf::ppi::ForwardingRoute;
275     };
276
277     /** \brief Active connector base-class
278
279         An active connector is a connector which emits I/O requests. Active connectors receive
280         throttling notifications. Depending on the type of connector (input or output) the
281         respective throttling is called forward or backward throttling.
282
283         Active connectors do not handle any throttling state, they just receive the
284         notifications. These notifications should then either be processed by the module or be
285         forwarded to other connectors.
286      */
287     class ActiveConnector
288         : public virtual Connector
289     {
290         typedef ppi::detail::Callback<>::type Callback;
291     public:
292         template <class Handler>
293         void onThrottle(Handler handler); ///< Register throttle notification handler
294                                         /**< The handler register here will be called, whenever a
295                                              throttle notification comes in. The \a handler argument
296                                              is either an arbitrary callable object or it is a
297                                              pointer-to-member to a member of the class which holds
298                                              this input. In the second case, the pointer will
299                                              automatically be bound to the containing instance.
300
301                                              \param[in] handler Handler to call on throttle
302                                                  notifications. */
303         void onThrottle();              ///< Clear throttle notification handler
304
305         template <class Handler>
306         void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
307                                         /**< The handler register here will be called, whenever an
308                                              unthrottle notification comes in. The \a handler
309                                              argument is either an arbitrary callable object or it
310                                              is a pointer-to-member to a member of the class which
311                                              holds this input. In the second case, the pointer will
312                                              automatically be bound to the containing instance.
313
314                                              \param[in] handler Handler to call on unthrottle
315                                                  notifications. */
316         void onUnthrottle();            ///< Clear unthrottle notification handler
317
318         bool throttled() const;         ///< \c true, if peer() is throttled
319
320         PassiveConnector & peer() const;
321
322     protected:
323         ActiveConnector();
324
325     private:
326         virtual void v_init();
327
328         // called by the peer() to forward throttling notifications
329         void notifyThrottle();
330         void notifyUnthrottle();
331
332         // called by ForwardingRoute to register a new route
333         void registerRoute(ForwardingRoute & route);
334
335         Callback throttleCallback_;
336         Callback unthrottleCallback_;
337
338         typedef std::vector<ForwardingRoute*> NotifyRoutes;
339         NotifyRoutes notifyRoutes_;
340
341         bool throttled_;        
342
343         friend class senf::ppi::ForwardingRoute;
344         friend class PassiveConnector;
345     };
346
347     /** \brief Input connector base-class
348
349         An input connector receives packets. It may be either an ActiveConnector or a
350         PassiveConnector. An input connector contains a packet queue. This queue enables processing
351         packets in batches or generating multiple output packets from a single input packet. The
352         queues have the potential to greatly simplify the module implementations.
353
354         \implementation Which container to use?
355             \li list has good insertion and deletion properties on both ends but it costs a dynamic
356                 memory allocation for every insertion. A very good property is, that iterators stay
357                 valid across insertions/deletions
358             \li vector is fast and has good amortized dynamic allocation properties. However, it is
359                 quite unusable as a queue
360             \li deque has comparable dynamic allocation properties as vector but also has good
361                 insertion/removal properties on both ends.
362
363             So probably we will use a deque. I'd like a container which keeps iterators intact on
364             insertion/deletion but I believe that list is just to expensive since every packet will
365             be added to the queue before it can be processed.
366      */
367     class InputConnector
368         : public virtual Connector
369     {
370         typedef std::deque<Packet> Queue;
371     public:
372         typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
373         typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
374
375
376         Packet operator()();            ///< Get a packet
377                                         /**< This member is the primary method to access received
378                                              data. On passive connectors, this operator will just
379                                              dequeue a packet from the packet queue. If the
380                                              connector is active, the connector will request new
381                                              packets from the connected module. If the packet
382                                              request cannot be fulfilled, this is considered to be a
383                                              logic error in the module implementation and an
384                                              exception is raised. */
385
386         Packet read();                  ///< Alias for operator()()
387
388         OutputConnector & peer() const;
389
390         queue_iterator begin() const;   ///< Access queue begin (head)
391         queue_iterator end() const;     ///< Access queue past-the-end (tail)
392         Packet peek() const;            ///< Return head element from the queue
393
394         size_type queueSize() const;    ///< Return number of elements in the queue
395         bool empty() const;             ///< Return queueSize() == 0
396
397     protected:
398         InputConnector();
399
400     private:
401         void enqueue(Packet const & p);
402
403         virtual void v_requestEvent();
404         virtual void v_enqueueEvent();
405         virtual void v_dequeueEvent();
406
407         Queue queue_;
408
409         friend class OutputConnector;
410     };
411
412     /** \brief Output connector base-class
413
414         An output connector sends out packets. It may be either an ActiveConnector or a
415         PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
416         the queueing of the connected input.
417      */
418     class OutputConnector
419         : public virtual Connector
420     {
421     public:
422         void operator()(Packet const & p);      ///< Send out a packet
423
424         void write(Packet const & p);           ///< Alias for operator()(Packet p)
425
426         InputConnector & peer() const;
427
428     protected:
429         OutputConnector();
430     };
431
432     /** \brief Combination of PassiveConnector and InputConnector
433
434         The GenericPassiveInput automatically controls the connectors throttling state using a
435         queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
436         the connection whenever the queue length reaches the high threshold and unthrottles the
437         connection when the queue reaches the low threshold. The default queueing discipline is
438         <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
439         non-empty.
440      */
441     class GenericPassiveInput
442         : public PassiveConnector, public InputConnector,
443           public safe_bool<GenericPassiveInput>
444     {
445     public:
446         GenericActiveOutput & peer() const;
447
448         bool boolean_test() const;      ///< \c true, if ! empty()
449
450         template <class QDisc>
451         void qdisc(QDisc const & disc); ///< Change the queueing discipline
452                                         /**< The queueing discipline is a class which provides the
453                                              QueueingDiscipline interface.
454
455                                              \param[in] disc New queueing discipline */
456
457     protected:
458         GenericPassiveInput();
459
460     private:
461         void v_enqueueEvent();
462         void v_dequeueEvent();
463         void v_unthrottleEvent();
464
465         boost::scoped_ptr<QueueingDiscipline> qdisc_;
466     };
467
468     /** \brief Combination of PassiveConnector and OutputConnector
469      */
470     class GenericPassiveOutput
471         : public PassiveConnector, public OutputConnector,
472           public safe_bool<GenericPassiveOutput>
473     {
474     public:
475         GenericActiveInput & peer() const;
476
477         bool boolean_test() const;      ///< Always \c true
478
479         void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
480
481         friend class GenericActiveInput;
482
483     protected:
484         GenericPassiveOutput();
485
486     };
487
488     /** \brief Combination of ActiveConnector and InputConnector
489      */
490     class GenericActiveInput
491         : public ActiveConnector, public InputConnector,
492           public safe_bool<GenericActiveInput>
493     {
494     public:
495         GenericPassiveOutput & peer() const;
496
497         bool boolean_test() const;      ///< \c true, if ! empty() or ! throttled()
498
499         void request();                 ///< request more packets without dequeuing any packet
500
501     protected:
502         GenericActiveInput();
503
504     private:
505         void v_requestEvent();
506     };
507
508     /** \brief Combination of ActiveConnector and OutputConnector
509      */
510     class GenericActiveOutput
511         : public ActiveConnector, public OutputConnector,
512           public safe_bool<GenericActiveOutput>
513     {
514     public:
515         GenericPassiveInput & peer() const;
516
517         bool boolean_test() const;      ///< \c true if peer() is ! throttled()
518
519         void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
520
521     protected:
522         GenericActiveOutput();
523
524     };
525
526 #ifndef DOXYGEN
527
528 #   define TypedConnector_Input read
529 #   define TypedConnector_Output write
530 #   define TypedConnector(pType, dir)                                                             \
531         template <class PacketType>                                                               \
532         class pType ## dir                                                                        \
533             : public Generic ## pType ## dir,                                                     \
534               private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>        \
535         {                                                                                         \
536             typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin;   \
537         public:                                                                                   \
538             using mixin::operator();                                                              \
539             using mixin::TypedConnector_ ## dir ;                                                 \
540         private:                                                                                  \
541             virtual std::type_info const & packetTypeID()                                         \
542                 { return typeid(typename PacketType::type); }                                     \
543             friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>;    \
544         };                                                                                        \
545         template <>                                                                               \
546         class pType ## dir <Packet> : public Generic ## pType ## dir                              \
547         {}
548
549     TypedConnector( Passive, Input  );
550     TypedConnector( Passive, Output );
551     TypedConnector( Active,  Input  );
552     TypedConnector( Active,  Output );
553
554 #   undef TypedConnector
555 #   undef TypedConnector_Input
556 #   undef TypedConnector_Output
557
558 #else
559
560     /** \brief Connector actively reading packets
561         
562         \tparam PacketType Type of packet to read. Defaults to senf::Packet
563
564         The %ActiveInput %connector template reads data actively from a connected %module. This
565         class is completely implemented via it's base-class, GenericActiveInput, the only 
566         difference is that read packets are returned as \a PacketType instead of generic 
567         senf::Packet references.
568
569         \see GenericActiveInput \n
570             senf::ppi::connector
571      */
572     template <class PacketType=Packet>
573     class ActiveInput : public GenericActiveInput
574     {
575     public:
576         PacketType operator()();        ///< Read packet
577                                         /**< \throws std::bad_cast if the %connector receives a
578                                              Packet which is not of type \a PacketType.
579                                              \returns newly read packet reference. */
580         PacketType read();              ///< Alias for operator()
581     };
582
583     /** \brief Connector passively receiving packets
584
585         \tparam PacketType Type of packet to read. Defaults to senf::Packet
586
587         The %PassiveInput %connector template receives packets sent to it from a connected
588         %module. This class is completely implemented via it's base-class, GenericPassiveInput, 
589         the only difference is that read packets are returned as \a PacketType instead of generic
590         senf::Packet references.
591
592         \see GenericPassiveInput \n
593             senf::ppi::connector
594      */
595     template <class PacketType=Packet>
596     class PassiveInput : public GenericPassiveInput
597     {
598     public:
599         PacketType operator()();        ///< Read packet
600                                         /**< \throws std::bad_cast if the %connector receives a
601                                              Packet which is not of type \a PacketType.
602                                              \returns newly read packet reference. */
603         PacketType read();              ///< Alias for operator()
604     };
605
606     /** \brief Connector actively sending packets
607
608         \tparam PacketType Type of packet to send. Defaults to senf::Packet
609
610         The %ActiveOutput %connector template sends data actively to a connected %module. This 
611         class is completely implemented via it's base-class, GenericActiveOutput, the only
612         difference is that it only sends packets of type \a PacketType.
613
614         \see GenericActiveOutput \n
615             senf::ppi::connector
616      */
617     template <class PacketType=Packet>
618     class ActiveOutput : public GenericActiveOutput
619     {
620     public:
621         operator()(PacketType packet);  ///< Send out a packet
622         void write(PacketType packet);  ///< Alias for operator()
623     };
624
625     /** \brief Connector passively providing packets
626
627         \tparam PacketType Type of packet to send. Defaults to senf::Packet
628
629         The %PassiveOutput %connector template provides data passively to a connected %module 
630         whenever signaled. This class is completely implemented via it's base-class, 
631         GenericPassiveOutput, the only difference is that it only sends packets of type 
632         \a PacketType.
633
634         \see GenericPassiveOutput \n
635             senf::ppi::connector
636      */
637     template <class PacketType=Packet>
638     class PassiveOutput : public GenericPassiveOutput
639     {
640     public:
641         operator()(PacketType packet);  ///< Send out a packet
642         void write(PacketType packet);  ///< Alias for operator()
643     };
644
645 #endif
646
647 }}}
648
649 ///////////////////////////////hh.e////////////////////////////////////////
650 #include "Connectors.cci"
651 //#include "Connectors.ct"
652 #include "Connectors.cti"
653 #endif
654
655 \f
656 // Local Variables:
657 // mode: c++
658 // fill-column: 100
659 // c-file-style: "senf"
660 // indent-tabs-mode: nil
661 // ispell-local-dictionary: "american"
662 // compile-command: "scons -u test"
663 // comment-column: 40
664 // End: