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_Connectors_
27 #define HH_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"
40 //#include "Connectors.mpp"
41 ///////////////////////////////hh.p////////////////////////////////////////
47 /** \namespace senf::ppi::connector
48 \brief Connector classes
50 A connector has two independent properties
51 - it may be \e active or \e passive
52 - it may be an \e input or an \e output
54 \e Active connectors are activated from within the module, \e passive connectors are
55 signaled by the external framework. \e Input modules receive packets, \e output modules send
58 All passive connectors call some onRequest callback whenever I/O needs to be performed. All
59 input modules possess a packet queue.
61 We therefore have 4 connector types:
62 - senf::ppi::connector::ActiveInput
63 - senf::ppi::connector::ActiveOutput
64 - senf::ppi::connector::PassiveInput
65 - senf::ppi::connector::PassiveOutput.
67 Connectors are declared as module data members and are then externally connected to other
70 The connectors each take an optional template argument. If this argument is specified, it
71 must be the type of packet expected or sent on this connector. If it is not specified,
72 packets will be passed using the generic Packet handle.
75 class IpFilter : public senf::ppi::module::Module
77 SENF_PPI_MODULE(SomeModule);
80 senf::ppi::connector::ActiveInput<senf::EthernetPacket> input;
81 senf::ppi::connector::PassiveOutput<senf::IpPacket> output;
85 input.onRequest(&IpFilter::onRequest);
90 // 'input()' will return a senf::EthernetPacket packet handle
91 try { output( input().find<IpPacket>() ); }
92 catch (senf::InvalidPacketChainException & ex) { ; }
98 senf::ppi::module::Module \n
99 senf::ppi::connect() \n
103 struct IncompatibleConnectorsException : public senf::Exception
104 { IncompatibleConnectorsException() : senf::Exception("Incompatible connectors") {} };
106 /** \brief Connector base-class
108 This connector provides access to the generic connector facilities. This includes the
109 connection management (access to the connected peer) and the containment management (access
110 to the containing module)
116 Connector & peer() const; ///< Get peer connected to this connector
117 module::Module & module() const; ///< Get this connectors containing module
121 virtual ~Connector();
123 void connect(Connector & target);
126 virtual std::type_info const & packetTypeID() = 0;
128 void setModule(module::Module & module);
131 module::Module * module_;
133 friend class module::Module;
136 /** \brief Passive connector base-class
138 A passive connector is a connector which is activated externally whenever an I/O request
139 occurs. Passive connectors are the origin of throttling notifications. Depending on the type
140 of connector (output or input) the respective throttling is called forward or backward
143 Passive connectors always handle two throttling states:
145 - The \e native throttling state is set manually by the module. It is the throttling state
146 originating in the current module
147 - The \e forwarded throttling state is the state as it is received by throttling
150 The accumulative throttling state is generated by combining all sub-states.
152 class PassiveConnector
153 : public virtual Connector
156 template <class Handler>
157 void onRequest(Handler handler);///< Register I/O event handler
158 /**< The registered handler will be called, whenever packets
159 arrive or should be generated by the module depending
160 on the connector type (input or output). The \a handler
161 argument is either an arbitrary callable object or it
162 is a pointer-to-member to a member of the class which
163 holds this input. In the second case, the pointer will
164 automatically be bound to the containing instance.
166 \param[in] handler Handler to call, whenever an I/O
167 operation is to be performed. */
170 bool throttled() const; ///< Get accumulative throttling state
171 bool nativeThrottled() const; ///< Get native throttling state
173 void throttle(); ///< Set native throttling
174 void unthrottle(); ///< Revoke native throttling
176 ActiveConnector & peer() const;
184 // Called by the routing to change the remote throttling state
185 void notifyThrottle(); ///< Forward a throttle notification to this connector
186 void notifyUnthrottle(); ///< Forward an unthrottle notification to this connector
188 // Internal members to emit throttling notifications
190 void emitUnthrottle();
192 // Called after unthrottling the connector
193 virtual void v_unthrottleEvent();
195 // called by ForwardingRoute to register a new route
196 void registerRoute(ForwardingRoute & route);
198 typedef ppi::detail::Callback<>::type Callback;
201 bool remoteThrottled_;
202 bool nativeThrottled_;
204 typedef std::vector<ForwardingRoute*> Routes;
207 friend class senf::ppi::ForwardingRoute;
210 /** \brief Active connector base-class
212 An active connector is a connector which emits I/O requests. Active connectors receive
213 throttling notifications. Depending on the type of connector (input or output) the
214 respective throttling is called forward or backward throttling.
216 Active connectors do not handle any throttling state, they just receive the
217 notifications. These notifications should then either be processed by the module or be
218 forwarded to other connectors.
220 class ActiveConnector
221 : public virtual Connector
223 typedef ppi::detail::Callback<>::type Callback;
225 template <class Handler>
226 void onThrottle(Handler handler); ///< Register throttle notification handler
227 /**< The handler register here will be called, whenever a
228 throttle notification comes in. The \a handler argument
229 is either an arbitrary callable object or it is a
230 pointer-to-member to a member of the class which holds
231 this input. In the second case, the pointer will
232 automatically be bound to the containing instance.
234 \param[in] handler Handler to call on throttle
236 void onThrottle(); ///< Clear throttle notification handler
238 template <class Handler>
239 void onUnthrottle(Handler handler); ///< Register unthrottle notification handler
240 /**< The handler register here will be called, whenever an
241 unthrottle notification comes in. The \a handler
242 argument is either an arbitrary callable object or it
243 is a pointer-to-member to a member of the class which
244 holds this input. In the second case, the pointer will
245 automatically be bound to the containing instance.
247 \param[in] handler Handler to call on unthrottle
249 void onUnthrottle(); ///< Clear unthrottle notification handler
251 bool throttled() const; ///< \c true, if peer() is throttled
253 PassiveConnector & peer() const;
259 // called by the peer() to forward throttling notifications
260 void notifyThrottle();
261 void notifyUnthrottle();
263 // called by ForwardingRoute to register a new route
264 void registerRoute(ForwardingRoute & route);
266 Callback throttleCallback_;
267 Callback unthrottleCallback_;
269 typedef std::vector<ForwardingRoute*> NotifyRoutes;
270 NotifyRoutes notifyRoutes_;
272 friend class senf::ppi::ForwardingRoute;
273 friend class PassiveConnector;
276 /** \brief Input connector base-class
278 An input connector receives packets. It may be either an ActiveConnector or a
279 PassiveConnector. An input connector contains a packet queue. This queue enables processing
280 packets in batches or generating multiple output packets from a single input packet. The
281 queues have the potential to greatly simplify the module implementations.
283 \implementation Which container to use?
284 \li list has good insertion and deletion properties on both ends but it costs a dynamic
285 memory allocation for every insertion. A very good property is, that iterators stay
286 valid across insertions/deletions
287 \li vector is fast and has good amortized dynamic allocation properties. However, it is
288 quite unusable as a queue
289 \li deque has comparable dynamic allocation properties as vector but also has good
290 insertion/removal properties on both ends.
292 So probably we will use a deque. I'd like a container which keeps iterators intact on
293 insertion/deletion but I believe that list is just to expensive since every packet will
294 be added to the queue before it can be processed.
297 : public virtual Connector
299 typedef std::deque<Packet> Queue;
301 typedef Queue::const_iterator queue_iterator; ///< Iterator type of the embedded queue
302 typedef Queue::size_type size_type; ///< Unsigned type for counting queue elements
305 Packet operator()(); ///< Get a packet
306 /**< This member is the primary method to access received
307 data. On passive connectors, this operator will just
308 dequeue a packet from the packet queue. If the
309 connector is active, the connector will request new
310 packets from the connected module. If the packet
311 request cannot be fulfilled, this is considered to be a
312 logic error in the module implementation and an
313 exception is raised. */
315 Packet read(); ///< Alias for operator()()
317 OutputConnector & peer() const;
319 queue_iterator begin() const; ///< Access queue begin (head)
320 queue_iterator end() const; ///< Access queue past-the-end (tail)
321 Packet peek() const; ///< Return head element from the queue
323 size_type queueSize() const; ///< Return number of elements in the queue
324 bool empty() const; ///< Return queueSize() == 0
330 void enqueue(Packet p);
332 virtual void v_requestEvent();
333 virtual void v_enqueueEvent();
334 virtual void v_dequeueEvent();
338 friend class OutputConnector;
341 /** \brief Output connector base-class
343 An output connector sends out packets. It may be either an ActiveConnector or a
344 PassiveConnector. An output connector does \e not have an built-in queueing, it relies on
345 the queueing of the connected input.
347 class OutputConnector
348 : public virtual Connector
351 void operator()(Packet p); ///< Send out a packet
353 void write(Packet p); ///< Alias for operator()(Packet p)
355 InputConnector & peer() const;
361 /** \brief Combination of PassiveConnector and InputConnector
363 The GenericPassiveInput automatically controls the connectors throttling state using a
364 queueing discipline. The standard queueing discipline is ThresholdQueueing, which throttles
365 the connection whenever the queue length reaches the high threshold and unthrottles the
366 connection when the queue reaches the low threshold. The default queueing discipline is
367 <tt>ThresholdQueueing(1,0)</tt> which will throttle the input whenever the queue is
370 class GenericPassiveInput
371 : public PassiveConnector, public InputConnector,
372 public safe_bool<GenericPassiveInput>
375 GenericActiveOutput & peer() const;
377 bool boolean_test() const; ///< \c true, if ! empty()
379 template <class QDisc>
380 void qdisc(QDisc const & disc); ///< Change the queueing discipline
381 /**< The queueing discipline is a class which provides the
382 QueueingDiscipline interface.
384 \param[in] disc New queueing discipline */
387 GenericPassiveInput();
390 void v_enqueueEvent();
391 void v_dequeueEvent();
392 void v_unthrottleEvent();
394 boost::scoped_ptr<QueueingDiscipline> qdisc_;
397 /** \brief Combination of PassiveConnector and OutputConnector
399 class GenericPassiveOutput
400 : public PassiveConnector, public OutputConnector,
401 public safe_bool<GenericPassiveOutput>
404 GenericActiveInput & peer() const;
406 bool boolean_test() const; ///< Always \c true
408 void connect(GenericActiveInput & target); ///< Internal: Use senf::ppi::connect() instead
410 friend class GenericActiveInput;
413 GenericPassiveOutput();
417 /** \brief Combination of ActiveConnector and InputConnector
419 class GenericActiveInput
420 : public ActiveConnector, public InputConnector,
421 public safe_bool<GenericActiveInput>
424 GenericPassiveOutput & peer() const;
426 bool boolean_test() const; ///< \c true, if ! empty() or ! throttled()
428 void request(); ///< request more packets without dequeuing any packet
431 GenericActiveInput();
434 void v_requestEvent();
437 /** \brief Combination of ActiveConnector and OutputConnector
439 class GenericActiveOutput
440 : public ActiveConnector, public OutputConnector,
441 public safe_bool<GenericActiveOutput>
444 GenericPassiveInput & peer() const;
446 bool boolean_test() const; ///< \c true if peer() is ! throttled()
448 void connect(GenericPassiveInput & target); ///< Internal: Use senf::ppi::connect() instead
451 GenericActiveOutput();
457 # define TypedConnector_Input read
458 # define TypedConnector_Output write
459 # define TypedConnector(pType, dir) \
460 template <class PacketType> \
462 : public Generic ## pType ## dir, \
463 private detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> \
465 typedef detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType> mixin; \
467 using mixin::operator(); \
468 using mixin::TypedConnector_ ## dir ; \
470 virtual std::type_info const & packetTypeID() \
471 { return typeid(typename PacketType::type); } \
472 friend class detail::Typed ## dir ## Mixin<pType ## dir <PacketType>, PacketType>; \
475 class pType ## dir <Packet> : public Generic ## pType ## dir \
478 virtual std::type_info const & packetTypeID() { return typeid(void); } \
481 TypedConnector( Passive, Input );
482 TypedConnector( Passive, Output );
483 TypedConnector( Active, Input );
484 TypedConnector( Active, Output );
486 # undef TypedConnector
487 # undef TypedConnector_Input
488 # undef TypedConnector_Output
492 /** \brief Connector actively reading packets
494 \tparam PacketType Type of packet to read. Defaults to senf::Packet
496 The ActiveInput connector template reads data actively from a connected module. This class
497 is completely implemented via it's base-class, GenericActiveInput, the only difference is
498 that read packets are returned as \a PacketType instead of generic senf::Packet references.
500 \see GenericActiveInput \n
503 template <class PacketType=Packet>
504 class ActiveInput : public GenericActiveInput
507 PacketType operator()(); ///< Read packet
508 /**< \throws std::bad_cast, if the connector receives a
509 Packet which is not of type \a PacketType.
510 \returns newly read packet reference. */
511 PacketType read(); ///< Alias for operator()
514 /** \brief Connector passively receiving packets
516 \tparam PacketType Type of packet to read. Defaults to senf::Packet
518 The PassiveInput connector template receives packets sent to it from a connected
519 module. This class is completely implemented via it's base-class, GenericPassiveInput, the
520 only difference is that read packets are returned as \a PacketType instead of generic
521 senf::Packet references.
523 \see GenericPassiveInput \n
526 template <class PacketType=Packet>
527 class PassiveInput : public GenericPassiveInput
530 PacketType operator()(); ///< Read packet
531 /**< \throws std::bad_cast, if the connector receives a
532 Packet which is not of type \a PacketType.
533 \returns newly read packet reference. */
534 PacketType read(); ///< Alias for operator()
537 /** \brief Connector actively sending packets
539 \tparam PacketType Type of packet to send. Defaults to senf::Packet
541 The ActiveOutput connector template sends data actively to a connected module. This class is
542 completely implemented via it's base-class, GenericActiveOutput, the only difference is that
543 it only sends packets of type \a PacketType.
545 \see GenericActiveOutput \n
548 template <class PacketType=Packet>
549 class ActiveOutput : public GenericActiveOutput
552 operator()(PacketType packet); ///< Send out a packet
553 write(PacketType packet); ///< Alias for operator()
556 /** \brief Connector passively providing packets
558 \tparam PacketType Type of packet to send. Defaults to senf::Packet
560 The PassiveOutput connector template provides data passively to a connected module whenever
561 signaled. This class is completely implemented via it's base-class, GenericPassiveOutput, the
562 only difference is that it only sends packets of type \a PacketType.
564 \see GenericPassiveOutput \n
567 template <class PacketType=Packet>
568 class PassiveOutput : public GenericPassiveOutput
571 operator()(PacketType packet); ///< Send out a packet
572 write(PacketType packet); ///< Alias for operator()
579 ///////////////////////////////hh.e////////////////////////////////////////
580 #include "Connectors.cci"
581 //#include "Connectors.ct"
582 #include "Connectors.cti"
589 // c-file-style: "senf"
590 // indent-tabs-mode: nil
591 // ispell-local-dictionary: "american"
592 // compile-command: "scons -u test"
593 // comment-column: 40