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