00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <oasys/util/OptParser.h>
00017
00018 #include "Link.h"
00019 #include "ContactManager.h"
00020 #include "AlwaysOnLink.h"
00021 #include "OndemandLink.h"
00022 #include "ScheduledLink.h"
00023 #include "OpportunisticLink.h"
00024
00025 #include "bundling/BundleDaemon.h"
00026 #include "bundling/BundleEvent.h"
00027 #include "conv_layers/ConvergenceLayer.h"
00028 #include "naming/EndpointIDOpt.h"
00029
00030 namespace dtn {
00031
00032
00034 Link::Params::Params()
00035 : mtu_(0),
00036 min_retry_interval_(5),
00037 max_retry_interval_(10 * 60),
00038 idle_close_time_(0),
00039 prevhop_hdr_(false) {}
00040
00041 Link::Params Link::default_params_;
00042
00043
00044 Link*
00045 Link::create_link(const std::string& name, link_type_t type,
00046 ConvergenceLayer* cl, const char* nexthop,
00047 int argc, const char* argv[],
00048 const char** invalid_argp)
00049 {
00050 Link* link;
00051 switch(type) {
00052 case ALWAYSON: link = new AlwaysOnLink(name, cl, nexthop); break;
00053 case ONDEMAND: link = new OndemandLink(name, cl, nexthop); break;
00054 case SCHEDULED: link = new ScheduledLink(name, cl, nexthop); break;
00055 case OPPORTUNISTIC: link = new OpportunisticLink(name, cl, nexthop); break;
00056 default: PANIC("bogus link_type_t");
00057 }
00058
00059
00060
00061 int count = link->parse_args(argc, argv, invalid_argp);
00062 if (count == -1) {
00063 delete link;
00064 return NULL;
00065 }
00066
00067 argc -= count;
00068
00069
00070
00071
00072
00073 ASSERT(link->clayer_);
00074 if (!link->clayer_->init_link(link, argc, argv)) {
00075 delete link;
00076 return NULL;
00077 }
00078
00079 link->logf(oasys::LOG_INFO, "new link *%p", link);
00080
00081
00082
00083
00084
00085 link->set_initial_state();
00086
00087 return link;
00088 }
00089
00090
00091 Link::Link(const std::string& name, link_type_t type,
00092 ConvergenceLayer* cl, const char* nexthop)
00093 : Logger("Link", "/dtn/link/%s", name.c_str()),
00094 type_(type),
00095 state_(UNAVAILABLE),
00096 nexthop_(nexthop),
00097 name_(name),
00098 reliable_(false),
00099 queue_(std::string("Link ") + name),
00100 contact_("Link"),
00101 clayer_(cl),
00102 cl_info_(NULL),
00103 remote_eid_(EndpointID::NULL_EID())
00104 {
00105 ASSERT(clayer_);
00106
00107 params_ = default_params_;
00108 retry_interval_ = 0;
00109
00110 memset(&stats_, 0, sizeof(Stats));
00111 }
00112
00113
00114 Link::Link(const oasys::Builder&)
00115 : Logger("Link", "/dtn/link/UNKNOWN!!!"),
00116 type_(LINK_INVALID),
00117 state_(UNAVAILABLE),
00118 nexthop_(""),
00119 name_(""),
00120 reliable_(false),
00121 queue_(""),
00122 contact_("Link"),
00123 clayer_(NULL),
00124 cl_info_(NULL),
00125 remote_eid_(EndpointID::NULL_EID())
00126 {
00127 }
00128
00129
00130 void
00131 Link::serialize(oasys::SerializeAction* a)
00132 {
00133 std::string cl_name;
00134 std::string type_str;
00135
00136 if (a->action_code() == oasys::Serialize::UNMARSHAL) {
00137 a->process("type", &type_str);
00138 type_ = str_to_link_type(type_str.c_str());
00139 ASSERT(type_ != LINK_INVALID);
00140 } else {
00141 type_str = link_type_to_str(static_cast<link_type_t>(type_));
00142 a->process("type", &type_str);
00143 }
00144
00145 a->process("nexthop", &nexthop_);
00146 a->process("name", &name_);
00147 a->process("state", &state_);
00148 a->process("reliable", &reliable_);
00149
00150 if (a->action_code() == oasys::Serialize::UNMARSHAL) {
00151 a->process("clayer", &cl_name);
00152 clayer_ = ConvergenceLayer::find_clayer(cl_name.c_str());
00153 ASSERT(clayer_);
00154 } else {
00155 cl_name = clayer_->name();
00156 a->process("clayer", &cl_name);
00157 if ((state_ == OPEN) || (state_ == BUSY))
00158 a->process("clinfo", contact_->cl_info());
00159 }
00160
00161 a->process("remote_eid", &remote_eid_);
00162 a->process("min_retry_interval", ¶ms_.min_retry_interval_);
00163 a->process("max_retry_interval", ¶ms_.max_retry_interval_);
00164 a->process("idle_close_time", ¶ms_.idle_close_time_);
00165
00166 if (a->action_code() == oasys::Serialize::UNMARSHAL) {
00167 logpathf("/dtn/link/%s", name_.c_str());
00168 }
00169 }
00170
00171
00172 int
00173 Link::parse_args(int argc, const char* argv[], const char** invalidp)
00174 {
00175 oasys::OptParser p;
00176
00177 p.addopt(new dtn::EndpointIDOpt("remote_eid", &remote_eid_));
00178 p.addopt(new oasys::BoolOpt("reliable", &reliable_));
00179 p.addopt(new oasys::UIntOpt("mtu", ¶ms_.mtu_));
00180 p.addopt(new oasys::UIntOpt("min_retry_interval",
00181 ¶ms_.min_retry_interval_));
00182 p.addopt(new oasys::UIntOpt("max_retry_interval",
00183 ¶ms_.max_retry_interval_));
00184 p.addopt(new oasys::UIntOpt("idle_close_time",
00185 ¶ms_.idle_close_time_));
00186 p.addopt(new oasys::BoolOpt("prevhop_hdr", ¶ms_.prevhop_hdr_));
00187
00188 int ret = p.parse_and_shift(argc, argv, invalidp);
00189 if (ret == -1) {
00190 return -1;
00191 }
00192
00193 if (params_.min_retry_interval_ == 0 ||
00194 params_.max_retry_interval_ == 0)
00195 {
00196 *invalidp = "invalid retry interval";
00197 return -1;
00198 }
00199
00200 if (params_.idle_close_time_ != 0 && type_ == ALWAYSON)
00201 {
00202 *invalidp = "idle_close_time must be zero for always on link";
00203 return -1;
00204 }
00205
00206 return ret;
00207 }
00208
00209
00210 void
00211 Link::set_initial_state()
00212 {
00213 }
00214
00215
00216 Link::~Link()
00217 {
00218
00219
00220
00221
00222
00223
00224
00225
00226 ASSERT(!isopen());
00227 ASSERT(cl_info_ == NULL);
00228 }
00229
00230
00231 void
00232 Link::set_state(state_t new_state)
00233 {
00234 log_debug("set_state %s -> %s",
00235 state_to_str(static_cast<state_t>(state_)),
00236 state_to_str(new_state));
00237
00238 #define ASSERT_STATE(condition) \
00239 if (!(condition)) { \
00240 log_err("set_state %s -> %s: expected %s", \
00241 state_to_str(static_cast<state_t>(state_)), \
00242 state_to_str(new_state), \
00243 #condition); \
00244 }
00245
00246 switch(new_state) {
00247 case UNAVAILABLE:
00248 break;
00249
00250 case AVAILABLE:
00251 ASSERT_STATE(state_ == OPEN || state_ == UNAVAILABLE);
00252 break;
00253
00254 case OPENING:
00255 ASSERT_STATE(state_ == AVAILABLE || state_ == UNAVAILABLE);
00256 break;
00257
00258 case OPEN:
00259 ASSERT_STATE(state_ == OPENING || state_ == BUSY ||
00260 state_ == UNAVAILABLE );
00261 break;
00262
00263 case BUSY:
00264 ASSERT_STATE(state_ == OPEN);
00265 break;
00266
00267 default:
00268 NOTREACHED;
00269 }
00270 #undef ASSERT_STATE
00271
00272 state_ = new_state;
00273 }
00274
00275
00276 void
00277 Link::open()
00278 {
00279 log_debug("Link::open");
00280
00281 if (state_ != AVAILABLE) {
00282 log_crit("Link::open in state %s: expected state AVAILABLE",
00283 state_to_str(static_cast<state_t>(state_)));
00284 return;
00285 }
00286
00287 set_state(OPENING);
00288
00289
00290
00291
00292 ASSERT(contact_ == NULL);
00293 contact_ = new Contact(this);
00294 clayer()->open_contact(contact_);
00295
00296 stats_.contact_attempts_++;
00297
00298 log_debug("*%p new contact %p", this, contact_.object());
00299 }
00300
00301
00302 void
00303 Link::close()
00304 {
00305 log_debug("Link::close");
00306
00307
00308 if (contact_ == NULL) {
00309 log_err("Link::close with no contact");
00310 return;
00311 }
00312
00313
00314
00315 clayer()->close_contact(contact_);
00316 ASSERT(contact_->cl_info() == NULL);
00317
00318
00319
00320 contact_ = NULL;
00321
00322 log_debug("Link::close complete");
00323 }
00324
00325
00326 int
00327 Link::format(char* buf, size_t sz) const
00328 {
00329 return snprintf(buf, sz, "%s [%s %s %s %s]",
00330 name(), nexthop(), remote_eid_.c_str(),
00331 link_type_to_str(static_cast<link_type_t>(type_)),
00332 state_to_str(static_cast<state_t>(state_)));
00333 }
00334
00335
00336 void
00337 Link::dump(oasys::StringBuffer* buf)
00338 {
00339 buf->appendf("Link %s:\n"
00340 "clayer: %s\n"
00341 "type: %s\n"
00342 "state: %s\n"
00343 "nexthop: %s\n"
00344 "remote eid: %s\n"
00345 "mtu: %u\n"
00346 "min_retry_interval: %u\n"
00347 "max_retry_interval: %u\n"
00348 "prevhop_hdr: %s\n",
00349 name(),
00350 clayer_->name(),
00351 link_type_to_str(static_cast<link_type_t>(type_)),
00352 state_to_str(static_cast<state_t>(state_)),
00353 nexthop(),
00354 remote_eid_.c_str(),
00355 params_.mtu_,
00356 params_.min_retry_interval_,
00357 params_.max_retry_interval_,
00358 params_.prevhop_hdr_ ? "true" : "false");
00359
00360 clayer_->dump_link(this, buf);
00361 }
00362
00363
00364 void
00365 Link::dump_stats(oasys::StringBuffer* buf)
00366 {
00367 buf->appendf("%u contact_attempts -- "
00368 "%u contacts -- "
00369 "%u bundles_transmitted -- "
00370 "%u bytes_transmitted -- "
00371 "%u bundles_queued -- "
00372 "%u bytes_queued ",
00373 stats_.contact_attempts_,
00374 stats_.contacts_,
00375 stats_.bundles_transmitted_,
00376 stats_.bytes_transmitted_,
00377 stats_.bundles_queued_,
00378 stats_.bytes_queued_);
00379 }
00380
00381 }