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