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