52663cc5b5289b8cc3cbaca6ac40da418bc6736c
[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_Connectors_
27 #define HH_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 "../Packets/Packets.hh"
35 #include "predecl.hh"
36 #include "detail/Callback.hh"
37 #include "Queueing.hh"
38
39 //#include "Connectors.mpp"
40 ///////////////////////////////hh.p////////////////////////////////////////
41
42 namespace senf {
43 namespace ppi {
44 namespace connector {
45
46     /** \namespace senf::ppi::connector
47         \brief Connector classes 
48
49         A connector has two independent properties
50         \li it may be \e active or \e passive
51         \li it may be an \e input or an \e output
52     
53         \e Active connectors are activated from within the module, \e passive connectors are
54         signaled by the external framework. \e Input modules receive packets, \e output modules send
55         packets.
56
57         All passive connectors call some onRequest callback whenever I/O needs to be performed. All
58         input modules possess a packet queue.
59
60         We therefore have 4 connector types: 
61         \li senf::ppi::connector::ActiveInput
62         \li senf::ppi::connector::ActiveOutput
63         \li senf::ppi::connector::PassiveInput
64         \li senf::ppi::connector::PassiveOutput.
65
66         Connectors are declared as module data members and are then externally connected to other
67         modules.
68
69         The connectors each take an optional template argument. If this argument is specified, it
70         must be the type of packet expected or sent on this connector. If it is not specified,
71         packets will be passed using the generic Packet handle.
72
73         \code
74         class IpFilter : public senf::ppi::module::Module
75         {
76             SENF_PPI_MODULE(SomeModule);
77
78         public:
79             senf::ppi::connector::ActiveInput<senf::EthernetPacket> input;
80             senf::ppi::connector::PassiveOutput<senf::IpPacket> output;
81
82             IpFilter() {
83                 route(input, output);
84                 input.onRequest(&IpFilter::onRequest);
85             }
86
87         private:
88             void onRequest() {
89                 // 'input()' will return a senf::EthernetPacket packet handle
90                 try { output( input().find<IpPacket>() ); }
91                 catch (senf::InvalidPacketChainException & ex) { ; }
92             }
93         };
94         \endcode
95
96         \see 
97             senf::ppi::module::Module \n
98             senf::ppi::connect() \n
99             \ref ppi_connectors
100      */
101
102     /** \brief Connector base-class
103
104         This connector provides access to the generic connector facilities. This includes the
105         connection management (access to the connected peer) and the containment management (access
106         to the containing module)
107      */
108     class Connector
109         : boost::noncopyable
110     {
111     public:
112         Connector & peer() const;       ///< Get peer connected to this connector
113         module::Module & module() const; ///< Get this connectors containing module
114
115     protected:
116         Connector();
117         virtual ~Connector();
118
119         void connect(Connector & target);
120
121     private:
122         void setModule(module::Module & module);
123
124         Connector * peer_;
125         module::Module * module_;
126
127         friend class module::Module;
128     };
129
130     /** \brief Passive connector base-class
131
132         A passive connector is a connector which is activated externally whenever an I/O request
133         occurs. Passive connectors are the origin of throttling notifications. Depending on the type
134         of connector (output or input) the respective throttling is called forward or backward
135         throttling.
136
137         Passive connectors always handle two throttling states: 
138         
139         \li The \e native throttling state is set manually by the module. It is the throttling state
140             originating in the current module
141         \li The \e forwarded throttling state is the state as it is received by throttling
142             notifications
143
144         The accumulative throttling state is generated by combining all sub-states.
145      */
146     class PassiveConnector 
147         : public virtual Connector
148     {
149     public:
150         template <class Handler>
151         void onRequest(Handler handler);///< Register I/O event handler
152                                         /**< The registered handler will be called, whenever packets
153                                              arrive or should be generated by the module depending
154                                              on the connector type (input or output). The \a handler
155                                              argument is either an arbitrary callable object or it
156                                              is a pointer-to-member to a member of the class which
157                                              holds this input. In the second case, the pointer will
158                                              automatically be bound to the containing instance.
159                                              
160                                              \param[in] handler Handler to call, whenever an I/O
161                                                  operation is to be performed. */
162
163         
164         bool throttled() const;         ///< Get accumulative throttling state
165         bool nativeThrottled() const;   ///< Get native throttling state
166
167         void throttle();                ///< Set native throttling
168         void unthrottle();              ///< Revoke native throttling
169         
170         ActiveConnector & peer() const;
171
172     protected:
173         PassiveConnector();
174
175         void emit();
176
177     private:
178         // Called by the routing to change the remote throttling state
179         void notifyThrottle();          ///< Forward a throttle notification to this connector
180         void notifyUnthrottle();        ///< Forward an unthrottle notification to this connector
181
182         // Internal members to emit throttling notifications
183         void emitThrottle();
184         void emitUnthrottle();
185
186         // Called after unthrottling the connector
187         virtual void v_unthrottleEvent();
188
189         // called by ForwardingRoute to register a new route
190         void registerRoute(ForwardingRoute & route);
191
192         typedef ppi::detail::Callback<>::type Callback;
193         Callback callback_;
194
195         bool remoteThrottled_;
196         bool nativeThrottled_;
197
198         typedef std::vector<ForwardingRoute*> Routes;
199         Routes routes_;
200
201         friend class senf::ppi::ForwardingRoute;
202     };
203
204     /** \brief Active connector base-class
205
206         An active connector is a connector which emits I/O requests. Active connectors receive
207         throttling notifications. Depending on the type of connector (input or output) the
208         respective throttling is called forward or backward throttling.
209
210         Active connectors do not handle any throttling state, they just receive the
211         notifications. These notifications should then either be processed by the module or be
212         forwarded to other connectors.
213      */
214     class ActiveConnector 
215         : public virtual Connector
216     {
217         typedef ppi::detail::Callback<>::type Callback;
218     public:
219         template <class Handler>
220         void onThrottle(Handler handler); ///< Register throttle notification handler
221                                         /**< The handler register here will be called, whenever a
222                                              throttle notification comes in. The \a handler argument
223                                              is either an arbitrary callable object or it is a
224                                              pointer-to-member to a member of the class which holds
225                                              this input. In the second case, the pointer will
226                                              automatically be bound to the containing instance.
227
228                                              \param[in] handler Handler to call on throttle
229                                                  notifications. */
230         void onThrottle();              ///< Clear throttle notification handler
231
232         template <class Handler>
233         void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
234                                         /**< The handler register here will be called, whenever an
235                                              unthrottle notification comes in. The \a handler
236                                              argument is either an arbitrary callable object or it
237                                              is a pointer-to-member to a member of the class which
238                                              holds this input. In the second case, the pointer will
239                                              automatically be bound to the containing instance.
240
241                                              \param[in] handler Handler to call on unthrottle
242                                                  notifications. */
243         void onUnthrottle();            ///< Clear unthrottle notification handler
244
245         bool throttled() const;         ///< \c true, if peer() is throttled
246
247         PassiveConnector & peer() const;
248
249     protected:
250         ActiveConnector();
251
252     private:
253         // called by the peer() to forward throttling notifications
254         void notifyThrottle();
255         void notifyUnthrottle();
256
257         // called by ForwardingRoute to register a new route
258         void registerRoute(ForwardingRoute & route);
259
260         Callback throttleCallback_;
261         Callback unthrottleCallback_;
262
263         typedef std::vector<ForwardingRoute*> NotifyRoutes;
264         NotifyRoutes notifyRoutes_;
265
266         friend class senf::ppi::ForwardingRoute;
267         friend class PassiveConnector;
268     };
269
270     /** \brief Input connector base-class
271
272         An input connector receives packets. It may be either an ActiveConnector or a
273         PassiveConnector. An input connector contains a packet queue. This queue enables processing
274         packets in batches or generating multiple output packets from a single input packet. The
275         queues have the potential to greatly simplify the module implementations.
276
277         \implementation Which container to use?
278             \li list has good insertion and deletion properties on both ends but it costs a dynamic
279                 memory allocation for every insertion. A very good property is, that iterators stay
280                 valid across insertions/deletions
281             \li vector is fast and has good amortized dynamic allocation properties. However, it is
282                 quite unusable as a queue
283             \li deque has comparable dynamic allocation properties as vector but also has good
284                 insertion/removal properties on both ends.
285
286             So probably we will use a deque. I'd like a container which keeps iterators intact on
287             insertion/deletion but I believe that list is just to expensive since every packet will
288             be added to the queue before it can be processed.
289      */
290     class InputConnector 
291         : public virtual Connector
292     {
293         typedef std::deque<Packet> Queue;
294     public:
295         typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
296         typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
297
298
299         Packet operator()();            ///< Get a packet
300                                         /**< This member is the primary method to access received
301                                              data. On passive connectors, this operator will just
302                                              dequeue a packet from the packet queue. If the
303                                              connector is active, the connector will request new
304                                              packets from the connected module. If the packet
305                                              request cannot be fulfilled, this is considered to be a
306                                              logic error in the module implementation and an
307                                              exception is raised. */
308
309         Packet read();                  ///< Alias for operator()()
310
311         OutputConnector & peer() const;
312
313         queue_iterator begin() const;   ///< Access queue begin (head)
314         queue_iterator end() const;     ///< Access queue past-the-end (tail)
315         Packet peek() const;            ///< Return head element from the queue
316
317         size_type queueSize() const;    ///< Return number of elements in the queue
318         bool empty() const;             ///< Return queueSize() == 0
319
320     protected:
321         InputConnector();
322         
323     private:
324         void enqueue(Packet p);
325         
326         virtual void v_requestEvent();
327         virtual void v_enqueueEvent();
328         virtual void v_dequeueEvent();
329
330         Queue queue_;
331
332         friend class OutputConnector;
333     };
334     
335     /** \brief Output connector base-class
336         
337         An output connector sends out packets. It may be either an ActiveConnector or a
338         PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
339         the queueing of the connected input.
340      */
341     class OutputConnector 
342         : public virtual Connector
343     {
344     public:
345         void operator()(Packet p);      ///< Send out a packet
346
347         void write(Packet p);           ///< Alias for operator()(Packet p)
348
349         InputConnector & peer() const;
350
351     protected:
352         OutputConnector();
353     };
354     
355     /** \brief Combination of PassiveConnector and InputConnector
356
357         The GenericPassiveInput automatically controls the connectors throttling state using a
358         queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
359         the connection whenever the queue length reaches the high threshold and unthrottles the
360         connection when the queue reaches the low threshold. The default queueing discipline is
361         <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
362         non-empty.
363      */
364     class GenericPassiveInput 
365         : public PassiveConnector, public InputConnector,
366           public safe_bool<GenericPassiveInput>
367     {
368     public:
369         GenericActiveOutput & peer() const;
370
371         bool boolean_test() const;      ///< \c true, if ! empty()
372
373         template <class QDisc>
374         void qdisc(QDisc const & disc); ///< Change the queueing discipline
375                                         /**< The queueing discipline is a class which provides the
376                                              QueueingDiscipline interface.
377                                              
378                                              \param[in] disc New queueing discipline */
379
380     protected:
381         GenericPassiveInput();
382
383     private:
384         void v_enqueueEvent();
385         void v_dequeueEvent();
386         void v_unthrottleEvent();
387
388         boost::scoped_ptr<QueueingDiscipline> qdisc_;
389     };
390
391     /** \brief Combination of PassiveConnector and OutputConnector
392      */
393     class GenericPassiveOutput
394         : public PassiveConnector, public OutputConnector,
395           public safe_bool<GenericPassiveOutput>
396     {
397     public:
398         GenericActiveInput & peer() const;
399
400         bool boolean_test() const;      ///< Always \c true
401
402         void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
403
404         friend class GenericActiveInput;
405
406     protected:
407         GenericPassiveOutput();
408
409     };
410
411     /** \brief Combination of ActiveConnector and InputConnector
412      */
413     class GenericActiveInput
414         : public ActiveConnector, public InputConnector,
415           public safe_bool<GenericActiveInput>
416     {
417     public:
418         GenericPassiveOutput & peer() const;
419
420         bool boolean_test() const;      ///< \c true, if ! empty() or ! throttled()
421
422         void request();                 ///< request more packets without dequeuing any packet
423
424     protected:
425         GenericActiveInput();
426
427     private:
428         void v_requestEvent();
429     };
430
431     /** \brief Combination of ActiveConnector and OutputConnector
432      */
433     class GenericActiveOutput
434         : public ActiveConnector, public OutputConnector,
435           public safe_bool<GenericActiveOutput>
436     {
437     public:
438         GenericPassiveInput & peer() const;
439
440         bool boolean_test() const;      ///< \c true if peer() is ! throttled()
441
442         void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
443
444     protected:
445         GenericActiveOutput();
446
447     };
448
449 #ifndef DOXYGEN
450
451 #   define TypedConnector_Input read
452 #   define TypedConnector_Output write
453 #   define TypedConnector(type, dir)                                                              \
454         template <class PacketType>                                                               \
455         class type ## dir                                                                         \
456             : public Generic ## type ## dir,                                                      \
457               private detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType>         \
458         {                                                                                         \
459             typedef detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType> mixin;    \
460         public:                                                                                   \
461             using mixin::operator();                                                              \
462             using mixin::TypedConnector_ ## dir ;                                                 \
463         };                                                                                        \
464         template <>                                                                               \
465         class type ## dir <Packet> : public Generic ## type ## dir                                \
466         {}
467
468     TypedConnector( Passive, Input  );
469     TypedConnector( Passive, Output );
470     TypedConnector( Active,  Input  );
471     TypedConnector( Active,  Output );
472
473 #   undef TypedConnector
474 #   undef TypedConnector_Input
475 #   undef TypedConnector_Output
476
477 #else
478
479     /** \brief Connector actively reading packets
480
481         The ActiveInput connector template reads data actively from a connected module. This class
482         is completely implemented via it's base-class, GenericActiveInput, the only difference is
483         that read packets are returned as \a PacketType instead of generic senf::Packet references.
484
485         \see GenericActiveInput \n
486             senf::ppi::connectro
487      */
488     template <class PacketType>
489     class ActiveInput : public GenericActiveInput
490     {
491     public:
492         PacketType operator()();        ///< Read packet
493                                         /**< \throws std::bad_cast, if the connector receives a
494                                              Packet which is not of type \a PacketType.
495                                              \returns newly read packet reference. */
496         PacketType read();              ///< Alias for operator()
497     };
498
499     /** \brief Connector passively receiving packets
500
501         The PassiveInput connector template receives packets sent to it from a connected
502         module. This class is completely implemented via it's base-class, GenericPassiveInput, the
503         only difference is that read packets are returned as \a PacketType instead of generic
504         senf::Packet references.
505
506         \see GenericPassiveInput \n
507             senf::ppi::connector
508      */
509     template <class PacketType=Packet>
510     class PassiveInput : public GenericPassiveInput
511     {
512     public:
513         PacketType operator()();        ///< Read packet
514                                         /**< \throws std::bad_cast, if the connector receives a
515                                              Packet which is not of type \a PacketType.
516                                              \returns newly read packet reference. */
517         PacketType read();              ///< Alias for operator()
518     };
519
520     /** \brief Connector actively sending packets
521
522         The ActiveOutput connector template sends data actively to a connected module. This class is
523         completely implemented via it's base-class, GenericActiveOutput, the only difference is that
524         it only sends packets of type \a PacketType.
525
526         \see GenericActiveOutput \n
527             senf::ppi::connector
528      */
529     template <class PacketType>
530     class ActiveOutput : public GenericActiveOutput
531     {
532     public:
533         PacketType operator()();
534         PacketType write();
535     };
536
537     /** \brief Connector passively providing packets
538
539         The PassiveOutput connector template provides data passively to a connected module whenever
540         signaled. This class is completely implemented via it's base-class, GenericPassiveOutput, the
541         only difference is that it only sends packets of type \a PacketType.
542
543         \see GenericPassiveOutput \n
544             senf::ppi::connector
545      */
546     template <class PacketType>
547     class PassiveOutput : public GenericPassiveOutput
548     {
549     public:
550         PacketType operator()();
551         PacketType write();
552     };
553
554 #endif
555
556 }}}
557
558 ///////////////////////////////hh.e////////////////////////////////////////
559 #include "Connectors.cci"
560 //#include "Connectors.ct"
561 #include "Connectors.cti"
562 #endif
563
564 \f
565 // Local Variables:
566 // mode: c++
567 // fill-column: 100
568 // c-file-style: "senf"
569 // indent-tabs-mode: nil
570 // ispell-local-dictionary: "american"
571 // compile-command: "scons -u test"
572 // comment-column: 40
573 // End: