Link.cc

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2004 Intel Corporation. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  * 
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 #include <oasys/util/OptParser.h>
00039 
00040 #include "Link.h"
00041 #include "ContactManager.h"
00042 #include "AlwaysOnLink.h"
00043 #include "OndemandLink.h"
00044 #include "ScheduledLink.h"
00045 #include "OpportunisticLink.h"
00046 
00047 #include "bundling/BundleDaemon.h"
00048 #include "bundling/BundleEvent.h"
00049 #include "conv_layers/ConvergenceLayer.h"
00050 #include "naming/EndpointIDOpt.h"
00051 
00052 namespace dtn {
00053 
00054 //----------------------------------------------------------------------
00056 Link::Params Link::default_params_ = {
00057     default_params_.mtu_                = 0,
00058     default_params_.min_retry_interval_ = 5,
00059     default_params_.max_retry_interval_ = 10 * 60,
00060     default_params_.idle_close_time_    = 0
00061 };
00062 
00063 //----------------------------------------------------------------------
00064 Link*
00065 Link::create_link(const std::string& name, link_type_t type,
00066                   ConvergenceLayer* cl, const char* nexthop,
00067                   int argc, const char* argv[],
00068                   const char** invalid_argp)
00069 {
00070     Link* link;
00071     switch(type) {
00072     case ALWAYSON:      link = new AlwaysOnLink(name, cl, nexthop); break;
00073     case ONDEMAND:      link = new OndemandLink(name, cl, nexthop); break;
00074     case SCHEDULED:     link = new ScheduledLink(name, cl, nexthop); break;
00075     case OPPORTUNISTIC: link = new OpportunisticLink(name, cl, nexthop); break;
00076     default:            PANIC("bogus link_type_t");
00077     }
00078 
00079     // hook for the link subclass that parses any arguments and shifts
00080     // argv appropriately
00081     int count = link->parse_args(argc, argv, invalid_argp);
00082     if (count == -1) {
00083         delete link;
00084         return NULL;
00085     }
00086 
00087     argc -= count;
00088 
00089     // notify the convergence layer, which parses the rest of the
00090     // arguments
00091     ASSERT(link->clayer_);
00092     if (!link->clayer_->init_link(link, argc, argv)) {
00093         delete link;
00094         return NULL;
00095     }
00096     
00097     link->logf(oasys::LOG_INFO, "new link *%p", link);
00098 
00099     // now dispatch to the subclass for any initial state events that
00100     // need to be posted. this needs to be done after all the above is
00101     // completed to avoid potential race conditions if the core of the
00102     // system tries to use the link before its completely created
00103     link->set_initial_state();
00104 
00105     return link;
00106 }
00107 
00108 //----------------------------------------------------------------------
00109 Link::Link(const std::string& name, link_type_t type,
00110            ConvergenceLayer* cl, const char* nexthop)
00111     :  Logger("Link", "/dtn/link/%s", name.c_str()),
00112        type_(type),
00113        state_(UNAVAILABLE),
00114        nexthop_(nexthop),
00115        name_(name),
00116        reliable_(false),
00117        contact_("Link"),
00118        clayer_(cl),
00119        cl_info_(NULL),
00120        remote_eid_(EndpointID::NULL_EID())
00121 {
00122     ASSERT(clayer_);
00123 
00124     params_         = default_params_;
00125     retry_interval_ = 0; // set in ContactManager
00126 
00127     memset(&stats_, 0, sizeof(Stats));
00128 }
00129 
00130 //----------------------------------------------------------------------
00131 Link::Link(const oasys::Builder&)
00132     : Logger("Link", "/dtn/link/UNKNOWN!!!"),
00133       type_(LINK_INVALID),
00134       state_(UNAVAILABLE),
00135       nexthop_(""),
00136       name_(""),
00137       reliable_(false),
00138       contact_("Link"),
00139       clayer_(NULL),
00140       cl_info_(NULL),
00141       remote_eid_(EndpointID::NULL_EID())
00142 {
00143 }
00144 
00145 //----------------------------------------------------------------------
00146 void
00147 Link::serialize(oasys::SerializeAction* a)
00148 {
00149     std::string cl_name;
00150     std::string type_str;
00151 
00152     if (a->action_code() == oasys::Serialize::UNMARSHAL) {
00153         a->process("type",     &type_str);
00154         type_ = str_to_link_type(type_str.c_str());
00155         ASSERT(type_ != LINK_INVALID);
00156     } else {
00157         type_str = link_type_to_str(type_);
00158         a->process("type",     &type_str);
00159     }
00160     
00161     a->process("nexthop",  &nexthop_);
00162     a->process("name",     &name_);
00163     a->process("reliable", &reliable_);
00164 
00165     if (a->action_code() == oasys::Serialize::UNMARSHAL) {
00166         a->process("clayer", &cl_name);
00167         clayer_ = ConvergenceLayer::find_clayer(cl_name.c_str());
00168         ASSERT(clayer_);
00169     } else {
00170         cl_name = clayer_->name();
00171         a->process("clayer", &cl_name);
00172     }
00173 
00174     a->process("remote_eid",         &remote_eid_);
00175     a->process("min_retry_interval", &params_.min_retry_interval_);
00176     a->process("max_retry_interval", &params_.max_retry_interval_);
00177     a->process("idle_close_time",    &params_.idle_close_time_);
00178 
00179     if (a->action_code() == oasys::Serialize::UNMARSHAL) {
00180         logpathf("/dtn/link/%s", name_.c_str());
00181     }
00182 }
00183 
00184 //----------------------------------------------------------------------
00185 int
00186 Link::parse_args(int argc, const char* argv[], const char** invalidp)
00187 {
00188     oasys::OptParser p;
00189 
00190     p.addopt(new dtn::EndpointIDOpt("remote_eid", &remote_eid_));
00191     p.addopt(new oasys::BoolOpt("reliable", &reliable_));
00192     p.addopt(new oasys::UIntOpt("mtu", &params_.mtu_));
00193     p.addopt(new oasys::UIntOpt("min_retry_interval",
00194                                 &params_.min_retry_interval_));
00195     p.addopt(new oasys::UIntOpt("max_retry_interval",
00196                                 &params_.max_retry_interval_));
00197     p.addopt(new oasys::UIntOpt("idle_close_time",
00198                                 &params_.idle_close_time_));
00199     
00200     int ret = p.parse_and_shift(argc, argv, invalidp);
00201     if (ret == -1) {
00202         return -1;
00203     }
00204 
00205     if (params_.min_retry_interval_ == 0 ||
00206         params_.max_retry_interval_ == 0)
00207     {
00208         *invalidp = "invalid retry interval";
00209         return -1;
00210     }
00211     
00212     if (params_.idle_close_time_ != 0 && type_ == ALWAYSON)
00213     {
00214         *invalidp = "idle_close_time must be zero for always on link";
00215         return -1;
00216     }
00217     
00218     return ret;
00219 }
00220 
00221 //----------------------------------------------------------------------
00222 void
00223 Link::set_initial_state()
00224 {
00225 }
00226 
00227 //----------------------------------------------------------------------
00228 Link::~Link()
00229 {
00230     /*
00231      * Once they're created, links are never actually deleted.
00232      * However, if there's a misconfiguration, then init_link may
00233      * delete the link, so we don't want to PANIC here.
00234      *
00235      * Note also that the destructor of the class is protected so
00236      * we're (relatively) sure this constraint does hold.
00237      */
00238     ASSERT(!isopen());
00239     ASSERT(cl_info_ == NULL);
00240 }
00241 
00242 //----------------------------------------------------------------------
00243 void
00244 Link::set_state(state_t new_state)
00245 {
00246     log_debug("set_state %s -> %s",
00247               state_to_str(state_), state_to_str(new_state));
00248 
00249 #define ASSERT_STATE(condition)                         \
00250     if (!(condition)) {                                 \
00251         log_err("set_state %s -> %s: expected %s",      \
00252                 state_to_str(state_),                   \
00253                 state_to_str(new_state),                \
00254                 #condition);                            \
00255     }
00256 
00257     switch(new_state) {
00258     case UNAVAILABLE:
00259         break; // any old state is valid
00260 
00261     case AVAILABLE:
00262         ASSERT_STATE(state_ == OPEN || state_ == UNAVAILABLE);
00263         break;
00264 
00265     case OPENING:
00266         ASSERT_STATE(state_ == AVAILABLE || state_ == UNAVAILABLE);
00267         break;
00268         
00269     case OPEN:
00270         ASSERT_STATE(state_ == OPENING || state_ == BUSY ||
00271                      state_ == UNAVAILABLE /* for opportunistic links */);
00272         break;
00273 
00274     case BUSY:
00275         ASSERT_STATE(state_ == OPEN);
00276         break;
00277     
00278     default:
00279         NOTREACHED;
00280     }
00281 #undef ASSERT_STATE
00282 
00283     state_ = new_state;
00284 }
00285 
00286 //----------------------------------------------------------------------
00287 void
00288 Link::open()
00289 {
00290     log_debug("Link::open");
00291 
00292     if (state_ != AVAILABLE) {
00293         log_crit("Link::open in state %s: expected state AVAILABLE",
00294                  state_to_str(state_));
00295         return;
00296     }
00297 
00298     set_state(OPENING);
00299 
00300     // tell the convergence layer to establish a new session however
00301     // it needs to, it will set the Link state to OPEN and post a
00302     // ContactUpEvent when it has done the deed
00303     ASSERT(contact_ == NULL);
00304     contact_ = new Contact(this);
00305     clayer()->open_contact(contact_);
00306 
00307     stats_.contact_attempts_++;
00308 
00309     log_debug("*%p new contact %p", this, contact_.object());
00310 }
00311     
00312 //----------------------------------------------------------------------
00313 void
00314 Link::close()
00315 {
00316     log_debug("Link::close");
00317 
00318     // we should always be open, therefore we must have a contact
00319     if (contact_ == NULL) {
00320         log_err("Link::close with no contact");
00321         return;
00322     }
00323     
00324     // Kick the convergence layer to close the contact and make sure
00325     // it cleaned up its state
00326     clayer()->close_contact(contact_);
00327     ASSERT(contact_->cl_info() == NULL);
00328 
00329     // Remove the reference from the link, which will clean up the
00330     // object eventually
00331     contact_ = NULL;
00332 
00333     log_debug("Link::close complete");
00334 }
00335 
00336 //----------------------------------------------------------------------
00337 int
00338 Link::format(char* buf, size_t sz) const
00339 {
00340     return snprintf(buf, sz, "%s [%s %s %s %s]",
00341                     name(), nexthop(), remote_eid_.c_str(),
00342                     link_type_to_str(type_), state_to_str(state_));
00343 }
00344 
00345 //----------------------------------------------------------------------
00346 void
00347 Link::dump(oasys::StringBuffer* buf)
00348 {
00349     buf->appendf("Link %s:\n"
00350                  "type: %s\n"
00351                  "state: %s\n"
00352                  "nexthop: %s\n"
00353                  "remote eid: %s\n"
00354                  "mtu: %u\n"
00355                  "min_retry_interval: %u\n"
00356                  "max_retry_interval: %u\n",
00357                  name(), 
00358                  link_type_to_str(type_),
00359                  state_to_str(state_),
00360                  nexthop(),
00361                  remote_eid_.c_str(),
00362                  params_.mtu_,
00363                  params_.min_retry_interval_,
00364                  params_.max_retry_interval_);
00365     
00366     clayer_->dump_link(this, buf);
00367 }
00368 
00369 //----------------------------------------------------------------------
00370 void
00371 Link::dump_stats(oasys::StringBuffer* buf)
00372 {
00373     buf->appendf("%u contact_attempts -- "
00374                  "%u contacts -- "
00375                  "%u bundles_transmitted -- "
00376                  "%u bytes_transmitted -- "
00377                  "%u bundles_inflight -- "
00378                  "%u bytes_inflight ",
00379                  stats_.contact_attempts_,
00380                  stats_.contacts_,
00381                  stats_.bundles_transmitted_,
00382                  stats_.bytes_transmitted_,
00383                  stats_.bundles_inflight_,
00384                  stats_.bytes_inflight_);
00385 }
00386 
00387 } // namespace dtn

Generated on Fri Dec 22 14:47:59 2006 for DTN Reference Implementation by  doxygen 1.5.1