TcaRouter.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2005-2006 University of Waterloo
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 
00018 #include "conv_layers/ConvergenceLayer.h"
00019 #include "bundling/BundleActions.h"
00020 #include "contacts/ContactManager.h"
00021 #include "bundling/BundleDaemon.h"
00022 #include "routing/RouteTable.h"
00023 #include  <oasys/io/NetUtils.h>
00024 #include "contacts/InterfaceTable.h"
00025 #include "conv_layers/TCPConvergenceLayer.h"
00026 
00027 #include "TcaRouter.h"
00028 
00029 namespace dtn {
00030 
00031 
00032 
00033 // Consts
00034 
00035 static const std::string BL = "tca://localhost/bundlelayer";
00036 
00037 
00039 // Functions
00040 
00041 
00042 // get_payload_str is a convenient one-call function to get the payload
00043 // of a simple bundle (must not contain any nulls)
00044 static std::string
00045 get_payload_str(const Bundle* b)
00046 {
00047     size_t len = b->payload_.length();
00048     u_char data[len+1];
00049     const u_char* p = b->payload_.read_data(0, len, data);
00050     return (const char*)p;
00051 }
00052 
00053 
00054 // debug: check for expected number of args in control bundle, w/ message
00055 static bool
00056 check_nargs(const TcaControlBundle& cb, uint n_expected)
00057 {
00058     if (cb.args_.size() != n_expected)
00059     {
00060         log_err_p("dtn/tca", "TcaRouter: bundle '%s' contains wrong number "
00061                   "of args. %d expected.", cb.str().c_str(), n_expected);
00062         return false;
00063     }
00064     return true;
00065 }
00066 
00067 
00068 // debug: log bundle wrapper (source -> dest) and optionally payload too
00069 static void
00070 log_bundle(const std::string& comment, const Bundle* b, bool include_payload)
00071 {
00072     (void)comment;
00073     (void)b;
00074     
00075     if (include_payload)
00076         log_debug_p("/dtn/tca", "%s [%s] -> [%s] : '%s'", comment.c_str(),
00077                     b->source_.str().c_str(), b->dest_.c_str(),
00078                     get_payload_str(b).c_str());
00079     else
00080         log_debug_p("/dtn/tca", "%s [%s] -> [%s]", comment.c_str(),
00081                     b->source_.str().c_str(), b->dest_.c_str());
00082 } 
00083     
00084 
00085 static void
00086 log_controlbundle(const TcaControlBundle& cb)
00087 {
00088     log_debug_p("/dtn/tca", "    code='%s', args=%d",
00089                 cb.code_.c_str(), (u_int)cb.args_.size());
00090     for (unsigned int i=0; i<cb.args_.size(); ++i)
00091     {
00092         log_debug_p("/dtn/tca", "        '%s'", cb.args_[i].c_str());
00093     }
00094 }
00095 
00096 
00097 /*
00098 // get_tcp_interface gets the "tcp0" Interface object.
00099 // No longer neeed.
00100 static Interface* get_tcp_interface()
00101 {
00102     InterfaceTable* p_iftab = InterfaceTable::instance();
00103     return p_iftab->find("tcp0");
00104 }
00105 */
00106 
00108 // class TcaRouter
00109 
00110 TcaRouter::TcaRouter(Role role)
00111     : TableBasedRouter("TcaRouter", "TcaRouter")
00112 {
00113     role_ = role;
00114 
00115     // Construct the eid of the local admin app.
00116     admin_app_ = BundleDaemon::instance()->local_eid();
00117     admin_app_.set_app("admin");
00118 
00119     logpathf("/dtn/tca");
00120 
00121     log_info("TcaRouter started: role='%s', admin_app='%s'",
00122              get_role_str().c_str(), admin_app_.c_str());
00123 }
00124 
00125 
00126 std::string
00127 TcaRouter::get_role_str() const
00128 {
00129     switch (role_)
00130     {
00131         case TCA_MOBILE: return "mobile";
00132         case TCA_ROUTER: return "router";
00133         case TCA_GATEWAY: return "gateway";
00134         default: return "null";
00135     }
00136 
00137 }
00138 
00139 
00140 void
00141 TcaRouter::handle_bundle_received(BundleReceivedEvent* event)
00142 {           
00143     Bundle* bundle = event->bundleref_.object();
00144     // log_debug("TcaRouter: handle bundle received: *%p", bundle);
00145 
00146     // Special handling for certain TCA bundles
00147     // Control bundles are identified by their dest eids.
00148     // Unbound data bundles need special handling as
00149     // TCA control bundles are the following:
00150     // Check for control bundles here (REG, COA, ASK, ADV)
00151 
00152     EndpointID dest = bundle->dest_;
00153 
00154     if (dest.scheme_str() == "tca")
00155     {
00156         log_bundle("TcaRouter: tca bundle received", bundle, true);
00157 
00158         TcaEndpointID tca_dest(dest);
00159   
00160         if (tca_dest.ssp() == "//registry")
00161         {
00162             handle_register(bundle);
00163         }
00164 
00165         else if (tca_dest.app() == "admin.coa")
00166         {
00167             handle_coa(bundle);
00168         }
00169 
00170         else if (tca_dest.ssp().substr(0,11) == "//anonymous")
00171         {
00172             handle_anonymous_bundle(bundle);
00173         }
00174 
00175         else if (tca_dest.ssp() == "//localhost/bundlelayer")
00176         {
00177             handle_bl_control_bundle(bundle);
00178         }
00179             
00180         else if (tca_dest.host() != admin_app_.host())
00181         {
00182             // What we're really checking for is whether the bundle is home.
00183             // ie. addressed to some app on the local host.
00184             // If not, then it's a late-bound data bundle:
00185             handle_tca_unbound_bundle(bundle);
00186         }
00187     }
00188     
00189     else
00190     {
00191         // Not a tca control or data bundle. Just forward the bundle.
00192         fwd_to_matching(bundle);
00193     }
00194 }
00195 
00196 
00197 void
00198 TcaRouter::handle_bundle_transmitted(BundleTransmittedEvent* event)
00199 {
00200     Bundle* b = event->bundleref_.object();
00201     log_debug("TcaRouter: handle bundle transmitted: *%p", b);
00202 
00203     EndpointID dest = b->dest_;
00204 
00205     if (dest.scheme_str() == "tca")
00206     {
00207         // TODO: These control codes appended to app (eg. admin.coa) were
00208         // a bad idea and should be eliminated. I did this initially so that
00209         // we could switch on control code without inspecting bundle payload.
00210         // However, if the bundle is addressed to an admin app, then it's
00211         // fair to assume it is a control bundle and inspect the payload.
00212         // The "adv" case below uses the preferred method. ask and coa should
00213         // follow suit.
00214         TcaEndpointID tca_dest(dest);
00215         if (tca_dest.app() == "admin.coa")
00216         {
00217             TcaControlBundle cb(get_payload_str(b));
00218             on_coa_transmitted(b, cb);
00219         }
00220         else if (tca_dest.app() == "admin.ask")
00221         {
00222             TcaControlBundle cb(get_payload_str(b));
00223             on_ask_transmitted(b, cb);
00224         }
00225         else if (tca_dest.app() == "admin")
00226         {
00227             TcaControlBundle cb(get_payload_str(b));
00228             if (cb.code_ == "adv")
00229             {
00230                 on_adv_transmitted(b, cb);
00231             }
00232         }
00233     }
00234 }   
00235  
00236 
00237 // Note: ContactUp and ContactDown are generated by a sending node when a
00238 // connection is opened.  As such, they're probably not relevant to TCA.
00239 
00240 void
00241 TcaRouter::handle_contact_up(ContactUpEvent* event)
00242 {
00243     // Note: *must* call the base class handler so that existing bundles
00244     // can be checked against the new contact.
00245     TableBasedRouter::handle_contact_up(event);
00246     log_debug("TcaRouter::contact up");
00247     post_bundle(BL, admin_app_, "contact_up");
00248 }
00249     
00250 
00251 void
00252 TcaRouter::handle_contact_down(ContactDownEvent* event)
00253 {
00254     (void)event;
00255     log_debug("TcaRouter::contact down");
00256     post_bundle(BL, admin_app_, "contact_down");
00257 
00258 }
00259 
00260 
00261 void
00262 TcaRouter::handle_link_available(LinkAvailableEvent* event)
00263 {
00264     // Note: *must* call the base class handler so that existing bundles
00265     // can be checked against the new link.
00266     TableBasedRouter::handle_link_available(event);
00267     log_debug("TcaRouter::link available");
00268     post_bundle(BL, admin_app_, "link_available");
00269 }
00270 
00271 
00272 void
00273 TcaRouter::handle_link_unavailable(LinkUnavailableEvent* event)
00274 {
00275     (void)event;
00276     log_debug("TcaRouter::link unavailable");
00277     post_bundle(BL, admin_app_, "link_unavailable");
00278 }
00279 
00280 
00281 void
00282 TcaRouter::handle_shutdown_request(ShutdownRequest* event)
00283 {
00284     (void)event;
00285     log_debug("TcaRouter::daemon shutdown");
00286     post_bundle(BL, admin_app_, "daemon_shutdown");
00287 }
00288         
00289 
00290 // fwd_to_all "broadcasts" a bundle to all tca routes (ie. "tca://*")
00291 // This is dead code at the moment.
00292 
00293 int
00294 TcaRouter::fwd_to_all(Bundle* bundle)
00295 {
00296     RouteEntryVec matches;
00297     RouteEntryVec::iterator iter;
00298 
00299     std::string pattern = "tca://*";
00300     EndpointID tca_all = pattern;
00301 
00302     route_table_->get_matching(tca_all, &matches);
00303 
00304     int count = 0;
00305     for (iter = matches.begin(); iter != matches.end(); ++iter)
00306     {
00307         log_debug("TcaRouter::fwd_to_all: %s",
00308                   (*iter)->dest_pattern_.str().c_str());
00309         fwd_to_nexthop(bundle, *iter);
00310         ++count;
00311     }
00312 
00313     log_debug("TcaRouter::fwd_to_all dest='%s': %d matches",
00314                 bundle->dest_.c_str(), count);
00315     return count;
00316 }
00317 
00318 
00319 // fwd_to_matching function overridden from TableBasedRouter
00320 // This is necessary to filter outgoing bundles. fwd_to_matching is
00321 // called via TableBasedRouter::check_next_hop on a variety of events
00322 // including link_available and on contact_up.
00323 
00324 int
00325 TcaRouter::fwd_to_matching(Bundle* bundle, Link* next_hop)
00326 {
00327     ForwardingRule fwd_rule = get_forwarding_rule(bundle);
00328     return fwd_to_matching_r(bundle, next_hop, fwd_rule);
00329 }
00330 
00331 
00332 // Specialized fwd_to_matching function with selective default-route handling
00333 // You can foward to the default route either never, always, or "if necessary"
00334 // where "if necessary" means iff there are no non-default routes.
00335 
00336 int
00337 TcaRouter::fwd_to_matching_r(Bundle* bundle, Link* next_hop,
00338                              ForwardingRule fwd_rule)
00339 {
00340     log_debug("TcaRouter::fwd_to_matching_r: owner='%s'",
00341             bundle->owner_.c_str());
00342     log_debug("TcaRouter::fwd_to_matching_r: fwd_rule=%d", fwd_rule);
00343 
00344     if (fwd_rule == FWD_NEVER) return 0;    // no matches
00345 
00346     RouteEntryVec matches;
00347     RouteEntryVec::iterator iter;
00348 
00349     route_table_->get_matching(bundle->dest_, &matches);
00350 
00351     // First step - split out the default route
00352     RouteEntry*     default_route = NULL;   
00353     RouteEntryVec   hard_matches;       // non-default matches
00354     for (iter = matches.begin(); iter != matches.end(); ++iter)
00355     {
00356         if ((*iter)->dest_pattern_.str() == "tca://*")
00357         {
00358             default_route = *iter;
00359         }
00360         else
00361         {
00362             hard_matches.push_back(*iter);
00363         }
00364     }
00365 
00366     if (fwd_rule == FWD_UDR_EXCLUSIVELY)
00367     {
00368         if (default_route != NULL)
00369         {
00370             fwd_to_nexthop(bundle, default_route);
00371             return 1;   // 1 match
00372         }
00373     }
00374 
00375     int count = 0;
00376 
00377     // handle default route...
00378     if (fwd_rule == FWD_UDR_ALWAYS || 
00379             (fwd_rule == FWD_UDR_IFNECESSARY && hard_matches.size() == 0))
00380     {
00381         if (default_route != NULL)
00382         {
00383             fwd_to_nexthop(bundle, default_route);
00384             ++ count;
00385         }
00386     }
00387 
00388     // handle hard matches...
00389     for (iter = hard_matches.begin(); iter != hard_matches.end(); ++iter)
00390     {
00391         if (next_hop == NULL || (next_hop == (*iter)->next_hop_))
00392         {
00393             fwd_to_nexthop(bundle, *iter);
00394             ++count;
00395         }
00396         else
00397         {
00398             log_debug("fwd_to_matching_r dest='%s': "
00399                 "ignoring match %s since next_hop link %s set",
00400                 bundle->dest_.c_str(), (*iter)->next_hop_->name(),
00401                 next_hop->name());
00402         }
00403     }
00404 
00405     log_debug("fwd_to_matching_r dest='%s': %d matches",
00406                 bundle->dest_.c_str(), count);
00407 
00408     return count;
00409 }
00410 
00411 
00412 bool
00413 TcaRouter::on_coa_transmitted(Bundle* b, const TcaControlBundle& cb)
00414 {   
00415     log_debug("TcaRouter: COA bundle transmitted");
00416             
00417     TcaWrappedBundle wb(cb);
00418     
00419     log_debug("    coa: source=%s, dest=%s",
00420                 b->source_.c_str(),
00421                 b->dest_.c_str());
00422     
00423     // todo: use a WrappedBundle here
00424     std::string coa_sent_payload = "coa_sent:";
00425     coa_sent_payload += b->source_.str();
00426     coa_sent_payload += "\t";
00427     coa_sent_payload += b->dest_.str();
00428     coa_sent_payload += "\t";
00429     coa_sent_payload += cb.args_[0]; // link_addr of mobile, from body of coa
00430 
00431     log_debug("    coa_sent, payload='%s'", coa_sent_payload.c_str());
00432     post_bundle(BL, admin_app_, coa_sent_payload);
00433 
00434     return true;
00435 }
00436 
00437 
00438 bool
00439 TcaRouter::on_ask_transmitted(Bundle* b, const TcaControlBundle& cb)
00440 {
00441     log_debug("TcaRouter: ASK bundle transmitted");
00442 
00443     if (!check_nargs(cb, 1)) return false;
00444 
00445     // todo: use a WrappedBundle here
00446     std::string ask_sent= "ask_sent:";
00447     ask_sent += b->source_.str();
00448     ask_sent += "\t";
00449     ask_sent += b->dest_.str();
00450     ask_sent += "\t";
00451     ask_sent += cb.args_[0];
00452 
00453     log_debug("    ask sent, payload='%s'", ask_sent.c_str());
00454     post_bundle(BL, admin_app_, ask_sent);
00455 
00456     return false;
00457 }
00458 
00459 
00460 bool
00461 TcaRouter::on_adv_transmitted(Bundle* b, const TcaControlBundle& cb)
00462 {
00463     log_debug("TcaRouter: ADV bundle transmitted");
00464 
00465     if (!check_nargs(cb, 2)) return false;
00466 
00467     // todo: use a WrappedBundle here
00468     std::string adv_sent= "adv_sent:";
00469     adv_sent += b->source_.str();
00470     adv_sent += "\t";
00471     adv_sent += b->dest_.str();
00472     adv_sent += "\t";
00473     adv_sent += cb.args_[0];
00474     adv_sent += "\t";
00475     adv_sent += cb.args_[1];
00476 
00477     log_debug("    adv_sent, payload='%s'", adv_sent.c_str());
00478     post_bundle(BL, admin_app_, adv_sent);
00479 
00480     return false;
00481 }
00482 
00483 
00484 bool
00485 TcaRouter::handle_register(Bundle* b)
00486 {
00487     // DK: New stuff - experimental
00488     // Register bundles come either from
00489     // 1) A client application (zero args, source eid important), or
00490     // 2) An admin app (2 args)
00491     
00492     if (b->source_.str() == admin_app_.str())
00493     {
00494         // The local admin app sent this bundle. Just forward it to the
00495         // default route:
00496         fwd_to_matching_r(b, NULL, FWD_UDR_EXCLUSIVELY);
00497     }
00498     else
00499     {
00500         // The bundle came from either a local app (non-admin) or
00501         // else another node. In either case, deliver it to local
00502         // admin app.
00503         TcaControlBundle cb(get_payload_str(b));
00504 
00505         TcaWrappedBundle reg_received("reg_received",
00506                 b->source_.str(), b->dest_.str());
00507 
00508         log_debug("TcaRouter::handle_register:");
00509         log_controlbundle(cb);
00510 
00511         if (cb.args_.size() == 2)
00512         {
00513             // This bundle came from another node, with mobile_eid
00514             // and last_hop fields filled in.
00515             reg_received.append_arg(cb.args_[0]);
00516             reg_received.append_arg(cb.args_[1]);
00517         }
00518         else
00519         {
00520             // This bundle came from an app on the local node
00521             // so fill in mobile_eid and NULL last_hop
00522             reg_received.append_arg(b->source_.str());
00523             reg_received.append_arg("NULL");
00524         }
00525         
00526         post_bundle(BL, admin_app_, reg_received.str());
00527     }
00528 
00529     return true;
00530 }
00531 
00532 
00533 bool
00534 TcaRouter::handle_coa(Bundle* b)
00535 {
00536     log_debug("TcaRouter: COA bundle received");
00537 
00538     // Propagate it along the reverse path, ignoring default route:
00539    fwd_to_matching_r(b, NULL, FWD_UDR_NEVER);
00540 
00541     // The old route is deleted after the coa bundle has been
00542     // transmitted, from on_coa_transmitted
00543     return true;
00544 }
00545 
00546 
00547 bool
00548 TcaRouter::handle_anonymous_bundle(Bundle* b)
00549 {
00550     // these are bundles addressed to a destination eid that begins
00551     // with tca://anonymous
00552     // so far, the "ask" bundle is the only one of its kind
00553 
00554     TcaEndpointID dest(b->dest_);
00555 
00556     TcaControlBundle cb(get_payload_str(b));
00557 
00558     if (cb.code_ == "ask")
00559     {
00560         return handle_ask(b, cb);
00561     }
00562     else
00563     {
00564         log_debug("TcaRouter:: unrecognized anonymous bundle code '%s'",
00565                 cb.code_.c_str());
00566         return false;
00567     }
00568 }
00569 
00570 
00571 bool
00572 TcaRouter::handle_ask(Bundle* b, const TcaControlBundle& cb)
00573 {   
00574     if (is_local_source(b))
00575     {
00576         // if the ask originated at this node, just forward it to
00577         // matching, omitting the default route.
00578         fwd_to_matching_r(b, NULL, FWD_UDR_NEVER);
00579     }
00580     else
00581     {
00582         if (!check_nargs(cb, 1)) return false;
00583     
00584         // generate ask_received for local admin app
00585         std::string payload = "ask_received:";
00586         payload += b->source_.str();
00587         payload += "\t";
00588         payload += b->dest_.str();
00589         payload += "\t";
00590         payload += cb.args_[0];
00591 
00592         post_bundle(BL, admin_app_, payload);
00593     }
00594 
00595     return true;
00596 }
00597 
00598 
00599 
00600 // handle_tca_control_bundle handles bundles addressed to
00601 // "localhost/bundlelayer" from the local control application
00602 
00603 bool
00604 TcaRouter::handle_bl_control_bundle(Bundle* b)
00605 {
00606     TcaControlBundle cb(get_payload_str(b));
00607 
00608     // handle ctl bundles:
00609     if (cb.code_ == "ask")
00610     {
00611         return handle_ask(b, cb);
00612     }
00613     else if (cb.code_ == "get_routes")
00614     {
00615         return handle_get_routes(b, cb);
00616     }
00617     else if (cb.code_ == "add_route")
00618     {
00619         return handle_add_route(b, cb);
00620     }
00621     else if (cb.code_ == "del_route")
00622     {
00623         return handle_del_route(b, cb);
00624     }
00625 
00626     log_debug("TcaRouter: unknown control bundle type '%s'", cb.code_.c_str());
00627     return false;
00628     
00629 }
00630 
00631 
00632 bool
00633 TcaRouter::handle_bl_ask(Bundle* b, const TcaControlBundle& cb)
00634 {
00635     (void)cb;
00636     // Note: We should never get here! asks should be addressed to the
00637     // control app, not bundle layer.
00638     return post_bundle(BL, b->source_,
00639         "adv:Don\'t ASK me. You should probably ASK the Control App,"
00640         " not the Bundle Layer.");
00641 }
00642 
00643 
00644 bool
00645 TcaRouter::handle_get_routes(Bundle* b, const TcaControlBundle& cb)
00646 {   
00647     if (!check_nargs(cb, 1)) return false;
00648 
00649     log_debug("TcaRouter:: get_routes bundle received. body = '%s'",
00650            cb.args_[0].c_str());
00651 
00652     RouteEntryVec matches;
00653     RouteEntryVec::iterator iter;
00654 
00655     EndpointIDPattern pattern(cb.args_[0]);
00656     route_table_->get_matching(pattern, &matches);
00657 
00658     std::string response = "routes:";
00659     for (iter = matches.begin(); iter != matches.end(); ++iter)
00660     {
00661         response += (*iter)->dest_pattern_.str().c_str();
00662         response += "\t";
00663     }
00664 
00665     post_bundle(BL, b->source_, response);
00666 
00667     return true;
00668 }
00669 
00670 
00671 bool
00672 TcaRouter::handle_add_route(Bundle* b, const TcaControlBundle& cb)
00673 {
00674     (void)b;
00675     
00676     if (!check_nargs(cb, 2)) return false;
00677 
00678     const std::string& pattern = cb.args_[0];
00679     const std::string& link = cb.args_[1];
00680 
00681     log_debug("TcaRouter:: add_route bundle received. "
00682               "pattern='%s', link='%s'\n", pattern.c_str(), link.c_str());
00683 
00684     if (pattern.length() == 0 || link.length() == 0) return false;
00685 
00686     // TODO: Some syntax-checking would be a very good idea. Right now,
00687     // just blast away:
00688     return create_route(pattern, link);
00689 }
00690 
00691 
00692 bool
00693 TcaRouter::handle_del_route(Bundle* b, const TcaControlBundle& cb)
00694 {
00695     (void)b;
00696     
00697     if (!check_nargs(cb, 1)) return false;
00698 
00699     log_debug("TcaRouter:: del_route bundle received. body = '%s'",
00700            cb.args_[0].c_str());
00701 
00702     // TODO: Some syntax-checking would be a very good idea. Right now,
00703     // just blast away:
00704     route_table_->del_entries(cb.args_[0]);
00705     return true;
00706 }
00707 
00708 
00709 // handle_tca_unbound_bundle handles routing of regular late-bound tca data
00710 // bundles.
00711 // This function assumes that this router is not the dest endpoint.
00712 // for the bundle. The logic goes like this:
00713 // First, forward the bundle to any existing route to dest, using the default
00714 // route iff there are no other matches.
00715 // If there are no matches at all, and if the local node is a gateway,
00716 // then push a "unb" bundle up to the control app for special handling.
00717 
00718 bool
00719 TcaRouter::handle_tca_unbound_bundle(Bundle* bundle)
00720 {
00721     log_debug("TcaRouter::handle_tca_unbound_bundle...");
00722 
00723     int n_matches = fwd_to_matching_r(bundle, NULL, FWD_UDR_IFNECESSARY);
00724 
00725     if (n_matches == 0)
00726     {
00727         if (role_ == TCA_ROUTER)
00728         {
00729             // If I'm a router, this is an error! All tca bundles must have
00730             // a default route up to a gateway.
00731             log_err("TcaRouter: Error. TCA_ROUTER has no route to dest %s",
00732                     bundle->dest_.c_str());
00733             return false;
00734         }
00735         else if (role_ == TCA_GATEWAY)
00736         {
00737             // If I'm a gateway, try late-binding...
00738             // Leave the unbound bundle alone, but push a control bundle up
00739             // to the control app, which will get registration and create a
00740             // route if possible.
00741             std::string payload = "unb:";
00742             payload += bundle->dest_.str();
00743             post_bundle(BL, admin_app_, payload);
00744         }
00745     }
00746     return true;
00747 }
00748 
00749 
00750 
00751 bool
00752 TcaRouter::is_local_source(Bundle* b)
00753 {
00754     TcaEndpointID src(b->source_);
00755     return src.get_hostid() == admin_app_.get_hostid();
00756 }
00757 
00758 
00759 TcaRouter::ForwardingRule
00760 TcaRouter::get_forwarding_rule(Bundle* b)
00761 {
00762     // all non-tca bundles should always be forwarded to all routes
00763     if (b->dest_.scheme_str() != "tca") return FWD_UDR_ALWAYS;
00764     
00765     TcaEndpointID dest(b->dest_);
00766 
00767     if (dest.ssp() == "//registry")
00768     {
00769         // forward to default route (exclusively) iff sent by the local
00770         // admin app
00771         if (b->source_.str() == admin_app_.str()) return FWD_UDR_EXCLUSIVELY;
00772         else return FWD_NEVER;
00773     }
00774 
00775     else if (dest.app() == "admin.coa")
00776     {
00777         // Never us the default route for the coa bundles. They are on their
00778         // way "down" the tree to a mobile and we don't want them getting
00779         // forwarded back up to a gateway too.
00780         return FWD_UDR_NEVER;
00781     }
00782 
00783     else if (dest.ssp().substr(0,11) == "//anonymous")
00784     {
00785         // Assume this is an ask bundle. (WARNING: If there are ever any
00786         // anonymous bundles other than ASK, this should be changed!)
00787         // For ask, forward only if originating at local node, and never
00788         // to the default route.
00789         if (is_local_source(b)) return FWD_UDR_NEVER;
00790         else return FWD_NEVER;
00791     }
00792 
00793     else if (dest.ssp() == "//localhost/bundlelayer")
00794     {
00795         // Never forward bundles sent to the local bundle layer
00796         return FWD_NEVER;
00797     }
00798 
00799     // These are all the special control dest cases. What remains are any
00800     // ordinarily addressed tca bundles
00801     else
00802     {
00803         if (dest.host() == admin_app_.host())
00804         {
00805             // If addressed to local admin app, do not forward. This bundle
00806             // is home.
00807             return FWD_NEVER;
00808         }
00809         else
00810         {
00811             // Treat this as an unbound tca bundle. Forward to matches, using
00812             // default route iff no other matches.
00813             return FWD_UDR_IFNECESSARY;
00814         }
00815     }
00816 }
00817 
00818 
00819 // create_link creates a link for the given link_addr iff it doesn't already
00820 // exist.
00821 // link_addr must be in the form "tcp://host:port"
00822 
00823 Link*
00824 TcaRouter::create_link(const std::string& link_addr)
00825 {
00826     // Note that deleting the old one and re-creating it is the wrong
00827     // thing to do, because when the link is re-created all pending
00828     // bundles (inlcuding the register bundle that initiated this) will
00829     // be matched and forwarded to the new link.
00830 
00831     EndpointID link_eid(link_addr);
00832     std::string clayer_name = link_eid.scheme_str();
00833     const std::string& ssp = link_eid.ssp();
00834     std::string host = ssp.substr(2, ssp.length()); // chop off the "//"
00835 
00836     ContactManager* p_man = BundleDaemon::instance()->contactmgr();
00837 
00838     // Check if there's an existing link of the same name.
00839     Link* p_link = p_man->find_link(host.c_str());
00840     if (p_link != NULL) return p_link;
00841 
00842     ConvergenceLayer* cl = ConvergenceLayer::find_clayer(clayer_name.c_str());
00843     if (!cl) {
00844         log_err("TcaRouter: create_link failed: invalid convergence layer"
00845                   " '%s'", clayer_name.c_str());
00846         return NULL;
00847     }
00848  
00849     p_link = Link::create_link(host, Link::ONDEMAND, cl, host.c_str(), 0, NULL);
00850     if (!p_link) return NULL;
00851         
00852     // Add the link to contact manager's table, which posts a
00853     // LinkCreatedEvent to the daemon
00854     BundleDaemon::instance()->contactmgr()->add_link(p_link);
00855     return p_link;
00856 
00857 }
00858 
00859 
00860 RouteEntry*
00861 TcaRouter::create_route(const std::string& pattern, Link* p_link)
00862 {
00863 
00864     log_debug("TcaRouter::create_route: pattern=%s, p_link=%p",
00865             pattern.c_str(), p_link);
00866 
00867     RouteEntry* p_entry = new RouteEntry(pattern, p_link);
00868     p_entry->action_ = ForwardingInfo::COPY_ACTION;
00869 
00870     route_table_->add_entry(p_entry);
00871 
00872     return p_entry;
00873 }
00874 
00875 
00876 bool
00877 TcaRouter::create_route(const std::string& pattern,
00878                         const std::string& link_addr)
00879 {
00880     // First find the right link, or create a new one if necesary
00881     Link* p_link = create_link(link_addr);
00882     if (!p_link)
00883     {
00884         log_err("TcaRouter::create_route: create_link failed");
00885         return false;
00886     }
00887 
00888     // Now create the new route entry
00889     if (!create_route(pattern, p_link))
00890     {
00891         log_err("TcaRouter::create_route: create_route failed");
00892         return false;
00893     }
00894 
00895     return true;
00896 }
00897 
00898 
00899 bool
00900 TcaRouter::post_bundle(const EndpointID& src, const EndpointID& dest,
00901                        const std::string& payload)
00902 {
00903 
00904     log_debug("TcaRouter::post_bundle: [%s] -> [%s] : '%s'\n",
00905                 src.c_str(), dest.c_str(), payload.c_str());
00906 
00907     // Construct bundle
00908     Bundle* b = new Bundle();
00909 
00910     // if source is unspecified, use bundlelayer
00911     if (src.length() == 0)
00912             b->source_ = EndpointID("tca://localhost/bundlelayer");
00913     else
00914             b->source_ = src;
00915 
00916     b->dest_ = dest;
00917     b->custodian_ = BundleDaemon::instance()->local_eid();
00918     b->replyto_ = BundleDaemon::instance()->local_eid();
00919 
00920     b->payload_.set_data(payload);
00921 
00922     // We need to set non-zero expiration or else the bundle
00923     // expires as soon as it arrives.
00924     b->expiration_ = 3600;
00925 
00926     // The default values are ok for the rest of the bundle fields.
00927 
00928     // Post the bundle by generating a BundleReceivedEvent
00929     BundleReceivedEvent* p_event = new BundleReceivedEvent(b, EVENTSRC_ADMIN);
00930     BundleDaemon::instance()->post(p_event);
00931 
00932     return true;
00933 }
00934 
00935 
00936 // dead code at the moment:
00937 bool
00938 TcaRouter::push_wrapped_bundle(const std::string& code,
00939                                const EndpointID& src,
00940                                const EndpointID& dest,
00941                                const std::string& bsp)
00942 {
00943     std::string payload = code;
00944     payload += ":";
00945     payload += src.str();
00946     payload += "\t";
00947     payload += dest.str();
00948     payload += "\t";
00949     payload += bsp;
00950     return post_bundle(BL, admin_app_, payload);
00951 }
00952 
00953 
00954 
00955 
00956 } // namespace dtn

Generated on Sat Sep 8 08:43:35 2007 for DTN Reference Implementation by  doxygen 1.5.3