|
1 /* |
|
2 * Copyright 2007 Baylor University |
|
3 * |
|
4 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 * you may not use this file except in compliance with the License. |
|
6 * You may obtain a copy of the License at |
|
7 * |
|
8 * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 * |
|
10 * Unless required by applicable law or agreed to in writing, software |
|
11 * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 * See the License for the specific language governing permissions and |
|
14 * limitations under the License. |
|
15 */ |
|
16 |
|
17 #ifdef HAVE_CONFIG_H |
|
18 # include <dtn-config.h> |
|
19 #endif |
|
20 |
|
21 #include "bundling/BundleProtocol.h" |
|
22 #include "bundling/BundleDaemon.h" |
|
23 #include <oasys/thread/Lock.h> |
|
24 |
|
25 #include "prophet/QueuePolicy.h" |
|
26 #include "ProphetRouter.h" |
|
27 |
|
28 namespace dtn |
|
29 { |
|
30 |
|
31 void prophet_router_shutdown(void*) |
|
32 { |
|
33 BundleDaemon::instance()->router()->shutdown(); |
|
34 } |
|
35 |
|
36 prophet::ProphetParams ProphetRouter::params_; |
|
37 |
|
38 bool ProphetRouter::is_init_ = false; |
|
39 |
|
40 ProphetRouter::ProphetRouter() |
|
41 : BundleRouter("ProphetRouter","prophet"), |
|
42 core_(NULL), oracle_(NULL), |
|
43 lock_(new oasys::SpinLock("ProphetRouter")) |
|
44 { |
|
45 } |
|
46 |
|
47 ProphetRouter::~ProphetRouter() |
|
48 { |
|
49 delete oracle_; |
|
50 delete core_; |
|
51 delete lock_; |
|
52 } |
|
53 |
|
54 void |
|
55 ProphetRouter::initialize() |
|
56 { |
|
57 ASSERT( is_init_ == false ); |
|
58 |
|
59 // create local instance of ProphetBundleCore, |
|
60 // prophet::Repository, and prophet::Controller |
|
61 std::string local_eid(BundleDaemon::instance()->local_eid().str()); |
|
62 |
|
63 core_ = new ProphetBundleCore(local_eid,actions_,lock_); |
|
64 oracle_ = new prophet::Controller(core_,core_->bundles(),¶ms_); |
|
65 |
|
66 // register the global shutdown function |
|
67 BundleDaemon::instance()->set_rtr_shutdown( |
|
68 prophet_router_shutdown, (void *) 0); |
|
69 |
|
70 // deserialize any routes from permanent storage |
|
71 core_->load_prophet_nodes(oracle_->nodes(),¶ms_); |
|
72 |
|
73 is_init_ = true; |
|
74 log_info("ProphetRouter initialization complete"); |
|
75 } |
|
76 |
|
77 void |
|
78 ProphetRouter::shutdown() |
|
79 { |
|
80 log_info("ProphetRouter shutdown"); |
|
81 oasys::ScopeLock l(lock_, "shutdown"); |
|
82 oracle_->shutdown(); |
|
83 core_->shutdown(); |
|
84 } |
|
85 |
|
86 void |
|
87 ProphetRouter::handle_event(BundleEvent* e) |
|
88 { |
|
89 dispatch_event(e); |
|
90 } |
|
91 |
|
92 void |
|
93 ProphetRouter::get_routing_state(oasys::StringBuffer* buf) |
|
94 { |
|
95 log_info("ProphetRouter get_routing_state"); |
|
96 oasys::ScopeLock l(lock_, "get_routing_state"); |
|
97 |
|
98 // summarize current number of routes, misc. statistics |
|
99 buf->appendf("ProphetRouter:\n" |
|
100 " %zu routes, %zu queued bundles, %zu ACKs, %zu active sessions\n", |
|
101 oracle_->nodes()->size(), |
|
102 core_->bundles()->size(), |
|
103 oracle_->acks()->size(), |
|
104 oracle_->size()); |
|
105 // iterate over Encounters and query their status |
|
106 buf->appendf("Active Sessions\n"); |
|
107 for (prophet::Controller::List::const_iterator i = oracle_->begin(); |
|
108 i != oracle_->end(); i++) |
|
109 { |
|
110 buf->appendf(" %4d: %-30s %s timeout %u\n", |
|
111 (*i)->local_instance(), |
|
112 (*i)->nexthop()->remote_eid(), |
|
113 (*i)->state_str(), |
|
114 (*i)->time_remaining()); |
|
115 } |
|
116 buf->appendf("Routes\n"); |
|
117 for (prophet::Table::const_iterator i = oracle_->nodes()->begin(); |
|
118 i != oracle_->nodes()->end(); i++) |
|
119 { |
|
120 buf->appendf(" %-30s: %.2f %s%s%s %lu s old\n", |
|
121 i->second->dest_id(), i->second->p_value(), |
|
122 i->second->relay() ? "R" : " ", |
|
123 i->second->custody() ? "C" : " ", |
|
124 i->second->internet_gw() ? "I" : " ", |
|
125 (time(0) - i->second->age())); |
|
126 } |
|
127 buf->appendf("\n R - relay C - custody I - internet gateway \n\n"); |
|
128 |
|
129 //XXX/wilson debug |
|
130 buf->appendf("Bundles:\n"); |
|
131 prophet::BundleList bundles = core_->bundles()->get_bundles(); |
|
132 for (prophet::BundleList::iterator i = bundles.begin(); |
|
133 i != bundles.end(); i++) |
|
134 { |
|
135 buf->appendf("%s -> %s (%u:%u)\n", |
|
136 (*i)->source_id().c_str(), |
|
137 (*i)->destination_id().c_str(), |
|
138 (*i)->creation_ts(), |
|
139 (*i)->sequence_num()); |
|
140 } |
|
141 } |
|
142 |
|
143 bool |
|
144 ProphetRouter::accept_bundle(Bundle* bundle, int* errp) |
|
145 { |
|
146 log_info("ProphetRouter accept_bundle"); |
|
147 |
|
148 // first ask base class |
|
149 if (!BundleRouter::accept_bundle(bundle,errp)) |
|
150 { |
|
151 log_debug("BundleRouter rejects *%p",bundle); |
|
152 return false; |
|
153 } |
|
154 |
|
155 BundleRef tmp("accept_bundle"); |
|
156 tmp = bundle; |
|
157 |
|
158 oasys::ScopeLock l(lock_, "accept_bundle"); |
|
159 // retrieve temp prophet handle to Bundle metadata |
|
160 const prophet::Bundle* b = core_->get_temp_bundle(tmp); |
|
161 if (errp != NULL) errp = (int) BundleProtocol::REASON_NO_ADDTL_INFO; |
|
162 // ask controller's opinion on this bundle |
|
163 bool ok = oracle_->accept_bundle(b); |
|
164 // clean up memory used by temporary wrapper |
|
165 delete b; |
|
166 log_debug("do%saccept bundle *%p", ok ? " " : " not ", bundle); |
|
167 return ok; |
|
168 } |
|
169 |
|
170 void |
|
171 ProphetRouter::handle_bundle_received(BundleReceivedEvent* e) |
|
172 { |
|
173 log_info("ProphetRouter handle_bundle_received"); |
|
174 |
|
175 // should not be reached, but somehow still is |
|
176 if (e->source_ == EVENTSRC_STORE) |
|
177 return; |
|
178 |
|
179 const prophet::Link* l = NULL; |
|
180 |
|
181 oasys::ScopeLock sl(lock_, "handle_bundle_received"); |
|
182 // Locally generated files do not have a link specified either |
|
183 // The ping reflector generates bundles with EVENTSRC_ADMIN |
|
184 // [Note from Elwyn Davies: Maybe using a special link might be useful] |
|
185 if ((e->source_ != EVENTSRC_APP) && (e->source_ != EVENTSRC_ADMIN)) |
|
186 { |
|
187 // The external CL does not set this field, which the Prophet |
|
188 // implementation needs. We want to fail quickly if we're |
|
189 // running with the ECL. |
|
190 ASSERT(e->link_ != NULL); |
|
191 |
|
192 // add DTN's Link to BundleCore facade |
|
193 core_->add(e->link_); |
|
194 |
|
195 // retrieve prophet's handle to Link metadata |
|
196 l = core_->get_link(e->link_.object()); |
|
197 |
|
198 if (l == NULL) return; |
|
199 } |
|
200 |
|
201 // create temporary prophet handle to Bundle metadata |
|
202 const prophet::Bundle* b = core_->get_temp_bundle(e->bundleref_); |
|
203 |
|
204 if (b == NULL) |
|
205 { |
|
206 log_err("failed to retrieve prophet handle for *%p", |
|
207 e->bundleref_.object()); |
|
208 return; |
|
209 } |
|
210 |
|
211 core_->bundles_.add(b); |
|
212 |
|
213 // inform Controller that a new bundle has arrived on this link |
|
214 oracle_->handle_bundle_received(b,l); |
|
215 } |
|
216 |
|
217 void |
|
218 ProphetRouter::handle_bundle_delivered(BundleDeliveredEvent* e) |
|
219 { |
|
220 log_info("ProphetRouter handle_bundle_delivered"); |
|
221 oasys::ScopeLock l(lock_, "handle_bundle_delivered"); |
|
222 |
|
223 Bundle* bundle = e->bundleref_.object(); |
|
224 if (bundle == NULL) return; |
|
225 |
|
226 // retrieve prophet's handle to Bundle metadata |
|
227 const prophet::Bundle* b = core_->get_bundle(bundle); |
|
228 if (b == NULL) |
|
229 { |
|
230 log_err("Failed to convert *%p to prophet object",bundle); |
|
231 return; |
|
232 } |
|
233 // BundleDeliveredEvent means prophet::Ack, which kicks Bundle out of Prophet |
|
234 oracle_->ack(b); |
|
235 } |
|
236 |
|
237 void |
|
238 ProphetRouter::handle_bundle_expired(BundleExpiredEvent* e) |
|
239 { |
|
240 log_info("ProphetRouter handle_bundle_expired"); |
|
241 oasys::ScopeLock l(lock_, "handle_bundle_expired"); |
|
242 |
|
243 const prophet::Bundle* b = NULL; |
|
244 Bundle* bundle = e->bundleref_.object(); |
|
245 if (bundle != NULL && ((b = core_->get_bundle(bundle)) != NULL)) |
|
246 { |
|
247 // drop Prophet stats on this bundle |
|
248 oracle_->stats()->drop_bundle(b); |
|
249 } |
|
250 |
|
251 core_->del(e->bundleref_); |
|
252 } |
|
253 |
|
254 void |
|
255 ProphetRouter::handle_bundle_transmitted(BundleTransmittedEvent* e) |
|
256 { |
|
257 const prophet::Bundle* bundle = core_->get_bundle(e->bundleref_.object()); |
|
258 const prophet::Link* link = core_->get_link(e->link_.object()); |
|
259 if (bundle != NULL && link != NULL) |
|
260 oracle_->handle_bundle_transmitted(bundle,link); |
|
261 } |
|
262 |
|
263 void |
|
264 ProphetRouter::handle_contact_up(ContactUpEvent* e) |
|
265 { |
|
266 log_info("ProphetRouter handle_contact_up"); |
|
267 oasys::ScopeLock lk(lock_, "handle_contact_up"); |
|
268 |
|
269 Link* link = e->contact_->link().object(); |
|
270 if (link == NULL) return; |
|
271 |
|
272 // add DTN's Link to BundleCore facade |
|
273 core_->add(e->contact_->link()); |
|
274 // retrieve prophet's handle to Link metadata |
|
275 const prophet::Link* l = core_->get_link(link); |
|
276 if (l == NULL) return; |
|
277 // tell Controller about our new friend |
|
278 oracle_->new_neighbor(l); |
|
279 } |
|
280 |
|
281 void |
|
282 ProphetRouter::handle_contact_down(ContactDownEvent* e) |
|
283 { |
|
284 log_info("ProphetRouter handle_contact_down"); |
|
285 oasys::ScopeLock lk(lock_, "handle_contact_down"); |
|
286 |
|
287 Link* link = e->contact_->link().object(); |
|
288 |
|
289 // retrieve prophet's handle to Link metadata |
|
290 const prophet::Link* l = NULL; |
|
291 if (link != NULL && |
|
292 (l = core_->get_link(e->contact_->link().object())) != NULL) |
|
293 // inform Controller about the loss |
|
294 oracle_->neighbor_gone(l); |
|
295 // drop BundleCore's knowledge about this Link |
|
296 core_->del(e->contact_->link()); |
|
297 } |
|
298 |
|
299 void |
|
300 ProphetRouter::handle_link_available(LinkAvailableEvent* e) |
|
301 { |
|
302 LinkRef next_hop = e->link_; |
|
303 ASSERT(next_hop != NULL); |
|
304 ASSERT(!next_hop->isdeleted()); |
|
305 |
|
306 // Prophet initiates its protocol based on handle_contact_up, |
|
307 // which fires upon success link open ... so poke it and see |
|
308 // what happens |
|
309 if (!next_hop->isopen()) |
|
310 { |
|
311 // request to open link |
|
312 actions_->open_link(next_hop); |
|
313 } |
|
314 } |
|
315 |
|
316 void |
|
317 ProphetRouter::set_queue_policy() |
|
318 { |
|
319 log_info("ProphetRouter set_queue_policy"); |
|
320 oasys::ScopeLock l(lock_, "set_queue_policy"); |
|
321 // tell Controller to reorganize internal bundle policy based on new |
|
322 // parameters written to params_ by ProphetCommand |
|
323 oracle_->set_queue_policy(); |
|
324 } |
|
325 |
|
326 void |
|
327 ProphetRouter::set_hello_interval() |
|
328 { |
|
329 log_info("ProphetRouter set_hello_interval"); |
|
330 oasys::ScopeLock l(lock_, "set_hello_interval"); |
|
331 // tell Controller to change internal protocol timeouts based on new |
|
332 // parameters written to params_ by ProphetCommand |
|
333 oracle_->set_hello_interval(); |
|
334 } |
|
335 |
|
336 void |
|
337 ProphetRouter::set_max_route() |
|
338 { |
|
339 log_info("ProphetRouter set_max_route"); |
|
340 oasys::ScopeLock l(lock_, "set_max_route"); |
|
341 // tell Controller to change internal limit on number of routes |
|
342 // to retain, based on changes made to params_ by ProphetCommand |
|
343 oracle_->set_max_route(); |
|
344 } |
|
345 |
|
346 }; // namespace dtn |