4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 // Stefan Bund <g0dil@berlios.de>
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.
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.
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.
24 \brief Connectors public header */
26 #ifndef HH_Connectors_
27 #define HH_Connectors_ 1
31 #include <boost/utility.hpp>
32 #include <boost/scoped_ptr.hpp>
33 #include "../Utils/safe_bool.hh"
34 #include "../Packets/Packets.hh"
36 #include "detail/Callback.hh"
37 #include "Queueing.hh"
39 //#include "Connectors.mpp"
40 ///////////////////////////////hh.p////////////////////////////////////////
46 /** \namespace senf::ppi::connector
47 \brief Connector classes
49 A connector has two independent properties
50 - it may be \e active or \e passive
51 - it may be an \e input or an \e output
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
57 All passive connectors call some onRequest callback whenever I/O needs to be performed. All
58 input modules possess a packet queue.
60 We therefore have 4 connector types:
61 - senf::ppi::connector::ActiveInput
62 - senf::ppi::connector::ActiveOutput
63 - senf::ppi::connector::PassiveInput
64 - senf::ppi::connector::PassiveOutput.
66 Connectors are declared as module data members and are then externally connected to other
69 The connectors each take an optional template argument. If this argument is specified, it
70 must be the type of packet expected or sent on this connector. If it is not specified,
71 packets will be passed using the generic Packet handle.
74 class IpFilter : public senf::ppi::module::Module
76 SENF_PPI_MODULE(SomeModule);
79 senf::ppi::connector::ActiveInput<senf::EthernetPacket> input;
80 senf::ppi::connector::PassiveOutput<senf::IpPacket> output;
84 input.onRequest(&IpFilter::onRequest);
89 // 'input()' will return a senf::EthernetPacket packet handle
90 try { output( input().find<IpPacket>() ); }
91 catch (senf::InvalidPacketChainException & ex) { ; }
97 senf::ppi::module::Module \n
98 senf::ppi::connect() \n
102 /** \brief Connector base-class
104 This connector provides access to the generic connector facilities. This includes the
105 connection management (access to the connected peer) and the containment management (access
106 to the containing module)
112 Connector & peer() const; ///< Get peer connected to this connector
113 module::Module & module() const; ///< Get this connectors containing module
117 virtual ~Connector();
119 void connect(Connector & target);
122 void setModule(module::Module & module);
125 module::Module * module_;
127 friend class module::Module;
130 /** \brief Passive connector base-class
132 A passive connector is a connector which is activated externally whenever an I/O request
133 occurs. Passive connectors are the origin of throttling notifications. Depending on the type
134 of connector (output or input) the respective throttling is called forward or backward
137 Passive connectors always handle two throttling states:
139 - The \e native throttling state is set manually by the module. It is the throttling state
140 originating in the current module
141 - The \e forwarded throttling state is the state as it is received by throttling
144 The accumulative throttling state is generated by combining all sub-states.
146 class PassiveConnector
147 : public virtual Connector
150 template <class Handler>
151 void onRequest(Handler handler);///< Register I/O event handler
152 /**< The registered handler will be called, whenever packets
153 arrive or should be generated by the module depending
154 on the connector type (input or output). The \a handler
155 argument is either an arbitrary callable object or it
156 is a pointer-to-member to a member of the class which
157 holds this input. In the second case, the pointer will
158 automatically be bound to the containing instance.
160 \param[in] handler Handler to call, whenever an I/O
161 operation is to be performed. */
164 bool throttled() const; ///< Get accumulative throttling state
165 bool nativeThrottled() const; ///< Get native throttling state
167 void throttle(); ///< Set native throttling
168 void unthrottle(); ///< Revoke native throttling
170 ActiveConnector & peer() const;
178 // Called by the routing to change the remote throttling state
179 void notifyThrottle(); ///< Forward a throttle notification to this connector
180 void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
182 // Internal members to emit throttling notifications
184 void emitUnthrottle();
186 // Called after unthrottling the connector
187 virtual void v_unthrottleEvent();
189 // called by ForwardingRoute to register a new route
190 void registerRoute(ForwardingRoute & route);
192 typedef ppi::detail::Callback<>::type Callback;
195 bool remoteThrottled_;
196 bool nativeThrottled_;
198 typedef std::vector<ForwardingRoute*> Routes;
201 friend class senf::ppi::ForwardingRoute;
204 /** \brief Active connector base-class
206 An active connector is a connector which emits I/O requests. Active connectors receive
207 throttling notifications. Depending on the type of connector (input or output) the
208 respective throttling is called forward or backward throttling.
210 Active connectors do not handle any throttling state, they just receive the
211 notifications. These notifications should then either be processed by the module or be
212 forwarded to other connectors.
214 class ActiveConnector
215 : public virtual Connector
217 typedef ppi::detail::Callback<>::type Callback;
219 template <class Handler>
220 void onThrottle(Handler handler); ///< Register throttle notification handler
221 /**< The handler register here will be called, whenever a
222 throttle notification comes in. The \a handler argument
223 is either an arbitrary callable object or it is a
224 pointer-to-member to a member of the class which holds
225 this input. In the second case, the pointer will
226 automatically be bound to the containing instance.
228 \param[in] handler Handler to call on throttle
230 void onThrottle(); ///< Clear throttle notification handler
232 template <class Handler>
233 void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
234 /**< The handler register here will be called, whenever an
235 unthrottle notification comes in. The \a handler
236 argument is either an arbitrary callable object or it
237 is a pointer-to-member to a member of the class which
238 holds this input. In the second case, the pointer will
239 automatically be bound to the containing instance.
241 \param[in] handler Handler to call on unthrottle
243 void onUnthrottle(); ///< Clear unthrottle notification handler
245 bool throttled() const; ///< \c true, if peer() is throttled
247 PassiveConnector & peer() const;
253 // called by the peer() to forward throttling notifications
254 void notifyThrottle();
255 void notifyUnthrottle();
257 // called by ForwardingRoute to register a new route
258 void registerRoute(ForwardingRoute & route);
260 Callback throttleCallback_;
261 Callback unthrottleCallback_;
263 typedef std::vector<ForwardingRoute*> NotifyRoutes;
264 NotifyRoutes notifyRoutes_;
266 friend class senf::ppi::ForwardingRoute;
267 friend class PassiveConnector;
270 /** \brief Input connector base-class
272 An input connector receives packets. It may be either an ActiveConnector or a
273 PassiveConnector. An input connector contains a packet queue. This queue enables processing
274 packets in batches or generating multiple output packets from a single input packet. The
275 queues have the potential to greatly simplify the module implementations.
277 \implementation Which container to use?
278 \li list has good insertion and deletion properties on both ends but it costs a dynamic
279 memory allocation for every insertion. A very good property is, that iterators stay
280 valid across insertions/deletions
281 \li vector is fast and has good amortized dynamic allocation properties. However, it is
282 quite unusable as a queue
283 \li deque has comparable dynamic allocation properties as vector but also has good
284 insertion/removal properties on both ends.
286 So probably we will use a deque. I'd like a container which keeps iterators intact on
287 insertion/deletion but I believe that list is just to expensive since every packet will
288 be added to the queue before it can be processed.
291 : public virtual Connector
293 typedef std::deque<Packet> Queue;
295 typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
296 typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
299 Packet operator()(); ///< Get a packet
300 /**< This member is the primary method to access received
301 data. On passive connectors, this operator will just
302 dequeue a packet from the packet queue. If the
303 connector is active, the connector will request new
304 packets from the connected module. If the packet
305 request cannot be fulfilled, this is considered to be a
306 logic error in the module implementation and an
307 exception is raised. */
309 Packet read(); ///< Alias for operator()()
311 OutputConnector & peer() const;
313 queue_iterator begin() const; ///< Access queue begin (head)
314 queue_iterator end() const; ///< Access queue past-the-end (tail)
315 Packet peek() const; ///< Return head element from the queue
317 size_type queueSize() const; ///< Return number of elements in the queue
318 bool empty() const; ///< Return queueSize() == 0
324 void enqueue(Packet p);
326 virtual void v_requestEvent();
327 virtual void v_enqueueEvent();
328 virtual void v_dequeueEvent();
332 friend class OutputConnector;
335 /** \brief Output connector base-class
337 An output connector sends out packets. It may be either an ActiveConnector or a
338 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
339 the queueing of the connected input.
341 class OutputConnector
342 : public virtual Connector
345 void operator()(Packet p); ///< Send out a packet
347 void write(Packet p); ///< Alias for operator()(Packet p)
349 InputConnector & peer() const;
355 /** \brief Combination of PassiveConnector and InputConnector
357 The GenericPassiveInput automatically controls the connectors throttling state using a
358 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
359 the connection whenever the queue length reaches the high threshold and unthrottles the
360 connection when the queue reaches the low threshold. The default queueing discipline is
361 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
364 class GenericPassiveInput
365 : public PassiveConnector, public InputConnector,
366 public safe_bool<GenericPassiveInput>
369 GenericActiveOutput & peer() const;
371 bool boolean_test() const; ///< \c true, if ! empty()
373 template <class QDisc>
374 void qdisc(QDisc const & disc); ///< Change the queueing discipline
375 /**< The queueing discipline is a class which provides the
376 QueueingDiscipline interface.
378 \param[in] disc New queueing discipline */
381 GenericPassiveInput();
384 void v_enqueueEvent();
385 void v_dequeueEvent();
386 void v_unthrottleEvent();
388 boost::scoped_ptr<QueueingDiscipline> qdisc_;
391 /** \brief Combination of PassiveConnector and OutputConnector
393 class GenericPassiveOutput
394 : public PassiveConnector, public OutputConnector,
395 public safe_bool<GenericPassiveOutput>
398 GenericActiveInput & peer() const;
400 bool boolean_test() const; ///< Always \c true
402 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
404 friend class GenericActiveInput;
407 GenericPassiveOutput();
411 /** \brief Combination of ActiveConnector and InputConnector
413 class GenericActiveInput
414 : public ActiveConnector, public InputConnector,
415 public safe_bool<GenericActiveInput>
418 GenericPassiveOutput & peer() const;
420 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
422 void request(); ///< request more packets without dequeuing any packet
425 GenericActiveInput();
428 void v_requestEvent();
431 /** \brief Combination of ActiveConnector and OutputConnector
433 class GenericActiveOutput
434 : public ActiveConnector, public OutputConnector,
435 public safe_bool<GenericActiveOutput>
438 GenericPassiveInput & peer() const;
440 bool boolean_test() const; ///< \c true if peer() is ! throttled()
442 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
445 GenericActiveOutput();
451 # define TypedConnector_Input read
452 # define TypedConnector_Output write
453 # define TypedConnector(type, dir) \
454 template <class PacketType> \
456 : public Generic ## type ## dir, \
457 private detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType> \
459 typedef detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType> mixin; \
461 using mixin::operator(); \
462 using mixin::TypedConnector_ ## dir ; \
464 friend class detail::Typed ## dir ## Mixin<type ## dir <PacketType>, PacketType>; \
467 class type ## dir <Packet> : public Generic ## type ## dir \
470 TypedConnector( Passive, Input );
471 TypedConnector( Passive, Output );
472 TypedConnector( Active, Input );
473 TypedConnector( Active, Output );
475 # undef TypedConnector
476 # undef TypedConnector_Input
477 # undef TypedConnector_Output
481 /** \brief Connector actively reading packets
483 \tparam PacketType Type of packet to read. Defaults to senf::Packet
485 The ActiveInput connector template reads data actively from a connected module. This class
486 is completely implemented via it's base-class, GenericActiveInput, the only difference is
487 that read packets are returned as \a PacketType instead of generic senf::Packet references.
489 \see GenericActiveInput \n
492 template <class PacketType=Packet>
493 class ActiveInput : public GenericActiveInput
496 PacketType operator()(); ///< Read packet
497 /**< \throws std::bad_cast, if the connector receives a
498 Packet which is not of type \a PacketType.
499 \returns newly read packet reference. */
500 PacketType read(); ///< Alias for operator()
503 /** \brief Connector passively receiving packets
505 \tparam PacketType Type of packet to read. Defaults to senf::Packet
507 The PassiveInput connector template receives packets sent to it from a connected
508 module. This class is completely implemented via it's base-class, GenericPassiveInput, the
509 only difference is that read packets are returned as \a PacketType instead of generic
510 senf::Packet references.
512 \see GenericPassiveInput \n
515 template <class PacketType=Packet>
516 class PassiveInput : public GenericPassiveInput
519 PacketType operator()(); ///< Read packet
520 /**< \throws std::bad_cast, if the connector receives a
521 Packet which is not of type \a PacketType.
522 \returns newly read packet reference. */
523 PacketType read(); ///< Alias for operator()
526 /** \brief Connector actively sending packets
528 \tparam PacketType Type of packet to send. Defaults to senf::Packet
530 The ActiveOutput connector template sends data actively to a connected module. This class is
531 completely implemented via it's base-class, GenericActiveOutput, the only difference is that
532 it only sends packets of type \a PacketType.
534 \see GenericActiveOutput \n
537 template <class PacketType=Packet>
538 class ActiveOutput : public GenericActiveOutput
541 operator()(PacketType packet); ///< Send out a packet
542 write(PacketType packet); ///< Alias for operator()
545 /** \brief Connector passively providing packets
547 \tparam PacketType Type of packet to send. Defaults to senf::Packet
549 The PassiveOutput connector template provides data passively to a connected module whenever
550 signaled. This class is completely implemented via it's base-class, GenericPassiveOutput, the
551 only difference is that it only sends packets of type \a PacketType.
553 \see GenericPassiveOutput \n
556 template <class PacketType=Packet>
557 class PassiveOutput : public GenericPassiveOutput
560 operator()(PacketType packet); ///< Send out a packet
561 write(PacketType packet); ///< Alias for operator()
568 ///////////////////////////////hh.e////////////////////////////////////////
569 #include "Connectors.cci"
570 //#include "Connectors.ct"
571 #include "Connectors.cti"
578 // c-file-style: "senf"
579 // indent-tabs-mode: nil
580 // ispell-local-dictionary: "american"
581 // compile-command: "scons -u test"
582 // comment-column: 40