e42bab9172e744f2ea7c6fdc1956f1b2d7a5f759
[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 #ifndef HH_Connectors_
25 #define HH_Connectors_ 1
26
27 // Custom includes
28 #include <deque>
29 #include <boost/utility.hpp>
30 #include <boost/scoped_ptr.hpp>
31 #include "../Utils/SafeBool.hh"
32 #include "../Packets/Packets.hh"
33 #include "predecl.hh"
34 #include "detail/Callback.hh"
35 #include "Queueing.hh"
36
37 //#include "Connectors.mpp"
38 ///////////////////////////////hh.p////////////////////////////////////////
39
40 namespace senf {
41 namespace ppi {
42 namespace connector {
43
44     /** \namespace senf::ppi::connector
45         \brief Connector classes 
46
47         A connector has two independent properties
48         \li it may be \e active or \e passive
49         \li it may be an \e input or an \e output
50     
51         \e Active connectors are activated from within the module, \e passive connectors are
52         signaled by the external framework. \e Input modules receive packets, \e output modules send
53         packets.
54
55         All passive connectors call some onRequest callback whenever I/O needs to be performed. All
56         input modules possess a packet queue.
57
58         We therefore have 4 connector types: senf::ppi::ActiveInput, senf::ppi::ActiveOutput,
59         senf::ppi::PassiveInput and senf::ppi::PassiveOutput.
60      */
61
62     /** \brief Connector base-class
63
64         This connector provides access to the generic connector facilities. This includes the
65         connection management (access to the connected peer) and the containment management (access
66         to the containing module)
67      */
68     class Connector
69         : boost::noncopyable
70     {
71     public:
72         Connector & peer() const;       ///< Get peer connected to this connector
73         module::Module & module() const; ///< Get this connectors containing module
74
75     protected:
76         Connector();
77         virtual ~Connector();
78
79         void connect(Connector & target);
80
81     private:
82         void setModule(module::Module & module);
83
84         Connector * peer_;
85         module::Module * module_;
86
87         friend class module::Module;
88     };
89
90     /** \brief Passive connector base-class
91
92         A passive connector is a connector which is activated externally whenever an I/O request
93         occurs. Passive connectors are the origin of throttling notifications. Depending on the type
94         of connector (output or input) the respective throttling is called forward or backward
95         throttling.
96
97         Passive connectors always handle two throttling states: 
98         
99         \li The \e native throttling state is set manually by the module. It is the throttling state
100             originating in the current module
101         \li The \e forwarded throttling state is the state as it is received by throttling
102             notifications
103
104         The accumulative throttling state is generated by combining all sub-states.
105      */
106     class PassiveConnector 
107         : public virtual Connector
108     {
109     public:
110         template <class Handler>
111         void onRequest(Handler handler);///< Register I/O event handler
112                                         /**< The registered handler will be called, whenever packets
113                                              arrive or should be generated by the module depending
114                                              on the connector type (input or output). The \a handler
115                                              argument is either an arbitrary callable object or it
116                                              is a pointer-to-member to a member of the class which
117                                              holds this input. In the second case, the pointer will
118                                              automatically be bound to the containing instance.
119                                              
120                                              \param[in] handler Handler to call, whenever an I/O
121                                                  operation is to be performed. */
122
123         
124         bool throttled() const;         ///< Get accumulative throttling state
125         bool nativeThrottled() const;   ///< Get native throttling state
126
127         void throttle();                ///< Set native throttling
128         void unthrottle();              ///< Revoke native throttling
129         
130         ActiveConnector & peer() const;
131
132     protected:
133         PassiveConnector();
134
135         void emit();
136
137     private:
138         // Called by the routing to change the remote throttling state
139         void notifyThrottle();          ///< Forward a throttle notification to this connector
140         void notifyUnthrottle();        ///< Forward an unthrottle notification to this connector
141
142         // Internal members to emit throttling notifications
143         void emitThrottle();
144         void emitUnthrottle();
145
146         // Called after unthrottling the connector
147         virtual void v_unthrottleEvent();
148
149         // called by ForwardingRoute to register a new route
150         void registerRoute(ForwardingRoute & route);
151
152         typedef detail::Callback<>::type Callback;
153         Callback callback_;
154
155         bool remoteThrottled_;
156         bool nativeThrottled_;
157
158         typedef std::vector<ForwardingRoute*> Routes;
159         Routes routes_;
160
161         friend class senf::ppi::ForwardingRoute;
162     };
163
164     /** \brief Active connector base-class
165
166         An active connector is a connector which emits I/O requests. Active connectors receive
167         throttling notifications. Depending on the type of connector (input or output) the
168         respective throttling is called forward or backward throttling.
169
170         Active connectors do not handle any throttling state, they just receive the
171         notifications. These notifications should then either be processed by the module or be
172         forwarded to other connectors.
173      */
174     class ActiveConnector 
175         : public virtual Connector
176     {
177         typedef detail::Callback<>::type Callback;
178     public:
179         template <class Handler>
180         void onThrottle(Handler handler); ///< Register throttle notification handler
181                                         /**< The handler register here will be called, whenever a
182                                              throttle notification comes in. The \a handler argument
183                                              is either an arbitrary callable object or it is a
184                                              pointer-to-member to a member of the class which holds
185                                              this input. In the second case, the pointer will
186                                              automatically be bound to the containing instance.
187
188                                              \param[in] handler Handler to call on throttle
189                                                  notifications. */
190         void onThrottle();              ///< Clear throttle notification handler
191
192         template <class Handler>
193         void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
194                                         /**< The handler register here will be called, whenever an
195                                              unthrottle notification comes in. The \a handler
196                                              argument is either an arbitrary callable object or it
197                                              is a pointer-to-member to a member of the class which
198                                              holds this input. In the second case, the pointer will
199                                              automatically be bound to the containing instance.
200
201                                              \param[in] handler Handler to call on unthrottle
202                                                  notifications. */
203         void onUnthrottle();            ///< Clear unthrottle notification handler
204
205         bool throttled() const;         ///< \c true, if peer() is throttled
206
207         PassiveConnector & peer() const;
208
209     protected:
210         ActiveConnector();
211
212     private:
213         // called by the peer() to forward throttling notifications
214         void notifyThrottle();
215         void notifyUnthrottle();
216
217         // called by ForwardingRoute to register a new route
218         void registerRoute(ForwardingRoute & route);
219
220         Callback throttleCallback_;
221         Callback unthrottleCallback_;
222
223         typedef std::vector<ForwardingRoute*> NotifyRoutes;
224         NotifyRoutes notifyRoutes_;
225
226         friend class senf::ppi::ForwardingRoute;
227         friend class PassiveConnector;
228     };
229
230     /** \brief Input connector base-class
231
232         An input connector receives packets. It may be either an ActiveConnector or a
233         PassiveConnector. An input connector contains a packet queue. This queue enables processing
234         packets in batches or generating multiple output packets from a single input packet. The
235         queues have the potential to greatly simplify the module implementations.
236
237         \implementation Which container to use?
238             \li list has good insertion and deletion properties on both ends but it costs a dynamic
239                 memory allocation for every insertion. A very good property is, that iterators stay
240                 valid across insertions/deletions
241             \li vector is fast and has good amortized dynamic allocation properties. However, it is
242                 quite unusable as a queue
243             \li deque has comparable dynamic allocation properties as vector but also has good
244                 insertion/removal properties on both ends.
245
246             So probably we will use a deque. I'd like a container which keeps iterators intact on
247             insertion/deletion but I believe that list is just to expensive since every packet will
248             be added to the queue before it can be processed.
249      */
250     class InputConnector 
251         : public virtual Connector
252     {
253         typedef std::deque<Packet> Queue;
254     public:
255         typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
256         typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
257
258
259         Packet operator()();            ///< Get a packet
260                                         /**< This member is the primary method to access received
261                                              data. On passive connectors, this operator will just
262                                              dequeue a packet from the packet queue. If the
263                                              connector is active, the connector will request new
264                                              packets from the connected module. If the packet
265                                              request cannot be fulfilled, this is considered to be a
266                                              logic error in the module implementation and an
267                                              exception is raised. */
268
269         Packet read();                  ///< Alias for \ref operator()()
270
271         OutputConnector & peer() const;
272
273         queue_iterator begin() const;   ///< Access queue begin (head)
274         queue_iterator end() const;     ///< Access queue past-the-end (tail)
275         Packet peek() const;            ///< Return head element from the queue
276
277         size_type queueSize() const;    ///< Return number of elements in the queue
278         bool empty() const;             ///< Return queueSize() == 0
279
280     protected:
281         InputConnector();
282         
283     private:
284         void enqueue(Packet p);
285         
286         virtual void v_requestEvent();
287         virtual void v_enqueueEvent();
288         virtual void v_dequeueEvent();
289
290         Queue queue_;
291
292         friend class OutputConnector;
293     };
294     
295     /** \brief Output connector base-class
296         
297         An output connector sends out packets. It may be either an ActiveConnector or a
298         PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
299         the queueing of the connected input.
300      */
301     class OutputConnector 
302         : public virtual Connector
303     {
304     public:
305         void operator()(Packet p);      ///< Send out a packet
306
307         void write(Packet p);           ///< Alias for \ref operator()()
308
309         InputConnector & peer() const;
310
311     protected:
312         OutputConnector();
313     };
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 ///////////////////////////////hh.e////////////////////////////////////////
400 #include "Connectors.cci"
401 //#include "Connectors.ct"
402 #include "Connectors.cti"
403 #endif
404
405 \f
406 // Local Variables:
407 // mode: c++
408 // fill-column: 100
409 // c-file-style: "senf"
410 // indent-tabs-mode: nil
411 // ispell-local-dictionary: "american"
412 // compile-command: "scons -u test"
413 // comment-column: 40
414 // End: