00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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;
00150 }
00151
00152 LinkAvailabilityTimer* timer = iter->second;
00153 availability_timers_.erase(event->link_);
00154
00155
00156
00157
00158
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
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
00180
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
00190
00191
00192
00193
00194
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
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
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 }