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