PPI: BUGFIX: Fix unthrottling when mixing multiple auto-forwarding routes with native...
[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
34 //#include "Connectors.mpp"
35 #define prefix_
36 ///////////////////////////////cc.p////////////////////////////////////////
37
38 ///////////////////////////////////////////////////////////////////////////
39 // senf::ppi::connector::Connector
40
41 prefix_ void senf::ppi::connector::Connector::connect(Connector & target)
42 {
43     // The connector is not registered -> route() or noroute() statement missing
44     SENF_ASSERT( module_ && 
45                  "senf::ppi::connector::Connector::connect(): (source) "
46                  "Missing route() or noroute()" );
47     // The connector is already connected
48     SENF_ASSERT( ! peer_ &&
49                  "senf::ppi::connector::Connector::connect(): (source) "
50                  "duplicate connection" );
51     // The target connector is not registered -> route() or noroute() statement missing
52     SENF_ASSERT( target.module_ &&
53                  "senf::ppi::connector::Connector::connect(): (target) "
54                  "Missing route() or noroute()" );
55     // The target connector is already connected
56     SENF_ASSERT( ! target.peer_ &&
57                  "senf::ppi::connector::Connector::connect(): (target) "
58                  "duplicate connection" );
59     if (! (packetTypeID() == typeid(void) ||
60            target.packetTypeID() == typeid(void) || 
61            packetTypeID() == target.packetTypeID()) )
62         throw IncompatibleConnectorsException() 
63             << ": " << prettyName(packetTypeID()) 
64             << " [in module " << prettyName(typeid(*module_))  << "] "
65             << ", " << prettyName(target.packetTypeID())
66             << " [in module " << prettyName(typeid(*target.module_)) << "]";
67             
68     peer_ = & target;
69     target.peer_ = this;
70
71     if (! initializationScheduled())
72         enqueueInitializable();
73     if (! peer().initializationScheduled())
74         peer().enqueueInitializable();
75 }
76
77 prefix_ void senf::ppi::connector::Connector::disconnect()
78 {
79     // Cannot disconnected a non-connected connector
80     SENF_ASSERT( peer_ &&
81                  "senf::ppi::connector::Connector::disconnect(): Not connected" );
82     Connector & peer (*peer_);
83     peer_ = 0;
84     peer.peer_ = 0;
85
86     if (! initializationScheduled())
87         enqueueInitializable();
88     if (! peer.initializationScheduled())
89         peer.enqueueInitializable();
90 }
91
92 prefix_ std::type_info const & senf::ppi::connector::Connector::packetTypeID()
93 {
94     return typeid(void);
95 }
96
97 ///////////////////////////////////////////////////////////////////////////
98 // senf::ppi::connector::PassiveConnector
99
100 ////////////////////////////////////////
101 // private members
102
103 prefix_ void senf::ppi::connector::PassiveConnector::v_init()
104 {
105     Routes::const_iterator i (routes_.begin());
106     Routes::const_iterator const i_end (routes_.end());
107     for (; i != i_end; ++i)
108         if ((*i)->throttled())
109             break;
110     if (i == i_end)
111         remoteThrottled_ = false;
112     if (throttled())
113         emitThrottle();
114     else
115         emitUnthrottle();
116 }
117
118 prefix_ void senf::ppi::connector::PassiveConnector::v_unthrottleEvent()
119 {}
120
121 prefix_ void senf::ppi::connector::PassiveConnector::notifyUnthrottle()
122 {
123     if (std::find_if(routes_.begin(), routes_.end(), 
124                      boost::bind(&ForwardingRoute::throttled, _1)) == routes_.end()) {
125         remoteThrottled_ = false;
126         if (!nativeThrottled_)
127             emitUnthrottle();
128     }
129 }
130
131 ///////////////////////////////////////////////////////////////////////////
132 // senf::ppi::connector::ActiveConnector
133
134 ////////////////////////////////////////
135 // private members
136
137 prefix_ void senf::ppi::connector::ActiveConnector::v_init()
138 {
139     if (! connected())
140         notifyThrottle();
141 }
142
143 prefix_ void senf::ppi::connector::ActiveConnector::notifyThrottle()
144 {
145     if (! throttled_) {
146         throttled_ = true;
147         if (throttleCallback_)
148             throttleCallback_();
149         NotifyRoutes::const_iterator i (notifyRoutes_.begin());
150         NotifyRoutes::const_iterator const i_end (notifyRoutes_.end());
151         for (; i != i_end; ++i)
152             (*i)->notifyThrottle();
153     }
154 }
155
156 prefix_ void senf::ppi::connector::ActiveConnector::notifyUnthrottle()
157 {
158     if (throttled_) {
159         throttled_ = false;
160         if (unthrottleCallback_)
161             unthrottleCallback_();
162         NotifyRoutes::const_iterator i (notifyRoutes_.begin());
163         NotifyRoutes::const_iterator const i_end (notifyRoutes_.end());
164         for (; i != i_end; ++i)
165             (*i)->notifyUnthrottle();
166     }
167 }
168
169 prefix_ void senf::ppi::connector::ActiveConnector::registerRoute(ForwardingRoute & route)
170 {
171     notifyRoutes_.push_back(&route);
172 }
173
174 ///////////////////////////////////////////////////////////////////////////
175 // senf::ppi::connector::InputConnector
176
177 prefix_ senf::Packet senf::ppi::connector::InputConnector::operator()()
178 {
179     if (empty())
180         v_requestEvent();
181     Packet p;
182     if (! empty()) {
183         p = peek();
184         queue_.pop_back();
185         v_dequeueEvent();
186     }
187     return p;
188 }
189
190 ////////////////////////////////////////
191 // private members
192
193 prefix_ void senf::ppi::connector::InputConnector::v_requestEvent()
194 {}
195
196 prefix_ void senf::ppi::connector::InputConnector::v_enqueueEvent()
197 {}
198
199 prefix_ void senf::ppi::connector::InputConnector::v_dequeueEvent()
200 {}
201
202 ///////////////////////////////////////////////////////////////////////////
203 // senf::ppi::connector::GenericActiveInput
204
205 ////////////////////////////////////////
206 // private members
207
208 prefix_ void senf::ppi::connector::GenericActiveInput::v_requestEvent()
209 {
210     request();
211 }
212
213 ///////////////////////////////////////////////////////////////////////////
214 // senf::ppi::connector::GenericPassiveInput
215
216 ////////////////////////////////////////
217 // private members 
218
219 prefix_ void senf::ppi::connector::GenericPassiveInput::v_enqueueEvent()
220 {
221     emit();
222     qdisc_->update(*this, QueueingDiscipline::ENQUEUE);
223 }
224
225 prefix_ void senf::ppi::connector::GenericPassiveInput::v_dequeueEvent()
226 {
227     qdisc_->update(*this, QueueingDiscipline::DEQUEUE);
228 }
229
230 prefix_ void senf::ppi::connector::GenericPassiveInput::v_unthrottleEvent()
231 {
232     size_type n (queueSize());
233     while (n) {
234         emit();
235         size_type nn (queueSize());
236         if (n == nn)
237             break;
238         n = nn;
239     }
240 }
241
242 ///////////////////////////////cc.e////////////////////////////////////////
243 #undef prefix_
244 //#include "Connectors.mpp"
245
246 \f
247 // Local Variables:
248 // mode: c++
249 // fill-column: 100
250 // comment-column: 40
251 // c-file-style: "senf"
252 // indent-tabs-mode: nil
253 // ispell-local-dictionary: "american"
254 // compile-command: "scons -u test"
255 // End: