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