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