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