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