e37ad1f2cc74ceaec60f0ae4b3260a83cd6a2ad0
[senf.git] / PPI / Connectors.hh
1 // Copyright (C) 2007 
2 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
3 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
4 //     Stefan Bund <g0dil@berlios.de>
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the
18 // Free Software Foundation, Inc.,
19 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 /** \file
22     \brief Connectors public header */
23
24 /** \defgroup connectors Connector classes
25
26     A connector has two independent properties
27     \li it may be \e active or \e passive
28     \li it may be an \e input or an \e output
29     
30     \e Active connectors are activated from within the module, \e passive connectors are signaled by
31     the external framework. \e Input modules receive packets, \e output modules send packets.
32
33     All passive connectors call some onRequest callback whenever I/O needs to be performed. All
34     input modules possess a packet queue.
35
36     We therefore have 4 connector types: senf::ppi::ActiveInput, senf::ppi::ActiveOutput,
37     senf::ppi::PassiveInput and senf::ppi::PassiveOutput.
38  */
39
40 #ifndef HH_Connectors_
41 #define HH_Connectors_ 1
42
43 // Custom includes
44 #include <deque>
45 #include <boost/utility.hpp>
46 #include <boost/scoped_ptr.hpp>
47 #include "Utils/SafeBool.hh"
48 #include "Packets/Packets.hh"
49 #include "predecl.hh"
50 #include "detail/Callback.hh"
51 #include "Queueing.hh"
52
53 //#include "Connectors.mpp"
54 ///////////////////////////////hh.p////////////////////////////////////////
55
56 namespace senf {
57 namespace ppi {
58 namespace connector {
59
60     /** \namespace senf::ppi::connector
61         \brief Connector classes 
62      */
63
64     /** \brief Connector base-class
65
66         This connector provides access to the generic connector facilities. This includes the
67         connection management (access to the connected peer) and the containment management (access
68         to the containing module)
69      */
70     class Connector
71         : boost::noncopyable
72     {
73     public:
74         Connector & peer() const;       ///< Get peer connected to this connector
75         module::Module & module() const; ///< Get this connectors containing module
76
77     protected:
78         Connector();
79         virtual ~Connector();
80
81         void connect(Connector & target);
82
83     private:
84         void setModule(module::Module & module);
85
86         Connector * peer_;
87         module::Module * module_;
88
89         friend class module::Module;
90     };
91
92     /** \brief Passive connector base-class
93
94         A passive connector is a connector which is activated externally whenever an I/O request
95         occurs. Passive connectors are the origin of throttling notifications. Depending on the type
96         of connector (output or input) the respective throttling is called forward or backward
97         throttling.
98
99         Passive connectors always handle two throttling states: 
100         
101         \li The \e native throttling state is set manually by the module. It is the throttling state
102             originating in the current module
103         \li The \e forwarded throttling state is the state as it is received by throttling
104             notifications
105
106         The accumulative throttling state is generated by combining all sub-states.
107      */
108     class PassiveConnector 
109         : public virtual Connector
110     {
111     public:
112         template <class Handler>
113         void onRequest(Handler handler);///< Register I/O event handler
114                                         /**< The registered handler will be called, whenever packets
115                                              arrive or should be generated by the module depending
116                                              on the connector type (input or output). The \a handler
117                                              argument is either an arbitrary callable object or it
118                                              is a pointer-to-member to a member of the class which
119                                              holds this input. In the second case, the pointer will
120                                              automatically be bound to the containing instance.
121                                              
122                                              \param[in] handler Handler to call, whenever an I/O
123                                                  operation is to be performed. */
124
125         
126         bool throttled() const;         ///< Get accumulative throttling state
127         bool nativeThrottled() const;   ///< Get native throttling state
128
129         void throttle();                ///< Set native throttling
130         void unthrottle();              ///< Revoke native throttling
131         
132         ActiveConnector & peer() const;
133
134     protected:
135         PassiveConnector();
136
137         void emit();
138
139     private:
140         // Called by the routing to change the remote throttling state
141         void notifyThrottle();          ///< Forward a throttle notification to this connector
142         void notifyUnthrottle();        ///< Forward an unthrottle notification to this connector
143
144         // Internal members to emit throttling notifications
145         void emitThrottle();
146         void emitUnthrottle();
147
148         // Called after unthrottling the connector
149         virtual void v_unthrottleEvent();
150
151         // called by ForwardingRoute to register a new route
152         void registerRoute(ForwardingRoute & route);
153
154         typedef detail::Callback<>::type Callback;
155         Callback callback_;
156
157         bool remoteThrottled_;
158         bool nativeThrottled_;
159
160         typedef std::vector<ForwardingRoute*> Routes;
161         Routes routes_;
162
163         friend class senf::ppi::ForwardingRoute;
164     };
165
166     /** \brief Active connector base-class
167
168         An active connector is a connector which emits I/O requests. Active connectors receive
169         throttling notifications. Depending on the type of connector (input or output) the
170         respective throttling is called forward or backward throttling.
171
172         Active connectors do not handle any throttling state, they just receive the
173         notifications. These notifications should then either be processed by the module or be
174         forwarded to other connectors.
175      */
176     class ActiveConnector 
177         : public virtual Connector
178     {
179         typedef detail::Callback<>::type Callback;
180     public:
181         template <class Handler>
182         void onThrottle(Handler handler); ///< Register throttle notification handler
183                                         /**< The handler register here will be called, whenever a
184                                              throttle notification comes in. The \a handler argument
185                                              is either an arbitrary callable object or it is a
186                                              pointer-to-member to a member of the class which holds
187                                              this input. In the second case, the pointer will
188                                              automatically be bound to the containing instance.
189
190                                              \param[in] handler Handler to call on throttle
191                                                  notifications. */
192         void onThrottle();              ///< Clear throttle notification handler
193
194         template <class Handler>
195         void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
196                                         /**< The handler register here will be called, whenever an
197                                              unthrottle notification comes in. The \a handler
198                                              argument is either an arbitrary callable object or it
199                                              is a pointer-to-member to a member of the class which
200                                              holds this input. In the second case, the pointer will
201                                              automatically be bound to the containing instance.
202
203                                              \param[in] handle Handler to call on unthrottle
204                                                  notifications. */
205         void onUnthrottle();            ///< Clear unthrottle notification handler
206
207         bool throttled() const;         ///< \c true, if peer() is throttled
208
209         PassiveConnector & peer() const;
210
211     protected:
212         ActiveConnector();
213
214     private:
215         // called by the peer() to forward throttling notifications
216         void notifyThrottle();
217         void notifyUnthrottle();
218
219         // called by ForwardingRoute to register a new route
220         void registerRoute(ForwardingRoute & route);
221
222         Callback throttleCallback_;
223         Callback unthrottleCallback_;
224
225         typedef std::vector<ForwardingRoute*> NotifyRoutes;
226         NotifyRoutes notifyRoutes_;
227
228         friend class senf::ppi::ForwardingRoute;
229         friend class PassiveConnector;
230     };
231
232     /** \brief Input connector base-class
233
234         An input connector receives packets. It may be either an ActiveConnector or a
235         PassiveConnector. An input connector contains a packet queue. This queue enables processing
236         packets in batches or generating multiple output packets from a single input packet. The
237         queues have the potential to greatly simplify the module implementations.
238
239         \implementation Which container to use?
240             \li list has good insertion and deletion properties on both ends but it costs a dynamic
241                 memory allocation for every insertion. A very good property is, that iterators stay
242                 valid across insertions/deletions
243             \li vector is fast and has good amortized dynamic allocation properties. However, it is
244                 quite unusable as a queue
245             \li deque has comparable dynamic allocation properties as vector but also has good
246                 insertion/removal properties on both ends.
247
248             So probably we will use a deque. I'd like a container which keeps iterators intact on
249             insertion/deletion but I believe that list is just to expensive since every packet will
250             be added to the queue before it can be processed.
251      */
252     class InputConnector 
253         : public virtual Connector
254     {
255         typedef std::deque<Packet> Queue;
256     public:
257         typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
258         typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
259
260         Packet operator()();            ///< Get a packet
261                                         /**< This member is the primary method to access received
262                                              data. On passive connectors, this operator will just
263                                              dequeue a packet from the packet queue. If the
264                                              connector is active, the connector will request new
265                                              packets from the connected module. If the packet
266                                              request cannot be fulfilled, this is considered to be a
267                                              logic error in the module implementation and an
268                                              exception is raised. */
269
270         OutputConnector & peer() const;
271
272         queue_iterator begin() const;   ///< Access queue begin (head)
273         queue_iterator end() const;     ///< Access queue past-the-end (tail)
274         Packet peek() const;            ///< Return head element from the queue
275
276         size_type queueSize() const;    ///< Return number of elements in the queue
277         bool empty() const;             ///< Return queueSize() == 0
278
279     protected:
280         InputConnector();
281         
282     private:
283         void enqueue(Packet p);
284         
285         virtual void v_requestEvent();
286         virtual void v_enqueueEvent();
287         virtual void v_dequeueEvent();
288
289         Queue queue_;
290
291         friend class OutputConnector;
292     };
293     
294     /** \brief Output connector base-class
295         
296         An output connector sends out packets. It may be either an ActiveConnector or a
297         PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
298         the queueing of the connected input.
299      */
300     class OutputConnector 
301         : public virtual Connector
302     {
303     public:
304         void operator()(Packet p);        ///< Send out a packet
305
306         InputConnector & peer() const;
307
308     protected:
309         OutputConnector();
310     };
311     
312     ///@{
313     ///\addtogroup connectors
314
315     /** \brief Combination of PassiveConnector and InputConnector
316
317         The PassiveInput automatically controls the connectors throttling state using a queueing
318         discipline. The standard queueing discipline is ThresholdQueueing, which throttles the
319         connection whenever the queue length reaches the high threshold and unthrottles the
320         connection when the queue reaches the low threshold. The default queueing discipline is
321         <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
322         non-empty.
323      */
324     class PassiveInput 
325         : public PassiveConnector, public InputConnector,
326           public SafeBool<PassiveInput>
327     {
328     public:
329         PassiveInput();
330
331         ActiveOutput & peer() const;
332
333         bool boolean_test() const;      ///< \c true, if ! empty()
334
335         template <class QDisc>
336         void qdisc(QDisc const & disc); ///< Change the queueing discipline
337                                         /**< The queueing discipline is a class which provides the
338                                              QueueingDiscipline interface.
339                                              
340                                              \param[in] disc New queueing discipline */
341
342     private:
343         void v_enqueueEvent();
344         void v_dequeueEvent();
345         void v_unthrottleEvent();
346
347         boost::scoped_ptr<QueueingDiscipline> qdisc_;
348     };
349
350     /** \brief Combination of PassiveConnector and OutputConnector
351      */
352     class PassiveOutput
353         : public PassiveConnector, public OutputConnector,
354           public SafeBool<PassiveOutput>
355     {
356     public:
357         ActiveInput & peer() const;
358
359         bool boolean_test() const;      ///< Always \c true
360
361         void connect(ActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
362
363         friend class ActiveInput;
364     };
365
366     /** \brief Combination of ActiveConnector and InputConnector
367      */
368     class ActiveInput
369         : public ActiveConnector, public InputConnector,
370           public SafeBool<ActiveInput>
371     {
372     public:
373         PassiveOutput & peer() const;
374
375         bool boolean_test() const;      ///< \c true, if ! empty() or ! throttled()
376
377         void request();                 ///< request more packets without dequeuing any packet
378
379     private:
380         void v_requestEvent();
381     };
382
383     /** \brief Combination of ActiveConnector and OutputConnector
384      */
385     class ActiveOutput
386         : public ActiveConnector, public OutputConnector,
387           public SafeBool<ActiveOutput>
388     {
389     public:
390         PassiveInput & peer() const;
391
392         bool boolean_test() const;      ///< \c true if peer() is ! throttled()
393
394         void connect(PassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
395     };
396
397     ///@}
398
399 }}}
400
401 ///////////////////////////////hh.e////////////////////////////////////////
402 #include "Connectors.cci"
403 //#include "Connectors.ct"
404 #include "Connectors.cti"
405 #endif
406
407 \f
408 // Local Variables:
409 // mode: c++
410 // fill-column: 100
411 // c-file-style: "senf"
412 // indent-tabs-mode: nil
413 // ispell-local-dictionary: "american"
414 // compile-command: "scons -u test"
415 // comment-column: 40
416 // End: