set keyword svn property on more files
[senf.git] / PPI / Connectors.hh
1 // $Id$
2 //
3 // Copyright (C) 2007 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS) 
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY 
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Connectors public header */
25
26 #ifndef HH_Connectors_
27 #define HH_Connectors_ 1
28
29 // Custom includes
30 #include <deque>
31 #include <boost/utility.hpp>
32 #include <boost/scoped_ptr.hpp>
33 #include "../Utils/safe_bool.hh"
34 #include "../Packets/Packets.hh"
35 #include "predecl.hh"
36 #include "detail/Callback.hh"
37 #include "Queueing.hh"
38
39 //#include "Connectors.mpp"
40 ///////////////////////////////hh.p////////////////////////////////////////
41
42 namespace senf {
43 namespace ppi {
44 namespace connector {
45
46     /** \namespace senf::ppi::connector
47         \brief Connector classes 
48
49         A connector has two independent properties
50         \li it may be \e active or \e passive
51         \li it may be an \e input or an \e output
52     
53         \e Active connectors are activated from within the module, \e passive connectors are
54         signaled by the external framework. \e Input modules receive packets, \e output modules send
55         packets.
56
57         All passive connectors call some onRequest callback whenever I/O needs to be performed. All
58         input modules possess a packet queue.
59
60         We therefore have 4 connector types: 
61         \li senf::ppi::connector::ActiveInput
62         \li senf::ppi::connector::ActiveOutput
63         \li senf::ppi::connector::PassiveInput
64         \li senf::ppi::connector::PassiveOutput.
65
66         Connectors are declared as module data members and are then externally connected to other
67         modules.
68
69         \see 
70             senf::ppi::module::Module \n
71             senf::ppi::connect()
72             \ref ppi_connectors
73      */
74
75     /** \brief Connector base-class
76
77         This connector provides access to the generic connector facilities. This includes the
78         connection management (access to the connected peer) and the containment management (access
79         to the containing module)
80      */
81     class Connector
82         : boost::noncopyable
83     {
84     public:
85         Connector & peer() const;       ///< Get peer connected to this connector
86         module::Module & module() const; ///< Get this connectors containing module
87
88     protected:
89         Connector();
90         virtual ~Connector();
91
92         void connect(Connector & target);
93
94     private:
95         void setModule(module::Module & module);
96
97         Connector * peer_;
98         module::Module * module_;
99
100         friend class module::Module;
101     };
102
103     /** \brief Passive connector base-class
104
105         A passive connector is a connector which is activated externally whenever an I/O request
106         occurs. Passive connectors are the origin of throttling notifications. Depending on the type
107         of connector (output or input) the respective throttling is called forward or backward
108         throttling.
109
110         Passive connectors always handle two throttling states: 
111         
112         \li The \e native throttling state is set manually by the module. It is the throttling state
113             originating in the current module
114         \li The \e forwarded throttling state is the state as it is received by throttling
115             notifications
116
117         The accumulative throttling state is generated by combining all sub-states.
118      */
119     class PassiveConnector 
120         : public virtual Connector
121     {
122     public:
123         template <class Handler>
124         void onRequest(Handler handler);///< Register I/O event handler
125                                         /**< The registered handler will be called, whenever packets
126                                              arrive or should be generated by the module depending
127                                              on the connector type (input or output). The \a handler
128                                              argument is either an arbitrary callable object or it
129                                              is a pointer-to-member to a member of the class which
130                                              holds this input. In the second case, the pointer will
131                                              automatically be bound to the containing instance.
132                                              
133                                              \param[in] handler Handler to call, whenever an I/O
134                                                  operation is to be performed. */
135
136         
137         bool throttled() const;         ///< Get accumulative throttling state
138         bool nativeThrottled() const;   ///< Get native throttling state
139
140         void throttle();                ///< Set native throttling
141         void unthrottle();              ///< Revoke native throttling
142         
143         ActiveConnector & peer() const;
144
145     protected:
146         PassiveConnector();
147
148         void emit();
149
150     private:
151         // Called by the routing to change the remote throttling state
152         void notifyThrottle();          ///< Forward a throttle notification to this connector
153         void notifyUnthrottle();        ///< Forward an unthrottle notification to this connector
154
155         // Internal members to emit throttling notifications
156         void emitThrottle();
157         void emitUnthrottle();
158
159         // Called after unthrottling the connector
160         virtual void v_unthrottleEvent();
161
162         // called by ForwardingRoute to register a new route
163         void registerRoute(ForwardingRoute & route);
164
165         typedef detail::Callback<>::type Callback;
166         Callback callback_;
167
168         bool remoteThrottled_;
169         bool nativeThrottled_;
170
171         typedef std::vector<ForwardingRoute*> Routes;
172         Routes routes_;
173
174         friend class senf::ppi::ForwardingRoute;
175     };
176
177     /** \brief Active connector base-class
178
179         An active connector is a connector which emits I/O requests. Active connectors receive
180         throttling notifications. Depending on the type of connector (input or output) the
181         respective throttling is called forward or backward throttling.
182
183         Active connectors do not handle any throttling state, they just receive the
184         notifications. These notifications should then either be processed by the module or be
185         forwarded to other connectors.
186      */
187     class ActiveConnector 
188         : public virtual Connector
189     {
190         typedef detail::Callback<>::type Callback;
191     public:
192         template <class Handler>
193         void onThrottle(Handler handler); ///< Register throttle notification handler
194                                         /**< The handler register here will be called, whenever a
195                                              throttle notification comes in. The \a handler argument
196                                              is either an arbitrary callable object or it is a
197                                              pointer-to-member to a member of the class which holds
198                                              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 throttle
202                                                  notifications. */
203         void onThrottle();              ///< Clear throttle notification handler
204
205         template <class Handler>
206         void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
207                                         /**< The handler register here will be called, whenever an
208                                              unthrottle notification comes in. The \a handler
209                                              argument is either an arbitrary callable object or it
210                                              is a pointer-to-member to a member of the class which
211                                              holds this input. In the second case, the pointer will
212                                              automatically be bound to the containing instance.
213
214                                              \param[in] handler Handler to call on unthrottle
215                                                  notifications. */
216         void onUnthrottle();            ///< Clear unthrottle notification handler
217
218         bool throttled() const;         ///< \c true, if peer() is throttled
219
220         PassiveConnector & peer() const;
221
222     protected:
223         ActiveConnector();
224
225     private:
226         // called by the peer() to forward throttling notifications
227         void notifyThrottle();
228         void notifyUnthrottle();
229
230         // called by ForwardingRoute to register a new route
231         void registerRoute(ForwardingRoute & route);
232
233         Callback throttleCallback_;
234         Callback unthrottleCallback_;
235
236         typedef std::vector<ForwardingRoute*> NotifyRoutes;
237         NotifyRoutes notifyRoutes_;
238
239         friend class senf::ppi::ForwardingRoute;
240         friend class PassiveConnector;
241     };
242
243     /** \brief Input connector base-class
244
245         An input connector receives packets. It may be either an ActiveConnector or a
246         PassiveConnector. An input connector contains a packet queue. This queue enables processing
247         packets in batches or generating multiple output packets from a single input packet. The
248         queues have the potential to greatly simplify the module implementations.
249
250         \implementation Which container to use?
251             \li list has good insertion and deletion properties on both ends but it costs a dynamic
252                 memory allocation for every insertion. A very good property is, that iterators stay
253                 valid across insertions/deletions
254             \li vector is fast and has good amortized dynamic allocation properties. However, it is
255                 quite unusable as a queue
256             \li deque has comparable dynamic allocation properties as vector but also has good
257                 insertion/removal properties on both ends.
258
259             So probably we will use a deque. I'd like a container which keeps iterators intact on
260             insertion/deletion but I believe that list is just to expensive since every packet will
261             be added to the queue before it can be processed.
262      */
263     class InputConnector 
264         : public virtual Connector
265     {
266         typedef std::deque<Packet> Queue;
267     public:
268         typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
269         typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
270
271
272         Packet operator()();            ///< Get a packet
273                                         /**< This member is the primary method to access received
274                                              data. On passive connectors, this operator will just
275                                              dequeue a packet from the packet queue. If the
276                                              connector is active, the connector will request new
277                                              packets from the connected module. If the packet
278                                              request cannot be fulfilled, this is considered to be a
279                                              logic error in the module implementation and an
280                                              exception is raised. */
281
282         Packet read();                  ///< Alias for operator()()
283
284         OutputConnector & peer() const;
285
286         queue_iterator begin() const;   ///< Access queue begin (head)
287         queue_iterator end() const;     ///< Access queue past-the-end (tail)
288         Packet peek() const;            ///< Return head element from the queue
289
290         size_type queueSize() const;    ///< Return number of elements in the queue
291         bool empty() const;             ///< Return queueSize() == 0
292
293     protected:
294         InputConnector();
295         
296     private:
297         void enqueue(Packet p);
298         
299         virtual void v_requestEvent();
300         virtual void v_enqueueEvent();
301         virtual void v_dequeueEvent();
302
303         Queue queue_;
304
305         friend class OutputConnector;
306     };
307     
308     /** \brief Output connector base-class
309         
310         An output connector sends out packets. It may be either an ActiveConnector or a
311         PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
312         the queueing of the connected input.
313      */
314     class OutputConnector 
315         : public virtual Connector
316     {
317     public:
318         void operator()(Packet p);      ///< Send out a packet
319
320         void write(Packet p);           ///< Alias for operator()(Packet p)
321
322         InputConnector & peer() const;
323
324     protected:
325         OutputConnector();
326     };
327     
328     /** \brief Combination of PassiveConnector and InputConnector
329
330         The PassiveInput automatically controls the connectors throttling state using a queueing
331         discipline. The standard queueing discipline is ThresholdQueueing, which throttles the
332         connection whenever the queue length reaches the high threshold and unthrottles the
333         connection when the queue reaches the low threshold. The default queueing discipline is
334         <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
335         non-empty.
336      */
337     class PassiveInput 
338         : public PassiveConnector, public InputConnector,
339           public safe_bool<PassiveInput>
340     {
341     public:
342         PassiveInput();
343
344         ActiveOutput & peer() const;
345
346         bool boolean_test() const;      ///< \c true, if ! empty()
347
348         template <class QDisc>
349         void qdisc(QDisc const & disc); ///< Change the queueing discipline
350                                         /**< The queueing discipline is a class which provides the
351                                              QueueingDiscipline interface.
352                                              
353                                              \param[in] disc New queueing discipline */
354
355     private:
356         void v_enqueueEvent();
357         void v_dequeueEvent();
358         void v_unthrottleEvent();
359
360         boost::scoped_ptr<QueueingDiscipline> qdisc_;
361     };
362
363     /** \brief Combination of PassiveConnector and OutputConnector
364      */
365     class PassiveOutput
366         : public PassiveConnector, public OutputConnector,
367           public safe_bool<PassiveOutput>
368     {
369     public:
370         ActiveInput & peer() const;
371
372         bool boolean_test() const;      ///< Always \c true
373
374         void connect(ActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
375
376         friend class ActiveInput;
377     };
378
379     /** \brief Combination of ActiveConnector and InputConnector
380      */
381     class ActiveInput
382         : public ActiveConnector, public InputConnector,
383           public safe_bool<ActiveInput>
384     {
385     public:
386         PassiveOutput & peer() const;
387
388         bool boolean_test() const;      ///< \c true, if ! empty() or ! throttled()
389
390         void request();                 ///< request more packets without dequeuing any packet
391
392     private:
393         void v_requestEvent();
394     };
395
396     /** \brief Combination of ActiveConnector and OutputConnector
397      */
398     class ActiveOutput
399         : public ActiveConnector, public OutputConnector,
400           public safe_bool<ActiveOutput>
401     {
402     public:
403         PassiveInput & peer() const;
404
405         bool boolean_test() const;      ///< \c true if peer() is ! throttled()
406
407         void connect(PassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
408     };
409
410 }}}
411
412 ///////////////////////////////hh.e////////////////////////////////////////
413 #include "Connectors.cci"
414 //#include "Connectors.ct"
415 #include "Connectors.cti"
416 #endif
417
418 \f
419 // Local Variables:
420 // mode: c++
421 // fill-column: 100
422 // c-file-style: "senf"
423 // indent-tabs-mode: nil
424 // ispell-local-dictionary: "american"
425 // compile-command: "scons -u test"
426 // comment-column: 40
427 // End: