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 senf::ppi::module::Module \n
102 senf::ppi::connect() \n
106 /** \brief Incompatible connectors connected
108 This exception is thrown, when two incompatible connectors are connected. This happens if
109 both connectors of a senf::ppi::connect() statement declare a packet type (the connector
110 template argument) but they don't declare the same packet type.
112 You need to ensure, that both connectors use the same packet type.
114 \see senf::ppi::connect()
116 struct IncompatibleConnectorsException : public senf::Exception
117 { IncompatibleConnectorsException() : senf::Exception("Incompatible connectors") {} };
119 /** \brief Connector base-class
121 This connector provides access to the generic connector facilities. This includes the
122 connection management (access to the connected peer) and the containment management (access
123 to the containing module)
126 : ModuleManager::Initializable, boost::noncopyable
129 Connector & peer() const; ///< Get peer connected to this connector
130 module::Module & module() const; ///< Get this connectors containing module
132 bool connected() const; ///< \c true, if connector connected, \c false otherwise
134 void disconnect(); ///< Disconnect connector from peer
138 virtual ~Connector();
140 void connect(Connector & target);
143 virtual std::type_info const & packetTypeID();
145 void setModule(module::Module & module);
148 module::Module * module_;
150 friend class module::Module;
153 /** \brief Passive connector base-class
155 A passive connector is a connector which is activated externally whenever an I/O request
156 occurs. Passive connectors are the origin of throttling notifications. Depending on the type
157 of connector (output or input) the respective throttling is called forward or backward
160 Passive connectors always handle two throttling states:
162 - The \e native throttling state is set manually by the module. It is the throttling state
163 originating in the current module
164 - The \e forwarded throttling state is the state as it is received by throttling
167 The accumulative throttling state is generated by combining all sub-states.
169 class PassiveConnector
170 : public virtual Connector
173 template <class Handler>
174 void onRequest(Handler handler);///< Register I/O event handler
175 /**< The registered handler will be called, whenever packets
176 arrive or should be generated by the module depending
177 on the connector type (input or output). The \a handler
178 argument is either an arbitrary callable object or it
179 is a pointer-to-member to a member of the class which
180 holds this input. In the second case, the pointer will
181 automatically be bound to the containing instance.
183 \param[in] handler Handler to call, whenever an I/O
184 operation is to be performed. */
187 bool throttled() const; ///< Get accumulative throttling state
188 bool nativeThrottled() const; ///< Get native throttling state
190 void throttle(); ///< Set native throttling
191 void unthrottle(); ///< Revoke native throttling
193 ActiveConnector & peer() const;
201 virtual void v_init();
203 // Called by the routing to change the remote throttling state
204 void notifyThrottle(); ///< Forward a throttle notification to this connector
205 void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
207 // Internal members to emit throttling notifications
209 void emitUnthrottle();
211 // Called after unthrottling the connector
212 virtual void v_unthrottleEvent();
214 // called by ForwardingRoute to register a new route
215 void registerRoute(ForwardingRoute & route);
217 typedef ppi::detail::Callback<>::type Callback;
220 bool remoteThrottled_;
221 bool nativeThrottled_;
223 typedef std::vector<ForwardingRoute*> Routes;
226 friend class senf::ppi::ForwardingRoute;
229 /** \brief Active connector base-class
231 An active connector is a connector which emits I/O requests. Active connectors receive
232 throttling notifications. Depending on the type of connector (input or output) the
233 respective throttling is called forward or backward throttling.
235 Active connectors do not handle any throttling state, they just receive the
236 notifications. These notifications should then either be processed by the module or be
237 forwarded to other connectors.
239 class ActiveConnector
240 : public virtual Connector
242 typedef ppi::detail::Callback<>::type Callback;
244 template <class Handler>
245 void onThrottle(Handler handler); ///< Register throttle notification handler
246 /**< The handler register here will be called, whenever a
247 throttle notification comes in. The \a handler argument
248 is either an arbitrary callable object or it is a
249 pointer-to-member to a member of the class which holds
250 this input. In the second case, the pointer will
251 automatically be bound to the containing instance.
253 \param[in] handler Handler to call on throttle
255 void onThrottle(); ///< Clear throttle notification handler
257 template <class Handler>
258 void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
259 /**< The handler register here will be called, whenever an
260 unthrottle notification comes in. The \a handler
261 argument is either an arbitrary callable object or it
262 is a pointer-to-member to a member of the class which
263 holds this input. In the second case, the pointer will
264 automatically be bound to the containing instance.
266 \param[in] handler Handler to call on unthrottle
268 void onUnthrottle(); ///< Clear unthrottle notification handler
270 bool throttled() const; ///< \c true, if peer() is throttled
272 PassiveConnector & peer() const;
278 virtual void v_init();
280 // called by the peer() to forward throttling notifications
281 void notifyThrottle();
282 void notifyUnthrottle();
284 // called by ForwardingRoute to register a new route
285 void registerRoute(ForwardingRoute & route);
287 Callback throttleCallback_;
288 Callback unthrottleCallback_;
290 typedef std::vector<ForwardingRoute*> NotifyRoutes;
291 NotifyRoutes notifyRoutes_;
295 friend class senf::ppi::ForwardingRoute;
296 friend class PassiveConnector;
299 /** \brief Input connector base-class
301 An input connector receives packets. It may be either an ActiveConnector or a
302 PassiveConnector. An input connector contains a packet queue. This queue enables processing
303 packets in batches or generating multiple output packets from a single input packet. The
304 queues have the potential to greatly simplify the module implementations.
306 \implementation Which container to use?
307 \li list has good insertion and deletion properties on both ends but it costs a dynamic
308 memory allocation for every insertion. A very good property is, that iterators stay
309 valid across insertions/deletions
310 \li vector is fast and has good amortized dynamic allocation properties. However, it is
311 quite unusable as a queue
312 \li deque has comparable dynamic allocation properties as vector but also has good
313 insertion/removal properties on both ends.
315 So probably we will use a deque. I'd like a container which keeps iterators intact on
316 insertion/deletion but I believe that list is just to expensive since every packet will
317 be added to the queue before it can be processed.
320 : public virtual Connector
322 typedef std::deque<Packet> Queue;
324 typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
325 typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
328 Packet operator()(); ///< Get a packet
329 /**< This member is the primary method to access received
330 data. On passive connectors, this operator will just
331 dequeue a packet from the packet queue. If the
332 connector is active, the connector will request new
333 packets from the connected module. If the packet
334 request cannot be fulfilled, this is considered to be a
335 logic error in the module implementation and an
336 exception is raised. */
338 Packet read(); ///< Alias for operator()()
340 OutputConnector & peer() const;
342 queue_iterator begin() const; ///< Access queue begin (head)
343 queue_iterator end() const; ///< Access queue past-the-end (tail)
344 Packet peek() const; ///< Return head element from the queue
346 size_type queueSize() const; ///< Return number of elements in the queue
347 bool empty() const; ///< Return queueSize() == 0
353 void enqueue(Packet const & p);
355 virtual void v_requestEvent();
356 virtual void v_enqueueEvent();
357 virtual void v_dequeueEvent();
361 friend class OutputConnector;
364 /** \brief Output connector base-class
366 An output connector sends out packets. It may be either an ActiveConnector or a
367 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
368 the queueing of the connected input.
370 class OutputConnector
371 : public virtual Connector
374 void operator()(Packet const & p); ///< Send out a packet
376 void write(Packet const & p); ///< Alias for operator()(Packet p)
378 InputConnector & peer() const;
384 /** \brief Combination of PassiveConnector and InputConnector
386 The GenericPassiveInput automatically controls the connectors throttling state using a
387 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
388 the connection whenever the queue length reaches the high threshold and unthrottles the
389 connection when the queue reaches the low threshold. The default queueing discipline is
390 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
393 class GenericPassiveInput
394 : public PassiveConnector, public InputConnector,
395 public safe_bool<GenericPassiveInput>
398 GenericActiveOutput & peer() const;
400 bool boolean_test() const; ///< \c true, if ! empty()
402 template <class QDisc>
403 void qdisc(QDisc const & disc); ///< Change the queueing discipline
404 /**< The queueing discipline is a class which provides the
405 QueueingDiscipline interface.
407 \param[in] disc New queueing discipline */
410 GenericPassiveInput();
413 void v_enqueueEvent();
414 void v_dequeueEvent();
415 void v_unthrottleEvent();
417 boost::scoped_ptr<QueueingDiscipline> qdisc_;
420 /** \brief Combination of PassiveConnector and OutputConnector
422 class GenericPassiveOutput
423 : public PassiveConnector, public OutputConnector,
424 public safe_bool<GenericPassiveOutput>
427 GenericActiveInput & peer() const;
429 bool boolean_test() const; ///< Always \c true
431 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
433 friend class GenericActiveInput;
436 GenericPassiveOutput();
440 /** \brief Combination of ActiveConnector and InputConnector
442 class GenericActiveInput
443 : public ActiveConnector, public InputConnector,
444 public safe_bool<GenericActiveInput>
447 GenericPassiveOutput & peer() const;
449 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
451 void request(); ///< request more packets without dequeuing any packet
454 GenericActiveInput();
457 void v_requestEvent();
460 /** \brief Combination of ActiveConnector and OutputConnector
462 class GenericActiveOutput
463 : public ActiveConnector, public OutputConnector,
464 public safe_bool<GenericActiveOutput>
467 GenericPassiveInput & peer() const;
469 bool boolean_test() const; ///< \c true if peer() is ! throttled()
471 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
474 GenericActiveOutput();
480 # define TypedConnector_Input read
481 # define TypedConnector_Output write
482 # define TypedConnector(pType, dir) \
483 template <class PacketType> \
485 : public Generic ## pType ## dir, \
486 private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
488 typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
490 using mixin::operator(); \
491 using mixin::TypedConnector_ ## dir ; \
493 virtual std::type_info const & packetTypeID() \
494 { return typeid(typename PacketType::type); } \
495 friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
498 class pType ## dir <Packet> : public Generic ## pType ## dir \
501 TypedConnector( Passive, Input );
502 TypedConnector( Passive, Output );
503 TypedConnector( Active, Input );
504 TypedConnector( Active, Output );
506 # undef TypedConnector
507 # undef TypedConnector_Input
508 # undef TypedConnector_Output
512 /** \brief Connector actively reading packets
514 \tparam PacketType Type of packet to read. Defaults to senf::Packet
516 The %ActiveInput %connector template reads data actively from a connected %module. This
517 class is completely implemented via it's base-class, GenericActiveInput, the only
518 difference is that read packets are returned as \a PacketType instead of generic
519 senf::Packet references.
521 \see GenericActiveInput \n
524 template <class PacketType=Packet>
525 class ActiveInput : public GenericActiveInput
528 PacketType operator()(); ///< Read packet
529 /**< \throws std::bad_cast, if the %connector receives a
530 Packet which is not of type \a PacketType.
531 \returns newly read packet reference. */
532 PacketType read(); ///< Alias for operator()
535 /** \brief Connector passively receiving packets
537 \tparam PacketType Type of packet to read. Defaults to senf::Packet
539 The %PassiveInput %connector template receives packets sent to it from a connected
540 %module. This class is completely implemented via it's base-class, GenericPassiveInput,
541 the only difference is that read packets are returned as \a PacketType instead of generic
542 senf::Packet references.
544 \see GenericPassiveInput \n
547 template <class PacketType=Packet>
548 class PassiveInput : public GenericPassiveInput
551 PacketType operator()(); ///< Read packet
552 /**< \throws std::bad_cast, if the %connector receives a
553 Packet which is not of type \a PacketType.
554 \returns newly read packet reference. */
555 PacketType read(); ///< Alias for operator()
558 /** \brief Connector actively sending packets
560 \tparam PacketType Type of packet to send. Defaults to senf::Packet
562 The %ActiveOutput %connector template sends data actively to a connected %module. This
563 class is completely implemented via it's base-class, GenericActiveOutput, the only
564 difference is that it only sends packets of type \a PacketType.
566 \see GenericActiveOutput \n
569 template <class PacketType=Packet>
570 class ActiveOutput : public GenericActiveOutput
573 operator()(PacketType packet); ///< Send out a packet
574 void write(PacketType packet); ///< Alias for operator()
577 /** \brief Connector passively providing packets
579 \tparam PacketType Type of packet to send. Defaults to senf::Packet
581 The %PassiveOutput %connector template provides data passively to a connected %module
582 whenever signaled. This class is completely implemented via it's base-class,
583 GenericPassiveOutput, the only difference is that it only sends packets of type
586 \see GenericPassiveOutput \n
589 template <class PacketType=Packet>
590 class PassiveOutput : public GenericPassiveOutput
593 operator()(PacketType packet); ///< Send out a packet
594 void write(PacketType packet); ///< Alias for operator()
601 ///////////////////////////////hh.e////////////////////////////////////////
602 #include "Connectors.cci"
603 //#include "Connectors.ct"
604 #include "Connectors.cti"
611 // c-file-style: "senf"
612 // indent-tabs-mode: nil
613 // ispell-local-dictionary: "american"
614 // compile-command: "scons -u test"
615 // comment-column: 40