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);
189 virtual std::type_info const & packetTypeID();
191 void setModule(module::Module & module);
194 module::Module * module_;
196 static TraceState traceState_;
198 friend class module::Module;
201 /** \brief Passive connector base-class
203 A passive connector is a connector which is activated externally whenever an I/O request
204 occurs. Passive connectors are the origin of throttling notifications. Depending on the type
205 of connector (output or input) the respective throttling is called forward or backward
208 Passive connectors always handle two throttling states:
210 - The \e native throttling state is set manually by the module. It is the throttling state
211 originating in the current module
212 - The \e forwarded throttling state is the state as it is received by throttling
215 The accumulative throttling state is generated by combining all sub-states.
217 class PassiveConnector
218 : public virtual Connector
221 template <class Handler>
222 void onRequest(Handler handler);///< Register I/O event handler
223 /**< The registered handler will be called, whenever packets
224 arrive or should be generated by the module depending
225 on the connector type (input or output). The \a handler
226 argument is either an arbitrary callable object or it
227 is a pointer-to-member to a member of the class which
228 holds this input. In the second case, the pointer will
229 automatically be bound to the containing instance.
231 \param[in] handler Handler to call, whenever an I/O
232 operation is to be performed. */
235 bool throttled() const; ///< Get accumulative throttling state
236 bool nativeThrottled() const; ///< Get native throttling state
238 void throttle(); ///< Set native throttling
239 void unthrottle(); ///< Revoke native throttling
241 ActiveConnector & peer() const;
249 virtual void v_init();
251 // Called by the routing to change the throttling state from forwarding routes
252 void notifyThrottle(); ///< Forward a throttle notification to this connector
253 void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
255 // Internal members to emit throttling notifications to the connected peer
257 void emitUnthrottle();
259 // Called after unthrottling the connector
260 virtual void v_unthrottleEvent();
262 // called by ForwardingRoute to register a new route
263 void registerRoute(ForwardingRoute & route);
265 typedef ppi::detail::Callback<>::type Callback;
268 bool remoteThrottled_;
269 bool nativeThrottled_;
271 typedef std::vector<ForwardingRoute*> Routes;
274 friend class senf::ppi::ForwardingRoute;
277 /** \brief Active connector base-class
279 An active connector is a connector which emits I/O requests. Active connectors receive
280 throttling notifications. Depending on the type of connector (input or output) the
281 respective throttling is called forward or backward throttling.
283 Active connectors do not handle any throttling state, they just receive the
284 notifications. These notifications should then either be processed by the module or be
285 forwarded to other connectors.
287 class ActiveConnector
288 : public virtual Connector
290 typedef ppi::detail::Callback<>::type Callback;
292 template <class Handler>
293 void onThrottle(Handler handler); ///< Register throttle notification handler
294 /**< The handler register here will be called, whenever a
295 throttle notification comes in. The \a handler argument
296 is either an arbitrary callable object or it is a
297 pointer-to-member to a member of the class which holds
298 this input. In the second case, the pointer will
299 automatically be bound to the containing instance.
301 \param[in] handler Handler to call on throttle
303 void onThrottle(); ///< Clear throttle notification handler
305 template <class Handler>
306 void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
307 /**< The handler register here will be called, whenever an
308 unthrottle notification comes in. The \a handler
309 argument is either an arbitrary callable object or it
310 is a pointer-to-member to a member of the class which
311 holds this input. In the second case, the pointer will
312 automatically be bound to the containing instance.
314 \param[in] handler Handler to call on unthrottle
316 void onUnthrottle(); ///< Clear unthrottle notification handler
318 bool throttled() const; ///< \c true, if peer() is throttled
320 PassiveConnector & peer() const;
326 virtual void v_init();
328 // called by the peer() to forward throttling notifications
329 void notifyThrottle();
330 void notifyUnthrottle();
332 // called by ForwardingRoute to register a new route
333 void registerRoute(ForwardingRoute & route);
335 Callback throttleCallback_;
336 Callback unthrottleCallback_;
338 typedef std::vector<ForwardingRoute*> NotifyRoutes;
339 NotifyRoutes notifyRoutes_;
343 friend class senf::ppi::ForwardingRoute;
344 friend class PassiveConnector;
347 /** \brief Input connector base-class
349 An input connector receives packets. It may be either an ActiveConnector or a
350 PassiveConnector. An input connector contains a packet queue. This queue enables processing
351 packets in batches or generating multiple output packets from a single input packet. The
352 queues have the potential to greatly simplify the module implementations.
354 \implementation Which container to use?
355 \li list has good insertion and deletion properties on both ends but it costs a dynamic
356 memory allocation for every insertion. A very good property is, that iterators stay
357 valid across insertions/deletions
358 \li vector is fast and has good amortized dynamic allocation properties. However, it is
359 quite unusable as a queue
360 \li deque has comparable dynamic allocation properties as vector but also has good
361 insertion/removal properties on both ends.
363 So probably we will use a deque. I'd like a container which keeps iterators intact on
364 insertion/deletion but I believe that list is just to expensive since every packet will
365 be added to the queue before it can be processed.
368 : public virtual Connector
370 typedef std::deque<Packet> Queue;
372 typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
373 typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
376 Packet operator()(); ///< Get a packet
377 /**< This member is the primary method to access received
378 data. On passive connectors, this operator will just
379 dequeue a packet from the packet queue. If the
380 connector is active, the connector will request new
381 packets from the connected module. If the packet
382 request cannot be fulfilled, this is considered to be a
383 logic error in the module implementation and an
384 exception is raised. */
386 Packet read(); ///< Alias for operator()()
388 OutputConnector & peer() const;
390 queue_iterator begin() const; ///< Access queue begin (head)
391 queue_iterator end() const; ///< Access queue past-the-end (tail)
392 Packet peek() const; ///< Return head element from the queue
394 size_type queueSize() const; ///< Return number of elements in the queue
395 bool empty() const; ///< Return queueSize() == 0
401 void enqueue(Packet const & p);
403 virtual void v_requestEvent();
404 virtual void v_enqueueEvent();
405 virtual void v_dequeueEvent();
409 friend class OutputConnector;
412 /** \brief Output connector base-class
414 An output connector sends out packets. It may be either an ActiveConnector or a
415 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
416 the queueing of the connected input.
418 class OutputConnector
419 : public virtual Connector
422 void operator()(Packet const & p); ///< Send out a packet
424 void write(Packet const & p); ///< Alias for operator()(Packet p)
426 InputConnector & peer() const;
432 /** \brief Combination of PassiveConnector and InputConnector
434 The GenericPassiveInput automatically controls the connectors throttling state using a
435 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
436 the connection whenever the queue length reaches the high threshold and unthrottles the
437 connection when the queue reaches the low threshold. The default queueing discipline is
438 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
441 class GenericPassiveInput
442 : public PassiveConnector, public InputConnector,
443 public safe_bool<GenericPassiveInput>
446 GenericActiveOutput & peer() const;
448 bool boolean_test() const; ///< \c true, if ! empty()
450 template <class QDisc>
451 void qdisc(QDisc const & disc); ///< Change the queueing discipline
452 /**< The queueing discipline is a class which provides the
453 QueueingDiscipline interface.
455 \param[in] disc New queueing discipline */
458 GenericPassiveInput();
461 void v_enqueueEvent();
462 void v_dequeueEvent();
463 void v_unthrottleEvent();
465 boost::scoped_ptr<QueueingDiscipline> qdisc_;
468 /** \brief Combination of PassiveConnector and OutputConnector
470 class GenericPassiveOutput
471 : public PassiveConnector, public OutputConnector,
472 public safe_bool<GenericPassiveOutput>
475 GenericActiveInput & peer() const;
477 bool boolean_test() const; ///< Always \c true
479 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
481 friend class GenericActiveInput;
484 GenericPassiveOutput();
488 /** \brief Combination of ActiveConnector and InputConnector
490 class GenericActiveInput
491 : public ActiveConnector, public InputConnector,
492 public safe_bool<GenericActiveInput>
495 GenericPassiveOutput & peer() const;
497 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
499 void request(); ///< request more packets without dequeuing any packet
502 GenericActiveInput();
505 void v_requestEvent();
508 /** \brief Combination of ActiveConnector and OutputConnector
510 class GenericActiveOutput
511 : public ActiveConnector, public OutputConnector,
512 public safe_bool<GenericActiveOutput>
515 GenericPassiveInput & peer() const;
517 bool boolean_test() const; ///< \c true if peer() is ! throttled()
519 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
522 GenericActiveOutput();
528 # define TypedConnector_Input read
529 # define TypedConnector_Output write
530 # define TypedConnector(pType, dir) \
531 template <class PacketType> \
533 : public Generic ## pType ## dir, \
534 private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
536 typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
538 using mixin::operator(); \
539 using mixin::TypedConnector_ ## dir ; \
541 virtual std::type_info const & packetTypeID() \
542 { return typeid(typename PacketType::type); } \
543 friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
546 class pType ## dir <Packet> : public Generic ## pType ## dir \
549 TypedConnector( Passive, Input );
550 TypedConnector( Passive, Output );
551 TypedConnector( Active, Input );
552 TypedConnector( Active, Output );
554 # undef TypedConnector
555 # undef TypedConnector_Input
556 # undef TypedConnector_Output
560 /** \brief Connector actively reading packets
562 \tparam PacketType Type of packet to read. Defaults to senf::Packet
564 The %ActiveInput %connector template reads data actively from a connected %module. This
565 class is completely implemented via it's base-class, GenericActiveInput, the only
566 difference is that read packets are returned as \a PacketType instead of generic
567 senf::Packet references.
569 \see GenericActiveInput \n
572 template <class PacketType=Packet>
573 class ActiveInput : public GenericActiveInput
576 PacketType operator()(); ///< Read packet
577 /**< \throws std::bad_cast if the %connector receives a
578 Packet which is not of type \a PacketType.
579 \returns newly read packet reference. */
580 PacketType read(); ///< Alias for operator()
583 /** \brief Connector passively receiving packets
585 \tparam PacketType Type of packet to read. Defaults to senf::Packet
587 The %PassiveInput %connector template receives packets sent to it from a connected
588 %module. This class is completely implemented via it's base-class, GenericPassiveInput,
589 the only difference is that read packets are returned as \a PacketType instead of generic
590 senf::Packet references.
592 \see GenericPassiveInput \n
595 template <class PacketType=Packet>
596 class PassiveInput : public GenericPassiveInput
599 PacketType operator()(); ///< Read packet
600 /**< \throws std::bad_cast if the %connector receives a
601 Packet which is not of type \a PacketType.
602 \returns newly read packet reference. */
603 PacketType read(); ///< Alias for operator()
606 /** \brief Connector actively sending packets
608 \tparam PacketType Type of packet to send. Defaults to senf::Packet
610 The %ActiveOutput %connector template sends data actively to a connected %module. This
611 class is completely implemented via it's base-class, GenericActiveOutput, the only
612 difference is that it only sends packets of type \a PacketType.
614 \see GenericActiveOutput \n
617 template <class PacketType=Packet>
618 class ActiveOutput : public GenericActiveOutput
621 operator()(PacketType packet); ///< Send out a packet
622 void write(PacketType packet); ///< Alias for operator()
625 /** \brief Connector passively providing packets
627 \tparam PacketType Type of packet to send. Defaults to senf::Packet
629 The %PassiveOutput %connector template provides data passively to a connected %module
630 whenever signaled. This class is completely implemented via it's base-class,
631 GenericPassiveOutput, the only difference is that it only sends packets of type
634 \see GenericPassiveOutput \n
637 template <class PacketType=Packet>
638 class PassiveOutput : public GenericPassiveOutput
641 operator()(PacketType packet); ///< Send out a packet
642 void write(PacketType packet); ///< Alias for operator()
649 ///////////////////////////////hh.e////////////////////////////////////////
650 #include "Connectors.cci"
651 //#include "Connectors.ct"
652 #include "Connectors.cti"
659 // c-file-style: "senf"
660 // indent-tabs-mode: nil
661 // ispell-local-dictionary: "american"
662 // compile-command: "scons -u test"
663 // comment-column: 40