servlib/contacts/ContactManager.cc
changeset 0 2b3e5ec03512
equal deleted inserted replaced
-1:000000000000 0:2b3e5ec03512
       
     1 /*
       
     2  *    Copyright 2004-2006 Intel Corporation
       
     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 <oasys/util/StringBuffer.h>
       
    22 
       
    23 #include "ContactManager.h"
       
    24 #include "Contact.h"
       
    25 #include "Link.h"
       
    26 #include "bundling/BundleDaemon.h"
       
    27 #include "bundling/BundleEvent.h"
       
    28 #include "conv_layers/ConvergenceLayer.h"
       
    29 
       
    30 namespace dtn {
       
    31 
       
    32 //----------------------------------------------------------------------
       
    33 ContactManager::ContactManager()
       
    34     : BundleEventHandler("ContactManager", "/dtn/contact/manager"),
       
    35       opportunistic_cnt_(0)
       
    36 {
       
    37     links_ = new LinkSet();
       
    38 }
       
    39 
       
    40 //----------------------------------------------------------------------
       
    41 ContactManager::~ContactManager()
       
    42 {
       
    43     delete links_;
       
    44 }
       
    45 
       
    46 //----------------------------------------------------------------------
       
    47 bool
       
    48 ContactManager::add_new_link(const LinkRef& link)
       
    49 {
       
    50     oasys::ScopeLock l(&lock_, "ContactManager::add_new_link");
       
    51 
       
    52     ASSERT(link != NULL);
       
    53     ASSERT(!link->isdeleted());
       
    54     
       
    55     log_debug("adding NEW link %s", link->name());
       
    56     if (has_link(link->name())) {
       
    57         return false;
       
    58     }
       
    59     links_->insert(LinkRef(link.object(), "ContactManager"));
       
    60 
       
    61     if (!link->is_create_pending()) {
       
    62         log_debug("posting LinkCreatedEvent");
       
    63         BundleDaemon::post(new LinkCreatedEvent(link));
       
    64     }
       
    65 
       
    66     return true;
       
    67 }
       
    68 
       
    69 //----------------------------------------------------------------------
       
    70 void
       
    71 ContactManager::del_link(const LinkRef& link, bool wait,
       
    72                          ContactEvent::reason_t reason)
       
    73 {
       
    74     oasys::ScopeLock l(&lock_, "ContactManager::del_link");
       
    75     ASSERT(link != NULL);
       
    76 
       
    77     if (!has_link(link)) {
       
    78         log_err("ContactManager::del_link: link %s does not exist",
       
    79                 link->name());
       
    80         return;
       
    81     }
       
    82     ASSERT(!link->isdeleted());
       
    83 
       
    84     log_debug("ContactManager::del_link: deleting link %s", link->name());
       
    85 
       
    86     if (!wait)
       
    87         link->delete_link();
       
    88 
       
    89     // Close the link if it is open or in the process of being opened.
       
    90     if (link->isopen() || link->isopening()) {
       
    91         BundleDaemon::instance()->post(
       
    92             new LinkStateChangeRequest(link, Link::CLOSED, reason));
       
    93     }
       
    94 
       
    95     // Cancel the link's availability timer (if one exists).
       
    96     AvailabilityTimerMap::iterator iter = availability_timers_.find(link);
       
    97     if (iter != availability_timers_.end()) {
       
    98         LinkAvailabilityTimer* timer = iter->second;
       
    99         availability_timers_.erase(link);
       
   100 
       
   101         // Attempt to cancel the timer, relying on the timer system to clean
       
   102         // up the timer state once it bubbles to the top of the timer queue.
       
   103         // If the timer is in the process of firing (i.e., race condition),
       
   104         // the timer should clean itself up in the timeout handler.
       
   105         if (!timer->cancel()) {
       
   106             log_warn("ContactManager::del_link: "
       
   107                      "failed to cancel availability timer -- race condition");
       
   108         }
       
   109     }
       
   110 
       
   111     links_->erase(link);
       
   112     
       
   113     if (wait) {
       
   114         l.unlock();
       
   115         // If some parent calling del_link already locked the Contact Manager,
       
   116         // the lock will remain locked, and an event ahead of the
       
   117         // LinkDeletedEvent may wait for the lock, causing deadlock
       
   118         ASSERT(!lock()->is_locked_by_me());
       
   119         oasys::Notifier notifier("ContactManager::del_link");
       
   120         BundleDaemon::post_and_wait(new LinkDeletedEvent(link), &notifier);
       
   121         link->delete_link();
       
   122     } else {
       
   123         BundleDaemon::post(new LinkDeletedEvent(link));
       
   124     }
       
   125 }
       
   126 
       
   127 //----------------------------------------------------------------------
       
   128 bool
       
   129 ContactManager::has_link(const LinkRef& link)
       
   130 {
       
   131     oasys::ScopeLock l(&lock_, "ContactManager::has_link");
       
   132     ASSERT(link != NULL);
       
   133     
       
   134     LinkSet::iterator iter = links_->find(link);
       
   135     if (iter == links_->end())
       
   136         return false;
       
   137     return true;
       
   138 }
       
   139 
       
   140 //----------------------------------------------------------------------
       
   141 bool
       
   142 ContactManager::has_link(const char* name)
       
   143 {
       
   144     oasys::ScopeLock l(&lock_, "ContactManager::has_link");
       
   145     ASSERT(name != NULL);
       
   146     
       
   147     LinkSet::iterator iter;
       
   148     for (iter = links_->begin(); iter != links_->end(); ++iter) {
       
   149         if (strcasecmp((*iter)->name(), name) == 0)
       
   150             return true;
       
   151     }
       
   152     return false;
       
   153 }
       
   154 
       
   155 //----------------------------------------------------------------------
       
   156 LinkRef
       
   157 ContactManager::find_link(const char* name)
       
   158 {
       
   159     oasys::ScopeLock l(&lock_, "ContactManager::find_link");
       
   160     
       
   161     LinkSet::iterator iter;
       
   162     LinkRef link("ContactManager::find_link: return value");
       
   163     
       
   164     for (iter = links_->begin(); iter != links_->end(); ++iter) {
       
   165         if (strcasecmp((*iter)->name(), name) == 0) {
       
   166             link = *iter;
       
   167             ASSERT(!link->isdeleted());
       
   168             return link;
       
   169         }
       
   170     }
       
   171     return link;
       
   172 }
       
   173 
       
   174 //----------------------------------------------------------------------
       
   175 const LinkSet*
       
   176 ContactManager::links()
       
   177 {
       
   178     ASSERTF(lock_.is_locked_by_me(),
       
   179             "ContactManager::links must be called while holding lock");
       
   180     return links_;
       
   181 }
       
   182 
       
   183 //----------------------------------------------------------------------
       
   184 void
       
   185 ContactManager::LinkAvailabilityTimer::timeout(const struct timeval& now)
       
   186 {
       
   187     (void)now;
       
   188     cm_->reopen_link(link_);
       
   189     delete this;
       
   190 }
       
   191 
       
   192 //----------------------------------------------------------------------
       
   193 void
       
   194 ContactManager::reopen_link(const LinkRef& link)
       
   195 {
       
   196     oasys::ScopeLock l(&lock_, "ContactManager::reopen_link");
       
   197     ASSERT(link != NULL);
       
   198 
       
   199     log_debug("reopen link %s", link->name());
       
   200 
       
   201     availability_timers_.erase(link);
       
   202 
       
   203     if (!has_link(link)) {
       
   204         log_warn("ContactManager::reopen_link: "
       
   205                  "link %s does not exist", link->name());
       
   206         return;
       
   207     }
       
   208     ASSERT(!link->isdeleted());
       
   209     
       
   210     if (link->state() == Link::UNAVAILABLE) {
       
   211         BundleDaemon::post(
       
   212             new LinkStateChangeRequest(link, Link::OPEN,
       
   213                                        ContactEvent::RECONNECT));
       
   214     } else {
       
   215         // state race (possibly due to user action)
       
   216         log_err("availability timer fired for link %s but state is %s",
       
   217                 link->name(), Link::state_to_str(link->state()));
       
   218     }
       
   219 }
       
   220 
       
   221 //----------------------------------------------------------------------
       
   222 void
       
   223 ContactManager::handle_link_created(LinkCreatedEvent* event)
       
   224 {
       
   225     oasys::ScopeLock l(&lock_, "ContactManager::handle_link_created");
       
   226 
       
   227     LinkRef link = event->link_;
       
   228     ASSERT(link != NULL);
       
   229     
       
   230     if(link->isdeleted())
       
   231     {
       
   232         log_warn("ContactManager::handle_link_created: "
       
   233                 "link %s is being deleted", link->name());
       
   234         return;
       
   235     }
       
   236         
       
   237     if (!has_link(link)) {
       
   238         log_err("ContactManager::handle_link_created: "
       
   239                 "link %s does not exist", link->name());
       
   240         return;
       
   241     }
       
   242 
       
   243     // Post initial state events; MOVED from Link::create_link().
       
   244     link->set_initial_state();
       
   245 }
       
   246 
       
   247 //----------------------------------------------------------------------
       
   248 void
       
   249 ContactManager::handle_link_available(LinkAvailableEvent* event)
       
   250 {
       
   251     oasys::ScopeLock l(&lock_, "ContactManager::handle_link_available");
       
   252 
       
   253     LinkRef link = event->link_;
       
   254     ASSERT(link != NULL);
       
   255     
       
   256     if(link->isdeleted())
       
   257     {
       
   258         log_warn("ContactManager::handle_link_available: "
       
   259                 "link %s is being deleted", link->name());
       
   260         return;
       
   261     }
       
   262 
       
   263     if (!has_link(link)) {
       
   264         log_warn("ContactManager::handle_link_available: "
       
   265                  "link %s does not exist", link->name());
       
   266         return;
       
   267     }
       
   268 
       
   269     AvailabilityTimerMap::iterator iter;
       
   270     iter = availability_timers_.find(link);
       
   271     if (iter == availability_timers_.end()) {
       
   272         return; // no timer for this link
       
   273     }
       
   274 
       
   275     LinkAvailabilityTimer* timer = iter->second;
       
   276     availability_timers_.erase(link);
       
   277 
       
   278     // try to cancel the timer and rely on the timer system to clean
       
   279     // it up once it bubbles to the top of the queue... if there's a
       
   280     // race and the timer is in the process of firing, it should clean
       
   281     // itself up in the timeout handler.
       
   282     if (!timer->cancel()) {
       
   283         log_warn("ContactManager::handle_link_available: "
       
   284                  "can't cancel availability timer: race condition");
       
   285     }
       
   286 }
       
   287 
       
   288 //----------------------------------------------------------------------
       
   289 void
       
   290 ContactManager::handle_link_unavailable(LinkUnavailableEvent* event)
       
   291 {
       
   292     oasys::ScopeLock l(&lock_, "ContactManager::handle_link_unavailable");
       
   293 
       
   294     LinkRef link = event->link_;
       
   295     ASSERT(link != NULL);
       
   296 
       
   297     if (!has_link(link)) {
       
   298         log_warn("ContactManager::handle_link_unavailable: "
       
   299                  "link %s does not exist", link->name());
       
   300         return;
       
   301     }
       
   302     
       
   303     if(link->isdeleted())
       
   304     {
       
   305         log_warn("ContactManager::handle_link_unavailable: "
       
   306                 "link %s is being deleted", link->name());
       
   307         return;
       
   308     }
       
   309 
       
   310     // don't do anything for links that aren't ondemand or alwayson
       
   311     if (link->type() != Link::ONDEMAND && link->type() != Link::ALWAYSON) {
       
   312         log_debug("ContactManager::handle_link_unavailable: "
       
   313                   "ignoring link unavailable for link of type %s",
       
   314                   link->type_str());
       
   315         return;
       
   316     }
       
   317     
       
   318     // or if the link wasn't broken but instead was closed by user
       
   319     // action or by going idle
       
   320     if (event->reason_ == ContactEvent::USER ||
       
   321         event->reason_ == ContactEvent::IDLE)
       
   322     {
       
   323         log_debug("ContactManager::handle_link_unavailable: "
       
   324                   "ignoring link unavailable due to %s",
       
   325                   event->reason_to_str(event->reason_));
       
   326         return;
       
   327     }
       
   328     
       
   329     // adjust the retry interval in the link to handle backoff in case
       
   330     // it continuously fails to open, then schedule the timer. note
       
   331     // that if this is the first time the link is opened, the
       
   332     // retry_interval will be initialized to zero so we set it to the
       
   333     // minimum here. the retry interval is reset in the link open
       
   334     // event handler.
       
   335     if (link->retry_interval_ == 0) {
       
   336         link->retry_interval_ = link->params().min_retry_interval_;
       
   337     }
       
   338 
       
   339     int timeout = link->retry_interval_;
       
   340     link->retry_interval_ *= 2;
       
   341     if (link->retry_interval_ > link->params().max_retry_interval_) {
       
   342         link->retry_interval_ = link->params().max_retry_interval_;
       
   343     }
       
   344 
       
   345     LinkAvailabilityTimer* timer = new LinkAvailabilityTimer(this, link);
       
   346 
       
   347     AvailabilityTimerMap::value_type val(link, timer);
       
   348     if (availability_timers_.insert(val).second == false) {
       
   349         log_err("ContactManager::handle_link_unavailable: "
       
   350                 "error inserting timer for link %s into table!", link->name());
       
   351         delete timer;
       
   352         return;
       
   353     }
       
   354 
       
   355     log_debug("link %s unavailable (%s): scheduling retry timer in %d seconds",
       
   356               link->name(), event->reason_to_str(event->reason_), timeout);
       
   357     timer->schedule_in(timeout * 1000);
       
   358 }
       
   359 
       
   360 //----------------------------------------------------------------------
       
   361 void
       
   362 ContactManager::handle_contact_up(ContactUpEvent* event)
       
   363 {
       
   364     oasys::ScopeLock l(&lock_, "ContactManager::handle_contact_up");
       
   365 
       
   366     LinkRef link = event->contact_->link();
       
   367     ASSERT(link != NULL);
       
   368 
       
   369     if(link->isdeleted())
       
   370     {
       
   371         log_warn("ContactManager::handle_contact_up: "
       
   372                  "link %s is being deleted, not marking its contact up", link->name());
       
   373         return;
       
   374     }
       
   375 
       
   376     if (!has_link(link)) {
       
   377         log_warn("ContactManager::handle_contact_up: "
       
   378                  "link %s does not exist", link->name());
       
   379         return;
       
   380     }
       
   381 
       
   382     if (link->type() == Link::ONDEMAND || link->type() == Link::ALWAYSON) {
       
   383         log_debug("ContactManager::handle_contact_up: "
       
   384                   "resetting retry interval for link %s: %d -> %d",
       
   385                   link->name(),
       
   386                   link->retry_interval_,
       
   387                   link->params().min_retry_interval_);
       
   388         link->retry_interval_ = link->params().min_retry_interval_;
       
   389     }
       
   390 }
       
   391 
       
   392 //----------------------------------------------------------------------
       
   393 LinkRef
       
   394 ContactManager::find_link_to(ConvergenceLayer* cl,
       
   395                              const std::string& nexthop,
       
   396                              const EndpointID& remote_eid,
       
   397                              Link::link_type_t type,
       
   398                              u_int states)
       
   399 {
       
   400     oasys::ScopeLock l(&lock_, "ContactManager::find_link_to");
       
   401     
       
   402     LinkSet::iterator iter;
       
   403     LinkRef link("ContactManager::find_link_to: return value");
       
   404     
       
   405     log_debug("find_link_to: cl %s nexthop %s remote_eid %s "
       
   406               "type %s states 0x%x",
       
   407               cl ? cl->name() : "ANY",
       
   408               nexthop.c_str(), remote_eid.c_str(),
       
   409               type == Link::LINK_INVALID ? "ANY" : Link::link_type_to_str(type),
       
   410               states);
       
   411 
       
   412     // make sure some sane criteria was specified
       
   413     ASSERT((cl != NULL) ||
       
   414            (nexthop != "") ||
       
   415            (remote_eid != EndpointID::NULL_EID()) ||
       
   416            (type != Link::LINK_INVALID));
       
   417     
       
   418     for (iter = links_->begin(); iter != links_->end(); ++iter) {
       
   419         if ( ((type == Link::LINK_INVALID) || (type == (*iter)->type())) &&
       
   420              ((cl == NULL) || ((*iter)->clayer() == cl)) &&
       
   421              ((nexthop == "") || (nexthop == (*iter)->nexthop())) &&
       
   422              ((remote_eid == EndpointID::NULL_EID()) ||
       
   423               (remote_eid == (*iter)->remote_eid())) &&
       
   424              ((states & (*iter)->state()) != 0) )
       
   425         {
       
   426             link = *iter;
       
   427             log_debug("ContactManager::find_link_to: "
       
   428                       "matched link *%p", link.object());
       
   429             ASSERT(!link->isdeleted());
       
   430             return link;
       
   431         }
       
   432     }
       
   433 
       
   434     log_debug("ContactManager::find_link_to: no match");
       
   435     return link;
       
   436 }
       
   437 
       
   438 //----------------------------------------------------------------------
       
   439 LinkRef
       
   440 ContactManager::new_opportunistic_link(ConvergenceLayer* cl,
       
   441                                        const std::string& nexthop,
       
   442                                        const EndpointID& remote_eid,
       
   443                                        const std::string* link_name)
       
   444 {
       
   445     log_debug("new_opportunistic_link: cl %s nexthop %s remote_eid %s",
       
   446               cl->name(), nexthop.c_str(), remote_eid.c_str());
       
   447     
       
   448     oasys::ScopeLock l(&lock_, "ContactManager::new_opportunistic_link");
       
   449 
       
   450     // find a unique link name
       
   451     char name[64];
       
   452     
       
   453     if (link_name) {
       
   454         strncpy(name, link_name->c_str(), sizeof(name));
       
   455         
       
   456         while (find_link(name) != NULL) {
       
   457             snprintf(name, sizeof(name), "%s-%d",
       
   458                      link_name->c_str(), opportunistic_cnt_);
       
   459                      
       
   460             opportunistic_cnt_++;
       
   461         }
       
   462     }
       
   463     
       
   464     else {
       
   465         do {
       
   466             snprintf(name, sizeof(name), "link-%d",
       
   467                     opportunistic_cnt_); 
       
   468             opportunistic_cnt_++;
       
   469         } while (find_link(name) != NULL);
       
   470     }
       
   471         
       
   472     LinkRef link = Link::create_link(name, Link::OPPORTUNISTIC, cl,
       
   473                                      nexthop.c_str(), 0, NULL);
       
   474     if (link == NULL) {
       
   475         log_warn("ContactManager::new_opportunistic_link: "
       
   476                  "unexpected error creating opportunistic link");
       
   477         return link;
       
   478     }
       
   479 
       
   480     LinkRef new_link(link.object(),
       
   481                      "ContactManager::new_opportunistic_link: return value");
       
   482     
       
   483     new_link->set_remote_eid(remote_eid);
       
   484 
       
   485     if (!add_new_link(new_link)) {
       
   486         new_link->delete_link();
       
   487         log_err("ContactManager::new_opportunistic_link: "
       
   488                  "failed to add new opportunistic link %s", new_link->name());
       
   489         new_link = NULL;
       
   490     }
       
   491     
       
   492     return new_link;
       
   493 }
       
   494     
       
   495 //----------------------------------------------------------------------
       
   496 void
       
   497 ContactManager::dump(oasys::StringBuffer* buf) const
       
   498 {
       
   499     oasys::ScopeLock l(&lock_, "ContactManager::dump");
       
   500     
       
   501     buf->append("Links:\n");
       
   502     LinkSet::iterator iter;
       
   503     for (iter = links_->begin(); iter != links_->end(); ++iter) {
       
   504         buf->appendf("*%p\n", (*iter).object());
       
   505     }
       
   506 }
       
   507 
       
   508 } // namespace dtn