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