00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 # include <dtn-config.h>
00019 #endif
00020
00021 #include <oasys/util/StringBuffer.h>
00022
00023 #include "ContactManager.h"
00024 #include "Contact.h"
00025 #include "Link.h"
00026 #include "bundling/BundleDaemon.h"
00027 #include "bundling/BundleEvent.h"
00028 #include "conv_layers/ConvergenceLayer.h"
00029
00030 namespace dtn {
00031
00032
00033 ContactManager::ContactManager()
00034 : BundleEventHandler("ContactManager", "/dtn/contact/manager"),
00035 opportunistic_cnt_(0)
00036 {
00037 links_ = new LinkSet();
00038 }
00039
00040
00041 ContactManager::~ContactManager()
00042 {
00043 delete links_;
00044 }
00045
00046
00047 bool
00048 ContactManager::add_new_link(const LinkRef& link)
00049 {
00050 oasys::ScopeLock l(&lock_, "ContactManager::add_new_link");
00051
00052 ASSERT(link != NULL);
00053 ASSERT(!link->isdeleted());
00054
00055 log_debug("adding NEW link %s", link->name());
00056 if (has_link(link->name())) {
00057 return false;
00058 }
00059 links_->insert(LinkRef(link.object(), "ContactManager"));
00060
00061 if (!link->is_create_pending()) {
00062 log_debug("posting LinkCreatedEvent");
00063 BundleDaemon::post(new LinkCreatedEvent(link));
00064 }
00065
00066 return true;
00067 }
00068
00069
00070 void
00071 ContactManager::del_link(const LinkRef& link, bool wait,
00072 ContactEvent::reason_t reason)
00073 {
00074 oasys::ScopeLock l(&lock_, "ContactManager::del_link");
00075 ASSERT(link != NULL);
00076
00077 if (!has_link(link)) {
00078 log_err("ContactManager::del_link: link %s does not exist",
00079 link->name());
00080 return;
00081 }
00082 ASSERT(!link->isdeleted());
00083
00084 log_debug("ContactManager::del_link: deleting link %s", link->name());
00085
00086 if (!wait)
00087 link->delete_link();
00088
00089
00090 if (link->isopen() || link->isopening()) {
00091 BundleDaemon::instance()->post(
00092 new LinkStateChangeRequest(link, Link::CLOSED, reason));
00093 }
00094
00095
00096 AvailabilityTimerMap::iterator iter = availability_timers_.find(link);
00097 if (iter != availability_timers_.end()) {
00098 LinkAvailabilityTimer* timer = iter->second;
00099 availability_timers_.erase(link);
00100
00101
00102
00103
00104
00105 if (!timer->cancel()) {
00106 log_warn("ContactManager::del_link: "
00107 "failed to cancel availability timer -- race condition");
00108 }
00109 }
00110
00111 links_->erase(link);
00112
00113 if (wait) {
00114 l.unlock();
00115
00116
00117
00118 ASSERT(!lock()->is_locked_by_me());
00119 oasys::Notifier notifier("ContactManager::del_link");
00120 BundleDaemon::post_and_wait(new LinkDeletedEvent(link), ¬ifier);
00121 link->delete_link();
00122 } else {
00123 BundleDaemon::post(new LinkDeletedEvent(link));
00124 }
00125 }
00126
00127
00128 bool
00129 ContactManager::has_link(const LinkRef& link)
00130 {
00131 oasys::ScopeLock l(&lock_, "ContactManager::has_link");
00132 ASSERT(link != NULL);
00133
00134 LinkSet::iterator iter = links_->find(link);
00135 if (iter == links_->end())
00136 return false;
00137 return true;
00138 }
00139
00140
00141 bool
00142 ContactManager::has_link(const char* name)
00143 {
00144 oasys::ScopeLock l(&lock_, "ContactManager::has_link");
00145 ASSERT(link != NULL);
00146
00147 LinkSet::iterator iter;
00148 for (iter = links_->begin(); iter != links_->end(); ++iter) {
00149 if (strcasecmp((*iter)->name(), name) == 0)
00150 return true;
00151 }
00152 return false;
00153 }
00154
00155
00156 LinkRef
00157 ContactManager::find_link(const char* name)
00158 {
00159 oasys::ScopeLock l(&lock_, "ContactManager::find_link");
00160
00161 LinkSet::iterator iter;
00162 LinkRef link("ContactManager::find_link: return value");
00163
00164 for (iter = links_->begin(); iter != links_->end(); ++iter) {
00165 if (strcasecmp((*iter)->name(), name) == 0) {
00166 link = *iter;
00167 ASSERT(!link->isdeleted());
00168 return link;
00169 }
00170 }
00171 return link;
00172 }
00173
00174
00175 const LinkSet*
00176 ContactManager::links()
00177 {
00178 ASSERTF(lock_.is_locked_by_me(),
00179 "ContactManager::links must be called while holding lock");
00180 return links_;
00181 }
00182
00183
00184 void
00185 ContactManager::LinkAvailabilityTimer::timeout(const struct timeval& now)
00186 {
00187 (void)now;
00188 cm_->reopen_link(link_);
00189 delete this;
00190 }
00191
00192
00193 void
00194 ContactManager::reopen_link(const LinkRef& link)
00195 {
00196 oasys::ScopeLock l(&lock_, "ContactManager::reopen_link");
00197 ASSERT(link != NULL);
00198
00199 log_debug("reopen link %s", link->name());
00200
00201 availability_timers_.erase(link);
00202
00203 if (!has_link(link)) {
00204 log_warn("ContactManager::reopen_link: "
00205 "link %s does not exist", link->name());
00206 return;
00207 }
00208 ASSERT(!link->isdeleted());
00209
00210 if (link->state() == Link::UNAVAILABLE) {
00211 BundleDaemon::post(
00212 new LinkStateChangeRequest(link, Link::OPEN,
00213 ContactEvent::RECONNECT));
00214 } else {
00215
00216 log_err("availability timer fired for link %s but state is %s",
00217 link->name(), Link::state_to_str(link->state()));
00218 }
00219 }
00220
00221
00222 void
00223 ContactManager::handle_link_created(LinkCreatedEvent* event)
00224 {
00225 oasys::ScopeLock l(&lock_, "ContactManager::handle_link_created");
00226
00227 LinkRef link = event->link_;
00228 ASSERT(link != NULL);
00229
00230 if(link->isdeleted())
00231 {
00232 log_warn("ContactManager::handle_link_created: "
00233 "link %s is being deleted", link->name());
00234 return;
00235 }
00236
00237 if (!has_link(link)) {
00238 log_err("ContactManager::handle_link_created: "
00239 "link %s does not exist", link->name());
00240 return;
00241 }
00242
00243
00244 link->set_initial_state();
00245 }
00246
00247
00248 void
00249 ContactManager::handle_link_available(LinkAvailableEvent* event)
00250 {
00251 oasys::ScopeLock l(&lock_, "ContactManager::handle_link_available");
00252
00253 LinkRef link = event->link_;
00254 ASSERT(link != NULL);
00255
00256 if(link->isdeleted())
00257 {
00258 log_warn("ContactManager::handle_link_available: "
00259 "link %s is being deleted", link->name());
00260 return;
00261 }
00262
00263 if (!has_link(link)) {
00264 log_warn("ContactManager::handle_link_available: "
00265 "link %s does not exist", link->name());
00266 return;
00267 }
00268
00269 AvailabilityTimerMap::iterator iter;
00270 iter = availability_timers_.find(link);
00271 if (iter == availability_timers_.end()) {
00272 return;
00273 }
00274
00275 LinkAvailabilityTimer* timer = iter->second;
00276 availability_timers_.erase(link);
00277
00278
00279
00280
00281
00282 if (!timer->cancel()) {
00283 log_warn("ContactManager::handle_link_available: "
00284 "can't cancel availability timer: race condition");
00285 }
00286 }
00287
00288
00289 void
00290 ContactManager::handle_link_unavailable(LinkUnavailableEvent* event)
00291 {
00292 oasys::ScopeLock l(&lock_, "ContactManager::handle_link_unavailable");
00293
00294 LinkRef link = event->link_;
00295 ASSERT(link != NULL);
00296
00297 if (!has_link(link)) {
00298 log_warn("ContactManager::handle_link_unavailable: "
00299 "link %s does not exist", link->name());
00300 return;
00301 }
00302
00303 if(link->isdeleted())
00304 {
00305 log_warn("ContactManager::handle_link_unavailable: "
00306 "link %s is being deleted", link->name());
00307 return;
00308 }
00309
00310
00311 if (link->type() != Link::ONDEMAND && link->type() != Link::ALWAYSON) {
00312 log_debug("ContactManager::handle_link_unavailable: "
00313 "ignoring link unavailable for link of type %s",
00314 link->type_str());
00315 return;
00316 }
00317
00318
00319
00320 if (event->reason_ == ContactEvent::USER ||
00321 event->reason_ == ContactEvent::IDLE)
00322 {
00323 log_debug("ContactManager::handle_link_unavailable: "
00324 "ignoring link unavailable due to %s",
00325 event->reason_to_str(event->reason_));
00326 return;
00327 }
00328
00329
00330
00331
00332
00333
00334
00335 if (link->retry_interval_ == 0) {
00336 link->retry_interval_ = link->params().min_retry_interval_;
00337 }
00338
00339 int timeout = link->retry_interval_;
00340 link->retry_interval_ *= 2;
00341 if (link->retry_interval_ > link->params().max_retry_interval_) {
00342 link->retry_interval_ = link->params().max_retry_interval_;
00343 }
00344
00345 LinkAvailabilityTimer* timer = new LinkAvailabilityTimer(this, link);
00346
00347 AvailabilityTimerMap::value_type val(link, timer);
00348 if (availability_timers_.insert(val).second == false) {
00349 log_err("ContactManager::handle_link_unavailable: "
00350 "error inserting timer for link %s into table!", link->name());
00351 delete timer;
00352 return;
00353 }
00354
00355 log_debug("link %s unavailable (%s): scheduling retry timer in %d seconds",
00356 link->name(), event->reason_to_str(event->reason_), timeout);
00357 timer->schedule_in(timeout * 1000);
00358 }
00359
00360
00361 void
00362 ContactManager::handle_contact_up(ContactUpEvent* event)
00363 {
00364 oasys::ScopeLock l(&lock_, "ContactManager::handle_contact_up");
00365
00366 LinkRef link = event->contact_->link();
00367 ASSERT(link != NULL);
00368
00369 if(link->isdeleted())
00370 {
00371 log_warn("ContactManager::handle_contact_up: "
00372 "link %s is being deleted, not marking its contact up", link->name());
00373 return;
00374 }
00375
00376 if (!has_link(link)) {
00377 log_warn("ContactManager::handle_contact_up: "
00378 "link %s does not exist", link->name());
00379 return;
00380 }
00381
00382 if (link->type() == Link::ONDEMAND || link->type() == Link::ALWAYSON) {
00383 log_debug("ContactManager::handle_contact_up: "
00384 "resetting retry interval for link %s: %d -> %d",
00385 link->name(),
00386 link->retry_interval_,
00387 link->params().min_retry_interval_);
00388 link->retry_interval_ = link->params().min_retry_interval_;
00389 }
00390 }
00391
00392
00393 LinkRef
00394 ContactManager::find_link_to(ConvergenceLayer* cl,
00395 const std::string& nexthop,
00396 const EndpointID& remote_eid,
00397 Link::link_type_t type,
00398 u_int states)
00399 {
00400 oasys::ScopeLock l(&lock_, "ContactManager::find_link_to");
00401
00402 LinkSet::iterator iter;
00403 LinkRef link("ContactManager::find_link_to: return value");
00404
00405 log_debug("find_link_to: cl %s nexthop %s remote_eid %s "
00406 "type %s states 0x%x",
00407 cl ? cl->name() : "ANY",
00408 nexthop.c_str(), remote_eid.c_str(),
00409 type == Link::LINK_INVALID ? "ANY" : Link::link_type_to_str(type),
00410 states);
00411
00412
00413 ASSERT((cl != NULL) ||
00414 (nexthop != "") ||
00415 (remote_eid != EndpointID::NULL_EID()) ||
00416 (type != Link::LINK_INVALID));
00417
00418 for (iter = links_->begin(); iter != links_->end(); ++iter) {
00419 if ( ((type == Link::LINK_INVALID) || (type == (*iter)->type())) &&
00420 ((cl == NULL) || ((*iter)->clayer() == cl)) &&
00421 ((nexthop == "") || (nexthop == (*iter)->nexthop())) &&
00422 ((remote_eid == EndpointID::NULL_EID()) ||
00423 (remote_eid == (*iter)->remote_eid())) &&
00424 ((states & (*iter)->state()) != 0) )
00425 {
00426 link = *iter;
00427 log_debug("ContactManager::find_link_to: "
00428 "matched link *%p", link.object());
00429 ASSERT(!link->isdeleted());
00430 return link;
00431 }
00432 }
00433
00434 log_debug("ContactManager::find_link_to: no match");
00435 return link;
00436 }
00437
00438
00439 LinkRef
00440 ContactManager::new_opportunistic_link(ConvergenceLayer* cl,
00441 const std::string& nexthop,
00442 const EndpointID& remote_eid,
00443 const std::string* link_name)
00444 {
00445 log_debug("new_opportunistic_link: cl %s nexthop %s remote_eid %s",
00446 cl->name(), nexthop.c_str(), remote_eid.c_str());
00447
00448 oasys::ScopeLock l(&lock_, "ContactManager::new_opportunistic_link");
00449
00450
00451 char name[64];
00452
00453 if (link_name) {
00454 strncpy(name, link_name->c_str(), sizeof(name));
00455
00456 while (find_link(name) != NULL) {
00457 snprintf(name, sizeof(name), "%s-%d",
00458 link_name->c_str(), opportunistic_cnt_);
00459
00460 opportunistic_cnt_++;
00461 }
00462 }
00463
00464 else {
00465 do {
00466 snprintf(name, sizeof(name), "link-%d",
00467 opportunistic_cnt_);
00468 opportunistic_cnt_++;
00469 } while (find_link(name) != NULL);
00470 }
00471
00472 LinkRef link = Link::create_link(name, Link::OPPORTUNISTIC, cl,
00473 nexthop.c_str(), 0, NULL);
00474 if (link == NULL) {
00475 log_warn("ContactManager::new_opportunistic_link: "
00476 "unexpected error creating opportunistic link");
00477 return link;
00478 }
00479
00480 LinkRef new_link(link.object(),
00481 "ContactManager::new_opportunistic_link: return value");
00482
00483 new_link->set_remote_eid(remote_eid);
00484
00485 if (!add_new_link(new_link)) {
00486 new_link->delete_link();
00487 log_err("ContactManager::new_opportunistic_link: "
00488 "failed to add new opportunistic link %s", new_link->name());
00489 new_link = NULL;
00490 }
00491
00492 return new_link;
00493 }
00494
00495
00496 void
00497 ContactManager::dump(oasys::StringBuffer* buf) const
00498 {
00499 oasys::ScopeLock l(&lock_, "ContactManager::dump");
00500
00501 buf->append("Links:\n");
00502 LinkSet::iterator iter;
00503 for (iter = links_->begin(); iter != links_->end(); ++iter) {
00504 buf->appendf("*%p\n", (*iter).object());
00505 }
00506 }
00507
00508 }