PPI: bugfix for FIFOQueueingAlgorithm
[senf.git] / senf / PPI / Connectors.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
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.
12 //
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.
17 //
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.
22
23 /** \file
24     \brief Connectors non-inline non-template implementation */
25
26 #include "Connectors.hh"
27 #include "Connectors.ih"
28
29 // Custom includes
30 #include "Route.hh"
31 #include "Module.hh"
32 #include "ModuleManager.hh"
33 #include <senf/Utils/Console/Console.hh>
34
35 //#include "Connectors.mpp"
36 #define prefix_
37 ///////////////////////////////cc.p////////////////////////////////////////
38
39 ///////////////////////////////////////////////////////////////////////////
40 // senf::ppi::connector::Connector
41
42 prefix_ senf::ppi::connector::Connector::~Connector()
43 {
44     if (connected()) {
45         Connector & peer (*peer_);
46         peer_->peer_ = 0;
47         if (! peer.initializationScheduled())
48             peer.enqueueInitializable();
49         peer.v_disconnected();
50     }
51 }
52
53 prefix_ void senf::ppi::connector::Connector::connect(Connector & target)
54 {
55     // The connector is not registered -> route() or noroute() statement missing
56     SENF_ASSERT( module_,
57                  "senf::ppi::connector::Connector::connect(): (source) "
58                  "Missing route() or noroute()" );
59     // The connector is already connected
60     SENF_ASSERT( ! peer_,
61                  "senf::ppi::connector::Connector::connect(): (source) "
62                  "duplicate connection" );
63     // The target connector is not registered -> route() or noroute() statement missing
64     SENF_ASSERT( target.module_,
65                  "senf::ppi::connector::Connector::connect(): (target) "
66                  "Missing route() or noroute()" );
67     // The target connector is already connected
68     SENF_ASSERT( ! target.peer_,
69                  "senf::ppi::connector::Connector::connect(): (target) "
70                  "duplicate connection" );
71     if (! (packetTypeID() == typeid(void) ||
72            target.packetTypeID() == typeid(void) ||
73            packetTypeID() == target.packetTypeID()) )
74         throw IncompatibleConnectorsException()
75             << ": " << prettyName(packetTypeID())
76             << " [in module " << prettyName(typeid(*module_))  << "] "
77             << ", " << prettyName(target.packetTypeID())
78             << " [in module " << prettyName(typeid(*target.module_)) << "]";
79
80     peer_ = & target;
81     target.peer_ = this;
82
83     if (! initializationScheduled())
84         enqueueInitializable();
85     if (! peer().initializationScheduled())
86         peer().enqueueInitializable();
87 }
88
89 senf::ppi::connector::Connector::TraceState senf::ppi::connector::Connector::traceState_ (
90     senf::ppi::connector::Connector::NO_TRACING);
91
92 prefix_ void senf::ppi::connector::Connector::trace(Packet const & p, char const * label)
93 {
94     if (traceState_ == NO_TRACING)
95         return;
96     SENF_LOG_BLOCK(({
97                 std::string type (prettyName(p.typeId().id()));
98                 log << "PPI packet trace: " << label << " 0x" << std::hex << p.id() << " "
99                     << type.substr(21, type.size()-22) << " on " << & module() << " "
100                     << prettyName(typeid(module())) << " connector 0x" << this << "\n";
101                 if (traceState_ == TRACE_CONTENTS)
102                     p.dump(log);
103             }));
104 }
105
106 prefix_ void senf::ppi::connector::Connector::throttleTrace(char const * label,
107                                                             char const * type)
108 {
109     if (traceState_ == NO_TRACING)
110         return;
111     SENF_LOG_BLOCK(({
112                 log << "PPI throttling trace: " << label << " " << type << " on " << & module()
113                     << " " << prettyName(typeid(module())) << " connector 0x" << this << "\n";
114             }));
115 }
116
117 namespace senf { namespace ppi { namespace connector {
118
119     SENF_CONSOLE_REGISTER_ENUM_MEMBER(
120         Connector, TraceState, (NO_TRACING)(TRACE_IDS)(TRACE_CONTENTS) );
121
122 }}}
123
124 namespace {
125
126     struct ConsoleRegister
127     {
128         ConsoleRegister();
129     };
130
131     ConsoleRegister::ConsoleRegister()
132     {
133 #ifndef SENF_PPI_NOTRACE
134         senf::ppi::ModuleManager::instance().consoleDir()
135             .add("tracing", senf::console::factory::Command(
136                      SENF_FNP(senf::ppi::connector::Connector::TraceState,
137                               senf::ppi::connector::Connector::tracing, ()))
138                  .doc("Log every packet sent or received by any module.\n"
139                       "There are three different tracing levels:\n"
140                       "\n"
141                       "    NO_TRACING      don't output any tracing information\n"
142                       "    TRACE_IDS       trace packet id's but do not show packet contents\n"
143                       "    TRACE_CONTENTS  trace complete packet contents\n"
144                       "\n"
145                       "A log message is generated whenever the packet traverses a connector. The\n"
146                       "TRACE_IDS log message has the following format:\n"
147                       "\n"
148                       "    PPI packet trace: <direction> <packet-id> <packet-type>\n"
149                       "                      on <module-id> <module-type> connector <connector-id>\n"
150                       "    PPI throttling trace: <direction> <throttle-msg>\n"
151                       "                      on <module-id> <module-type> connector <connector-id>\n"
152                       "\n"
153                       "The fields are:\n"
154                       "\n"
155                       "    direction       'IN' for packets/throttle notifications entering the module,\n"
156                       "                    'OUT' for packets/throttle notifications leaving it\n"
157                       "    packet-id       Numeric unique packet id. This value is unique for packets\n"
158                       "                    alive at the same time, packets at different times may (and\n"
159                       "                    will) share id's\n"
160                       "    packet-type     The type of the packet header\n"
161                       "    module-id       Unique module id\n"
162                       "    module-type     Type of the module the packet is sent to/from\n"
163                       "    connector-id    Unique connector id\n"
164                       "    throttle-msg    Type of throttling event\n")
165                 );
166
167         senf::ppi::ModuleManager::instance().consoleDir()
168             .add("tracing", senf::console::factory::Command(
169                      SENF_FNP(void, senf::ppi::connector::Connector::tracing,
170                               (senf::ppi::connector::Connector::TraceState)))
171                  .arg("state", "new tracing state")
172                 );
173 #endif
174     }
175
176     ConsoleRegister consoleRegister;
177
178 }
179
180 prefix_ void senf::ppi::connector::Connector::disconnect()
181 {
182     // Cannot disconnected a non-connected connector
183     SENF_ASSERT( peer_,
184                  "senf::ppi::connector::Connector::disconnect(): Not connected" );
185
186     Connector & peer (*peer_);
187     peer_ = 0;
188     peer.peer_ = 0;
189
190     if (! initializationScheduled())
191         enqueueInitializable();
192     if (! peer.initializationScheduled())
193         peer.enqueueInitializable();
194
195     v_disconnected();
196     peer.v_disconnected();
197 }
198
199 prefix_ std::type_info const & senf::ppi::connector::Connector::packetTypeID()
200 {
201     return typeid(void);
202 }
203
204 prefix_ void senf::ppi::connector::Connector::v_disconnected()
205     const
206 {}
207
208 ///////////////////////////////////////////////////////////////////////////
209 // senf::ppi::connector::PassiveConnector
210
211 prefix_ senf::ppi::connector::PassiveConnector::~PassiveConnector()
212 {
213     // Must be here and NOT in base so it is called before destructing the routes_ member
214     unregisterConnector();
215 }
216
217 ////////////////////////////////////////
218 // private members
219
220 prefix_ void senf::ppi::connector::PassiveConnector::v_init()
221 {
222     Routes::const_iterator i (routes_.begin());
223     Routes::const_iterator const i_end (routes_.end());
224     for (; i != i_end; ++i)
225         if ((*i)->throttled())
226             break;
227     if (i == i_end)
228         remoteThrottled_ = false;
229     if (throttled())
230         emitThrottle();
231     else
232         emitUnthrottle();
233 }
234
235 prefix_ void senf::ppi::connector::PassiveConnector::registerRoute(ForwardingRoute & route)
236 {
237     routes_.push_back(&route);
238 }
239
240 prefix_ void senf::ppi::connector::PassiveConnector::unregisterRoute(ForwardingRoute & route)
241 {
242     Routes::iterator i (std::find(routes_.begin(), routes_.end(), &route));
243     if (i != routes_.end())
244         routes_.erase(i);
245 }
246
247 prefix_ void senf::ppi::connector::PassiveConnector::v_unthrottleEvent()
248 {}
249
250 prefix_ void senf::ppi::connector::PassiveConnector::notifyUnthrottle()
251 {
252     if (std::find_if(routes_.begin(), routes_.end(),
253                      boost::bind(&ForwardingRoute::throttled, _1)) == routes_.end()) {
254         remoteThrottled_ = false;
255         if (!nativeThrottled_)
256             emitUnthrottle();
257     } else
258         SENF_PPI_THROTTLE_TRACE("OUT", "not forwarding unthrottle event");
259 }
260
261 ///////////////////////////////////////////////////////////////////////////
262 // senf::ppi::connector::ActiveConnector
263
264 prefix_ senf::ppi::connector::ActiveConnector::~ActiveConnector()
265 {
266     // Must be here and NOT in base so it is called before destructing the routes_ member
267     unregisterConnector();
268 }
269
270 ////////////////////////////////////////
271 // private members
272
273 prefix_ void senf::ppi::connector::ActiveConnector::v_init()
274 {
275     if (! connected())
276         notifyThrottle();
277 }
278
279 prefix_ void senf::ppi::connector::ActiveConnector::notifyThrottle()
280 {
281     SENF_PPI_THROTTLE_TRACE("IN ", "throttle");
282     if (! throttled_) {
283         throttled_ = true;
284         if (throttleCallback_)
285             throttleCallback_();
286         NotifyRoutes::const_iterator i (notifyRoutes_.begin());
287         NotifyRoutes::const_iterator const i_end (notifyRoutes_.end());
288         for (; i != i_end; ++i)
289             (*i)->notifyThrottle();
290     }
291 }
292
293 prefix_ void senf::ppi::connector::ActiveConnector::notifyUnthrottle()
294 {
295     SENF_PPI_THROTTLE_TRACE("IN ", "unthrottle");
296     if (throttled_) {
297         throttled_ = false;
298         if (unthrottleCallback_)
299             unthrottleCallback_();
300         NotifyRoutes::const_iterator i (notifyRoutes_.begin());
301         NotifyRoutes::const_iterator const i_end (notifyRoutes_.end());
302         for (; i != i_end; ++i)
303             (*i)->notifyUnthrottle();
304     }
305 }
306
307 prefix_ void senf::ppi::connector::ActiveConnector::registerRoute(ForwardingRoute & route)
308 {
309     notifyRoutes_.push_back(&route);
310 }
311
312 prefix_ void senf::ppi::connector::ActiveConnector::unregisterRoute(ForwardingRoute & route)
313 {
314     NotifyRoutes::iterator i (std::find(notifyRoutes_.begin(), notifyRoutes_.end(), &route));
315     if (i != notifyRoutes_.end())
316         notifyRoutes_.erase(i);
317 }
318
319 ///////////////////////////////////////////////////////////////////////////
320 // senf::ppi::connector::InputConnector
321
322 prefix_ senf::Packet senf::ppi::connector::InputConnector::operator()()
323 {
324     if (empty())
325         v_requestEvent();
326     if (! empty()) {
327         Packet p ( queue_.back());
328         queue_.pop_back();
329         v_dequeueEvent();
330         SENF_PPI_TRACE(p, "IN ");
331         return p;
332     } else {
333         SENF_PPI_TRACE(Packet(), "IN ");
334         return Packet();
335     }
336 }
337
338 ////////////////////////////////////////
339 // private members
340
341 prefix_ void senf::ppi::connector::InputConnector::v_requestEvent()
342 {}
343
344 prefix_ void senf::ppi::connector::InputConnector::v_enqueueEvent()
345 {}
346
347 prefix_ void senf::ppi::connector::InputConnector::v_dequeueEvent()
348 {}
349
350 ///////////////////////////////////////////////////////////////////////////
351 // senf::ppi::connector::GenericActiveInput
352
353 ////////////////////////////////////////
354 // private members
355
356 prefix_ void senf::ppi::connector::GenericActiveInput::v_requestEvent()
357 {
358     request();
359 }
360
361 ///////////////////////////////////////////////////////////////////////////
362 // senf::ppi::connector::GenericPassiveInput
363
364 ////////////////////////////////////////
365 // private members
366
367 prefix_ void senf::ppi::connector::GenericPassiveInput::v_enqueueEvent()
368 {
369     emit();
370     if (qdisc_)
371         qdisc_->update(*this, QueueingDiscipline::ENQUEUE);
372 }
373
374 prefix_ void senf::ppi::connector::GenericPassiveInput::v_dequeueEvent()
375 {
376     if (qdisc_)
377         qdisc_->update(*this, QueueingDiscipline::DEQUEUE);
378 }
379
380 prefix_ void senf::ppi::connector::GenericPassiveInput::qdisc(QueueingDiscipline::None_t)
381 {
382     qdisc_.reset( 0);
383 }
384
385 prefix_ void senf::ppi::connector::GenericPassiveInput::v_unthrottleEvent()
386 {
387     size_type n (queueSize());
388     while (n) {
389         emit();
390         size_type nn (queueSize());
391         if (n == nn)
392             break;
393         n = nn;
394     }
395 }
396
397 ///////////////////////////////cc.e////////////////////////////////////////
398 #undef prefix_
399 //#include "Connectors.mpp"
400
401 \f
402 // Local Variables:
403 // mode: c++
404 // fill-column: 100
405 // comment-column: 40
406 // c-file-style: "senf"
407 // indent-tabs-mode: nil
408 // ispell-local-dictionary: "american"
409 // compile-command: "scons -u test"
410 // End: