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