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