PPI: Implement DebugEvent
[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         typedef detail::Callback<>::type Callback;
148         Callback callback_;
149
150         bool remoteThrottled_;
151         bool nativeThrottled_;
152
153         friend class senf::ppi::ForwardingRoute;
154     };
155
156     /** \brief Active connector baseclass
157
158         An active connector is a connector which emits I/O requests. Active connectors receive
159         throttling notifications. Depending on the type of connector (input or output) the
160         respective throttling is called forward or backward throttling.
161
162         Active connectors do not handle any throttling state, they just receive the
163         notifications. These notifications should then either be processed by the module or be
164         forwarded to other connectors.
165      */
166     class ActiveConnector 
167         : public virtual Connector
168     {
169         typedef detail::Callback<>::type Callback;
170     public:
171         template <class Handler>
172         void onThrottle(Handler handler); ///< Register throttle notification handler
173                                         /**< The handler register here will be called, whenever a
174                                              throttle notification comes in. The \a handler argument
175                                              is either an arbitrary callable object or it is a
176                                              pointer-to-member to a member of the class which holds
177                                              this input. In the second case, the pointer will
178                                              automatically be bound to the containing instance.
179
180                                              \param[in] handler Handler to call on throttle
181                                                  notifications. */
182         void onThrottle();
183
184         template <class Handler>
185         void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
186                                         /**< The handler register here will be called, whenever an
187                                              unthrottle notification comes in. The \a handler
188                                              argument is either an arbitrary callable object or it
189                                              is a pointer-to-member to a member of the class which
190                                              holds this input. In the second case, the pointer will
191                                              automatically be bound to the containing instance.
192
193                                              \param[in] handle Handler to call on unthrottle
194                                                  notifications. */
195         void onUnthrottle();
196
197         PassiveConnector & peer() const;
198
199     protected:
200         ActiveConnector();
201
202     private:
203         // called by the peer() to forward throttling notifications
204         void notifyThrottle();
205         void notifyUnthrottle();
206
207         // called by ForwardingRoute to register a new route
208         void registerRoute(ForwardingRoute & route);
209
210         Callback throttleCallback_;
211         Callback unthrottleCallback_;
212
213         typedef std::vector<ForwardingRoute*> NotifyRoutes;
214         NotifyRoutes notifyRoutes_;
215
216         friend class senf::ppi::ForwardingRoute;
217         friend class PassiveConnector;
218     };
219
220     /** \brief Input connector baseclass
221
222         An input connector receives packets. It may be either an ActiveConnector or a
223         PassiveConnector. An input connector contains a packet queue. This queue enables processing
224         packets in batches or generating multiple output packets from a single input packet. The
225         queues have the potential to greatly simplify the module implementations.
226
227         \implementation Which container to use?
228             \li list has good insertion and deletion properties on both ends but it costs a dynamic
229                 memory allocation for every insertion. A very good property is, that iterators stay
230                 valid across insertions/deletions
231             \li vector is fast and has good amortized dynamic allocation properties. However, it is
232                 quite unusable as a queue
233             \li deque has comparable dynamic allocation properties as vector but also has good
234                 insertion/removal properties on both ends.
235
236             So probably we will use a deque. I'd like a container which keeps iterators intact on
237             isertion/deletion but I believe that list is just to expensive since every packet will
238             be added to the queue before it can be processed.
239      */
240     class InputConnector 
241         : public virtual Connector
242     {
243         typedef std::deque<Packet> Queue;
244     public:
245         typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
246         typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
247
248         Packet operator()();            ///< Get a packet
249                                         /**< This member is the primary method to access received
250                                              data. On passive connectors, this operator will just
251                                              dequeue a packet from the packet queue. If the
252                                              connector is active, the connector will request new
253                                              packets from the connected module. If the packet
254                                              request cannot be fulfilled, this is considered to be a
255                                              logic error in the module implementation and an
256                                              exception is raised. */
257
258         OutputConnector & peer() const;
259
260         queue_iterator begin() const;   ///< Access queue begin (head)
261         queue_iterator end() const;     ///< Access queue past-the-end (tail)
262         Packet peek() const;            ///< Return head element from the queue
263
264         size_type queueSize() const;    ///< Return number of elements in the queue
265         bool empty() const;             ///< Return queueSize() == 0
266
267     protected:
268         InputConnector();
269         
270     private:
271         void enqueue(Packet p);
272         
273         virtual void v_requestEvent();
274         virtual void v_enqueueEvent();
275         virtual void v_dequeueEvent();
276
277         Queue queue_;
278
279         friend class OutputConnector;
280     };
281     
282     /** \brief Output connector baseclass
283         
284         An output connector sends out packets. It may be either an ActiveConnector or a
285         PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
286         the queueing of the connected input.
287      */
288     class OutputConnector 
289         : public virtual Connector
290     {
291     public:
292         void operator()(Packet p);        ///< Send out a packet
293
294         InputConnector & peer() const;
295
296     protected:
297         OutputConnector();
298     };
299     
300     ///@{
301     ///\addtogroup connectors
302
303     /** \brief Combination of PassiveConnector and InputConnector
304
305         The PassiveInput automatically controls the connectors throttling state using a queueing
306         discipline. The standard queueing discipline is ThresholdQueueing, which throttles the
307         connection whenever the queue length reaches the high threshold and unthrottles the
308         connection when the queue reaches the low threshold. The default queueing discipline is
309         <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
310         non-empty.
311      */
312     class PassiveInput 
313         : public PassiveConnector, public InputConnector,
314           public SafeBool<PassiveInput>
315     {
316     public:
317         PassiveInput();
318
319         ActiveOutput & peer() const;
320
321         bool boolean_test() const;
322
323         template <class QDisc>
324         void qdisc(QDisc const & disc); ///< Change the queueing discipline
325                                         /**< The queueing discipline is a class which provides the
326                                              QueueingDiscipline interface.
327                                              
328                                              \param[in] disc New queueing discipline */
329
330     private:
331         void v_enqueueEvent();
332         void v_dequeueEvent();
333         void v_unthrottleEvent();
334
335         boost::scoped_ptr<QueueingDiscipline> qdisc_;
336     };
337
338     /** \brief Combination of PassiveConnector and OutputConnector
339      */
340     class PassiveOutput
341         : public PassiveConnector, public OutputConnector,
342           public SafeBool<PassiveOutput>
343     {
344     public:
345         ActiveInput & peer() const;
346
347         bool boolean_test() const;
348
349         void connect(ActiveInput & target);
350
351         friend class ActiveInput;
352     };
353
354     /** \brief Combination of ActiveConnector and InputConnector
355      */
356     class ActiveInput
357         : public ActiveConnector, public InputConnector,
358           public SafeBool<ActiveInput>
359     {
360     public:
361         PassiveOutput & peer() const;
362
363         bool boolean_test() const;
364
365         void request();                 ///< request more packets without dequeuing any packet
366
367     private:
368         void v_requestEvent();
369     };
370
371     /** \brief Combination of ActiveConnector and OutputConnector
372      */
373     class ActiveOutput
374         : public ActiveConnector, public OutputConnector,
375           public SafeBool<ActiveOutput>
376     {
377     public:
378         PassiveInput & peer() const;
379
380         bool boolean_test() const;
381
382         void connect(PassiveInput & target);
383     };
384
385     ///@}
386
387 }}}
388
389 ///////////////////////////////hh.e////////////////////////////////////////
390 #include "Connectors.cci"
391 //#include "Connectors.ct"
392 #include "Connectors.cti"
393 #endif
394
395 \f
396 // Local Variables:
397 // mode: c++
398 // fill-column: 100
399 // c-file-style: "senf"
400 // indent-tabs-mode: nil
401 // ispell-local-dictionary: "american"
402 // compile-command: "scons -u test"
403 // comment-column: 40
404 // End: