Link.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 #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     // hook for the link subclass that parses any arguments and shifts
00060     // argv appropriately
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     // XXX/demmer need to pass invalid_argp to the convergence layer
00070 
00071     // notify the convergence layer, which parses the rest of the
00072     // arguments
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     // now dispatch to the subclass for any initial state events that
00082     // need to be posted. this needs to be done after all the above is
00083     // completed to avoid potential race conditions if the core of the
00084     // system tries to use the link before its completely created
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; // set in ContactManager
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", &params_.min_retry_interval_);
00163     a->process("max_retry_interval", &params_.max_retry_interval_);
00164     a->process("idle_close_time",    &params_.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", &params_.mtu_));
00180     p.addopt(new oasys::UIntOpt("min_retry_interval",
00181                                 &params_.min_retry_interval_));
00182     p.addopt(new oasys::UIntOpt("max_retry_interval",
00183                                 &params_.max_retry_interval_));
00184     p.addopt(new oasys::UIntOpt("idle_close_time",
00185                                 &params_.idle_close_time_));
00186     p.addopt(new oasys::BoolOpt("prevhop_hdr", &params_.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      * Once they're created, links are never actually deleted.
00220      * However, if there's a misconfiguration, then init_link may
00221      * delete the link, so we don't want to PANIC here.
00222      *
00223      * Note also that the destructor of the class is protected so
00224      * we're (relatively) sure this constraint does hold.
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; // any old state is valid
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 /* for opportunistic links */);
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     // tell the convergence layer to establish a new session however
00290     // it needs to, it will set the Link state to OPEN and post a
00291     // ContactUpEvent when it has done the deed
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     // we should always be open, therefore we must have a contact
00308     if (contact_ == NULL) {
00309         log_err("Link::close with no contact");
00310         return;
00311     }
00312     
00313     // Kick the convergence layer to close the contact and make sure
00314     // it cleaned up its state
00315     clayer()->close_contact(contact_);
00316     ASSERT(contact_->cl_info() == NULL);
00317 
00318     // Remove the reference from the link, which will clean up the
00319     // object eventually
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 } // namespace dtn

Generated on Sat Sep 8 08:36:17 2007 for DTN Reference Implementation by  doxygen 1.5.3