ContactManager.cc

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2004-2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 
00018 #include <oasys/util/StringBuffer.h>
00019 
00020 #include "ContactManager.h"
00021 #include "Contact.h"
00022 #include "Link.h"
00023 #include "bundling/BundleDaemon.h"
00024 #include "bundling/BundleEvent.h"
00025 #include "conv_layers/ConvergenceLayer.h"
00026 
00027 namespace dtn {
00028 
00029 //----------------------------------------------------------------------
00030 ContactManager::ContactManager()
00031     : BundleEventHandler("ContactManager", "/dtn/contact/manager"),
00032       opportunistic_cnt_(0)
00033 {
00034     links_ = new LinkSet();
00035 }
00036 
00037 //----------------------------------------------------------------------
00038 ContactManager::~ContactManager()
00039 {
00040     delete links_;
00041 }
00042 
00043 //----------------------------------------------------------------------
00044 void
00045 ContactManager::add_link(Link* link)
00046 {
00047     oasys::ScopeLock l(&lock_, "ContactManager::add_link");
00048     
00049     log_debug("adding link %s", link->name());
00050     links_->insert(link);
00051     
00052     BundleDaemon::post(new LinkCreatedEvent(link));
00053 }
00054 
00055 //----------------------------------------------------------------------
00056 void
00057 ContactManager::del_link(Link *link)
00058 {
00059     oasys::ScopeLock l(&lock_, "ContactManager::del_link");
00060     
00061     log_debug("deleting link %s", link->name());
00062     if (!has_link(link)) {
00063         log_err("Error in del_link: link %s does not exist \n",
00064                 link->name());
00065         return;
00066     }
00067 
00068     links_->erase(link);
00069     BundleDaemon::post(new LinkDeletedEvent(link));
00070 }
00071 
00072 //----------------------------------------------------------------------
00073 bool
00074 ContactManager::has_link(Link *link)
00075 {
00076     oasys::ScopeLock l(&lock_, "ContactManager::has_link");
00077     
00078     LinkSet::iterator iter = links_->find(link);
00079     if (iter == links_->end())
00080         return false;
00081     return true;
00082 }
00083 
00084 //----------------------------------------------------------------------
00085 Link*
00086 ContactManager::find_link(const char* name)
00087 {
00088     oasys::ScopeLock l(&lock_, "ContactManager::find_link");
00089     
00090     LinkSet::iterator iter;
00091     Link* link = NULL;
00092     for (iter = links_->begin(); iter != links_->end(); ++iter)
00093     {
00094         link = *iter;
00095         if (strcasecmp(link->name(), name) == 0)
00096             return link;
00097     }
00098     return NULL;
00099 }
00100 
00101 //----------------------------------------------------------------------
00102 const LinkSet*
00103 ContactManager::links()
00104 {
00105     ASSERTF(lock_.is_locked_by_me(),
00106             "ContactManager::links must be called while holding lock");
00107     return links_;
00108 }
00109 
00110 //----------------------------------------------------------------------
00111 void
00112 ContactManager::LinkAvailabilityTimer::timeout(const struct timeval& now)
00113 {
00114     (void)now;
00115     cm_->reopen_link(link_);
00116     delete this;
00117 }
00118 
00119 //----------------------------------------------------------------------
00120 void
00121 ContactManager::reopen_link(Link* link)
00122 {
00123     oasys::ScopeLock l(&lock_, "ContactManager::reopen_link");
00124     
00125     log_debug("reopen link %s", link->name());
00126 
00127     availability_timers_.erase(link);
00128     
00129     if (link->state() == Link::UNAVAILABLE) {
00130         BundleDaemon::post(
00131             new LinkStateChangeRequest(link, Link::OPEN,
00132                                        ContactEvent::RECONNECT));
00133     } else {
00134         // state race (possibly due to user action)
00135         log_err("availability timer fired for link %s but state is %s",
00136                 link->name(), Link::state_to_str(link->state()));
00137     }
00138 }
00139 
00140 //----------------------------------------------------------------------
00141 void
00142 ContactManager::handle_link_available(LinkAvailableEvent* event)
00143 {
00144     oasys::ScopeLock l(&lock_, "ContactManager::handle_link_available");
00145     
00146     AvailabilityTimerMap::iterator iter;
00147     iter = availability_timers_.find(event->link_);
00148     if (iter == availability_timers_.end()) {
00149         return; // no timer for this link
00150     }
00151     
00152     LinkAvailabilityTimer* timer = iter->second;
00153     availability_timers_.erase(event->link_);
00154     
00155     // try to cancel the timer and rely on the timer system to clean
00156     // it up once it bubbles to the top of the queue... if there's a
00157     // race and the timer is in the process of firing, it should clean
00158     // itself up in the timeout handler.
00159     if (! timer->cancel()) {
00160         log_warn("can't cancel availability timer: race condition ");
00161     }
00162 }
00163 
00164 //----------------------------------------------------------------------
00165 void
00166 ContactManager::handle_link_unavailable(LinkUnavailableEvent* event)
00167 {
00168     oasys::ScopeLock l(&lock_, "ContactManager::handle_link_unavailable");
00169     
00170     // don't do anything for links that aren't ondemand or alwayson
00171     if (event->link_->type() != Link::ONDEMAND &&
00172         event->link_->type() != Link::ALWAYSON)
00173     {
00174         log_debug("ignoring link unavailable for link of type %s",
00175                   event->link_->type_str());
00176         return;
00177     }
00178     
00179     // or if the link wasn't broken but instead was closed by user
00180     // action or by going idle
00181     if (event->reason_ == ContactEvent::USER ||
00182         event->reason_ == ContactEvent::IDLE)
00183     {
00184         log_debug("ignoring link unavailable due to %s",
00185                   event->reason_to_str(event->reason_));
00186         return;
00187     }
00188     
00189     // adjust the retry interval in the link to handle backoff in case
00190     // it continuously fails to open, then schedule the timer. note
00191     // that if this is the first time the link is opened, the
00192     // retry_interval will be initialized to zero so we set it to the
00193     // minimum here. the retry interval is reset in the link open
00194     // event handler.
00195     Link* link = event->link_;
00196     if (link->retry_interval_ == 0) {
00197         link->retry_interval_ = link->params().min_retry_interval_;
00198     }
00199 
00200     int timeout = link->retry_interval_;
00201     link->retry_interval_ *= 2;
00202     if (link->retry_interval_ > link->params().max_retry_interval_) {
00203         link->retry_interval_ = link->params().max_retry_interval_;
00204     }
00205 
00206     LinkAvailabilityTimer* timer = new LinkAvailabilityTimer(this, link);
00207 
00208     AvailabilityTimerMap::value_type val(link, timer);
00209     if (availability_timers_.insert(val).second == false) {
00210         log_err("error inserting timer for link %s into table!",
00211                 link->name());
00212         delete timer;
00213         return;
00214     }
00215 
00216     log_debug("link %s unavailable (%s): scheduling retry timer in %d seconds",
00217               link->name(), event->reason_to_str(event->reason_), timeout);
00218     timer->schedule_in(timeout * 1000);
00219 }
00220 
00221 
00222 //----------------------------------------------------------------------
00223 void
00224 ContactManager::handle_contact_up(ContactUpEvent* event)
00225 {
00226     Link* link = event->contact_->link();
00227     if (link->type() == Link::ONDEMAND ||
00228         link->type() == Link::ALWAYSON)
00229     {
00230         log_debug("resetting retry interval for link %s: %d -> %d",
00231                   link->name(),
00232                   link->retry_interval_,
00233                   link->params().min_retry_interval_);
00234         link->retry_interval_ = link->params().min_retry_interval_;
00235     }
00236 }
00237 
00238 //----------------------------------------------------------------------
00239 Link*
00240 ContactManager::find_link_to(ConvergenceLayer* cl,
00241                              const std::string& nexthop,
00242                              const EndpointID& remote_eid,
00243                              Link::link_type_t type,
00244                              u_int states)
00245 {
00246     oasys::ScopeLock l(&lock_, "ContactManager::find_link_to");
00247     
00248     LinkSet::iterator iter;
00249     Link* link = NULL;
00250     
00251     log_debug("find_link_to: cl %s nexthop %s remote_eid %s "
00252               "type %s states 0x%x",
00253               cl ? cl->name() : "ANY",
00254               nexthop.c_str(), remote_eid.c_str(),
00255               type == Link::LINK_INVALID ? "ANY" : Link::link_type_to_str(type),
00256               states);
00257 
00258     // make sure some sane criteria was specified
00259     ASSERT((cl != NULL) ||
00260            (nexthop != "") ||
00261            (remote_eid != EndpointID::NULL_EID()) ||
00262            (type != Link::LINK_INVALID));
00263     
00264     for (iter = links_->begin(); iter != links_->end(); ++iter)
00265     {
00266         link = *iter;
00267 
00268         if ( ((type == Link::LINK_INVALID) || (type == link->type())) &&
00269              ((cl == NULL) || (link->clayer() == cl)) &&
00270              ((nexthop == "") || (nexthop == link->nexthop())) &&
00271              ((remote_eid == EndpointID::NULL_EID()) ||
00272               (remote_eid == link->remote_eid())) &&
00273              ((states & link->state()) != 0) )
00274         {
00275             log_debug("find_link_to: matched link *%p", link);
00276             return link;
00277         }
00278     }
00279 
00280     log_debug("find_link_to: no match");
00281     return NULL;
00282 }
00283 
00284 //----------------------------------------------------------------------
00285 Link*
00286 ContactManager::new_opportunistic_link(ConvergenceLayer* cl,
00287                                        const std::string& nexthop,
00288                                        const EndpointID& remote_eid)
00289 {
00290     log_debug("new_opportunistic_link: cl %s nexthop %s remote_eid %s",
00291               cl->name(), nexthop.c_str(), remote_eid.c_str());
00292     
00293     oasys::ScopeLock l(&lock_, "ContactManager::new_opportunistic_link");
00294 
00295     // find a unique link name
00296     char name[64];
00297     Link* link = NULL;
00298     do {
00299         snprintf(name, sizeof(name), "opportunistic-%d",
00300                  opportunistic_cnt_);
00301         opportunistic_cnt_++;
00302         link = find_link(name);
00303     } while (link != NULL);
00304         
00305     link = Link::create_link(name, Link::OPPORTUNISTIC, cl,
00306                              nexthop.c_str(), 0, NULL);
00307     ASSERTF(link, "unexpected error creating opportunistic link!!");
00308     link->set_remote_eid(remote_eid);
00309     add_link(link);
00310     
00311     return link;
00312 }
00313     
00314 //----------------------------------------------------------------------
00315 void
00316 ContactManager::dump(oasys::StringBuffer* buf) const
00317 {
00318     oasys::ScopeLock l(&lock_, "ContactManager::dump");
00319     
00320     buf->append("Links:\n");
00321     LinkSet::iterator iter;
00322     Link* link = NULL;
00323     for (iter = links_->begin(); iter != links_->end(); ++iter)
00324     {
00325         link = *iter;
00326         buf->appendf("*%p\n", link);
00327     }
00328 }
00329 
00330 } // namespace dtn

Generated on Thu Jun 7 12:54:26 2007 for DTN Reference Implementation by  doxygen 1.5.1