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 modules receive packets, \e output modules send
59 All passive connectors call some onRequest callback whenever I/O needs to be performed. All
60 input modules 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<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
133 virtual ~Connector();
135 void connect(Connector & target);
138 virtual std::type_info const & packetTypeID();
140 void setModule(module::Module & module);
143 module::Module * module_;
145 friend class module::Module;
148 /** \brief Passive connector base-class
150 A passive connector is a connector which is activated externally whenever an I/O request
151 occurs. Passive connectors are the origin of throttling notifications. Depending on the type
152 of connector (output or input) the respective throttling is called forward or backward
155 Passive connectors always handle two throttling states:
157 - The \e native throttling state is set manually by the module. It is the throttling state
158 originating in the current module
159 - The \e forwarded throttling state is the state as it is received by throttling
162 The accumulative throttling state is generated by combining all sub-states.
164 class PassiveConnector
165 : public virtual Connector
168 template <class Handler>
169 void onRequest(Handler handler);///< Register I/O event handler
170 /**< The registered handler will be called, whenever packets
171 arrive or should be generated by the module depending
172 on the connector type (input or output). The \a handler
173 argument is either an arbitrary callable object or it
174 is a pointer-to-member to a member of the class which
175 holds this input. In the second case, the pointer will
176 automatically be bound to the containing instance.
178 \param[in] handler Handler to call, whenever an I/O
179 operation is to be performed. */
182 bool throttled() const; ///< Get accumulative throttling state
183 bool nativeThrottled() const; ///< Get native throttling state
185 void throttle(); ///< Set native throttling
186 void unthrottle(); ///< Revoke native throttling
188 ActiveConnector & peer() const;
196 // Called by the routing to change the remote throttling state
197 void notifyThrottle(); ///< Forward a throttle notification to this connector
198 void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
200 // Internal members to emit throttling notifications
202 void emitUnthrottle();
204 // Called after unthrottling the connector
205 virtual void v_unthrottleEvent();
207 // called by ForwardingRoute to register a new route
208 void registerRoute(ForwardingRoute & route);
210 typedef ppi::detail::Callback<>::type Callback;
213 bool remoteThrottled_;
214 bool nativeThrottled_;
216 typedef std::vector<ForwardingRoute*> Routes;
219 friend class senf::ppi::ForwardingRoute;
222 /** \brief Active connector base-class
224 An active connector is a connector which emits I/O requests. Active connectors receive
225 throttling notifications. Depending on the type of connector (input or output) the
226 respective throttling is called forward or backward throttling.
228 Active connectors do not handle any throttling state, they just receive the
229 notifications. These notifications should then either be processed by the module or be
230 forwarded to other connectors.
232 class ActiveConnector
233 : public virtual Connector
235 typedef ppi::detail::Callback<>::type Callback;
237 template <class Handler>
238 void onThrottle(Handler handler); ///< Register throttle notification handler
239 /**< The handler register here will be called, whenever a
240 throttle notification comes in. The \a handler argument
241 is either an arbitrary callable object or it is a
242 pointer-to-member to a member of the class which holds
243 this input. In the second case, the pointer will
244 automatically be bound to the containing instance.
246 \param[in] handler Handler to call on throttle
248 void onThrottle(); ///< Clear throttle notification handler
250 template <class Handler>
251 void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
252 /**< The handler register here will be called, whenever an
253 unthrottle notification comes in. The \a handler
254 argument is either an arbitrary callable object or it
255 is a pointer-to-member to a member of the class which
256 holds this input. In the second case, the pointer will
257 automatically be bound to the containing instance.
259 \param[in] handler Handler to call on unthrottle
261 void onUnthrottle(); ///< Clear unthrottle notification handler
263 bool throttled() const; ///< \c true, if peer() is throttled
265 PassiveConnector & peer() const;
271 // called by the peer() to forward throttling notifications
272 void notifyThrottle();
273 void notifyUnthrottle();
275 // called by ForwardingRoute to register a new route
276 void registerRoute(ForwardingRoute & route);
278 Callback throttleCallback_;
279 Callback unthrottleCallback_;
281 typedef std::vector<ForwardingRoute*> NotifyRoutes;
282 NotifyRoutes notifyRoutes_;
284 friend class senf::ppi::ForwardingRoute;
285 friend class PassiveConnector;
288 /** \brief Input connector base-class
290 An input connector receives packets. It may be either an ActiveConnector or a
291 PassiveConnector. An input connector contains a packet queue. This queue enables processing
292 packets in batches or generating multiple output packets from a single input packet. The
293 queues have the potential to greatly simplify the module implementations.
295 \implementation Which container to use?
296 \li list has good insertion and deletion properties on both ends but it costs a dynamic
297 memory allocation for every insertion. A very good property is, that iterators stay
298 valid across insertions/deletions
299 \li vector is fast and has good amortized dynamic allocation properties. However, it is
300 quite unusable as a queue
301 \li deque has comparable dynamic allocation properties as vector but also has good
302 insertion/removal properties on both ends.
304 So probably we will use a deque. I'd like a container which keeps iterators intact on
305 insertion/deletion but I believe that list is just to expensive since every packet will
306 be added to the queue before it can be processed.
309 : public virtual Connector
311 typedef std::deque<Packet> Queue;
313 typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
314 typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
317 Packet operator()(); ///< Get a packet
318 /**< This member is the primary method to access received
319 data. On passive connectors, this operator will just
320 dequeue a packet from the packet queue. If the
321 connector is active, the connector will request new
322 packets from the connected module. If the packet
323 request cannot be fulfilled, this is considered to be a
324 logic error in the module implementation and an
325 exception is raised. */
327 Packet read(); ///< Alias for operator()()
329 OutputConnector & peer() const;
331 queue_iterator begin() const; ///< Access queue begin (head)
332 queue_iterator end() const; ///< Access queue past-the-end (tail)
333 Packet peek() const; ///< Return head element from the queue
335 size_type queueSize() const; ///< Return number of elements in the queue
336 bool empty() const; ///< Return queueSize() == 0
342 void enqueue(Packet p);
344 virtual void v_requestEvent();
345 virtual void v_enqueueEvent();
346 virtual void v_dequeueEvent();
350 friend class OutputConnector;
353 /** \brief Output connector base-class
355 An output connector sends out packets. It may be either an ActiveConnector or a
356 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
357 the queueing of the connected input.
359 class OutputConnector
360 : public virtual Connector
363 void operator()(Packet p); ///< Send out a packet
365 void write(Packet p); ///< Alias for operator()(Packet p)
367 InputConnector & peer() const;
373 /** \brief Combination of PassiveConnector and InputConnector
375 The GenericPassiveInput automatically controls the connectors throttling state using a
376 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
377 the connection whenever the queue length reaches the high threshold and unthrottles the
378 connection when the queue reaches the low threshold. The default queueing discipline is
379 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
382 class GenericPassiveInput
383 : public PassiveConnector, public InputConnector,
384 public safe_bool<GenericPassiveInput>
387 GenericActiveOutput & peer() const;
389 bool boolean_test() const; ///< \c true, if ! empty()
391 template <class QDisc>
392 void qdisc(QDisc const & disc); ///< Change the queueing discipline
393 /**< The queueing discipline is a class which provides the
394 QueueingDiscipline interface.
396 \param[in] disc New queueing discipline */
399 GenericPassiveInput();
402 void v_enqueueEvent();
403 void v_dequeueEvent();
404 void v_unthrottleEvent();
406 boost::scoped_ptr<QueueingDiscipline> qdisc_;
409 /** \brief Combination of PassiveConnector and OutputConnector
411 class GenericPassiveOutput
412 : public PassiveConnector, public OutputConnector,
413 public safe_bool<GenericPassiveOutput>
416 GenericActiveInput & peer() const;
418 bool boolean_test() const; ///< Always \c true
420 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
422 friend class GenericActiveInput;
425 GenericPassiveOutput();
429 /** \brief Combination of ActiveConnector and InputConnector
431 class GenericActiveInput
432 : public ActiveConnector, public InputConnector,
433 public safe_bool<GenericActiveInput>
436 GenericPassiveOutput & peer() const;
438 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
440 void request(); ///< request more packets without dequeuing any packet
443 GenericActiveInput();
446 void v_requestEvent();
449 /** \brief Combination of ActiveConnector and OutputConnector
451 class GenericActiveOutput
452 : public ActiveConnector, public OutputConnector,
453 public safe_bool<GenericActiveOutput>
456 GenericPassiveInput & peer() const;
458 bool boolean_test() const; ///< \c true if peer() is ! throttled()
460 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
463 GenericActiveOutput();
469 # define TypedConnector_Input read
470 # define TypedConnector_Output write
471 # define TypedConnector(pType, dir) \
472 template <class PacketType> \
474 : public Generic ## pType ## dir, \
475 private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
477 typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
479 using mixin::operator(); \
480 using mixin::TypedConnector_ ## dir ; \
482 virtual std::type_info const & packetTypeID() \
483 { return typeid(typename PacketType::type); } \
484 friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
487 class pType ## dir <Packet> : public Generic ## pType ## dir \
490 TypedConnector( Passive, Input );
491 TypedConnector( Passive, Output );
492 TypedConnector( Active, Input );
493 TypedConnector( Active, Output );
495 # undef TypedConnector
496 # undef TypedConnector_Input
497 # undef TypedConnector_Output
501 /** \brief Connector actively reading packets
503 \tparam PacketType Type of packet to read. Defaults to senf::Packet
505 The ActiveInput connector template reads data actively from a connected module. This class
506 is completely implemented via it's base-class, GenericActiveInput, the only difference is
507 that read packets are returned as \a PacketType instead of generic senf::Packet references.
509 \see GenericActiveInput \n
512 template <class PacketType=Packet>
513 class ActiveInput : public GenericActiveInput
516 PacketType operator()(); ///< Read packet
517 /**< \throws std::bad_cast, if the connector receives a
518 Packet which is not of type \a PacketType.
519 \returns newly read packet reference. */
520 PacketType read(); ///< Alias for operator()
523 /** \brief Connector passively receiving packets
525 \tparam PacketType Type of packet to read. Defaults to senf::Packet
527 The PassiveInput connector template receives packets sent to it from a connected
528 module. This class is completely implemented via it's base-class, GenericPassiveInput, the
529 only difference is that read packets are returned as \a PacketType instead of generic
530 senf::Packet references.
532 \see GenericPassiveInput \n
535 template <class PacketType=Packet>
536 class PassiveInput : public GenericPassiveInput
539 PacketType operator()(); ///< Read packet
540 /**< \throws std::bad_cast, if the connector receives a
541 Packet which is not of type \a PacketType.
542 \returns newly read packet reference. */
543 PacketType read(); ///< Alias for operator()
546 /** \brief Connector actively sending packets
548 \tparam PacketType Type of packet to send. Defaults to senf::Packet
550 The ActiveOutput connector template sends data actively to a connected module. This class is
551 completely implemented via it's base-class, GenericActiveOutput, the only difference is that
552 it only sends packets of type \a PacketType.
554 \see GenericActiveOutput \n
557 template <class PacketType=Packet>
558 class ActiveOutput : public GenericActiveOutput
561 operator()(PacketType packet); ///< Send out a packet
562 write(PacketType packet); ///< Alias for operator()
565 /** \brief Connector passively providing packets
567 \tparam PacketType Type of packet to send. Defaults to senf::Packet
569 The PassiveOutput connector template provides data passively to a connected module whenever
570 signaled. This class is completely implemented via it's base-class, GenericPassiveOutput, the
571 only difference is that it only sends packets of type \a PacketType.
573 \see GenericPassiveOutput \n
576 template <class PacketType=Packet>
577 class PassiveOutput : public GenericPassiveOutput
580 operator()(PacketType packet); ///< Send out a packet
581 write(PacketType packet); ///< Alias for operator()
588 ///////////////////////////////hh.e////////////////////////////////////////
589 #include "Connectors.cci"
590 //#include "Connectors.ct"
591 #include "Connectors.cti"
598 // c-file-style: "senf"
599 // indent-tabs-mode: nil
600 // ispell-local-dictionary: "american"
601 // compile-command: "scons -u test"
602 // comment-column: 40