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