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