TcaController.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 <stdio.h>
00040 #include <unistd.h>
00041 #include <errno.h>
00042 //#include <strings.h>
00043 //#include <stdlib.h>
00044 //#include <sys/time.h>
00045 
00046 //#include <string>
00047 #include "dtn_api.h"
00048 #include "TcaController.h"
00049 
00050 
00051 static const int debug = 1;
00052 
00053 
00054 // RECV_TIMEOUT can be made very large. It's just used as a timeout for a
00055 // blocking function call to receive bundle.
00056 static const int RECV_TIMEOUT = 30000;  // 30s
00057 
00058 
00059 // REG_EXPIRATION_TIME is how long the registration lasts. We want it to
00060 // last forever, but we're up against maxint.
00061 // The value specified here is multiplied by 1000 in class Registration
00062 // to get milliseconds, and I think that deeper in the actual timer code it's
00063 // converted to a signed int, so 2000000 (23 days) is about as high as we
00064 // can go here.
00065 static const u_int32_t REG_EXPIRATION_TIME = 2000000; 
00066 
00067 
00068 
00069 // Fake spec constructor. For conveniently building a dtn_bundle_spec_t
00070 
00071 bool
00072 make_spec(dtn_bundle_spec_t& spec,
00073           std::string source,
00074           std::string dest,
00075           std::string replyto,
00076           int expiration,
00077           dtn_bundle_priority_t priority = COS_NORMAL,
00078           dtn_bundle_delivery_opts_t dopts = DOPTS_NONE
00079           )
00080 {
00081     memset(&spec, 0, sizeof(spec));
00082 
00083     if (dtn_parse_eid_string(&spec.source, source.c_str()))
00084     {
00085         fprintf(stderr, "make_spec: invalid source eid '%s'\n",
00086                     source.c_str());
00087         return false;
00088     }
00089 
00090     if (dtn_parse_eid_string(&spec.dest, dest.c_str()))
00091     {
00092         fprintf(stderr, "make_spec: invalid dest eid '%s'\n",
00093                     dest.c_str());
00094         return false;
00095     }
00096 
00097     if (dtn_parse_eid_string(&spec.replyto, replyto.c_str()))
00098     {
00099         fprintf(stderr, "make_spec: invalid replyto eid '%s'\n",
00100                     replyto.c_str());
00101         return false;
00102     }
00103 
00104     spec.priority = priority;
00105     spec.dopts = dopts;
00106     spec.expiration = expiration;
00107 
00108     return true;
00109 }
00110 
00111 
00112 static bool
00113 check_nargs(const TcaControlBundle& cb, uint n_expected)
00114 {
00115     if (cb.args_.size() != n_expected)
00116     {
00117         printf("TcaController: bundle '%s' contains wrong number of args. "
00118                 "%d expected.\n", cb.str().c_str(), n_expected);
00119         return false;
00120     }
00121     return true;
00122 }
00123 
00124 
00125 TcaController::TcaController(TcaController::Role role,
00126                              const std::string& link_id,
00127                              const std::string& ask_addr,
00128                              const std::string& adv_str,
00129                              int registry_ttl, int control_ttl)
00130     : role_(role), link_id_(link_id),
00131       ask_addr_(ask_addr), adv_str_(adv_str),
00132       registry_ttl_(registry_ttl), control_ttl_(control_ttl)
00133 
00134 {
00135 
00136 }
00137 
00138 
00139 TcaController::~TcaController()
00140 {
00141     dtn_close(handle_);
00142 }
00143 
00144 
00145 bool
00146 TcaController::dtn_reg(dtn_endpoint_id_t& eid, dtn_reg_id_t& id)
00147 {   
00148     // register eid for specified app, eg. "tca://hail/admin"
00149 
00150     // create a new registration
00151     dtn_reg_info_t reginfo;
00152     // dtn_reg_id_t regid;
00153     int ret;
00154 
00155     memset(&reginfo, 0, sizeof(reginfo));
00156     dtn_copy_eid(&reginfo.endpoint, &eid);
00157     reginfo.failure_action = DTN_REG_DEFER;
00158     reginfo.regid = DTN_REGID_NONE;
00159     reginfo.expiration = REG_EXPIRATION_TIME;
00160     if ((ret = dtn_register(handle_, &reginfo, &id)) != 0) {
00161         fprintf(stderr, "error creating registration: %d (%s)\n",
00162                 ret, dtn_strerror(dtn_errno(handle_)));
00163         return false;
00164     }    
00165     // if (debug) printf("dtn_register succeeded, id 0x%x\n", id);
00166     
00167     printf("TcaController::dtn_reg: app registered as %s, id=0x%x\n",
00168             eid.uri, id);
00169 
00170     return true;
00171 }
00172 
00173 
00174 bool
00175 TcaController::init(bool tidy)
00176 {
00177     // open the ipc handle
00178     int err = dtn_open(&handle_);
00179     if (err != DTN_SUCCESS) {
00180         fprintf(stderr, "fatal error opening dtn handle: %s\n",
00181                 dtn_strerror(err));
00182         return false;
00183     }
00184 
00185     printf("TcaController::init: dtn_open succeeded\n");
00186 
00187     // build local eid and register it:
00188     dtn_reg_id_t app_id;
00189     dtn_build_local_eid(handle_, &local_eid_, "/admin");
00190     if (!dtn_reg(local_eid_, app_id)) return false;
00191 
00192     /*
00193     // test: register another eid and make sure that works
00194     dtn_reg_id_t test_id;
00195     dtn_endpoint_id_t test_eid;
00196     dtn_build_local_eid(handle_, &test_eid, "/testing123");
00197     if (!dtn_reg(test_eid, test_id)) return false;
00198     */
00199 
00200     // discard any pending bundles iff 'tidy' option specified
00201     if (tidy) eat_bundles();
00202 
00203     if (role_ == TCA_GATEWAY)
00204     {
00205         // now initialize the list of live registry nodes
00206         registry_.init_nodes();
00207         if (!registry_.init_addrs())
00208         {
00209             // This is an unrecoverable failure condition -- no dht nodes
00210             // available. The gateway will not be able to do its job,
00211             // so we might as well exit().
00212             fprintf(stderr,
00213                 "TcaController fatal error: no registry nodes available!\n");
00214             return false;
00215         }
00216     }
00217 
00218     return true;
00219 }
00220 
00221 
00222 void
00223 TcaController::run()
00224 {
00225 
00226     if (ask_addr_.length() != 0)
00227     {
00228         // user has specified an ask address. Send out an ask bundle.
00229         ask(ask_addr_);
00230     }
00231    
00232     dtn_bundle_spec_t spec;
00233     std::string payload;
00234 
00235     for (;;)
00236     {
00237         if (recv_bundle(spec, payload, RECV_TIMEOUT))
00238         {
00239             handle_bundle_received(spec, payload);
00240         }
00241     }
00242 }
00243 
00244 
00245 bool
00246 TcaController::handle_bundle_received(const dtn_bundle_spec_t& spec,
00247                                       const std::string& payload)
00248 {
00249     TcaControlBundle cb(payload);
00250 
00251     // handle control bundles:
00252     switch (cb.type_)
00253     {
00254         case TcaControlBundle::CB_LINK_ANNOUNCE:
00255             handle_link_announce(spec, cb);
00256             break;
00257         case TcaControlBundle::CB_ASK:
00258             handle_ask(spec, cb);
00259             break;
00260         case TcaControlBundle::CB_ASK_RECEIVED:
00261             handle_ask_received(spec, cb);
00262             break;
00263         case TcaControlBundle::CB_ASK_SENT:
00264             handle_ask_sent(spec, cb);
00265             break;
00266         case TcaControlBundle::CB_ADV:
00267             handle_adv(spec, cb);
00268             break;
00269         case TcaControlBundle::CB_ADV_SENT:
00270             handle_adv_sent(spec, cb);
00271             break;
00272         case TcaControlBundle::CB_REG_RECEIVED:
00273             handle_reg_received(spec, cb);
00274             break;
00275         case TcaControlBundle::CB_UNB:
00276             handle_unb(spec, cb);
00277             break;
00278         case TcaControlBundle::CB_COA:
00279             // all of the real coa logic is in the bundle_tranmitted handler
00280             // in bundle layer
00281             break;
00282         case TcaControlBundle::CB_COA_SENT:
00283             handle_coa_sent(spec, cb);
00284             break;
00285         case TcaControlBundle::CB_ROUTES:
00286             handle_routes(spec, cb);
00287             break;
00288         case TcaControlBundle::CB_LINK_AVAILABLE:
00289             break;
00290         case TcaControlBundle::CB_LINK_UNAVAILABLE:
00291             break;
00292         case TcaControlBundle::CB_CONTACT_UP:
00293             break;
00294         case TcaControlBundle::CB_CONTACT_DOWN:
00295             break;
00296         default:
00297             printf("TcaController: unrecognized bundle code received: '%s'\n",
00298                 cb.code_.c_str());
00299     }
00300 
00301     return true;
00302 }
00303 
00304 
00305 
00306 bool
00307 TcaController::handle_reg_received(const dtn_bundle_spec_t& spec,
00308                                    const TcaControlBundle& cb)
00309 {
00310     switch (role_)
00311     {
00312         case TCA_MOBILE:
00313             // TODO: This isn't an error. Just add the link addr and forward
00314             // the bundle to default route. Exactly the same logic as
00315             // for a router.
00316             return route_reg(spec, cb);
00317             break;
00318         case TCA_ROUTER:
00319             return route_reg(spec, cb);
00320             break;
00321         case TCA_GATEWAY:
00322             return gate_reg(spec, cb);
00323             break;
00324     }   
00325 
00326     return false;
00327 }
00328 
00329 
00330 bool
00331 TcaController::handle_unb(const dtn_bundle_spec_t& spec,
00332                           const TcaControlBundle& cb)
00333 {
00334     (void)spec;
00335     
00336     if (role_ != TCA_GATEWAY)
00337     {
00338         printf("TcaController error: non-gateway received unb bundle.\n");
00339         return false;
00340     }
00341 
00342     TcaEndpointID dest_eid(cb.args_[0]);
00343     RegRecord rr;
00344 
00345     if (!get_registration(dest_eid, rr))
00346     {
00347         printf("TcaController: bind failed: unregistered node [%s]\n",
00348             dest_eid.c_str());
00349         // TODO: What should happen here?
00350         // dest may never have registered, or may have previously registered
00351         // but expired. Depending how we want to handle registration
00352         // lifetime, we may need to re-try this get_registration later.
00353         return false;
00354     }
00355 
00356     // Found it! Add a route.
00357     // Note: There's no point deleting old routes for this endpoint. We
00358     // got here because no old routes exist!
00359 
00360     if (!add_route(dest_eid.str(), rr.link_addr_)) return false;
00361 
00362     return true;
00363 }
00364 
00365 
00366 bool
00367 TcaController::handle_coa_sent(const dtn_bundle_spec_t& spec,
00368                                const TcaControlBundle& cb)
00369 {
00370     (void)spec;
00371     
00372     if (role_ == TCA_MOBILE)
00373     {
00374         printf("TcaController error: mobile received coa_sent bundle.\n");
00375         return false;
00376     }
00377 
00378     // TODO: update this to use ControlBundle class
00379     const std::string& src = cb.args_[0];   // coa src (gateway)
00380     const std::string& dest = cb.args_[1];  // coa dest (mobile)
00381     const std::string& link = cb.args_[2];  // last hop to mobile
00382 
00383     // if we're a router or a gateway, delete routes to the bundle dest:
00384     TcaEndpointID pattern = dest;
00385     pattern.set_app("*");
00386     del_route(pattern.str());
00387     
00388     // if the coa bundle originated at *this* gateway node then we have to
00389     // update the registry and finally add the route back to the 
00390     // registering mobile
00391     if (src == local_eid_.uri)
00392     {
00393         TcaEndpointID tca_dest = dest;
00394         if (!do_registration(tca_dest, link_id_)) return false;
00395 
00396         tca_dest.set_app("*");
00397         if (!add_route(tca_dest.str(), link)) return false;
00398     }
00399 
00400     return true;
00401 }
00402 
00403 
00404 bool
00405 TcaController::handle_link_announce(const dtn_bundle_spec_t& spec,
00406                                     const TcaControlBundle& cb)
00407 {
00408     (void)spec;
00409             
00410     // Note: the port number is omitted from the link_announce bundle.
00411     // It is up to TcaController to decide which port to probe.
00412     if (!check_nargs(cb, 1)) return false;
00413     std::string link_spec = cb.args_[0];
00414     link_spec += ":5000";
00415     return ask(link_spec);
00416 }
00417 
00418 
00419 bool
00420 TcaController::handle_ask(const dtn_bundle_spec_t& spec,
00421                           const TcaControlBundle& cb)
00422 {
00423     (void)spec;
00424     (void)cb;
00425     printf("error -- we should never receive an ask bundle!\n");
00426 
00427     return true;
00428 }
00429 
00430 
00431 bool
00432 TcaController::handle_ask_received(const dtn_bundle_spec_t& spec,
00433                                    const TcaControlBundle& cb)
00434 {
00435     (void)spec;
00436     TcaWrappedBundle wb(cb);
00437 
00438     // respond by adding a route and sending adv
00439 
00440     TcaEndpointID src_eid = wb.source();
00441     src_eid.set_app("*");
00442 
00443     if (!add_route(src_eid.str(), wb.args_[2])) return false;
00444     
00445     // respond with adv
00446     // note that adv is a regular bundle addressed to asking node eid
00447     // (not an inter-layer WrappedBundle)
00448     std::string response = "adv:";
00449     response += wb.dest();  // echo original ask dest
00450     response += "\t";
00451     response += adv_str_;       // send adv string
00452     send_bundle(wb.source(), response);
00453     
00454     return true;
00455 }
00456 
00457 
00458 bool
00459 TcaController::handle_ask_sent(const dtn_bundle_spec_t& spec,
00460                                const TcaControlBundle& cb)
00461 {
00462     (void)spec;
00463     TcaWrappedBundle wb(cb);
00464 
00465     // respond by deleting the route
00466     TcaEndpointID dest_eid = wb.dest(); // dest of original ask
00467     dest_eid.set_app("*");
00468 
00469     if (!del_route(dest_eid.str())) return false;
00470     return true;
00471 }
00472 
00473 
00474 bool
00475 TcaController::handle_adv(const dtn_bundle_spec_t& spec,
00476                           const TcaControlBundle& cb)
00477 {
00478     (void)spec;
00479     (void)cb;
00480     // TODO: This is the place to be smart and try to decide on a
00481     // router to use for the default route.
00482     // For now, do nothing.
00483     return true;
00484 }
00485 
00486 
00487 bool
00488 TcaController::handle_adv_sent(const dtn_bundle_spec_t& spec,
00489                                const TcaControlBundle& cb)
00490 {
00491     (void)spec;
00492     TcaWrappedBundle wb(cb);
00493 
00494     // respond by deleting the route
00495     // TODO: This is actually more complicated! We should only delete the
00496     // route if it was created by the ask bundle that spawned this adv
00497     // (ie. if it was a pre-existing route, we should keep it!)
00498     // Best idea on how to do that is to use the route table to store
00499     // extra info on creating the entry, indicating it's a temp route.
00500     TcaEndpointID dest_eid = wb.dest(); // dest of original ask
00501     dest_eid.set_app("*");
00502 
00503     if (!del_route(dest_eid.str())) return false;
00504     return true;
00505 }
00506 
00507 
00508 bool
00509 TcaController::handle_routes(const dtn_bundle_spec_t& spec,
00510                              const TcaControlBundle& cb)
00511 {
00512     (void)spec;
00513 
00514     printf("routes:\n");
00515     for (unsigned int i=0; i<cb.args_.size(); ++i)
00516     {
00517         printf("    %s \n", cb.args_[i].c_str());
00518     }
00519     return true;
00520 }
00521 
00522 
00523 bool
00524 TcaController::route_reg(const dtn_bundle_spec_t& spec,
00525                          const TcaControlBundle& cb)
00526 {
00527     (void)spec;
00528     // A (small) problem is that we will get 2 links for a node that
00529     // already has an link defined explicitly in the dtn.conf file.
00530     // Another link will be auto-created with a different name, same params.
00531     // We could be smarter and check for this.
00532 
00533     if (!check_nargs(cb, 4)) return false;
00534 
00535     TcaWrappedBundle wb(cb);
00536 
00537     std::string mobile_eid = wb.args_[2];
00538     std::string last_hop = wb.args_[3];
00539 
00540     if (last_hop != "NULL")
00541     {
00542         // The register bundle did not originate at this node.
00543         // Add a link and route back to mobile.
00544 
00545         mobile_eid = wb.args_[2];
00546         last_hop = wb.args_[3];
00547 
00548         TcaEndpointID pattern(mobile_eid);
00549 
00550         // Delete the old route to mobile.
00551         // This is the correct behaviour because there should not
00552         // be any static routes for a tca mobile, only the one obtained
00553         // through the previous registration, and that one's now invalid.
00554         pattern.set_app("*");
00555         printf("deleteing routes for %s\n", pattern.str().c_str());
00556         if (!del_route(pattern.str())) return false;
00557 
00558         // Create the new route to mobile.
00559         if (!add_route(pattern.str(), last_hop)) return false;
00560     }
00561 
00562     // Now propagate the registry bundle (actually send a new one with
00563     // last_hop set to local node).
00564     // Skip this step if we're a gateway.
00565     
00566     if (role_ != TCA_GATEWAY)
00567     {
00568         std::string new_payload = "register:";
00569         new_payload += mobile_eid;      // original mobile id
00570         new_payload += "\t";
00571         new_payload += link_id_;        // link id of this router (last hop)
00572 
00573         if (!send_bundle("tca://registry", new_payload)) return false;
00574     }
00575 
00576     return true;
00577 }
00578 
00579 
00580 bool
00581 TcaController::gate_reg(const dtn_bundle_spec_t& spec,
00582                         const TcaControlBundle& cb)
00583 {
00584     (void)spec;
00585     TcaWrappedBundle wb(cb);
00586 
00587     std::string mobile_eid = wb.args_[2];
00588     std::string last_hop = wb.args_[3];
00589 
00590     TcaEndpointID src(mobile_eid);
00591 
00592     // First, get the old gateway for the source endpoint. We'll need it later.
00593     // It's ok if it doesn't exist -- then this is a new registration.
00594     // printf("TcaController: reading old registration...\n");
00595     RegRecord old_reg;
00596     bool prev_reg_exists = get_registration(src, old_reg);
00597 
00598     if (prev_reg_exists) 
00599     {
00600         // if (old_gateway == me) don't bother re-registering
00601         if (old_reg.link_addr_ == link_id_)
00602         {
00603             printf("TcaController: ignoring re-registration with same"
00604                     " gateway\n");
00605 
00606             // TODO: We still need to destruct old reverse path, even
00607             // if the mobile has re-registerd in the same gateway.
00608             // In this case, only part of the route is different.
00609             // Probably each router should check for this case on
00610             // handling the reg bundle -- if duplicate for same endpoint
00611             // destruct old route and construct new one. Don't even propagate
00612             // the reg. up to the gateway.
00613             return true;
00614         }
00615         else
00616         {
00617             printf("TcaController: initiating change-of-address\n");
00618 
00619             // There is a previous registration with another gateway.
00620             // We need to send a coa bundle to that gateway. Don't re-register
00621             // until this is done (handle_bundle_transmitted).
00622 
00623             // First we need to create a route to the old gateway,
00624             // as in gate_unbound_bundle.
00625 
00626             // Construct a route pattern based on the source eid.
00627             // Note: we use the special application "admin.coa" to ensure
00628             // that this route is only used for the coa bundle.
00629             TcaEndpointID pattern = src;
00630             pattern.set_app("admin.coa");
00631 
00632             printf("TcaController: adding route %s -> %s\n",
00633                     pattern.c_str(), old_reg.link_addr_.c_str());
00634 
00635             if (!add_route(pattern.str(), old_reg.link_addr_)) return false;
00636 
00637 
00638             TcaEndpointID dest_eid = src;
00639             dest_eid.set_app("admin.coa");
00640 
00641             // Construct coa bundle.
00642             // source:  this gateway
00643             // dest:    original mobile with special app "admin.coa"
00644 
00645             // This is a bit of a kludge...
00646             // The last thing done by the gateway after issuing the coa
00647             // bundle and updating the registry, is to create the route
00648             // back to the mobile (just like during routing of a reg bundle)
00649             // We'll need the last_hop link to do that. So we put it in
00650             // the body of the coa bundle, to be used on this very same node
00651             // on bundle transmitted.
00652 
00653             std::string coa_payload = "coa:";
00654             coa_payload += last_hop;
00655 
00656             dtn_bundle_spec_t coa_spec;
00657             if (!make_spec(coa_spec, local_eid_.uri, dest_eid.str(),
00658                     local_eid_.uri, control_ttl_, COS_NORMAL, DOPTS_NONE))
00659                 return false;
00660 
00661             // We need to set non-zero expiration or else the bundle
00662             // expires as soon as it arrives.
00663             // The default values are ok for the rest of the bundle fields.
00664 
00665             if (!send_bundle(coa_spec, coa_payload)) return false;
00666 
00667             // Note: I thought we might have a problem here. The send_bundle
00668             // will cause a BundleReceivedEvent in the daemon, but it's ok
00669             // because the BL checks for a null last-hop, indicating that
00670             // the bundle came from this node.
00671         }
00672 
00673         // Note: We do *not* update the link and route just yet.
00674         // Do it on handle_bundle_transmitted instead, at which point
00675         // we should delete the temporary admin.coa route (to the mobile's
00676         // old location and add a new route to the mobile's new location.
00677     }
00678 
00679     else
00680     {
00681         // No previous registration so no change-of-address required.
00682         // Go ahead and register.
00683         // update the registry entry for the source endpoint
00684         // printf("TcaController: doing new registration...\n");
00685         if (!do_registration(src, link_id_)) return false;
00686 
00687         // update local link and route
00688         if (!route_reg(spec, cb)) return false;
00689     }
00690 
00691     return true;
00692 
00693 }
00694 
00695 
00696 bool
00697 TcaController::ask(const std::string& link)
00698 {
00699     // "ask" on an unknown link
00700     // Idea: create temporary route and send ask bundle
00701     // on handling the corresponding adv, delete the route
00702     
00703 
00704     std::string host = "tca://anonymous";
00705     // omit prefix "tcp://" due to slashes:
00706     host += link.substr(6, link.length());
00707 
00708     std::string pattern = host + "/*";
00709 
00710     if (!add_route(pattern, link)) return false;
00711 
00712     std::string payload = "ask:";
00713     payload += link_id_;            // our own link, for return route
00714 
00715     std::string dest = host + "/admin.ask";
00716 
00717     if (!send_bundle(dest, payload))
00718     {
00719         fprintf(stderr,
00720                 "TcaController::ask: error: failed to send ask bundle\n");
00721         return false;
00722     }
00723 
00724     return true;
00725 }
00726 
00727 
00728 bool
00729 TcaController::get_routes()
00730 {
00731     if (!send_bundle("tca://localhost/bundlelayer", "get_routes:tca://*"))
00732     {
00733         fprintf(stderr, "error: failed to send get_routes bundle\n");
00734         return false;
00735     }
00736    
00737     return true;
00738 }
00739 
00740 
00741 bool
00742 TcaController::add_route(const std::string& route_pattern,
00743                          const std::string& link)
00744 {
00745     std::string body = "add_route:";
00746     body += route_pattern;
00747     body += "\t";
00748     body += link;
00749 
00750     // testing -- try to add a route
00751     if (!send_bundle("tca://localhost/bundlelayer", body))
00752     {
00753         fprintf(stderr, "error: failed to send add_route bundle\n");
00754         return false;
00755     }
00756 
00757     return true;
00758 }
00759 
00760 
00761 bool
00762 TcaController::del_route(const std::string& route_pattern)
00763 {
00764     std::string body = "del_route:";
00765     body += route_pattern;
00766 
00767     if (!send_bundle("tca://localhost/bundlelayer", body))
00768     {
00769         fprintf(stderr, "error: failed to send del_route bundle\n");
00770         return false;
00771     }
00772    
00773     return true;
00774 }
00775 
00776 
00777 bool
00778 TcaController::get_registration(const TcaEndpointID& eid, RegRecord& rr)
00779 {
00780     rr.host_ = eid.get_hostid();
00781     if (registry_.read(rr))
00782     {
00783         printf("TcaController: found registry entry %s\n", rr.str().c_str());
00784         return true;
00785     }
00786     else
00787     {
00788         printf("TcaController: no registry entry for host %s\n",
00789                 rr.host_.c_str());
00790         return false;
00791     }
00792 }
00793 
00794 
00795 // TODO: Make this async, with periodic refresh
00796 bool
00797 TcaController::do_registration(const TcaEndpointID& eid,
00798                                const std::string& link_addr)
00799 {
00800     RegRecord rr(eid.get_hostid(), link_addr);
00801 
00802     if (registry_.write(rr, registry_ttl_))
00803     {
00804         printf("TcaController: wrote registry entry %s\n", rr.str().c_str());
00805         return true;
00806     }
00807     else
00808     {
00809         printf("TcaController: failed to write registry entry %s\n",
00810                     rr.str().c_str());
00811         return false;
00812     }
00813 
00814 }
00815 
00816 
00817 bool
00818 TcaController::test_all()
00819 {
00820     get_routes();
00821 
00822     add_route("tca://booyah", "tcp://9.8.7.6:54321");
00823     sleep(5);
00824 
00825     get_routes();
00826 
00827     del_route("tca://booyah");
00828     sleep(5);
00829 
00830     get_routes();
00831     
00832     return true;
00833 }
00834 
00835 
00836 void
00837 TcaController::eat_bundles(bool verbose)
00838 {
00839     // check for any bundles queued for this registration and discard them.
00840 
00841     dtn_bundle_spec_t recv_spec;
00842     std::string payload;
00843 
00844     printf("checking for queued bundles...\n");
00845 
00846     if (verbose)
00847     {
00848         while (recv_bundle(recv_spec, payload, 0))
00849             printf("    discarding bundle: %s\n", payload.c_str());
00850     }
00851     else
00852     {
00853         dtn_bundle_payload_t    recv_payload;
00854         int ret;
00855         do
00856         {
00857             memset(&recv_spec, 0, sizeof(recv_spec));
00858             memset(&recv_payload, 0, sizeof(recv_payload));
00859         
00860             ret = dtn_recv(handle_, &recv_spec,
00861                        DTN_PAYLOAD_MEM, &recv_payload, 0);
00862 
00863             if (ret == 0)
00864             {
00865                 fprintf(stderr, "error: unexpected bundle already queued... "
00866                         "discarding\n");
00867             }
00868             else if (dtn_errno(handle_) != DTN_ETIMEOUT)
00869             {
00870                 fprintf(stderr, "error: "
00871                     "unexpected error checking for queued bundles: %s\n",
00872                     dtn_strerror(dtn_errno(handle_)));
00873                 return;
00874             }
00875         } while (ret == 0);
00876     }
00877 }
00878 
00879 
00880 bool
00881 TcaController::send_bundle(const dtn_bundle_spec_t& spec,
00882                            const std::string& payload)
00883 {
00884     printf("send_bundle: [%s] -> [%s] : '%s'\n",
00885                 spec.source.uri, spec.dest.uri, payload.c_str());
00886 
00887     dtn_bundle_payload_t send_payload;
00888     memset(&send_payload, 0, sizeof(send_payload));
00889     dtn_set_payload(&send_payload, DTN_PAYLOAD_MEM,
00890             const_cast<char*>(payload.c_str()), payload.length());
00891 
00892     dtn_bundle_id_t bundle_id;
00893     memset(&bundle_id, 0, sizeof(bundle_id));
00894 
00895     int r = 0;    
00896     if ((r = dtn_send(handle_,
00897                     const_cast<dtn_bundle_spec_t*>(&spec),
00898                     &send_payload, &bundle_id)) != 0)
00899     {
00900         fprintf(stderr, "TcaController::send_bundle error %d (%s)\n",
00901                 r, dtn_strerror(dtn_errno(handle_)));
00902         return false;
00903     }
00904 
00905     return true;
00906 }
00907 
00908 
00909 bool
00910 TcaController::recv_bundle(dtn_bundle_spec_t& spec,
00911                            std::string& payload,
00912                            unsigned int timeout)
00913 {   
00914     dtn_bundle_payload_t recv_payload;
00915     memset(&spec, 0, sizeof(spec));
00916     memset(&recv_payload, 0, sizeof(recv_payload));
00917         
00918     // now we block waiting for the echo reply
00919     // DK: original timeout was -1, causes compile warning with gcc
00920     int r;
00921     if ((r = dtn_recv(handle_, &spec,
00922                         DTN_PAYLOAD_MEM, &recv_payload, timeout)) < 0)
00923     {
00924         // fprintf(stderr, "TcaController::recv_bundle error %d (%s)\n",
00925         //        r, dtn_strerror(dtn_errno(handle_)));
00926         return false;
00927     }
00928 
00929     int n = recv_payload.dtn_bundle_payload_t_u.buf.buf_len;
00930     char s_buf[n+1];
00931     memcpy(s_buf, recv_payload.dtn_bundle_payload_t_u.buf.buf_val, n);
00932     s_buf[n] = '\0';
00933 
00934     payload = s_buf;
00935 
00936     printf("%d bytes from [%s]: %s\n",
00937                // recv_payload.dtn_bundle_payload_t_u.buf.buf_len,
00938                n,
00939                spec.source.uri,
00940                payload.c_str());
00941 
00942     return true;
00943 }
00944 
00945 
00946 // a more convenient send, using reasonable defaults for most args
00947 bool
00948 TcaController::send_bundle(const std::string& dest,
00949                            const std::string& payload)
00950 {
00951     // printf("send_bundle: [%s] -> [%s] : '%s'\n",
00952     //              local_eid_.uri, dest.c_str(), payload.c_str());
00953 
00954     dtn_bundle_spec_t spec;
00955     memset(&spec, 0, sizeof(spec));
00956 
00957     // set the source and reply_to to be the local eid
00958     dtn_copy_eid(&spec.source, &local_eid_);
00959     dtn_copy_eid(&spec.replyto, &local_eid_);
00960 
00961     if (dtn_parse_eid_string(&spec.dest, dest.c_str()))
00962     {
00963         fprintf(stderr, "TcaController::send_bundle: invalid destination"
00964                 " eid string, %s\n", dest.c_str());
00965         return false;
00966     }
00967 
00968     // set the expiration time and the return receipt option
00969     spec.priority = COS_NORMAL;
00970     spec.dopts = DOPTS_NONE;
00971     spec.expiration = control_ttl_;
00972 
00973     return send_bundle(spec, payload);
00974 }
00975 
00976 
00977 

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