Whitespce cleanup: Remove whitespace at end-on-line, remove tabs, wrap
[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         senf::ppi::ModuleManager::instance().consoleDir()
123             .add("tracing", senf::console::factory::Command(
124                      SENF_FNP(senf::ppi::connector::Connector::TraceState,
125                               senf::ppi::connector::Connector::tracing, ()))
126                  .doc("Log every packet sent or received by any module.\n"
127                       "There are three different tracing levels:\n"
128                       "\n"
129                       "    NO_TRACING      don't output any tracing information\n"
130                       "    TRACE_IDS       trace packet id's but do not show packet contents\n"
131                       "    TRACE_CONTENTS  trace complete packet contents\n"
132                       "\n"
133                       "A log message is generated whenever the packet traverses a connector. The\n"
134                       "TRACE_IDS log message has the following format:\n"
135                       "\n"
136                       "    PPI packet trace: <direction> <packet-id> <packet-type>\n"
137                       "                      on <module-id> <module-type> connector <connector-id>\n"
138                       "    PPI throttling trace: <direction> <throttle-msg>\n"
139                       "                      on <module-id> <module-type> connector <connector-id>\n"
140                       "\n"
141                       "The fields are:\n"
142                       "\n"
143                       "    direction       'IN' for packets/throttle notifications entering the module,\n"
144                       "                    'OUT' for packets/throttle notifications leaving it\n"
145                       "    packet-id       Numeric unique packet id. This value is unique for packets\n"
146                       "                    alive at the same time, packets at different times may (and\n"
147                       "                    will) share id's\n"
148                       "    packet-type     The type of the packet header\n"
149                       "    module-id       Unique module id\n"
150                       "    module-type     Type of the module the packet is sent to/from\n"
151                       "    connector-id    Unique connector id\n"
152                       "    throttle-msg    Type of throttling event\n")
153                 );
154
155         senf::ppi::ModuleManager::instance().consoleDir()
156             .add("tracing", senf::console::factory::Command(
157                      SENF_FNP(void, senf::ppi::connector::Connector::tracing,
158                               (senf::ppi::connector::Connector::TraceState)))
159                  .arg("state", "new tracing state")
160                 );
161     }
162
163     ConsoleRegister consoleRegister;
164
165 }
166
167 prefix_ void senf::ppi::connector::Connector::disconnect()
168 {
169     // Cannot disconnected a non-connected connector
170     SENF_ASSERT( peer_ &&
171                  "senf::ppi::connector::Connector::disconnect(): Not connected" );
172
173     Connector & peer (*peer_);
174     peer_ = 0;
175     peer.peer_ = 0;
176
177     if (! initializationScheduled())
178         enqueueInitializable();
179     if (! peer.initializationScheduled())
180         peer.enqueueInitializable();
181
182     v_disconnected();
183     peer.v_disconnected();
184 }
185
186 prefix_ std::type_info const & senf::ppi::connector::Connector::packetTypeID()
187 {
188     return typeid(void);
189 }
190
191 prefix_ void senf::ppi::connector::Connector::v_disconnected()
192     const
193 {}
194
195 ///////////////////////////////////////////////////////////////////////////
196 // senf::ppi::connector::PassiveConnector
197
198 ////////////////////////////////////////
199 // private members
200
201 prefix_ void senf::ppi::connector::PassiveConnector::v_init()
202 {
203     Routes::const_iterator i (routes_.begin());
204     Routes::const_iterator const i_end (routes_.end());
205     for (; i != i_end; ++i)
206         if ((*i)->throttled())
207             break;
208     if (i == i_end)
209         remoteThrottled_ = false;
210     if (throttled())
211         emitThrottle();
212     else
213         emitUnthrottle();
214 }
215
216 prefix_ void senf::ppi::connector::PassiveConnector::v_unthrottleEvent()
217 {}
218
219 prefix_ void senf::ppi::connector::PassiveConnector::notifyUnthrottle()
220 {
221     if (std::find_if(routes_.begin(), routes_.end(),
222                      boost::bind(&ForwardingRoute::throttled, _1)) == routes_.end()) {
223         remoteThrottled_ = false;
224         if (!nativeThrottled_)
225             emitUnthrottle();
226     } else
227         throttleTrace("OUT", "not forwarding unthrottle event");
228 }
229
230 ///////////////////////////////////////////////////////////////////////////
231 // senf::ppi::connector::ActiveConnector
232
233 ////////////////////////////////////////
234 // private members
235
236 prefix_ void senf::ppi::connector::ActiveConnector::v_init()
237 {
238     if (! connected())
239         notifyThrottle();
240 }
241
242 prefix_ void senf::ppi::connector::ActiveConnector::notifyThrottle()
243 {
244     throttleTrace("IN ", "throttle");
245     if (! throttled_) {
246         throttled_ = true;
247         if (throttleCallback_)
248             throttleCallback_();
249         NotifyRoutes::const_iterator i (notifyRoutes_.begin());
250         NotifyRoutes::const_iterator const i_end (notifyRoutes_.end());
251         for (; i != i_end; ++i)
252             (*i)->notifyThrottle();
253     }
254 }
255
256 prefix_ void senf::ppi::connector::ActiveConnector::notifyUnthrottle()
257 {
258     throttleTrace("IN ", "unthrottle");
259     if (throttled_) {
260         throttled_ = false;
261         if (unthrottleCallback_)
262             unthrottleCallback_();
263         NotifyRoutes::const_iterator i (notifyRoutes_.begin());
264         NotifyRoutes::const_iterator const i_end (notifyRoutes_.end());
265         for (; i != i_end; ++i)
266             (*i)->notifyUnthrottle();
267     }
268 }
269
270 prefix_ void senf::ppi::connector::ActiveConnector::registerRoute(ForwardingRoute & route)
271 {
272     notifyRoutes_.push_back(&route);
273 }
274
275 prefix_ void senf::ppi::connector::ActiveConnector::unregisterRoute(ForwardingRoute & route)
276 {
277     NotifyRoutes::iterator i (std::find(notifyRoutes_.begin(), notifyRoutes_.end(), &route));
278     if (i != notifyRoutes_.end())
279         notifyRoutes_.erase(i);
280 }
281
282 ///////////////////////////////////////////////////////////////////////////
283 // senf::ppi::connector::InputConnector
284
285 prefix_ senf::Packet senf::ppi::connector::InputConnector::operator()()
286 {
287     if (empty())
288         v_requestEvent();
289     Packet p;
290     if (! empty()) {
291         p = peek();
292         queue_.pop_back();
293         v_dequeueEvent();
294     }
295     trace(p, "IN ");
296     return p;
297 }
298
299 ////////////////////////////////////////
300 // private members
301
302 prefix_ void senf::ppi::connector::InputConnector::v_requestEvent()
303 {}
304
305 prefix_ void senf::ppi::connector::InputConnector::v_enqueueEvent()
306 {}
307
308 prefix_ void senf::ppi::connector::InputConnector::v_dequeueEvent()
309 {}
310
311 ///////////////////////////////////////////////////////////////////////////
312 // senf::ppi::connector::GenericActiveInput
313
314 ////////////////////////////////////////
315 // private members
316
317 prefix_ void senf::ppi::connector::GenericActiveInput::v_requestEvent()
318 {
319     request();
320 }
321
322 ///////////////////////////////////////////////////////////////////////////
323 // senf::ppi::connector::GenericPassiveInput
324
325 ////////////////////////////////////////
326 // private members
327
328 prefix_ void senf::ppi::connector::GenericPassiveInput::v_enqueueEvent()
329 {
330     emit();
331     qdisc_->update(*this, QueueingDiscipline::ENQUEUE);
332 }
333
334 prefix_ void senf::ppi::connector::GenericPassiveInput::v_dequeueEvent()
335 {
336     qdisc_->update(*this, QueueingDiscipline::DEQUEUE);
337 }
338
339 prefix_ void senf::ppi::connector::GenericPassiveInput::v_unthrottleEvent()
340 {
341     size_type n (queueSize());
342     while (n) {
343         emit();
344         size_type nn (queueSize());
345         if (n == nn)
346             break;
347         n = nn;
348     }
349 }
350
351 ///////////////////////////////cc.e////////////////////////////////////////
352 #undef prefix_
353 //#include "Connectors.mpp"
354
355 \f
356 // Local Variables:
357 // mode: c++
358 // fill-column: 100
359 // comment-column: 40
360 // c-file-style: "senf"
361 // indent-tabs-mode: nil
362 // ispell-local-dictionary: "american"
363 // compile-command: "scons -u test"
364 // End: