ContactManager.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  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2004 Intel Corporation. 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 Intel Corporation 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 INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 
00039 #include <oasys/util/StringBuffer.h>
00040 
00041 #include "ContactManager.h"
00042 #include "Contact.h"
00043 #include "Link.h"
00044 #include "bundling/BundleDaemon.h"
00045 #include "bundling/BundleEvent.h"
00046 #include "conv_layers/ConvergenceLayer.h"
00047 
00048 namespace dtn {
00049 
00050 //----------------------------------------------------------------------
00051 ContactManager::ContactManager()
00052     : BundleEventHandler("ContactManager", "/dtn/contact/manager"),
00053       opportunistic_cnt_(0)
00054 {
00055     links_ = new LinkSet();
00056 }
00057 
00058 //----------------------------------------------------------------------
00059 ContactManager::~ContactManager()
00060 {
00061 }
00062 
00063 //----------------------------------------------------------------------
00064 void
00065 ContactManager::add_link(Link* link)
00066 {
00067     oasys::ScopeLock l(&lock_, "ContactManager");
00068     
00069     log_debug("adding link %s", link->name());
00070     links_->insert(link);
00071     
00072     BundleDaemon::post(new LinkCreatedEvent(link));
00073 }
00074 
00075 //----------------------------------------------------------------------
00076 void
00077 ContactManager::del_link(Link *link)
00078 {
00079     oasys::ScopeLock l(&lock_, "ContactManager");
00080     
00081     log_debug("deleting link %s", link->name());
00082     if (!has_link(link)) {
00083         log_err("Error in del_link: link %s does not exist \n",
00084                 link->name());
00085         return;
00086     }
00087 
00088     links_->erase(link);
00089     BundleDaemon::post(new LinkDeletedEvent(link));
00090 }
00091 
00092 //----------------------------------------------------------------------
00093 bool
00094 ContactManager::has_link(Link *link)
00095 {
00096     oasys::ScopeLock l(&lock_, "ContactManager");
00097     
00098     LinkSet::iterator iter = links_->find(link);
00099     if (iter == links_->end())
00100         return false;
00101     return true;
00102 }
00103 
00104 //----------------------------------------------------------------------
00105 Link*
00106 ContactManager::find_link(const char* name)
00107 {
00108     oasys::ScopeLock l(&lock_, "ContactManager");
00109     
00110     LinkSet::iterator iter;
00111     Link* link = NULL;
00112     for (iter = links_->begin(); iter != links_->end(); ++iter)
00113     {
00114         link = *iter;
00115         if (strcasecmp(link->name(), name) == 0)
00116             return link;
00117     }
00118     return NULL;
00119 }
00120 
00121 //----------------------------------------------------------------------
00122 const LinkSet*
00123 ContactManager::links()
00124 {
00125     ASSERTF(lock_.is_locked_by_me(),
00126             "ContactManager::links must be called while holding lock");
00127     return links_;
00128 }
00129 
00130 //----------------------------------------------------------------------
00131 void
00132 ContactManager::LinkAvailabilityTimer::timeout(const struct timeval& now)
00133 {
00134     (void)now;
00135     cm_->reopen_link(link_);
00136     delete this;
00137 }
00138 
00139 //----------------------------------------------------------------------
00140 void
00141 ContactManager::reopen_link(Link* link)
00142 {
00143     oasys::ScopeLock l(&lock_, "ContactManager");
00144     
00145     log_debug("reopen link %s", link->name());
00146 
00147     availability_timers_.erase(link);
00148     
00149     if (link->state() == Link::UNAVAILABLE) {
00150         BundleDaemon::post(
00151             new LinkStateChangeRequest(link, Link::OPEN,
00152                                        ContactEvent::RECONNECT));
00153     } else {
00154         // state race (possibly due to user action)
00155         log_err("availability timer fired for link %s but state is %s",
00156                 link->name(), Link::state_to_str(link->state()));
00157     }
00158 }
00159 
00160 //----------------------------------------------------------------------
00161 void
00162 ContactManager::handle_link_available(LinkAvailableEvent* event)
00163 {
00164     oasys::ScopeLock l(&lock_, "ContactManager");
00165     
00166     AvailabilityTimerMap::iterator iter;
00167     iter = availability_timers_.find(event->link_);
00168     if (iter == availability_timers_.end()) {
00169         return; // no timer for this link
00170     }
00171     
00172     LinkAvailabilityTimer* timer = iter->second;
00173     availability_timers_.erase(event->link_);
00174     
00175     // try to cancel the timer and rely on the timer system to clean
00176     // it up once it bubbles to the top of the queue... if there's a
00177     // race and the timer is in the process of firing, it should clean
00178     // itself up in the timeout handler.
00179     if (! timer->cancel()) {
00180         log_warn("can't cancel availability timer: race condition ");
00181     }
00182 }
00183 
00184 //----------------------------------------------------------------------
00185 void
00186 ContactManager::handle_link_unavailable(LinkUnavailableEvent* event)
00187 {
00188     oasys::ScopeLock l(&lock_, "ContactManager");
00189     
00190     // don't do anything for links that aren't ondemand or alwayson
00191     if (event->link_->type() != Link::ONDEMAND &&
00192         event->link_->type() != Link::ALWAYSON)
00193     {
00194         log_debug("ignoring link unavailable for link of type %s",
00195                   event->link_->type_str());
00196         return;
00197     }
00198     
00199     // or if the link wasn't broken but instead was closed by user
00200     // action or by going idle
00201     if (event->reason_ == ContactEvent::USER ||
00202         event->reason_ == ContactEvent::IDLE)
00203     {
00204         log_debug("ignoring link unavailable due to %s",
00205                   event->reason_to_str(event->reason_));
00206         return;
00207     }
00208     
00209     // adjust the retry interval in the link to handle backoff in case
00210     // it continuously fails to open, then schedule the timer. note
00211     // that if this is the first time the link is opened, the
00212     // retry_interval will be initialized to zero so we set it to the
00213     // minimum here. the retry interval is reset in the link open
00214     // event handler.
00215     Link* link = event->link_;
00216     if (link->retry_interval_ == 0) {
00217         link->retry_interval_ = link->params().min_retry_interval_;
00218     }
00219 
00220     int timeout = link->retry_interval_;
00221     link->retry_interval_ *= 2;
00222     if (link->retry_interval_ > link->params().max_retry_interval_) {
00223         link->retry_interval_ = link->params().max_retry_interval_;
00224     }
00225 
00226     LinkAvailabilityTimer* timer = new LinkAvailabilityTimer(this, link);
00227 
00228     AvailabilityTimerMap::value_type val(link, timer);
00229     if (availability_timers_.insert(val).second == false) {
00230         log_err("error inserting timer for link %s into table!",
00231                 link->name());
00232         delete timer;
00233         return;
00234     }
00235 
00236     log_debug("link %s unavailable (%s): scheduling retry timer in %d seconds",
00237               link->name(), event->reason_to_str(event->reason_), timeout);
00238     timer->schedule_in(timeout * 1000);
00239 }
00240 
00241 
00242 //----------------------------------------------------------------------
00243 void
00244 ContactManager::handle_contact_up(ContactUpEvent* event)
00245 {
00246     Link* link = event->contact_->link();
00247     if (link->type() == Link::ONDEMAND ||
00248         link->type() == Link::ALWAYSON)
00249     {
00250         log_debug("resetting retry interval for link %s: %d -> %d",
00251                   link->name(),
00252                   link->retry_interval_,
00253                   link->params().min_retry_interval_);
00254         link->retry_interval_ = link->params().min_retry_interval_;
00255     }
00256 }
00257 
00258 //----------------------------------------------------------------------
00259 Link*
00260 ContactManager::find_link_to(ConvergenceLayer* cl,
00261                              const std::string& nexthop,
00262                              const EndpointID& remote_eid,
00263                              Link::link_type_t type,
00264                              u_int states)
00265 {
00266     oasys::ScopeLock l(&lock_, "ContactManager");
00267     
00268     LinkSet::iterator iter;
00269     Link* link = NULL;
00270     
00271     log_debug("find_link_to: cl %s nexthop %s remote_eid %s "
00272               "type %s states 0x%x",
00273               cl ? cl->name() : "ANY",
00274               nexthop.c_str(), remote_eid.c_str(),
00275               type == Link::LINK_INVALID ? "ANY" : Link::link_type_to_str(type),
00276               states);
00277 
00278     // make sure some sane criteria was specified
00279     ASSERT((cl != NULL) ||
00280            (nexthop != "") ||
00281            (remote_eid != EndpointID::NULL_EID()) ||
00282            (type != Link::LINK_INVALID));
00283     
00284     for (iter = links_->begin(); iter != links_->end(); ++iter)
00285     {
00286         link = *iter;
00287 
00288         if ( ((type == Link::LINK_INVALID) || (type == link->type())) &&
00289              ((cl == NULL) || (link->clayer() == cl)) &&
00290              ((nexthop == "") || (nexthop == link->nexthop())) &&
00291              ((remote_eid == EndpointID::NULL_EID()) ||
00292               (remote_eid == link->remote_eid())) &&
00293              ((states & link->state()) != 0) )
00294         {
00295             log_debug("find_link_to: matched link *%p", link);
00296             return link;
00297         }
00298     }
00299 
00300     log_debug("find_link_to: no match");
00301     return NULL;
00302 }
00303 
00304 //----------------------------------------------------------------------
00305 Link*
00306 ContactManager::new_opportunistic_link(ConvergenceLayer* cl,
00307                                        const std::string& nexthop,
00308                                        const EndpointID& remote_eid)
00309 {
00310     log_debug("new_opportunistic_link: cl %s nexthop %s remote_eid %s",
00311               cl->name(), nexthop.c_str(), remote_eid.c_str());
00312     
00313     oasys::ScopeLock l(&lock_, "ContactManager");
00314 
00315     // find a unique link name
00316     char name[64];
00317     Link* link = NULL;
00318     do {
00319         snprintf(name, sizeof(name), "opportunistic-%d",
00320                  opportunistic_cnt_);
00321         opportunistic_cnt_++;
00322         link = find_link(name);
00323     } while (link != NULL);
00324         
00325     link = Link::create_link(name, Link::OPPORTUNISTIC, cl,
00326                              nexthop.c_str(), 0, NULL);
00327     ASSERTF(link, "unexpected error creating opportunistic link!!");
00328     link->set_remote_eid(remote_eid);
00329     add_link(link);
00330     
00331     return link;
00332 }
00333     
00334 //----------------------------------------------------------------------
00335 void
00336 ContactManager::dump(oasys::StringBuffer* buf) const
00337 {
00338     oasys::ScopeLock l(&lock_, "ContactManager");
00339     
00340     buf->append("Links:\n");
00341     LinkSet::iterator iter;
00342     Link* link = NULL;
00343     for (iter = links_->begin(); iter != links_->end(); ++iter)
00344     {
00345         link = *iter;
00346         buf->appendf("*%p\n", link);
00347     }
00348 }
00349 
00350 } // namespace dtn

Generated on Fri Dec 22 14:47:58 2006 for DTN Reference Implementation by  doxygen 1.5.1