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 "../Utils/safe_bool.hh"
34 #include "../Utils/Exception.hh"
35 #include "../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
165 Connector & peer() const; ///< Get peer connected to this connector
166 module::Module & module() const; ///< Get this connectors containing module
168 bool connected() const; ///< \c true, if connector connected, \c false otherwise
170 void disconnect(); ///< Disconnect connector from peer
174 virtual ~Connector();
176 void connect(Connector & target);
179 virtual std::type_info const & packetTypeID();
181 void setModule(module::Module & module);
184 module::Module * module_;
186 friend class module::Module;
189 /** \brief Passive connector base-class
191 A passive connector is a connector which is activated externally whenever an I/O request
192 occurs. Passive connectors are the origin of throttling notifications. Depending on the type
193 of connector (output or input) the respective throttling is called forward or backward
196 Passive connectors always handle two throttling states:
198 - The \e native throttling state is set manually by the module. It is the throttling state
199 originating in the current module
200 - The \e forwarded throttling state is the state as it is received by throttling
203 The accumulative throttling state is generated by combining all sub-states.
205 class PassiveConnector
206 : public virtual Connector
209 template <class Handler>
210 void onRequest(Handler handler);///< Register I/O event handler
211 /**< The registered handler will be called, whenever packets
212 arrive or should be generated by the module depending
213 on the connector type (input or output). The \a handler
214 argument is either an arbitrary callable object or it
215 is a pointer-to-member to a member of the class which
216 holds this input. In the second case, the pointer will
217 automatically be bound to the containing instance.
219 \param[in] handler Handler to call, whenever an I/O
220 operation is to be performed. */
223 bool throttled() const; ///< Get accumulative throttling state
224 bool nativeThrottled() const; ///< Get native throttling state
226 void throttle(); ///< Set native throttling
227 void unthrottle(); ///< Revoke native throttling
229 ActiveConnector & peer() const;
237 virtual void v_init();
239 // Called by the routing to change the remote throttling state
240 void notifyThrottle(); ///< Forward a throttle notification to this connector
241 void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
243 // Internal members to emit throttling notifications
245 void emitUnthrottle();
247 // Called after unthrottling the connector
248 virtual void v_unthrottleEvent();
250 // called by ForwardingRoute to register a new route
251 void registerRoute(ForwardingRoute & route);
253 typedef ppi::detail::Callback<>::type Callback;
256 bool remoteThrottled_;
257 bool nativeThrottled_;
259 typedef std::vector<ForwardingRoute*> Routes;
262 friend class senf::ppi::ForwardingRoute;
265 /** \brief Active connector base-class
267 An active connector is a connector which emits I/O requests. Active connectors receive
268 throttling notifications. Depending on the type of connector (input or output) the
269 respective throttling is called forward or backward throttling.
271 Active connectors do not handle any throttling state, they just receive the
272 notifications. These notifications should then either be processed by the module or be
273 forwarded to other connectors.
275 class ActiveConnector
276 : public virtual Connector
278 typedef ppi::detail::Callback<>::type Callback;
280 template <class Handler>
281 void onThrottle(Handler handler); ///< Register throttle notification handler
282 /**< The handler register here will be called, whenever a
283 throttle notification comes in. The \a handler argument
284 is either an arbitrary callable object or it is a
285 pointer-to-member to a member of the class which holds
286 this input. In the second case, the pointer will
287 automatically be bound to the containing instance.
289 \param[in] handler Handler to call on throttle
291 void onThrottle(); ///< Clear throttle notification handler
293 template <class Handler>
294 void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
295 /**< The handler register here will be called, whenever an
296 unthrottle notification comes in. The \a handler
297 argument is either an arbitrary callable object or it
298 is a pointer-to-member to a member of the class which
299 holds this input. In the second case, the pointer will
300 automatically be bound to the containing instance.
302 \param[in] handler Handler to call on unthrottle
304 void onUnthrottle(); ///< Clear unthrottle notification handler
306 bool throttled() const; ///< \c true, if peer() is throttled
308 PassiveConnector & peer() const;
314 virtual void v_init();
316 // called by the peer() to forward throttling notifications
317 void notifyThrottle();
318 void notifyUnthrottle();
320 // called by ForwardingRoute to register a new route
321 void registerRoute(ForwardingRoute & route);
323 Callback throttleCallback_;
324 Callback unthrottleCallback_;
326 typedef std::vector<ForwardingRoute*> NotifyRoutes;
327 NotifyRoutes notifyRoutes_;
331 friend class senf::ppi::ForwardingRoute;
332 friend class PassiveConnector;
335 /** \brief Input connector base-class
337 An input connector receives packets. It may be either an ActiveConnector or a
338 PassiveConnector. An input connector contains a packet queue. This queue enables processing
339 packets in batches or generating multiple output packets from a single input packet. The
340 queues have the potential to greatly simplify the module implementations.
342 \implementation Which container to use?
343 \li list has good insertion and deletion properties on both ends but it costs a dynamic
344 memory allocation for every insertion. A very good property is, that iterators stay
345 valid across insertions/deletions
346 \li vector is fast and has good amortized dynamic allocation properties. However, it is
347 quite unusable as a queue
348 \li deque has comparable dynamic allocation properties as vector but also has good
349 insertion/removal properties on both ends.
351 So probably we will use a deque. I'd like a container which keeps iterators intact on
352 insertion/deletion but I believe that list is just to expensive since every packet will
353 be added to the queue before it can be processed.
356 : public virtual Connector
358 typedef std::deque<Packet> Queue;
360 typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
361 typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
364 Packet operator()(); ///< Get a packet
365 /**< This member is the primary method to access received
366 data. On passive connectors, this operator will just
367 dequeue a packet from the packet queue. If the
368 connector is active, the connector will request new
369 packets from the connected module. If the packet
370 request cannot be fulfilled, this is considered to be a
371 logic error in the module implementation and an
372 exception is raised. */
374 Packet read(); ///< Alias for operator()()
376 OutputConnector & peer() const;
378 queue_iterator begin() const; ///< Access queue begin (head)
379 queue_iterator end() const; ///< Access queue past-the-end (tail)
380 Packet peek() const; ///< Return head element from the queue
382 size_type queueSize() const; ///< Return number of elements in the queue
383 bool empty() const; ///< Return queueSize() == 0
389 void enqueue(Packet const & p);
391 virtual void v_requestEvent();
392 virtual void v_enqueueEvent();
393 virtual void v_dequeueEvent();
397 friend class OutputConnector;
400 /** \brief Output connector base-class
402 An output connector sends out packets. It may be either an ActiveConnector or a
403 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
404 the queueing of the connected input.
406 class OutputConnector
407 : public virtual Connector
410 void operator()(Packet const & p); ///< Send out a packet
412 void write(Packet const & p); ///< Alias for operator()(Packet p)
414 InputConnector & peer() const;
420 /** \brief Combination of PassiveConnector and InputConnector
422 The GenericPassiveInput automatically controls the connectors throttling state using a
423 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
424 the connection whenever the queue length reaches the high threshold and unthrottles the
425 connection when the queue reaches the low threshold. The default queueing discipline is
426 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
429 class GenericPassiveInput
430 : public PassiveConnector, public InputConnector,
431 public safe_bool<GenericPassiveInput>
434 GenericActiveOutput & peer() const;
436 bool boolean_test() const; ///< \c true, if ! empty()
438 template <class QDisc>
439 void qdisc(QDisc const & disc); ///< Change the queueing discipline
440 /**< The queueing discipline is a class which provides the
441 QueueingDiscipline interface.
443 \param[in] disc New queueing discipline */
446 GenericPassiveInput();
449 void v_enqueueEvent();
450 void v_dequeueEvent();
451 void v_unthrottleEvent();
453 boost::scoped_ptr<QueueingDiscipline> qdisc_;
456 /** \brief Combination of PassiveConnector and OutputConnector
458 class GenericPassiveOutput
459 : public PassiveConnector, public OutputConnector,
460 public safe_bool<GenericPassiveOutput>
463 GenericActiveInput & peer() const;
465 bool boolean_test() const; ///< Always \c true
467 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
469 friend class GenericActiveInput;
472 GenericPassiveOutput();
476 /** \brief Combination of ActiveConnector and InputConnector
478 class GenericActiveInput
479 : public ActiveConnector, public InputConnector,
480 public safe_bool<GenericActiveInput>
483 GenericPassiveOutput & peer() const;
485 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
487 void request(); ///< request more packets without dequeuing any packet
490 GenericActiveInput();
493 void v_requestEvent();
496 /** \brief Combination of ActiveConnector and OutputConnector
498 class GenericActiveOutput
499 : public ActiveConnector, public OutputConnector,
500 public safe_bool<GenericActiveOutput>
503 GenericPassiveInput & peer() const;
505 bool boolean_test() const; ///< \c true if peer() is ! throttled()
507 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
510 GenericActiveOutput();
516 # define TypedConnector_Input read
517 # define TypedConnector_Output write
518 # define TypedConnector(pType, dir) \
519 template <class PacketType> \
521 : public Generic ## pType ## dir, \
522 private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
524 typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
526 using mixin::operator(); \
527 using mixin::TypedConnector_ ## dir ; \
529 virtual std::type_info const & packetTypeID() \
530 { return typeid(typename PacketType::type); } \
531 friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
534 class pType ## dir <Packet> : public Generic ## pType ## dir \
537 TypedConnector( Passive, Input );
538 TypedConnector( Passive, Output );
539 TypedConnector( Active, Input );
540 TypedConnector( Active, Output );
542 # undef TypedConnector
543 # undef TypedConnector_Input
544 # undef TypedConnector_Output
548 /** \brief Connector actively reading packets
550 \tparam PacketType Type of packet to read. Defaults to senf::Packet
552 The %ActiveInput %connector template reads data actively from a connected %module. This
553 class is completely implemented via it's base-class, GenericActiveInput, the only
554 difference is that read packets are returned as \a PacketType instead of generic
555 senf::Packet references.
557 \see GenericActiveInput \n
560 template <class PacketType=Packet>
561 class ActiveInput : public GenericActiveInput
564 PacketType operator()(); ///< Read packet
565 /**< \throws std::bad_cast if the %connector receives a
566 Packet which is not of type \a PacketType.
567 \returns newly read packet reference. */
568 PacketType read(); ///< Alias for operator()
571 /** \brief Connector passively receiving packets
573 \tparam PacketType Type of packet to read. Defaults to senf::Packet
575 The %PassiveInput %connector template receives packets sent to it from a connected
576 %module. This class is completely implemented via it's base-class, GenericPassiveInput,
577 the only difference is that read packets are returned as \a PacketType instead of generic
578 senf::Packet references.
580 \see GenericPassiveInput \n
583 template <class PacketType=Packet>
584 class PassiveInput : public GenericPassiveInput
587 PacketType operator()(); ///< Read packet
588 /**< \throws std::bad_cast if the %connector receives a
589 Packet which is not of type \a PacketType.
590 \returns newly read packet reference. */
591 PacketType read(); ///< Alias for operator()
594 /** \brief Connector actively sending packets
596 \tparam PacketType Type of packet to send. Defaults to senf::Packet
598 The %ActiveOutput %connector template sends data actively to a connected %module. This
599 class is completely implemented via it's base-class, GenericActiveOutput, the only
600 difference is that it only sends packets of type \a PacketType.
602 \see GenericActiveOutput \n
605 template <class PacketType=Packet>
606 class ActiveOutput : public GenericActiveOutput
609 operator()(PacketType packet); ///< Send out a packet
610 void write(PacketType packet); ///< Alias for operator()
613 /** \brief Connector passively providing packets
615 \tparam PacketType Type of packet to send. Defaults to senf::Packet
617 The %PassiveOutput %connector template provides data passively to a connected %module
618 whenever signaled. This class is completely implemented via it's base-class,
619 GenericPassiveOutput, the only difference is that it only sends packets of type
622 \see GenericPassiveOutput \n
625 template <class PacketType=Packet>
626 class PassiveOutput : public GenericPassiveOutput
629 operator()(PacketType packet); ///< Send out a packet
630 void write(PacketType packet); ///< Alias for operator()
637 ///////////////////////////////hh.e////////////////////////////////////////
638 #include "Connectors.cci"
639 //#include "Connectors.ct"
640 #include "Connectors.cti"
647 // c-file-style: "senf"
648 // indent-tabs-mode: nil
649 // ispell-local-dictionary: "american"
650 // compile-command: "scons -u test"
651 // comment-column: 40