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 & v_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 const & 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 const & read(); ///< Alias for operator()()
413 OutputConnector & peer() const;
415 size_type queueSize() const; ///< Return number of elements in the queue
416 bool empty() const; ///< Return queueSize() == 0
421 virtual void v_disconnected();
422 virtual void v_connected();
425 void enqueue(Packet const & p);
427 virtual void v_requestEvent();
428 virtual void v_enqueueEvent();
429 virtual void v_dequeueEvent();
431 OutputConnector * peer_;
433 Packet const * fastPacket_;
436 friend class OutputConnector;
439 /** \brief Output connector base-class
441 An output connector sends out packets. It may be either an ActiveConnector or a
442 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
443 the queueing of the connected input.
445 class OutputConnector
446 : public virtual Connector
449 void operator()(Packet const & p); ///< Send out a packet
451 void write(Packet const & p); ///< Alias for operator()(Packet p)
453 InputConnector & peer() const;
458 virtual void v_disconnected();
459 virtual void v_connected();
462 InputConnector * peer_;
465 /** \brief Combination of PassiveConnector and InputConnector
467 The GenericPassiveInput automatically controls the connectors throttling state using a
468 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
469 the connection whenever the queue length reaches the high threshold and unthrottles the
470 connection when the queue reaches the low threshold. The default queueing discipline is
471 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
474 class GenericPassiveInput
475 : public PassiveConnector, public InputConnector,
476 public safe_bool<GenericPassiveInput>
479 GenericActiveOutput & peer() const;
481 bool boolean_test() const; ///< \c true, if ! empty()
483 template <class QDisc>
484 void qdisc(QDisc const & disc); ///< Change the queueing discipline
485 /**< The queueing discipline is a class which provides the
486 QueueingDiscipline interface.
488 \param[in] disc New queueing discipline */
489 void qdisc(QueueingDiscipline::None_t);
490 ///< Disable queueing discipline
493 GenericPassiveInput();
495 virtual void v_disconnected();
496 virtual void v_connected();
499 void v_enqueueEvent();
500 void v_dequeueEvent();
501 void v_unthrottleEvent();
503 GenericActiveOutput * peer_;
504 boost::scoped_ptr<QueueingDiscipline> qdisc_;
507 /** \brief Combination of PassiveConnector and OutputConnector
509 class GenericPassiveOutput
510 : public PassiveConnector, public OutputConnector,
511 public safe_bool<GenericPassiveOutput>
514 GenericActiveInput & peer() const;
516 bool boolean_test() const; ///< Always \c true
518 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
520 friend class GenericActiveInput;
523 GenericPassiveOutput();
525 virtual void v_disconnected();
526 virtual void v_connected();
529 GenericActiveInput * peer_;
532 /** \brief Combination of ActiveConnector and InputConnector
534 class GenericActiveInput
535 : public ActiveConnector, public InputConnector,
536 public safe_bool<GenericActiveInput>
539 GenericPassiveOutput & peer() const;
541 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
543 void request(); ///< request more packets without dequeuing any packet
546 GenericActiveInput();
548 virtual void v_disconnected();
549 virtual void v_connected();
552 void v_requestEvent();
554 GenericPassiveOutput * peer_;
557 /** \brief Combination of ActiveConnector and OutputConnector
559 class GenericActiveOutput
560 : public ActiveConnector, public OutputConnector,
561 public safe_bool<GenericActiveOutput>
564 GenericPassiveInput & peer() const;
566 bool boolean_test() const; ///< \c true if peer() is ! throttled()
568 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
571 GenericActiveOutput();
573 virtual void v_disconnected();
574 virtual void v_connected();
577 GenericPassiveInput * peer_;
583 # define TypedConnector_Input read
584 # define TypedConnector_Output write
585 # define TypedConnector(pType, dir) \
586 template <class PacketType> \
588 : public Generic ## pType ## dir, \
589 private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
591 typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
593 using mixin::operator(); \
594 using mixin::TypedConnector_ ## dir ; \
596 virtual std::type_info const & v_packetTypeId() \
597 { return typeid(typename PacketType::type); } \
598 friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
601 class pType ## dir <Packet> : public Generic ## pType ## dir \
604 TypedConnector( Passive, Input );
605 TypedConnector( Passive, Output );
606 TypedConnector( Active, Input );
607 TypedConnector( Active, Output );
609 # undef TypedConnector
610 # undef TypedConnector_Input
611 # undef TypedConnector_Output
615 /** \brief Connector actively reading packets
617 \tparam PacketType Type of packet to read. Defaults to senf::Packet
619 The %ActiveInput %connector template reads data actively from a connected %module. This
620 class is completely implemented via it's base-class, GenericActiveInput, the only
621 difference is that read packets are returned as \a PacketType instead of generic
622 senf::Packet references.
624 \see GenericActiveInput \n
627 template <class PacketType=Packet>
628 class ActiveInput : public GenericActiveInput
631 PacketType operator()(); ///< Read packet
632 /**< \throws std::bad_cast if the %connector receives a
633 Packet which is not of type \a PacketType.
634 \returns newly read packet reference. */
635 PacketType read(); ///< Alias for operator()
638 /** \brief Connector passively receiving packets
640 \tparam PacketType Type of packet to read. Defaults to senf::Packet
642 The %PassiveInput %connector template receives packets sent to it from a connected
643 %module. This class is completely implemented via it's base-class, GenericPassiveInput,
644 the only difference is that read packets are returned as \a PacketType instead of generic
645 senf::Packet references.
647 \see GenericPassiveInput \n
650 template <class PacketType=Packet>
651 class PassiveInput : public GenericPassiveInput
654 PacketType operator()(); ///< Read packet
655 /**< \throws std::bad_cast if the %connector receives a
656 Packet which is not of type \a PacketType.
657 \returns newly read packet reference. */
658 PacketType read(); ///< Alias for operator()
661 /** \brief Connector actively sending packets
663 \tparam PacketType Type of packet to send. Defaults to senf::Packet
665 The %ActiveOutput %connector template sends data actively to a connected %module. This
666 class is completely implemented via it's base-class, GenericActiveOutput, the only
667 difference is that it only sends packets of type \a PacketType.
669 \see GenericActiveOutput \n
672 template <class PacketType=Packet>
673 class ActiveOutput : public GenericActiveOutput
676 void operator()(PacketType packet); ///< Send out a packet
677 void write(PacketType packet); ///< Alias for operator()
680 /** \brief Connector passively providing packets
682 \tparam PacketType Type of packet to send. Defaults to senf::Packet
684 The %PassiveOutput %connector template provides data passively to a connected %module
685 whenever signaled. This class is completely implemented via it's base-class,
686 GenericPassiveOutput, the only difference is that it only sends packets of type
689 \see GenericPassiveOutput \n
692 template <class PacketType=Packet>
693 class PassiveOutput : public GenericPassiveOutput
696 void operator()(PacketType packet); ///< Send out a packet
697 void write(PacketType packet); ///< Alias for operator()
704 //-/////////////////////////////////////////////////////////////////////////////////////////////////
705 #include "Connectors.cci"
706 #include "Connectors.ct"
707 #include "Connectors.cti"
714 // c-file-style: "senf"
715 // indent-tabs-mode: nil
716 // ispell-local-dictionary: "american"
717 // compile-command: "scons -u test"
718 // comment-column: 40