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_SENF_PPI_Connectors_
27 #define HH_SENF_PPI_Connectors_ 1
31 #include <boost/utility.hpp>
32 #include <boost/scoped_ptr.hpp>
33 #include <senf/Utils/safe_bool.hh>
34 #include <senf/Utils/Exception.hh>
35 #include <senf/Packets/Packets.hh>
37 #include "detail/Callback.hh"
38 #include "Queueing.hh"
39 #include "ModuleManager.hh"
41 //#include "Connectors.mpp"
42 ///////////////////////////////hh.p////////////////////////////////////////
48 /** \namespace senf::ppi::connector
49 \brief Connector classes
51 A connector has three independent properties
52 \li it may be \e active or \e passive
53 \li it may be an \e input or an \e output
54 \li it has an (optional) packet type
56 \e Active connectors are activated from within the module, \e passive connectors are
57 signaled by the external framework. \e Input connectors receive packets, \e output
58 connectors send packets.
60 All passive connectors call some onRequest callback whenever I/O needs to be performed. All
61 input connectors possess a packet queue.
63 We therefore have 4 connector types each of which is parameterized by the type of packet
64 traversing the connector:
65 \li senf::ppi::connector::ActiveInput
66 \li senf::ppi::connector::ActiveOutput
67 \li senf::ppi::connector::PassiveInput
68 \li senf::ppi::connector::PassiveOutput.
70 Connectors are declared as module data members and are then externally connected to other
73 The connectors each take an optional template argument. If this argument is specified, it
74 must be the type of packet expected or sent on this connector. If it is not specified,
75 packets will be passed using the generic Packet handle.
78 class IpFilter : public senf::ppi::module::Module
80 SENF_PPI_MODULE(SomeModule);
83 senf::ppi::connector::ActiveInput<senf::EthernetPacket> input;
84 senf::ppi::connector::PassiveOutput<senf::IpPacket> output;
88 input.onRequest(&IpFilter::onRequest);
93 // 'input()' will return a senf::EthernetPacket packet handle
94 try { output( input().find<senf::IpPacket>() ); }
95 catch (senf::InvalidPacketChainException & ex) { ; }
101 \section ppi_jacks Jacks
103 A Jack is a packet type aware and possibly packet type converting reference to an arbitrary
104 connector of the same type. Jacks are used in groups to indirectly declare the input's and
111 senf::ppi::module::PassiveQueue queue;
112 senf::ppi::module::RateAnalyzer analyzer;
115 senf::ppi::connector::ActiveInputJack<senf::EthernetPacket> input;
116 senf::ppi::connector::ActiveOutputJack<senf::EthernetPacket> output;
119 : queue (), analyzer (), input (queue.input), output (analyzer.output)
121 senf::ppi::connect(queue, analyzer);
126 The jacks are initialized by passing an arbitrary compatible connector to the jack
127 constructor. A connector is compatible, if
128 \li It has the same input/output active/passive specification
129 \li Either the Jack or the Connector are generic (senf::Packet) or Jack and Connector have
132 Jacks can be used wherever connectors may be used. Jacks may be defined anywhere, not only
133 in modules. It is however important to ensure that the lifetime of the jack does not exceed
134 the lifetime of the referenced connector.
137 senf::ppi::module::Module \n
138 senf::ppi::connect() \n
142 /** \brief Incompatible connectors connected
144 This exception is thrown, when two incompatible connectors are connected. This happens if
145 both connectors of a senf::ppi::connect() statement declare a packet type (the connector
146 template argument) but they don't declare the same packet type.
148 You need to ensure, that both connectors use the same packet type.
150 \see senf::ppi::connect()
152 struct IncompatibleConnectorsException : public senf::Exception
153 { IncompatibleConnectorsException() : senf::Exception("Incompatible connectors") {} };
155 /** \brief Connector base-class
157 This connector provides access to the generic connector facilities. This includes the
158 connection management (access to the connected peer) and the containment management (access
159 to the containing module)
162 : ModuleManager::Initializable, boost::noncopyable
164 SENF_LOG_CLASS_AREA();
165 SENF_LOG_DEFAULT_LEVEL(senf::log::NOTICE);
167 Connector & peer() const; ///< Get peer connected to this connector
168 module::Module & module() const; ///< Get this connectors containing module
170 bool connected() const; ///< \c true, if connector connected, \c false otherwise
172 void disconnect(); ///< Disconnect connector from peer
174 enum TraceState { NO_TRACING, TRACE_IDS, TRACE_CONTENTS };
176 static void tracing(TraceState state);
177 static TraceState tracing();
181 virtual ~Connector();
183 void connect(Connector & target);
185 void trace(Packet const & p, char const * label);
186 void throttleTrace(char const * label, char const * type);
188 void unregisterConnector();
190 virtual void v_disconnected();
191 virtual void v_connected();
194 virtual std::type_info const & packetTypeID();
196 void setModule(module::Module & module);
199 module::Module * module_;
201 static TraceState traceState_;
203 friend class module::Module;
206 /** \brief Passive connector base-class
208 A passive connector is a connector which is activated externally whenever an I/O request
209 occurs. Passive connectors are the origin of throttling notifications. Depending on the type
210 of connector (output or input) the respective throttling is called forward or backward
213 Passive connectors always handle two throttling states:
215 - The \e native throttling state is set manually by the module. It is the throttling state
216 originating in the current module
217 - The \e forwarded throttling state is the state as it is received by throttling
220 The accumulative throttling state is generated by combining all sub-states.
222 class PassiveConnector
223 : public virtual Connector
228 template <class Handler>
229 void onRequest(Handler handler);///< Register I/O event handler
230 /**< The registered handler will be called, whenever packets
231 arrive or should be generated by the module depending
232 on the connector type (input or output). The \a handler
233 argument is either an arbitrary callable object or it
234 is a pointer-to-member to a member of the class which
235 holds this input. In the second case, the pointer will
236 automatically be bound to the containing instance.
238 \param[in] handler Handler to call, whenever an I/O
239 operation is to be performed. */
242 bool throttled() const; ///< Get accumulative throttling state
243 bool nativeThrottled() const; ///< Get native throttling state
245 void throttle(); ///< Set native throttling
246 void unthrottle(); ///< Revoke native throttling
248 ActiveConnector & peer() const;
255 virtual void v_disconnected();
256 virtual void v_connected();
259 virtual void v_init();
261 // Called by the routing to change the throttling state from forwarding routes
262 void notifyThrottle(); ///< Forward a throttle notification to this connector
263 void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
265 // Internal members to emit throttling notifications to the connected peer
267 void emitUnthrottle();
269 // Called after unthrottling the connector
270 virtual void v_unthrottleEvent();
272 // called by ForwardingRoute to register a new route
273 void registerRoute(ForwardingRoute & route);
274 void unregisterRoute(ForwardingRoute & route);
276 ActiveConnector * peer_;
278 typedef ppi::detail::Callback<>::type Callback;
281 bool remoteThrottled_;
282 bool nativeThrottled_;
283 ActiveConnector * myPeer_;
285 typedef std::vector<ForwardingRoute*> Routes;
288 friend class senf::ppi::ForwardingRoute;
291 /** \brief Active connector base-class
293 An active connector is a connector which emits I/O requests. Active connectors receive
294 throttling notifications. Depending on the type of connector (input or output) the
295 respective throttling is called forward or backward throttling.
297 Active connectors do not handle any throttling state, they just receive the
298 notifications. These notifications should then either be processed by the module or be
299 forwarded to other connectors.
301 class ActiveConnector
302 : public virtual Connector
304 typedef ppi::detail::Callback<>::type Callback;
308 template <class Handler>
309 void onThrottle(Handler handler); ///< Register throttle notification handler
310 /**< The handler register here will be called, whenever a
311 throttle notification comes in. The \a handler argument
312 is either an arbitrary callable object or it is a
313 pointer-to-member to a member of the class which holds
314 this input. In the second case, the pointer will
315 automatically be bound to the containing instance.
317 \param[in] handler Handler to call on throttle
319 void onThrottle(); ///< Clear throttle notification handler
321 template <class Handler>
322 void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
323 /**< The handler register here will be called, whenever an
324 unthrottle notification comes in. The \a handler
325 argument is either an arbitrary callable object or it
326 is a pointer-to-member to a member of the class which
327 holds this input. In the second case, the pointer will
328 automatically be bound to the containing instance.
330 \param[in] handler Handler to call on unthrottle
332 void onUnthrottle(); ///< Clear unthrottle notification handler
334 bool throttled() const; ///< \c true, if peer() is throttled
336 PassiveConnector & peer() const;
341 virtual void v_disconnected();
342 virtual void v_connected();
345 virtual void v_init();
347 // called by the peer() to forward throttling notifications
348 void notifyThrottle();
349 void notifyUnthrottle();
351 // called by ForwardingRoute to register a new route
352 void registerRoute(ForwardingRoute & route);
353 void unregisterRoute(ForwardingRoute & route);
355 PassiveConnector * peer_;
357 Callback throttleCallback_;
358 Callback unthrottleCallback_;
360 typedef std::vector<ForwardingRoute*> NotifyRoutes;
361 NotifyRoutes notifyRoutes_;
365 friend class senf::ppi::ForwardingRoute;
366 friend class PassiveConnector;
369 /** \brief Input connector base-class
371 An input connector receives packets. It may be either an ActiveConnector or a
372 PassiveConnector. An input connector contains a packet queue. This queue enables processing
373 packets in batches or generating multiple output packets from a single input packet. The
374 queues have the potential to greatly simplify the module implementations.
376 \implementation Which container to use?
377 \li list has good insertion and deletion properties on both ends but it costs a dynamic
378 memory allocation for every insertion. A very good property is, that iterators stay
379 valid across insertions/deletions
380 \li vector is fast and has good amortized dynamic allocation properties. However, it is
381 quite unusable as a queue
382 \li deque has comparable dynamic allocation properties as vector but also has good
383 insertion/removal properties on both ends.
385 So probably we will use a deque. I'd like a container which keeps iterators intact on
386 insertion/deletion but I believe that list is just to expensive since every packet will
387 be added to the queue before it can be processed.
390 : public virtual Connector
392 typedef std::deque<Packet> Queue;
394 typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
395 typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
398 Packet operator()(); ///< Get a packet
399 /**< This member is the primary method to access received
400 data. On passive connectors, this operator will just
401 dequeue a packet from the packet queue. If the
402 connector is active, the connector will request new
403 packets from the connected module. If the packet
404 request cannot be fulfilled an in-valid Packet is
407 Packet read(); ///< Alias for operator()()
409 OutputConnector & peer() const;
411 queue_iterator begin() const; ///< Access queue begin (head)
412 queue_iterator end() const; ///< Access queue past-the-end (tail)
413 Packet peek() const; ///< Return head element from the queue
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_;
434 friend class OutputConnector;
437 /** \brief Output connector base-class
439 An output connector sends out packets. It may be either an ActiveConnector or a
440 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
441 the queueing of the connected input.
443 class OutputConnector
444 : public virtual Connector
447 void operator()(Packet const & p); ///< Send out a packet
449 void write(Packet const & p); ///< Alias for operator()(Packet p)
451 InputConnector & peer() const;
456 virtual void v_disconnected();
457 virtual void v_connected();
460 InputConnector * peer_;
463 /** \brief Combination of PassiveConnector and InputConnector
465 The GenericPassiveInput automatically controls the connectors throttling state using a
466 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
467 the connection whenever the queue length reaches the high threshold and unthrottles the
468 connection when the queue reaches the low threshold. The default queueing discipline is
469 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
472 class GenericPassiveInput
473 : public PassiveConnector, public InputConnector,
474 public safe_bool<GenericPassiveInput>
477 GenericActiveOutput & peer() const;
479 bool boolean_test() const; ///< \c true, if ! empty()
481 template <class QDisc>
482 void qdisc(QDisc const & disc); ///< Change the queueing discipline
483 /**< The queueing discipline is a class which provides the
484 QueueingDiscipline interface.
486 \param[in] disc New queueing discipline */
487 void qdisc(QueueingDiscipline::None_t);
488 ///< Disable queueing discipline
491 GenericPassiveInput();
493 virtual void v_disconnected();
494 virtual void v_connected();
497 void v_enqueueEvent();
498 void v_dequeueEvent();
499 void v_unthrottleEvent();
501 GenericActiveOutput * peer_;
502 boost::scoped_ptr<QueueingDiscipline> qdisc_;
505 /** \brief Combination of PassiveConnector and OutputConnector
507 class GenericPassiveOutput
508 : public PassiveConnector, public OutputConnector,
509 public safe_bool<GenericPassiveOutput>
512 GenericActiveInput & peer() const;
514 bool boolean_test() const; ///< Always \c true
516 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
518 friend class GenericActiveInput;
521 GenericPassiveOutput();
523 virtual void v_disconnected();
524 virtual void v_connected();
527 GenericActiveInput * peer_;
530 /** \brief Combination of ActiveConnector and InputConnector
532 class GenericActiveInput
533 : public ActiveConnector, public InputConnector,
534 public safe_bool<GenericActiveInput>
537 GenericPassiveOutput & peer() const;
539 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
541 void request(); ///< request more packets without dequeuing any packet
544 GenericActiveInput();
546 virtual void v_disconnected();
547 virtual void v_connected();
550 void v_requestEvent();
552 GenericPassiveOutput * peer_;
555 /** \brief Combination of ActiveConnector and OutputConnector
557 class GenericActiveOutput
558 : public ActiveConnector, public OutputConnector,
559 public safe_bool<GenericActiveOutput>
562 GenericPassiveInput & peer() const;
564 bool boolean_test() const; ///< \c true if peer() is ! throttled()
566 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
569 GenericActiveOutput();
571 virtual void v_disconnected();
572 virtual void v_connected();
575 GenericPassiveInput * peer_;
581 # define TypedConnector_Input read
582 # define TypedConnector_Output write
583 # define TypedConnector(pType, dir) \
584 template <class PacketType> \
586 : public Generic ## pType ## dir, \
587 private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
589 typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
591 using mixin::operator(); \
592 using mixin::TypedConnector_ ## dir ; \
594 virtual std::type_info const & packetTypeID() \
595 { return typeid(typename PacketType::type); } \
596 friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
599 class pType ## dir <Packet> : public Generic ## pType ## dir \
602 TypedConnector( Passive, Input );
603 TypedConnector( Passive, Output );
604 TypedConnector( Active, Input );
605 TypedConnector( Active, Output );
607 # undef TypedConnector
608 # undef TypedConnector_Input
609 # undef TypedConnector_Output
613 /** \brief Connector actively reading packets
615 \tparam PacketType Type of packet to read. Defaults to senf::Packet
617 The %ActiveInput %connector template reads data actively from a connected %module. This
618 class is completely implemented via it's base-class, GenericActiveInput, the only
619 difference is that read packets are returned as \a PacketType instead of generic
620 senf::Packet references.
622 \see GenericActiveInput \n
625 template <class PacketType=Packet>
626 class ActiveInput : public GenericActiveInput
629 PacketType operator()(); ///< Read packet
630 /**< \throws std::bad_cast if the %connector receives a
631 Packet which is not of type \a PacketType.
632 \returns newly read packet reference. */
633 PacketType read(); ///< Alias for operator()
636 /** \brief Connector passively receiving packets
638 \tparam PacketType Type of packet to read. Defaults to senf::Packet
640 The %PassiveInput %connector template receives packets sent to it from a connected
641 %module. This class is completely implemented via it's base-class, GenericPassiveInput,
642 the only difference is that read packets are returned as \a PacketType instead of generic
643 senf::Packet references.
645 \see GenericPassiveInput \n
648 template <class PacketType=Packet>
649 class PassiveInput : public GenericPassiveInput
652 PacketType operator()(); ///< Read packet
653 /**< \throws std::bad_cast if the %connector receives a
654 Packet which is not of type \a PacketType.
655 \returns newly read packet reference. */
656 PacketType read(); ///< Alias for operator()
659 /** \brief Connector actively sending packets
661 \tparam PacketType Type of packet to send. Defaults to senf::Packet
663 The %ActiveOutput %connector template sends data actively to a connected %module. This
664 class is completely implemented via it's base-class, GenericActiveOutput, the only
665 difference is that it only sends packets of type \a PacketType.
667 \see GenericActiveOutput \n
670 template <class PacketType=Packet>
671 class ActiveOutput : public GenericActiveOutput
674 operator()(PacketType packet); ///< Send out a packet
675 void write(PacketType packet); ///< Alias for operator()
678 /** \brief Connector passively providing packets
680 \tparam PacketType Type of packet to send. Defaults to senf::Packet
682 The %PassiveOutput %connector template provides data passively to a connected %module
683 whenever signaled. This class is completely implemented via it's base-class,
684 GenericPassiveOutput, the only difference is that it only sends packets of type
687 \see GenericPassiveOutput \n
690 template <class PacketType=Packet>
691 class PassiveOutput : public GenericPassiveOutput
694 operator()(PacketType packet); ///< Send out a packet
695 void write(PacketType packet); ///< Alias for operator()
702 ///////////////////////////////hh.e////////////////////////////////////////
703 #include "Connectors.cci"
704 #include "Connectors.ct"
705 #include "Connectors.cti"
712 // c-file-style: "senf"
713 // indent-tabs-mode: nil
714 // ispell-local-dictionary: "american"
715 // compile-command: "scons -u test"
716 // comment-column: 40