TcaRouter.cc

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

Generated on Fri Dec 22 14:48:01 2006 for DTN Reference Implementation by  doxygen 1.5.1