fbaafb63924acec6467db0a0a69f198523a8244d
[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] handle 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         Packet operator()();            ///< Get a packet
259                                         /**< This member is the primary method to access received
260                                              data. On passive connectors, this operator will just
261                                              dequeue a packet from the packet queue. If the
262                                              connector is active, the connector will request new
263                                              packets from the connected module. If the packet
264                                              request cannot be fulfilled, this is considered to be a
265                                              logic error in the module implementation and an
266                                              exception is raised. */
267
268         OutputConnector & peer() const;
269
270         queue_iterator begin() const;   ///< Access queue begin (head)
271         queue_iterator end() const;     ///< Access queue past-the-end (tail)
272         Packet peek() const;            ///< Return head element from the queue
273
274         size_type queueSize() const;    ///< Return number of elements in the queue
275         bool empty() const;             ///< Return queueSize() == 0
276
277     protected:
278         InputConnector();
279         
280     private:
281         void enqueue(Packet p);
282         
283         virtual void v_requestEvent();
284         virtual void v_enqueueEvent();
285         virtual void v_dequeueEvent();
286
287         Queue queue_;
288
289         friend class OutputConnector;
290     };
291     
292     /** \brief Output connector base-class
293         
294         An output connector sends out packets. It may be either an ActiveConnector or a
295         PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
296         the queueing of the connected input.
297      */
298     class OutputConnector 
299         : public virtual Connector
300     {
301     public:
302         void operator()(Packet p);        ///< Send out a packet
303
304         InputConnector & peer() const;
305
306     protected:
307         OutputConnector();
308     };
309     
310     /** \brief Combination of PassiveConnector and InputConnector
311
312         The PassiveInput automatically controls the connectors throttling state using a queueing
313         discipline. The standard queueing discipline is ThresholdQueueing, which throttles the
314         connection whenever the queue length reaches the high threshold and unthrottles the
315         connection when the queue reaches the low threshold. The default queueing discipline is
316         <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
317         non-empty.
318      */
319     class PassiveInput 
320         : public PassiveConnector, public InputConnector,
321           public SafeBool<PassiveInput>
322     {
323     public:
324         PassiveInput();
325
326         ActiveOutput & peer() const;
327
328         bool boolean_test() const;      ///< \c true, if ! empty()
329
330         template <class QDisc>
331         void qdisc(QDisc const & disc); ///< Change the queueing discipline
332                                         /**< The queueing discipline is a class which provides the
333                                              QueueingDiscipline interface.
334                                              
335                                              \param[in] disc New queueing discipline */
336
337     private:
338         void v_enqueueEvent();
339         void v_dequeueEvent();
340         void v_unthrottleEvent();
341
342         boost::scoped_ptr<QueueingDiscipline> qdisc_;
343     };
344
345     /** \brief Combination of PassiveConnector and OutputConnector
346      */
347     class PassiveOutput
348         : public PassiveConnector, public OutputConnector,
349           public SafeBool<PassiveOutput>
350     {
351     public:
352         ActiveInput & peer() const;
353
354         bool boolean_test() const;      ///< Always \c true
355
356         void connect(ActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
357
358         friend class ActiveInput;
359     };
360
361     /** \brief Combination of ActiveConnector and InputConnector
362      */
363     class ActiveInput
364         : public ActiveConnector, public InputConnector,
365           public SafeBool<ActiveInput>
366     {
367     public:
368         PassiveOutput & peer() const;
369
370         bool boolean_test() const;      ///< \c true, if ! empty() or ! throttled()
371
372         void request();                 ///< request more packets without dequeuing any packet
373
374     private:
375         void v_requestEvent();
376     };
377
378     /** \brief Combination of ActiveConnector and OutputConnector
379      */
380     class ActiveOutput
381         : public ActiveConnector, public OutputConnector,
382           public SafeBool<ActiveOutput>
383     {
384     public:
385         PassiveInput & peer() const;
386
387         bool boolean_test() const;      ///< \c true if peer() is ! throttled()
388
389         void connect(PassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
390     };
391
392 }}}
393
394 ///////////////////////////////hh.e////////////////////////////////////////
395 #include "Connectors.cci"
396 //#include "Connectors.ct"
397 #include "Connectors.cti"
398 #endif
399
400 \f
401 // Local Variables:
402 // mode: c++
403 // fill-column: 100
404 // c-file-style: "senf"
405 // indent-tabs-mode: nil
406 // ispell-local-dictionary: "american"
407 // compile-command: "scons -u test"
408 // comment-column: 40
409 // End: