485312dfaba1cf38b187e40ad619c4b785a86ca2
[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     v_connected();
89     peer_->v_connected();
90
91 }
92
93 senf::ppi::connector::Connector::TraceState senf::ppi::connector::Connector::traceState_ (
94     senf::ppi::connector::Connector::NO_TRACING);
95
96 prefix_ void senf::ppi::connector::Connector::trace(Packet const & p, char const * label)
97 {
98     if (traceState_ == NO_TRACING)
99         return;
100     SENF_LOG_BLOCK(({
101                 std::string type (prettyName(p.typeId().id()));
102                 log << "PPI packet trace: " << label << " 0x" << std::hex << p.id() << " "
103                     << type.substr(21, type.size()-22) << " on " << & module() << " "
104                     << prettyName(typeid(module())) << " connector 0x" << this << "\n";
105                 if (traceState_ == TRACE_CONTENTS)
106                     p.dump(log);
107             }));
108 }
109
110 prefix_ void senf::ppi::connector::Connector::throttleTrace(char const * label,
111                                                             char const * type)
112 {
113     if (traceState_ == NO_TRACING)
114         return;
115     SENF_LOG_BLOCK(({
116                 log << "PPI throttling trace: " << label << " " << type << " on " << & module()
117                     << " " << prettyName(typeid(module())) << " connector 0x" << this << "\n";
118             }));
119 }
120
121 namespace senf { namespace ppi { namespace connector {
122
123     SENF_CONSOLE_REGISTER_ENUM_MEMBER(
124         Connector, TraceState, (NO_TRACING)(TRACE_IDS)(TRACE_CONTENTS) );
125
126 }}}
127
128 namespace {
129
130     struct ConsoleRegister
131     {
132         ConsoleRegister();
133     };
134
135     ConsoleRegister::ConsoleRegister()
136     {
137 #ifndef SENF_PPI_NOTRACE
138         senf::ppi::ModuleManager::instance().consoleDir()
139             .add("tracing", senf::console::factory::Command(
140                      SENF_FNP(senf::ppi::connector::Connector::TraceState,
141                               senf::ppi::connector::Connector::tracing, ()))
142                  .doc("Log every packet sent or received by any module.\n"
143                       "There are three different tracing levels:\n"
144                       "\n"
145                       "    NO_TRACING      don't output any tracing information\n"
146                       "    TRACE_IDS       trace packet id's but do not show packet contents\n"
147                       "    TRACE_CONTENTS  trace complete packet contents\n"
148                       "\n"
149                       "A log message is generated whenever the packet traverses a connector. The\n"
150                       "TRACE_IDS log message has the following format:\n"
151                       "\n"
152                       "    PPI packet trace: <direction> <packet-id> <packet-type>\n"
153                       "                      on <module-id> <module-type> connector <connector-id>\n"
154                       "    PPI throttling trace: <direction> <throttle-msg>\n"
155                       "                      on <module-id> <module-type> connector <connector-id>\n"
156                       "\n"
157                       "The fields are:\n"
158                       "\n"
159                       "    direction       'IN' for packets/throttle notifications entering the module,\n"
160                       "                    'OUT' for packets/throttle notifications leaving it\n"
161                       "    packet-id       Numeric unique packet id. This value is unique for packets\n"
162                       "                    alive at the same time, packets at different times may (and\n"
163                       "                    will) share id's\n"
164                       "    packet-type     The type of the packet header\n"
165                       "    module-id       Unique module id\n"
166                       "    module-type     Type of the module the packet is sent to/from\n"
167                       "    connector-id    Unique connector id\n"
168                       "    throttle-msg    Type of throttling event\n")
169                 );
170
171         senf::ppi::ModuleManager::instance().consoleDir()
172             .add("tracing", senf::console::factory::Command(
173                      SENF_FNP(void, senf::ppi::connector::Connector::tracing,
174                               (senf::ppi::connector::Connector::TraceState)))
175                  .arg("state", "new tracing state")
176                 );
177 #endif
178     }
179
180     ConsoleRegister consoleRegister;
181
182 }
183
184 prefix_ void senf::ppi::connector::Connector::disconnect()
185 {
186     // Cannot disconnected a non-connected connector
187     SENF_ASSERT( peer_,
188                  "senf::ppi::connector::Connector::disconnect(): Not connected" );
189
190     Connector & peer (*peer_);
191     peer_ = 0;
192     peer.peer_ = 0;
193
194     if (! initializationScheduled())
195         enqueueInitializable();
196     if (! peer.initializationScheduled())
197         peer.enqueueInitializable();
198
199     v_disconnected();
200     peer.v_disconnected();
201 }
202
203 prefix_ std::type_info const & senf::ppi::connector::Connector::packetTypeID()
204 {
205     return typeid(void);
206 }
207
208 prefix_ void senf::ppi::connector::Connector::unregisterConnector()
209 {
210     if (module_)
211         module_->unregisterConnector(*this);
212 }
213
214 prefix_ void senf::ppi::connector::Connector::setModule(module::Module & module)
215 {
216     module_ = &module;
217 }
218
219 prefix_ void senf::ppi::connector::Connector::v_disconnected()
220 {}
221
222 prefix_ void senf::ppi::connector::Connector::v_connected()
223 {}
224
225 ///////////////////////////////////////////////////////////////////////////
226 // senf::ppi::connector::PassiveConnector
227
228 prefix_ senf::ppi::connector::PassiveConnector::~PassiveConnector()
229 {
230     // Must be here and NOT in base so it is called before destructing the routes_ member
231     unregisterConnector();
232 }
233
234 prefix_ void senf::ppi::connector::PassiveConnector::v_disconnected()
235 {
236     Connector::v_disconnected();
237     peer_ = 0;
238 }
239
240 prefix_ void senf::ppi::connector::PassiveConnector::v_connected()
241 {
242     Connector::v_connected();
243     peer_ = & dynamic_cast<ActiveConnector&>(Connector::peer());
244 }
245
246 ////////////////////////////////////////
247 // private members
248
249 prefix_ void senf::ppi::connector::PassiveConnector::v_init()
250 {
251     Routes::const_iterator i (routes_.begin());
252     Routes::const_iterator const i_end (routes_.end());
253     for (; i != i_end; ++i)
254         if ((*i)->throttled())
255             break;
256     if (i == i_end)
257         remoteThrottled_ = false;
258     if (throttled())
259         emitThrottle();
260     else
261         emitUnthrottle();
262 }
263
264 prefix_ void senf::ppi::connector::PassiveConnector::registerRoute(ForwardingRoute & route)
265 {
266     routes_.push_back(&route);
267 }
268
269 prefix_ void senf::ppi::connector::PassiveConnector::unregisterRoute(ForwardingRoute & route)
270 {
271     Routes::iterator i (std::find(routes_.begin(), routes_.end(), &route));
272     if (i != routes_.end())
273         routes_.erase(i);
274 }
275
276 prefix_ void senf::ppi::connector::PassiveConnector::v_unthrottleEvent()
277 {}
278
279 prefix_ void senf::ppi::connector::PassiveConnector::notifyUnthrottle()
280 {
281     if (std::find_if(routes_.begin(), routes_.end(),
282                      boost::bind(&ForwardingRoute::throttled, _1)) == routes_.end()) {
283         remoteThrottled_ = false;
284         if (!nativeThrottled_)
285             emitUnthrottle();
286     } else
287         SENF_PPI_THROTTLE_TRACE("OUT", "not forwarding unthrottle event");
288 }
289
290 ///////////////////////////////////////////////////////////////////////////
291 // senf::ppi::connector::ActiveConnector
292
293 prefix_ senf::ppi::connector::ActiveConnector::~ActiveConnector()
294 {
295     // Must be here and NOT in base so it is called before destructing the routes_ member
296     unregisterConnector();
297 }
298
299 prefix_ void senf::ppi::connector::ActiveConnector::v_disconnected()
300 {
301     Connector::v_disconnected();
302     peer_ = 0;
303 }
304
305 prefix_ void senf::ppi::connector::ActiveConnector::v_connected()
306 {
307     Connector::v_connected();
308     peer_ = & dynamic_cast<PassiveConnector&>(Connector::peer());
309 }
310
311 ////////////////////////////////////////
312 // private members
313
314 prefix_ void senf::ppi::connector::ActiveConnector::v_init()
315 {
316     if (! connected())
317         notifyThrottle();
318 }
319
320 prefix_ void senf::ppi::connector::ActiveConnector::notifyThrottle()
321 {
322     SENF_PPI_THROTTLE_TRACE("IN ", "throttle");
323     if (! throttled_) {
324         throttled_ = true;
325         if (throttleCallback_)
326             throttleCallback_();
327         NotifyRoutes::const_iterator i (notifyRoutes_.begin());
328         NotifyRoutes::const_iterator const i_end (notifyRoutes_.end());
329         for (; i != i_end; ++i)
330             (*i)->notifyThrottle();
331     }
332 }
333
334 prefix_ void senf::ppi::connector::ActiveConnector::notifyUnthrottle()
335 {
336     SENF_PPI_THROTTLE_TRACE("IN ", "unthrottle");
337     if (throttled_) {
338         throttled_ = false;
339         if (unthrottleCallback_)
340             unthrottleCallback_();
341         NotifyRoutes::const_iterator i (notifyRoutes_.begin());
342         NotifyRoutes::const_iterator const i_end (notifyRoutes_.end());
343         for (; i != i_end; ++i)
344             (*i)->notifyUnthrottle();
345     }
346 }
347
348 prefix_ void senf::ppi::connector::ActiveConnector::registerRoute(ForwardingRoute & route)
349 {
350     notifyRoutes_.push_back(&route);
351 }
352
353 prefix_ void senf::ppi::connector::ActiveConnector::unregisterRoute(ForwardingRoute & route)
354 {
355     NotifyRoutes::iterator i (std::find(notifyRoutes_.begin(), notifyRoutes_.end(), &route));
356     if (i != notifyRoutes_.end())
357         notifyRoutes_.erase(i);
358 }
359
360 ///////////////////////////////////////////////////////////////////////////
361 // senf::ppi::connector::InputConnector
362
363 prefix_ senf::Packet senf::ppi::connector::InputConnector::operator()()
364 {
365     if (empty())
366         v_requestEvent();
367     if (! empty()) {
368         Packet p ( queue_.back());
369         queue_.pop_back();
370         v_dequeueEvent();
371         SENF_PPI_TRACE(p, "IN ");
372         return p;
373     } else {
374         SENF_PPI_TRACE(Packet(), "IN ");
375         return Packet();
376     }
377 }
378
379 prefix_ void senf::ppi::connector::InputConnector::v_disconnected()
380 {
381     Connector::v_disconnected();
382     peer_ = 0;
383 }
384
385 prefix_ void senf::ppi::connector::InputConnector::v_connected()
386 {
387     Connector::v_connected();
388     peer_ = & dynamic_cast<OutputConnector&>(Connector::peer());
389 }
390
391 ////////////////////////////////////////
392 // private members
393
394 prefix_ void senf::ppi::connector::InputConnector::v_requestEvent()
395 {}
396
397 prefix_ void senf::ppi::connector::InputConnector::v_enqueueEvent()
398 {}
399
400 prefix_ void senf::ppi::connector::InputConnector::v_dequeueEvent()
401 {}
402
403 ///////////////////////////////////////////////////////////////////////////
404 // senf::ppi::connector::OutputConnector
405
406 prefix_ void senf::ppi::connector::OutputConnector::v_disconnected()
407 {
408     Connector::v_disconnected();
409     peer_ = 0;
410 }
411
412 prefix_ void senf::ppi::connector::OutputConnector::v_connected()
413 {
414     Connector::v_connected();
415     peer_ = & dynamic_cast<InputConnector&>(Connector::peer());
416 }
417
418 ///////////////////////////////////////////////////////////////////////////
419 // senf::ppi::connector::GenericActiveInput
420
421 ////////////////////////////////////////
422 // private members
423
424 prefix_ void senf::ppi::connector::GenericActiveInput::v_requestEvent()
425 {
426     request();
427 }
428
429 ///////////////////////////////////////////////////////////////////////////
430 // senf::ppi::connector::GenericPassiveInput
431
432 prefix_ void senf::ppi::connector::GenericPassiveInput::v_disconnected()
433 {
434     PassiveConnector::v_disconnected();
435     InputConnector::v_disconnected();
436     peer_ = 0;
437 }
438
439 prefix_ void senf::ppi::connector::GenericPassiveInput::v_connected()
440 {
441     PassiveConnector::v_connected();
442     InputConnector::v_connected();
443     peer_ = & dynamic_cast<GenericActiveOutput&>(Connector::peer());
444 }
445
446 ////////////////////////////////////////
447 // private members
448
449 prefix_ void senf::ppi::connector::GenericPassiveInput::v_enqueueEvent()
450 {
451     emit();
452     if (qdisc_)
453         qdisc_->update(*this, QueueingDiscipline::ENQUEUE);
454 }
455
456 prefix_ void senf::ppi::connector::GenericPassiveInput::v_dequeueEvent()
457 {
458     if (qdisc_)
459         qdisc_->update(*this, QueueingDiscipline::DEQUEUE);
460 }
461
462 prefix_ void senf::ppi::connector::GenericPassiveInput::qdisc(QueueingDiscipline::None_t)
463 {
464     qdisc_.reset( 0);
465 }
466
467 prefix_ void senf::ppi::connector::GenericPassiveInput::v_unthrottleEvent()
468 {
469     size_type n (queueSize());
470     while (n) {
471         emit();
472         size_type nn (queueSize());
473         if (n == nn)
474             break;
475         n = nn;
476     }
477 }
478
479 ///////////////////////////////////////////////////////////////////////////
480 // senf::ppi::connector::GenericPassiveOutput
481
482 prefix_ void senf::ppi::connector::GenericPassiveOutput::v_disconnected()
483 {
484     PassiveConnector::v_disconnected();
485     OutputConnector::v_disconnected();
486     peer_ = 0;
487 }
488
489 prefix_ void senf::ppi::connector::GenericPassiveOutput::v_connected()
490 {
491     PassiveConnector::v_connected();
492     OutputConnector::v_connected();
493     peer_ = & dynamic_cast<GenericActiveInput&>(Connector::peer());
494 }
495
496 ///////////////////////////////////////////////////////////////////////////
497 // senf::ppi::connector::GenericActiveInput
498
499 prefix_ void senf::ppi::connector::GenericActiveInput::v_disconnected()
500 {
501     ActiveConnector::v_disconnected();
502     InputConnector::v_disconnected();
503     peer_ = 0;
504 }
505
506 prefix_ void senf::ppi::connector::GenericActiveInput::v_connected()
507 {
508     ActiveConnector::v_connected();
509     InputConnector::v_connected();
510     peer_ = & dynamic_cast<GenericPassiveOutput&>(Connector::peer());
511 }
512
513 ///////////////////////////////////////////////////////////////////////////
514 // senf::ppi::connector::GenericActiveOutput
515
516 prefix_ void senf::ppi::connector::GenericActiveOutput::v_disconnected()
517 {
518     ActiveConnector::v_disconnected();
519     OutputConnector::v_disconnected();
520     peer_ = 0;
521 }
522
523 prefix_ void senf::ppi::connector::GenericActiveOutput::v_connected()
524 {
525     ActiveConnector::v_connected();
526     OutputConnector::v_connected();
527     peer_ = & dynamic_cast<GenericPassiveInput&>(Connector::peer());
528 }
529
530
531 ///////////////////////////////cc.e////////////////////////////////////////
532 #undef prefix_
533 //#include "Connectors.mpp"
534
535 \f
536 // Local Variables:
537 // mode: c++
538 // fill-column: 100
539 // comment-column: 40
540 // c-file-style: "senf"
541 // indent-tabs-mode: nil
542 // ispell-local-dictionary: "american"
543 // compile-command: "scons -u test"
544 // End: