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 "../Utils/Exception.hh"
35 #include "../Packets/Packets.hh"
37 #include "detail/Callback.hh"
38 #include "Queueing.hh"
40 //#include "Connectors.mpp"
41 ///////////////////////////////hh.p////////////////////////////////////////
47 /** \namespace senf::ppi::connector
48 \brief Connector classes
50 A connector has three independent properties
51 \li it may be \e active or \e passive
52 \li it may be an \e input or an \e output
53 \li it has an (optional) packet type
55 \e Active connectors are activated from within the module, \e passive connectors are
56 signaled by the external framework. \e Input connectors receive packets, \e output
57 connectors send packets.
59 All passive connectors call some onRequest callback whenever I/O needs to be performed. All
60 input connectors possess a packet queue.
62 We therefore have 4 connector types each of which is parameterized by the type of packet
63 traversing the connector:
64 \li senf::ppi::connector::ActiveInput
65 \li senf::ppi::connector::ActiveOutput
66 \li senf::ppi::connector::PassiveInput
67 \li senf::ppi::connector::PassiveOutput.
69 Connectors are declared as module data members and are then externally connected to other
72 The connectors each take an optional template argument. If this argument is specified, it
73 must be the type of packet expected or sent on this connector. If it is not specified,
74 packets will be passed using the generic Packet handle.
77 class IpFilter : public senf::ppi::module::Module
79 SENF_PPI_MODULE(SomeModule);
82 senf::ppi::connector::ActiveInput<senf::EthernetPacket> input;
83 senf::ppi::connector::PassiveOutput<senf::IpPacket> output;
87 input.onRequest(&IpFilter::onRequest);
92 // 'input()' will return a senf::EthernetPacket packet handle
93 try { output( input().find<senf::IpPacket>() ); }
94 catch (senf::InvalidPacketChainException & ex) { ; }
100 senf::ppi::module::Module \n
101 senf::ppi::connect() \n
105 /** \brief Incompatible connectors connected
107 This exception is thrown, when two incompatible connectors are connected. This happens if
108 both connectors of a senf::ppi::connect() statement declare a packet type (the connector
109 template argument) but they don't declare the same packet type.
111 You need to ensure, that both connectors use the same packet type.
113 \see senf::ppi::connect()
115 struct IncompatibleConnectorsException : public senf::Exception
116 { IncompatibleConnectorsException() : senf::Exception("Incompatible connectors") {} };
118 /** \brief Connector base-class
120 This connector provides access to the generic connector facilities. This includes the
121 connection management (access to the connected peer) and the containment management (access
122 to the containing module)
128 Connector & peer() const; ///< Get peer connected to this connector
129 module::Module & module() const; ///< Get this connectors containing module
131 bool connected() const; ///< \c true, if connector connected, \c false otherwise
135 virtual ~Connector();
137 void connect(Connector & target);
140 virtual std::type_info const & packetTypeID();
142 void setModule(module::Module & module);
144 virtual void v_init() = 0;
147 module::Module * module_;
149 friend class module::Module;
152 /** \brief Passive connector base-class
154 A passive connector is a connector which is activated externally whenever an I/O request
155 occurs. Passive connectors are the origin of throttling notifications. Depending on the type
156 of connector (output or input) the respective throttling is called forward or backward
159 Passive connectors always handle two throttling states:
161 - The \e native throttling state is set manually by the module. It is the throttling state
162 originating in the current module
163 - The \e forwarded throttling state is the state as it is received by throttling
166 The accumulative throttling state is generated by combining all sub-states.
168 class PassiveConnector
169 : public virtual Connector
172 template <class Handler>
173 void onRequest(Handler handler);///< Register I/O event handler
174 /**< The registered handler will be called, whenever packets
175 arrive or should be generated by the module depending
176 on the connector type (input or output). The \a handler
177 argument is either an arbitrary callable object or it
178 is a pointer-to-member to a member of the class which
179 holds this input. In the second case, the pointer will
180 automatically be bound to the containing instance.
182 \param[in] handler Handler to call, whenever an I/O
183 operation is to be performed. */
186 bool throttled() const; ///< Get accumulative throttling state
187 bool nativeThrottled() const; ///< Get native throttling state
189 void throttle(); ///< Set native throttling
190 void unthrottle(); ///< Revoke native throttling
192 ActiveConnector & peer() const;
200 virtual void v_init();
202 // Called by the routing to change the remote throttling state
203 void notifyThrottle(); ///< Forward a throttle notification to this connector
204 void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
206 // Internal members to emit throttling notifications
208 void emitUnthrottle();
210 // Called after unthrottling the connector
211 virtual void v_unthrottleEvent();
213 // called by ForwardingRoute to register a new route
214 void registerRoute(ForwardingRoute & route);
216 typedef ppi::detail::Callback<>::type Callback;
219 bool remoteThrottled_;
220 bool nativeThrottled_;
222 typedef std::vector<ForwardingRoute*> Routes;
225 friend class senf::ppi::ForwardingRoute;
228 /** \brief Active connector base-class
230 An active connector is a connector which emits I/O requests. Active connectors receive
231 throttling notifications. Depending on the type of connector (input or output) the
232 respective throttling is called forward or backward throttling.
234 Active connectors do not handle any throttling state, they just receive the
235 notifications. These notifications should then either be processed by the module or be
236 forwarded to other connectors.
238 class ActiveConnector
239 : public virtual Connector
241 typedef ppi::detail::Callback<>::type Callback;
243 template <class Handler>
244 void onThrottle(Handler handler); ///< Register throttle notification handler
245 /**< The handler register here will be called, whenever a
246 throttle notification comes in. The \a handler argument
247 is either an arbitrary callable object or it is a
248 pointer-to-member to a member of the class which holds
249 this input. In the second case, the pointer will
250 automatically be bound to the containing instance.
252 \param[in] handler Handler to call on throttle
254 void onThrottle(); ///< Clear throttle notification handler
256 template <class Handler>
257 void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
258 /**< The handler register here will be called, whenever an
259 unthrottle notification comes in. The \a handler
260 argument is either an arbitrary callable object or it
261 is a pointer-to-member to a member of the class which
262 holds this input. In the second case, the pointer will
263 automatically be bound to the containing instance.
265 \param[in] handler Handler to call on unthrottle
267 void onUnthrottle(); ///< Clear unthrottle notification handler
269 bool throttled() const; ///< \c true, if peer() is throttled
271 PassiveConnector & peer() const;
277 virtual void v_init();
279 // called by the peer() to forward throttling notifications
280 void notifyThrottle();
281 void notifyUnthrottle();
283 // called by ForwardingRoute to register a new route
284 void registerRoute(ForwardingRoute & route);
286 Callback throttleCallback_;
287 Callback unthrottleCallback_;
289 typedef std::vector<ForwardingRoute*> NotifyRoutes;
290 NotifyRoutes notifyRoutes_;
294 friend class senf::ppi::ForwardingRoute;
295 friend class PassiveConnector;
298 /** \brief Input connector base-class
300 An input connector receives packets. It may be either an ActiveConnector or a
301 PassiveConnector. An input connector contains a packet queue. This queue enables processing
302 packets in batches or generating multiple output packets from a single input packet. The
303 queues have the potential to greatly simplify the module implementations.
305 \implementation Which container to use?
306 \li list has good insertion and deletion properties on both ends but it costs a dynamic
307 memory allocation for every insertion. A very good property is, that iterators stay
308 valid across insertions/deletions
309 \li vector is fast and has good amortized dynamic allocation properties. However, it is
310 quite unusable as a queue
311 \li deque has comparable dynamic allocation properties as vector but also has good
312 insertion/removal properties on both ends.
314 So probably we will use a deque. I'd like a container which keeps iterators intact on
315 insertion/deletion but I believe that list is just to expensive since every packet will
316 be added to the queue before it can be processed.
319 : public virtual Connector
321 typedef std::deque<Packet> Queue;
323 typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
324 typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
327 Packet operator()(); ///< Get a packet
328 /**< This member is the primary method to access received
329 data. On passive connectors, this operator will just
330 dequeue a packet from the packet queue. If the
331 connector is active, the connector will request new
332 packets from the connected module. If the packet
333 request cannot be fulfilled, this is considered to be a
334 logic error in the module implementation and an
335 exception is raised. */
337 Packet read(); ///< Alias for operator()()
339 OutputConnector & peer() const;
341 queue_iterator begin() const; ///< Access queue begin (head)
342 queue_iterator end() const; ///< Access queue past-the-end (tail)
343 Packet peek() const; ///< Return head element from the queue
345 size_type queueSize() const; ///< Return number of elements in the queue
346 bool empty() const; ///< Return queueSize() == 0
352 void enqueue(Packet p);
354 virtual void v_requestEvent();
355 virtual void v_enqueueEvent();
356 virtual void v_dequeueEvent();
360 friend class OutputConnector;
363 /** \brief Output connector base-class
365 An output connector sends out packets. It may be either an ActiveConnector or a
366 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
367 the queueing of the connected input.
369 class OutputConnector
370 : public virtual Connector
373 void operator()(Packet p); ///< Send out a packet
375 void write(Packet p); ///< Alias for operator()(Packet p)
377 InputConnector & peer() const;
383 /** \brief Combination of PassiveConnector and InputConnector
385 The GenericPassiveInput automatically controls the connectors throttling state using a
386 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
387 the connection whenever the queue length reaches the high threshold and unthrottles the
388 connection when the queue reaches the low threshold. The default queueing discipline is
389 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
392 class GenericPassiveInput
393 : public PassiveConnector, public InputConnector,
394 public safe_bool<GenericPassiveInput>
397 GenericActiveOutput & peer() const;
399 bool boolean_test() const; ///< \c true, if ! empty()
401 template <class QDisc>
402 void qdisc(QDisc const & disc); ///< Change the queueing discipline
403 /**< The queueing discipline is a class which provides the
404 QueueingDiscipline interface.
406 \param[in] disc New queueing discipline */
409 GenericPassiveInput();
412 void v_enqueueEvent();
413 void v_dequeueEvent();
414 void v_unthrottleEvent();
416 boost::scoped_ptr<QueueingDiscipline> qdisc_;
419 /** \brief Combination of PassiveConnector and OutputConnector
421 class GenericPassiveOutput
422 : public PassiveConnector, public OutputConnector,
423 public safe_bool<GenericPassiveOutput>
426 GenericActiveInput & peer() const;
428 bool boolean_test() const; ///< Always \c true
430 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
432 friend class GenericActiveInput;
435 GenericPassiveOutput();
439 /** \brief Combination of ActiveConnector and InputConnector
441 class GenericActiveInput
442 : public ActiveConnector, public InputConnector,
443 public safe_bool<GenericActiveInput>
446 GenericPassiveOutput & peer() const;
448 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
450 void request(); ///< request more packets without dequeuing any packet
453 GenericActiveInput();
456 void v_requestEvent();
459 /** \brief Combination of ActiveConnector and OutputConnector
461 class GenericActiveOutput
462 : public ActiveConnector, public OutputConnector,
463 public safe_bool<GenericActiveOutput>
466 GenericPassiveInput & peer() const;
468 bool boolean_test() const; ///< \c true if peer() is ! throttled()
470 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
473 GenericActiveOutput();
479 # define TypedConnector_Input read
480 # define TypedConnector_Output write
481 # define TypedConnector(pType, dir) \
482 template <class PacketType> \
484 : public Generic ## pType ## dir, \
485 private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
487 typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
489 using mixin::operator(); \
490 using mixin::TypedConnector_ ## dir ; \
492 virtual std::type_info const & packetTypeID() \
493 { return typeid(typename PacketType::type); } \
494 friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
497 class pType ## dir <Packet> : public Generic ## pType ## dir \
500 TypedConnector( Passive, Input );
501 TypedConnector( Passive, Output );
502 TypedConnector( Active, Input );
503 TypedConnector( Active, Output );
505 # undef TypedConnector
506 # undef TypedConnector_Input
507 # undef TypedConnector_Output
511 /** \brief Connector actively reading packets
513 \tparam PacketType Type of packet to read. Defaults to senf::Packet
515 The %ActiveInput %connector template reads data actively from a connected %module. This
516 class is completely implemented via it's base-class, GenericActiveInput, the only
517 difference is that read packets are returned as \a PacketType instead of generic
518 senf::Packet references.
520 \see GenericActiveInput \n
523 template <class PacketType=Packet>
524 class ActiveInput : public GenericActiveInput
527 PacketType operator()(); ///< Read packet
528 /**< \throws std::bad_cast, if the %connector receives a
529 Packet which is not of type \a PacketType.
530 \returns newly read packet reference. */
531 PacketType read(); ///< Alias for operator()
534 /** \brief Connector passively receiving packets
536 \tparam PacketType Type of packet to read. Defaults to senf::Packet
538 The %PassiveInput %connector template receives packets sent to it from a connected
539 %module. This class is completely implemented via it's base-class, GenericPassiveInput,
540 the only difference is that read packets are returned as \a PacketType instead of generic
541 senf::Packet references.
543 \see GenericPassiveInput \n
546 template <class PacketType=Packet>
547 class PassiveInput : public GenericPassiveInput
550 PacketType operator()(); ///< Read packet
551 /**< \throws std::bad_cast, if the %connector receives a
552 Packet which is not of type \a PacketType.
553 \returns newly read packet reference. */
554 PacketType read(); ///< Alias for operator()
557 /** \brief Connector actively sending packets
559 \tparam PacketType Type of packet to send. Defaults to senf::Packet
561 The %ActiveOutput %connector template sends data actively to a connected %module. This
562 class is completely implemented via it's base-class, GenericActiveOutput, the only
563 difference is that it only sends packets of type \a PacketType.
565 \see GenericActiveOutput \n
568 template <class PacketType=Packet>
569 class ActiveOutput : public GenericActiveOutput
572 operator()(PacketType packet); ///< Send out a packet
573 void write(PacketType packet); ///< Alias for operator()
576 /** \brief Connector passively providing packets
578 \tparam PacketType Type of packet to send. Defaults to senf::Packet
580 The %PassiveOutput %connector template provides data passively to a connected %module
581 whenever signaled. This class is completely implemented via it's base-class,
582 GenericPassiveOutput, the only difference is that it only sends packets of type
585 \see GenericPassiveOutput \n
588 template <class PacketType=Packet>
589 class PassiveOutput : public GenericPassiveOutput
592 operator()(PacketType packet); ///< Send out a packet
593 void write(PacketType packet); ///< Alias for operator()
600 ///////////////////////////////hh.e////////////////////////////////////////
601 #include "Connectors.cci"
602 //#include "Connectors.ct"
603 #include "Connectors.cti"
610 // c-file-style: "senf"
611 // indent-tabs-mode: nil
612 // ispell-local-dictionary: "american"
613 // compile-command: "scons -u test"
614 // comment-column: 40