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