4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at
9 // http://senf.berlios.de/license.html
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on,
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
15 // Software distributed under the License is distributed on an "AS IS" basis,
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
17 // for the specific language governing rights and limitations under the License.
19 // The Original Code is Fraunhofer FOKUS code.
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V.
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
26 // Stefan Bund <g0dil@berlios.de>
29 \brief Connectors public header */
31 #ifndef HH_SENF_PPI_Connectors_
32 #define HH_SENF_PPI_Connectors_ 1
36 #include <boost/utility.hpp>
37 #include <boost/scoped_ptr.hpp>
38 #include <senf/Utils/safe_bool.hh>
39 #include <senf/Utils/Exception.hh>
40 #include <senf/Packets/Packets.hh>
42 #include "detail/Callback.hh"
43 #include "Queueing.hh"
44 #include "ModuleManager.hh"
46 //#include "Connectors.mpp"
47 //-/////////////////////////////////////////////////////////////////////////////////////////////////
53 /** \namespace senf::ppi::connector
54 \brief Connector classes
56 A connector has three independent properties
57 \li it may be \e active or \e passive
58 \li it may be an \e input or an \e output
59 \li it has an (optional) packet type
61 \e Active connectors are activated from within the module, \e passive connectors are
62 signaled by the external framework. \e Input connectors receive packets, \e output
63 connectors send packets.
65 All passive connectors call some onRequest callback whenever I/O needs to be performed. All
66 input connectors possess a packet queue.
68 We therefore have 4 connector types each of which is parameterized by the type of packet
69 traversing the connector:
70 \li senf::ppi::connector::ActiveInput
71 \li senf::ppi::connector::ActiveOutput
72 \li senf::ppi::connector::PassiveInput
73 \li senf::ppi::connector::PassiveOutput.
75 Connectors are declared as module data members and are then externally connected to other
78 The connectors each take an optional template argument. If this argument is specified, it
79 must be the type of packet expected or sent on this connector. If it is not specified,
80 packets will be passed using the generic Packet handle.
83 class IpFilter : public senf::ppi::module::Module
85 SENF_PPI_MODULE(SomeModule);
88 senf::ppi::connector::ActiveInput<senf::EthernetPacket> input;
89 senf::ppi::connector::PassiveOutput<senf::IpPacket> output;
93 input.onRequest(&IpFilter::onRequest);
98 // 'input()' will return a senf::EthernetPacket packet handle
99 try { output( input().find<senf::IpPacket>() ); }
100 catch (senf::InvalidPacketChainException & ex) { ; }
106 \section ppi_jacks Jacks
108 A Jack is a packet type aware and possibly packet type converting reference to an arbitrary
109 connector of the same type. Jacks are used in groups to indirectly declare the input's and
116 senf::ppi::module::PassiveQueue queue;
117 senf::ppi::module::RateAnalyzer analyzer;
120 senf::ppi::connector::ActiveInputJack<senf::EthernetPacket> input;
121 senf::ppi::connector::ActiveOutputJack<senf::EthernetPacket> output;
124 : queue (), analyzer (), input (queue.input), output (analyzer.output)
126 senf::ppi::connect(queue, analyzer);
131 The jacks are initialized by passing an arbitrary compatible connector to the jack
132 constructor. A connector is compatible, if
133 \li It has the same input/output active/passive specification
134 \li Either the Jack or the Connector are generic (senf::Packet) or Jack and Connector have
137 Jacks can be used wherever connectors may be used. Jacks may be defined anywhere, not only
138 in modules. It is however important to ensure that the lifetime of the jack does not exceed
139 the lifetime of the referenced connector.
142 senf::ppi::module::Module \n
143 senf::ppi::connect() \n
147 /** \brief Incompatible connectors connected
149 This exception is thrown, when two incompatible connectors are connected. This happens if
150 both connectors of a senf::ppi::connect() statement declare a packet type (the connector
151 template argument) but they don't declare the same packet type.
153 You need to ensure, that both connectors use the same packet type.
155 \see senf::ppi::connect()
157 struct IncompatibleConnectorsException : public senf::Exception
158 { IncompatibleConnectorsException() : senf::Exception("Incompatible connectors") {} };
160 /** \brief Connector base-class
162 This connector provides access to the generic connector facilities. This includes the
163 connection management (access to the connected peer) and the containment management (access
164 to the containing module)
167 : ModuleManager::Initializable, boost::noncopyable
169 SENF_LOG_CLASS_AREA();
170 SENF_LOG_DEFAULT_LEVEL(senf::log::NOTICE);
172 Connector & peer() const; ///< Get peer connected to this connector
173 module::Module & module() const; ///< Get this connectors containing module
175 bool connected() const; ///< \c true, if connector connected, \c false otherwise
177 void disconnect(); ///< Disconnect connector from peer
179 enum TraceState { NO_TRACING, TRACE_IDS, TRACE_CONTENTS };
181 static void tracing(TraceState state);
182 static TraceState tracing();
186 virtual ~Connector();
188 void connect(Connector & target);
190 void trace(Packet const & p, char const * label);
191 void throttleTrace(char const * label, char const * type);
193 void unregisterConnector();
195 virtual void v_disconnected();
196 virtual void v_connected();
199 virtual std::type_info const & packetTypeID();
201 void setModule(module::Module & module);
204 module::Module * module_;
206 static TraceState traceState_;
208 friend class module::Module;
211 /** \brief Passive connector base-class
213 A passive connector is a connector which is activated externally whenever an I/O request
214 occurs. Passive connectors are the origin of throttling notifications. Depending on the type
215 of connector (output or input) the respective throttling is called forward or backward
218 Passive connectors always handle two throttling states:
220 - The \e native throttling state is set manually by the module. It is the throttling state
221 originating in the current module
222 - The \e forwarded throttling state is the state as it is received by throttling
225 The accumulative throttling state is generated by combining all sub-states.
227 class PassiveConnector
228 : public virtual Connector
233 template <class Handler>
234 void onRequest(Handler handler);///< Register I/O event handler
235 /**< The registered handler will be called, whenever packets
236 arrive or should be generated by the module depending
237 on the connector type (input or output). The \a handler
238 argument is either an arbitrary callable object or it
239 is a pointer-to-member to a member of the class which
240 holds this input. In the second case, the pointer will
241 automatically be bound to the containing instance.
243 \param[in] handler Handler to call, whenever an I/O
244 operation is to be performed. */
247 bool throttled() const; ///< Get accumulative throttling state
248 bool nativeThrottled() const; ///< Get native throttling state
250 void throttle(); ///< Set native throttling
251 void unthrottle(); ///< Revoke native throttling
253 ActiveConnector & peer() const;
260 virtual void v_disconnected();
261 virtual void v_connected();
264 virtual void v_init();
266 // Called by the routing to change the throttling state from forwarding routes
267 void notifyThrottle(); ///< Forward a throttle notification to this connector
268 void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
270 // Internal members to emit throttling notifications to the connected peer
272 void emitUnthrottle();
274 // Called after unthrottling the connector
275 virtual void v_unthrottleEvent();
277 // called by ForwardingRoute to register a new route
278 void registerRoute(ForwardingRoute & route);
279 void unregisterRoute(ForwardingRoute & route);
281 ActiveConnector * peer_;
283 typedef ppi::detail::Callback<>::type Callback;
286 bool remoteThrottled_;
287 bool nativeThrottled_;
289 typedef std::vector<ForwardingRoute*> Routes;
292 friend class senf::ppi::ForwardingRoute;
295 /** \brief Active connector base-class
297 An active connector is a connector which emits I/O requests. Active connectors receive
298 throttling notifications. Depending on the type of connector (input or output) the
299 respective throttling is called forward or backward throttling.
301 Active connectors do not handle any throttling state, they just receive the
302 notifications. These notifications should then either be processed by the module or be
303 forwarded to other connectors.
305 class ActiveConnector
306 : public virtual Connector
308 typedef ppi::detail::Callback<>::type Callback;
312 template <class Handler>
313 void onThrottle(Handler handler); ///< Register throttle notification handler
314 /**< The handler register here will be called, whenever a
315 throttle notification comes in. The \a handler argument
316 is either an arbitrary callable object or it is a
317 pointer-to-member to a member of the class which holds
318 this input. In the second case, the pointer will
319 automatically be bound to the containing instance.
321 \param[in] handler Handler to call on throttle
323 void onThrottle(); ///< Clear throttle notification handler
325 template <class Handler>
326 void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
327 /**< The handler register here will be called, whenever an
328 unthrottle notification comes in. The \a handler
329 argument is either an arbitrary callable object or it
330 is a pointer-to-member to a member of the class which
331 holds this input. In the second case, the pointer will
332 automatically be bound to the containing instance.
334 \param[in] handler Handler to call on unthrottle
336 void onUnthrottle(); ///< Clear unthrottle notification handler
338 bool throttled() const; ///< \c true, if peer() is throttled
340 PassiveConnector & peer() const;
345 virtual void v_disconnected();
346 virtual void v_connected();
349 virtual void v_init();
351 // called by the peer() to forward throttling notifications
352 void notifyThrottle();
353 void notifyUnthrottle();
355 // called by ForwardingRoute to register a new route
356 void registerRoute(ForwardingRoute & route);
357 void unregisterRoute(ForwardingRoute & route);
359 PassiveConnector * peer_;
361 Callback throttleCallback_;
362 Callback unthrottleCallback_;
364 typedef std::vector<ForwardingRoute*> NotifyRoutes;
365 NotifyRoutes notifyRoutes_;
369 friend class senf::ppi::ForwardingRoute;
370 friend class PassiveConnector;
373 /** \brief Input connector base-class
375 An input connector receives packets. It may be either an ActiveConnector or a
376 PassiveConnector. An input connector contains a packet queue. This queue enables processing
377 packets in batches or generating multiple output packets from a single input packet. The
378 queues have the potential to greatly simplify the module implementations.
380 \implementation Which container to use?
381 \li list has good insertion and deletion properties on both ends but it costs a dynamic
382 memory allocation for every insertion. A very good property is, that iterators stay
383 valid across insertions/deletions
384 \li vector is fast and has good amortized dynamic allocation properties. However, it is
385 quite unusable as a queue
386 \li deque has comparable dynamic allocation properties as vector but also has good
387 insertion/removal properties on both ends.
389 So probably we will use a deque. I'd like a container which keeps iterators intact on
390 insertion/deletion but I believe that list is just to expensive since every packet will
391 be added to the queue before it can be processed.
394 : public virtual Connector
396 typedef std::deque<Packet> Queue;
398 typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
399 typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
402 Packet operator()(); ///< Get a packet
403 /**< This member is the primary method to access received
404 data. On passive connectors, this operator will just
405 dequeue a packet from the packet queue. If the
406 connector is active, the connector will request new
407 packets from the connected module. If the packet
408 request cannot be fulfilled an in-valid Packet is
411 Packet read(); ///< Alias for operator()()
413 OutputConnector & peer() const;
415 queue_iterator begin() const; ///< Access queue begin (head)
416 queue_iterator end() const; ///< Access queue past-the-end (tail)
417 Packet peek() const; ///< Return head element from the queue
419 size_type queueSize() const; ///< Return number of elements in the queue
420 bool empty() const; ///< Return queueSize() == 0
425 virtual void v_disconnected();
426 virtual void v_connected();
429 void enqueue(Packet const & p);
431 virtual void v_requestEvent();
432 virtual void v_enqueueEvent();
433 virtual void v_dequeueEvent();
435 OutputConnector * peer_;
438 friend class OutputConnector;
441 /** \brief Output connector base-class
443 An output connector sends out packets. It may be either an ActiveConnector or a
444 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
445 the queueing of the connected input.
447 class OutputConnector
448 : public virtual Connector
451 void operator()(Packet const & p); ///< Send out a packet
453 void write(Packet const & p); ///< Alias for operator()(Packet p)
455 InputConnector & peer() const;
460 virtual void v_disconnected();
461 virtual void v_connected();
464 InputConnector * peer_;
467 /** \brief Combination of PassiveConnector and InputConnector
469 The GenericPassiveInput automatically controls the connectors throttling state using a
470 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
471 the connection whenever the queue length reaches the high threshold and unthrottles the
472 connection when the queue reaches the low threshold. The default queueing discipline is
473 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
476 class GenericPassiveInput
477 : public PassiveConnector, public InputConnector,
478 public safe_bool<GenericPassiveInput>
481 GenericActiveOutput & peer() const;
483 bool boolean_test() const; ///< \c true, if ! empty()
485 template <class QDisc>
486 void qdisc(QDisc const & disc); ///< Change the queueing discipline
487 /**< The queueing discipline is a class which provides the
488 QueueingDiscipline interface.
490 \param[in] disc New queueing discipline */
491 void qdisc(QueueingDiscipline::None_t);
492 ///< Disable queueing discipline
495 GenericPassiveInput();
497 virtual void v_disconnected();
498 virtual void v_connected();
501 void v_enqueueEvent();
502 void v_dequeueEvent();
503 void v_unthrottleEvent();
505 GenericActiveOutput * peer_;
506 boost::scoped_ptr<QueueingDiscipline> qdisc_;
509 /** \brief Combination of PassiveConnector and OutputConnector
511 class GenericPassiveOutput
512 : public PassiveConnector, public OutputConnector,
513 public safe_bool<GenericPassiveOutput>
516 GenericActiveInput & peer() const;
518 bool boolean_test() const; ///< Always \c true
520 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
522 friend class GenericActiveInput;
525 GenericPassiveOutput();
527 virtual void v_disconnected();
528 virtual void v_connected();
531 GenericActiveInput * peer_;
534 /** \brief Combination of ActiveConnector and InputConnector
536 class GenericActiveInput
537 : public ActiveConnector, public InputConnector,
538 public safe_bool<GenericActiveInput>
541 GenericPassiveOutput & peer() const;
543 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
545 void request(); ///< request more packets without dequeuing any packet
548 GenericActiveInput();
550 virtual void v_disconnected();
551 virtual void v_connected();
554 void v_requestEvent();
556 GenericPassiveOutput * peer_;
559 /** \brief Combination of ActiveConnector and OutputConnector
561 class GenericActiveOutput
562 : public ActiveConnector, public OutputConnector,
563 public safe_bool<GenericActiveOutput>
566 GenericPassiveInput & peer() const;
568 bool boolean_test() const; ///< \c true if peer() is ! throttled()
570 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
573 GenericActiveOutput();
575 virtual void v_disconnected();
576 virtual void v_connected();
579 GenericPassiveInput * peer_;
585 # define TypedConnector_Input read
586 # define TypedConnector_Output write
587 # define TypedConnector(pType, dir) \
588 template <class PacketType> \
590 : public Generic ## pType ## dir, \
591 private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
593 typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
595 using mixin::operator(); \
596 using mixin::TypedConnector_ ## dir ; \
598 virtual std::type_info const & packetTypeID() \
599 { return typeid(typename PacketType::type); } \
600 friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
603 class pType ## dir <Packet> : public Generic ## pType ## dir \
606 TypedConnector( Passive, Input );
607 TypedConnector( Passive, Output );
608 TypedConnector( Active, Input );
609 TypedConnector( Active, Output );
611 # undef TypedConnector
612 # undef TypedConnector_Input
613 # undef TypedConnector_Output
617 /** \brief Connector actively reading packets
619 \tparam PacketType Type of packet to read. Defaults to senf::Packet
621 The %ActiveInput %connector template reads data actively from a connected %module. This
622 class is completely implemented via it's base-class, GenericActiveInput, the only
623 difference is that read packets are returned as \a PacketType instead of generic
624 senf::Packet references.
626 \see GenericActiveInput \n
629 template <class PacketType=Packet>
630 class ActiveInput : public GenericActiveInput
633 PacketType operator()(); ///< Read packet
634 /**< \throws std::bad_cast if the %connector receives a
635 Packet which is not of type \a PacketType.
636 \returns newly read packet reference. */
637 PacketType read(); ///< Alias for operator()
640 /** \brief Connector passively receiving packets
642 \tparam PacketType Type of packet to read. Defaults to senf::Packet
644 The %PassiveInput %connector template receives packets sent to it from a connected
645 %module. This class is completely implemented via it's base-class, GenericPassiveInput,
646 the only difference is that read packets are returned as \a PacketType instead of generic
647 senf::Packet references.
649 \see GenericPassiveInput \n
652 template <class PacketType=Packet>
653 class PassiveInput : public GenericPassiveInput
656 PacketType operator()(); ///< Read packet
657 /**< \throws std::bad_cast if the %connector receives a
658 Packet which is not of type \a PacketType.
659 \returns newly read packet reference. */
660 PacketType read(); ///< Alias for operator()
663 /** \brief Connector actively sending packets
665 \tparam PacketType Type of packet to send. Defaults to senf::Packet
667 The %ActiveOutput %connector template sends data actively to a connected %module. This
668 class is completely implemented via it's base-class, GenericActiveOutput, the only
669 difference is that it only sends packets of type \a PacketType.
671 \see GenericActiveOutput \n
674 template <class PacketType=Packet>
675 class ActiveOutput : public GenericActiveOutput
678 void operator()(PacketType packet); ///< Send out a packet
679 void write(PacketType packet); ///< Alias for operator()
682 /** \brief Connector passively providing packets
684 \tparam PacketType Type of packet to send. Defaults to senf::Packet
686 The %PassiveOutput %connector template provides data passively to a connected %module
687 whenever signaled. This class is completely implemented via it's base-class,
688 GenericPassiveOutput, the only difference is that it only sends packets of type
691 \see GenericPassiveOutput \n
694 template <class PacketType=Packet>
695 class PassiveOutput : public GenericPassiveOutput
698 void operator()(PacketType packet); ///< Send out a packet
699 void write(PacketType packet); ///< Alias for operator()
706 //-/////////////////////////////////////////////////////////////////////////////////////////////////
707 #include "Connectors.cci"
708 #include "Connectors.ct"
709 #include "Connectors.cti"
716 // c-file-style: "senf"
717 // indent-tabs-mode: nil
718 // ispell-local-dictionary: "american"
719 // compile-command: "scons -u test"
720 // comment-column: 40