--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlib/contacts/Link.h Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,762 @@
+/*
+ * Copyright 2004-2006 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LINK_H_
+#define _LINK_H_
+
+#include <set>
+#include <oasys/debug/Formatter.h>
+#include <oasys/serialize/Serialize.h>
+#include <oasys/thread/SpinLock.h>
+#include <oasys/util/Ref.h>
+#include <oasys/util/RefCountedObject.h>
+
+#include "bundling/BundleList.h"
+#include "naming/EndpointID.h"
+
+#include "Contact.h"
+#include "NamedAttribute.h"
+
+namespace dtn {
+
+class ConvergenceLayer;
+class CLInfo;
+class Contact;
+class Link;
+class RouterInfo;
+
+/**
+ * Typedef for a reference on a link.
+ */
+typedef oasys::Ref<Link> LinkRef;
+
+/**
+ * Set of links
+ */
+class LinkSet : public std::set<LinkRef> {};
+
+/**
+ * Abstraction for a DTN link, i.e. a one way communication channel to
+ * a next hop node in the DTN overlay.
+ *
+ * The state of a link (regarding its availability) is described by
+ * the Link::state_t enumerated type.
+ *
+ * All links in the OPEN state have an associated contact that
+ * represents an actual connection.
+ *
+ * Every link has a unique name associated with it which is used to
+ * identify it. The name is configured explicitly when the link is
+ * created.
+ *
+ * Creating new links:
+ * Links are created explicitly in the configuration file. Syntax is:
+ * @code
+ * link add <name> <nexthop> <type> <conv_layer> <args>
+ * @endcode
+ * See servlib/cmd/LinkCommand.cc for implementation of this TCL cmd.
+ *
+ * ----------------------------------------------------------
+ *
+ * Links are of three types as discussed in the DTN architecture
+ * ONDEMAND, SCHEDULED, OPPORTUNISTIC.
+ *
+ * The key differences from an implementation perspective are "who"
+ * and "when" manipulates the link state regarding availability.
+ *
+ * ONDEMAND links are initializd in the AVAILABLE state, as one would
+ * expect. It remains in this state until a router explicitly opens
+ * it.
+ *
+ * An ONDEMAND link can then be closed either due to connection
+ * failure or because the link has been idle for too long, both
+ * triggered by the convergence layer. If an ONDEMAND link is closed
+ * due to connection failure, then the contact manager is notified of
+ * this event and periodically tries to re-establish the link.
+ *
+ * For OPPORTUNISTIC links the availability state is set by the code
+ * which detects that there is a new link available to be used.
+ *
+ * SCHEDULED links have their availability dictated by the schedule
+ * implementation.
+ *
+ * ----------------------------------------------------------
+ *
+ * Links are used for input and/or output. In other words, for
+ * connection-oriented convergence layers like TCP, a link object is
+ * created whenever a new connection is made to a peer or when a
+ * connection arrives from a peer.
+ */
+class Link : public oasys::RefCountedObject,
+ public oasys::Logger,
+ public oasys::SerializableObject {
+public:
+ /**
+ * Valid types for a link.
+ */
+ typedef enum
+ {
+ LINK_INVALID = -1,
+
+ /**
+ * The link is expected to be ALWAYS available, and any
+ * convergence layer connection state is always maintained for
+ * it.
+ */
+ ALWAYSON = 1,
+
+ /**
+ * The link is expected to be either always available, or can
+ * be made available easily. Examples include DSL (always),
+ * and dialup (easily available). Convergence layers are free
+ * to tear down idle connection state, but are expected to be
+ * able to easily re-establish it.
+ */
+ ONDEMAND = 2,
+
+ /**
+ * The link is only available at pre-determined times.
+ */
+ SCHEDULED = 3,
+
+ /**
+ * The link may or may not be available, based on
+ * uncontrollable factors. Examples include a wireless link
+ * whose connectivity depends on the relative locations of the
+ * two nodes.
+ */
+ OPPORTUNISTIC = 4
+ }
+ link_type_t;
+
+ /**
+ * Link type string conversion.
+ */
+ static inline const char*
+ link_type_to_str(link_type_t type)
+ {
+ switch(type) {
+ case ALWAYSON: return "ALWAYSON";
+ case ONDEMAND: return "ONDEMAND";
+ case SCHEDULED: return "SCHEDULED";
+ case OPPORTUNISTIC: return "OPPORTUNISTIC";
+ default: PANIC("bogus link_type_t");
+ }
+ }
+
+ static inline link_type_t
+ str_to_link_type(const char* str)
+ {
+ if (strcasecmp(str, "ALWAYSON") == 0)
+ return ALWAYSON;
+
+ if (strcasecmp(str, "ONDEMAND") == 0)
+ return ONDEMAND;
+
+ if (strcasecmp(str, "SCHEDULED") == 0)
+ return SCHEDULED;
+
+ if (strcasecmp(str, "OPPORTUNISTIC") == 0)
+ return OPPORTUNISTIC;
+
+ return LINK_INVALID;
+ }
+
+ /**
+ * The possible states for a link. These are defined as distinct
+ * bitfield values so that various functions can match on a set of
+ * states (e.g. see ContactManager::find_link_to).
+ */
+ typedef enum {
+ UNAVAILABLE = 1,///< The link is closed and not able to be
+ /// opened currently.
+
+ AVAILABLE = 2, ///< The link is closed but is able to be
+ /// opened, either because it is an on demand
+ /// link, or because an opportunistic peer
+ /// node is in close proximity but no
+ /// convergence layer session has yet been
+ /// opened.
+
+ OPENING = 4, ///< A convergence layer session is in the
+ /// process of being established.
+
+ OPEN = 8, ///< A convergence layer session has been
+ /// established, and the link has capacity
+ /// for a bundle to be sent on it. This may
+ /// be because no bundle is currently being
+ /// sent, or because the convergence layer
+ /// can handle multiple simultaneous bundle
+ /// transmissions.
+
+ CLOSED = 16 ///< Bogus state that's never actually used in
+ /// the Link state_ variable, but is used for
+ /// signalling the daemon thread with a
+ /// LinkStateChangeRequest
+
+ } state_t;
+
+ /**
+ * Convert a link state into a string.
+ */
+ static inline const char*
+ state_to_str(state_t state)
+ {
+ switch(state) {
+ case UNAVAILABLE: return "UNAVAILABLE";
+ case AVAILABLE: return "AVAILABLE";
+ case OPENING: return "OPENING";
+ case OPEN: return "OPEN";
+ case CLOSED: return "CLOSED";
+ }
+
+ NOTREACHED;
+ }
+
+ /**
+ * Static function to create appropriate link object from link type.
+ */
+ static LinkRef create_link(const std::string& name, link_type_t type,
+ ConvergenceLayer* cl, const char* nexthop,
+ int argc, const char* argv[],
+ const char** invalid_argp = NULL);
+
+ /**
+ * Constructor / Destructor
+ */
+ Link(const std::string& name, link_type_t type,
+ ConvergenceLayer* cl, const char* nexthop);
+
+ /**
+ * Constructor for unserialization.
+ */
+ Link(const oasys::Builder& b);
+
+ /**
+ * Handle and mark deleted link.
+ */
+ virtual void delete_link();
+
+ /**
+ * Reconfigure the link parameters.
+ */
+ virtual bool reconfigure_link(int argc, const char* argv[]);
+
+ virtual void reconfigure_link(AttributeVector& params);
+
+ /**
+ * Virtual from SerializableObject
+ */
+ void serialize(oasys::SerializeAction* action);
+
+ /**
+ * Hook for subclass to parse arguments.
+ */
+ virtual int parse_args(int argc, const char* argv[],
+ const char** invalidp = NULL);
+
+ /**
+ * Hook for subclass to post events to control the initial link
+ * state, after all initialization is complete.
+ */
+ virtual void set_initial_state();
+
+ /**
+ * Return the type of the link.
+ */
+ link_type_t type() const { return static_cast<link_type_t>(type_); }
+
+ /**
+ * Return the string for of the link.
+ */
+ const char* type_str() const { return link_type_to_str(type()); }
+
+ /**
+ * Return whether or not the link is open.
+ */
+ bool isopen() const { return ( (state_ == OPEN) ); }
+
+ /**
+ * Return the availability state of the link.
+ */
+ bool isavailable() const { return (state_ != UNAVAILABLE); }
+
+ /**
+ * Return whether the link is in the process of opening.
+ */
+ bool isopening() const { return (state_ == OPENING); }
+
+ /**
+ * Returns true if the link has been deleted; otherwise returns false.
+ */
+ bool isdeleted() const;
+
+ /**
+ * Return the actual state.
+ */
+ state_t state() const { return static_cast<state_t>(state_); }
+
+ /**
+ * Sets the state of the link. Performs various assertions to
+ * ensure the state transitions are legal.
+ *
+ * This function should only ever be called by the main
+ * BundleDaemon thread and helper classes. All other threads must
+ * use a LinkStateChangeRequest event to cause changes in the link
+ * state.
+ *
+ * The function isn't protected since some callers (i.e.
+ * convergence layers) are not friend classes but some functions
+ * are run by the BundleDaemon thread.
+ */
+ void set_state(state_t state);
+
+ /**
+ * Set/get the create_pending_ flag on the link.
+ */
+ void set_create_pending(bool create_pending = true)
+ { create_pending_ = create_pending; }
+ bool is_create_pending() const { return create_pending_; }
+
+ /**
+ * Set/get the usable_ flag on the link.
+ */
+ void set_usable(bool usable = true) { usable_ = usable; }
+ bool is_usable() const { return usable_; }
+
+ /**
+ * Return the current contact information (if any).
+ */
+ const ContactRef& contact() const { return contact_; }
+
+ /**
+ * Set the contact information.
+ */
+ void set_contact(Contact* contact)
+ {
+ // XXX/demmer check this invariant
+ ASSERT(contact_ == NULL);
+ contact_ = contact;
+ }
+
+ /**
+ * Store convergence layer state associated with the link.
+ */
+ void set_cl_info(CLInfo* cl_info)
+ {
+ ASSERT((cl_info_ == NULL && cl_info != NULL) ||
+ (cl_info_ != NULL && cl_info == NULL));
+
+ cl_info_ = cl_info;
+ }
+
+ /**
+ * Accessor to the convergence layer state.
+ */
+ CLInfo* cl_info() const { return cl_info_; }
+
+ /**
+ * Store router state associated with the link.
+ */
+ void set_router_info(RouterInfo* router_info)
+ {
+ ASSERT((router_info_ == NULL && router_info != NULL) ||
+ (router_info_ != NULL && router_info == NULL));
+
+ router_info_ = router_info;
+ }
+
+ /**
+ * Accessor to the convergence layer state.
+ */
+ RouterInfo* router_info() const { return router_info_; }
+
+ /**
+ * Accessor to this contact's convergence layer.
+ */
+ ConvergenceLayer* clayer() const { return clayer_; }
+
+ /**
+ * Accessor to this links name
+ */
+ const char* name() const { return name_.c_str(); }
+
+ /**
+ * Accessor to this links name as a c++ string
+ */
+ const std::string& name_str() const { return name_; }
+
+ /**
+ * Accessor to next hop string
+ */
+ const char* nexthop() const { return nexthop_.c_str(); }
+
+ /**
+ * Accessor to next hop string
+ */
+ const std::string& nexthop_str() const { return nexthop_; }
+
+ /**
+ * Override for the next hop string.
+ */
+ void set_nexthop(const std::string& nexthop) { nexthop_.assign(nexthop); }
+
+ /**
+ * Accessor to the reliability bit.
+ */
+ bool is_reliable() const { return reliable_; }
+
+ /**
+ * Accessor to set the reliability bit when the link is created.
+ */
+ void set_reliable(bool r) { reliable_ = r; }
+
+ /**
+ * Accessor to set the remote endpoint id.
+ */
+ void set_remote_eid(const EndpointID& remote) {
+ remote_eid_.assign(remote);
+ }
+
+ /**
+ * Accessor to the remote endpoint id.
+ */
+ const EndpointID& remote_eid() { return remote_eid_; }
+
+ /**
+ * Accessor for the link's queue of bundles that are awaiting
+ * transmission.
+ */
+ const BundleList* queue() { return &queue_; }
+
+ /**
+ * Return whether or not the queue is full, based on the
+ * configured queue limits.
+ */
+ bool queue_is_full() const;
+
+ /**
+ * Return whether or not the queue has space, based on the
+ * configured queue limits.
+ */
+ bool queue_has_space() const;
+
+ /**
+ * Accessor for the link's list of bundles that have been
+ * transmitted but for which the convergence layer is awaiting
+ * acknowledgement.
+ */
+ const BundleList* inflight() { return &inflight_; }
+
+ /// @{
+ /**
+ * Accessor functions to add/remove bundles from the link queue
+ * and inflight list, keeping the statistics in-sync with the
+ * state of the lists.
+ */
+ bool add_to_queue(const BundleRef& bundle, size_t total_len);
+ bool del_from_queue(const BundleRef& bundle, size_t total_len);
+ bool add_to_inflight(const BundleRef& bundle, size_t total_len);
+ bool del_from_inflight(const BundleRef& bundle, size_t total_len);
+ /// @}
+
+ /**
+ * Virtual from formatter
+ */
+ int format(char* buf, size_t sz) const;
+
+ /**
+ * Debugging printout.
+ */
+ void dump(oasys::StringBuffer* buf);
+
+ /**************************************************************
+ * Link Parameters
+ */
+ struct Params {
+ /**
+ * Default constructor.
+ */
+ Params();
+
+ /**
+ * MTU of the link, used to control proactive fragmentation.
+ */
+ u_int mtu_;
+
+ /**
+ * Minimum amount to wait between attempts to re-open the link
+ * (in seconds).
+ *
+ * Default is set by the various Link types but can be overridden
+ * by configuration parameters.
+ */
+ u_int min_retry_interval_;
+
+ /**
+ * Maximum amount to wait between attempts to re-open the link
+ * (in seconds).
+ *
+ * Default is set by the various Link types but can be overridden
+ * by configuration parameters.
+ */
+ u_int max_retry_interval_;
+
+ /**
+ * Seconds of idle time before the link is closed. Must be
+ * zero for always on links (i.e. they are never closed).
+ *
+ * Default is 30 seconds for on demand links, zero for
+ * opportunistic links.
+ */
+ u_int idle_close_time_;
+
+ /**
+ * Conservative estimate of the maximum amount of time that
+ * the link may be down during "normal" operation. Used by
+ * routing algorithms to determine how long to leave bundles
+ * queued on the down link before rerouting them. Fefault is
+ * 30 seconds.
+ */
+ u_int potential_downtime_;
+
+ /**
+ * Whether or not to send the previous hop header on this
+ * link. Default is false.
+ */
+ bool prevhop_hdr_;
+
+ /**
+ * Abstract cost of the link, used by routing algorithms.
+ * Default is 100.
+ */
+ u_int cost_;
+
+ /** @{
+ *
+ * Configurable high / low limits on the number of
+ * bundles/bytes that should be queued on the link.
+ *
+ * The high limits are used by Link::is_queue_full() to
+ * indicate whether or not more bundles can be queued onto the
+ * link to effect backpressure from the convergence layers.
+ *
+ * The low limits can be used by the router to determine when
+ * to re-scan the pending bundle lists
+ */
+ u_int qlimit_bundles_high_;
+ u_int64_t qlimit_bytes_high_;
+ u_int qlimit_bundles_low_;
+ u_int64_t qlimit_bytes_low_;
+ /// @}
+ };
+
+ /**
+ * Seconds to wait between attempts to re-open an unavailable
+ * link. Initially set to min_retry_interval_, then doubles up to
+ * max_retry_interval_.
+ */
+ u_int retry_interval_;
+
+ /**
+ * Accessor for the parameter structure.
+ */
+ const Params& params() const { return params_; }
+ Params& params() { return params_; }
+
+ /*************************************************************
+ * Link Statistics
+ */
+ struct Stats {
+ /**
+ * Number of times the link attempted to be opened.
+ */
+ u_int contact_attempts_;
+
+ /**
+ * Number of contacts ever successfully opened on the link
+ * (equivalent to the number of times the link was open)
+ */
+ u_int contacts_;
+
+ /**
+ * Number of bundles transmitted over the link.
+ */
+ u_int bundles_transmitted_;
+
+ /**
+ * Total byte count transmitted over the link.
+ */
+ u_int bytes_transmitted_;
+
+ /**
+ * Number of bundles with cancelled transmission.
+ */
+ u_int bundles_cancelled_;
+
+ /**
+ * The total uptime of the link, not counting the current
+ * contact.
+ */
+ u_int uptime_;
+
+ /**
+ * The availablity of the link, as measured over time by the
+ * convergence layer.
+ */
+ u_int availability_;
+
+ /**
+ * The reliability of the link, as measured over time by the
+ * convergence layer. This is different from the is_reliable
+ * setting, which indicates whether the convergence layer should
+ * expect acks from the peer.
+ */
+ u_int reliability_;
+ };
+
+ /**
+ * Accessor for the stats structure.
+ */
+ Stats* stats() { return &stats_; }
+
+ /**
+ * Reset the stats.
+ */
+ void reset_stats() const
+ {
+ memset(&stats_, 0, sizeof(stats_));
+ }
+
+ /**
+ * Dump a printable version of the stats.
+ */
+ void dump_stats(oasys::StringBuffer* buf);
+
+ /// @{ Accessors for the link queue stats
+ u_int bundles_queued() { return bundles_queued_; }
+ u_int bytes_queued() { return bytes_queued_; }
+ u_int bundles_inflight() { return bundles_inflight_; }
+ u_int bytes_inflight() { return bytes_inflight_; }
+ /// @}
+
+ /**
+ * Accessor for the Link state lock.
+ */
+ oasys::Lock* lock() { return &lock_; }
+
+protected:
+ friend class BundleActions;
+ friend class BundleDaemon;
+ friend class ContactManager;
+ friend class ParamCommand;
+
+ /**
+ * Open the link. Protected to make sure only the friend
+ * components can call it and virtual to allow subclasses to
+ * override it.
+ */
+ virtual void open();
+
+ /**
+ * Close the link. Protected to make sure only the friend
+ * components can call it and virtual to allow subclasses to
+ * override it.
+ */
+ virtual void close();
+
+ /// Type of the link
+ int type_;
+
+ /// State of the link
+ u_int32_t state_;
+
+ /// Flag, that when set to true, indicates that the link has been deleted.
+ bool deleted_;
+
+ /// Flag, that when set to true, indicates that the creation of the
+ /// link is pending; the convergence layer will post a creation event
+ /// when the creation is complete. While creation is pending, the
+ /// link cannot be opened nor can bundles be queued for it.
+ bool create_pending_;
+
+ /// Flag, that when set to true, indicates that the link is allowed
+ /// to be used to transmit bundles.
+ bool usable_;
+
+ /// Next hop address
+ std::string nexthop_;
+
+ /// Internal name of the link
+ std::string name_;
+
+ /// Whether or not this link is reliable
+ bool reliable_;
+
+ /// Parameters of the link
+ Params params_;
+
+ /// Default parameters of the link
+ static Params default_params_;
+
+ /// Lock to protect internal data structures and state.
+ oasys::SpinLock lock_;
+
+ /// Queue of bundles currently active or pending transmission on the Link
+ BundleList queue_;
+
+ /// Queue of bundles that have been sent but not yet acknowledged
+ BundleList inflight_;
+
+ /** @{
+ *
+ * Data counters about the link queues, both in terms of bundles
+ * and bytes.
+ *
+ * *_queued: the link queue size
+ * *_inflight: transmitted but not yet acknowledged
+ */
+ u_int bundles_queued_;
+ u_int bytes_queued_;
+ u_int bundles_inflight_;
+ u_int bytes_inflight_;
+ /** @} */
+
+ /// Stats for the link
+ mutable Stats stats_;
+
+ /// Current contact. contact_ != null iff link is open
+ ContactRef contact_;
+
+ /// Pointer to convergence layer
+ ConvergenceLayer* clayer_;
+
+ /// Convergence layer specific info, if needed
+ CLInfo* cl_info_;
+
+ /// Router specific info, if needed
+ RouterInfo* router_info_;
+
+ /// Remote's endpoint ID (eg, dtn://hostname.dtn)
+ EndpointID remote_eid_;
+
+ /// Destructor -- protected since links shouldn't be deleted
+ virtual ~Link();
+};
+
+} // namespace dtn
+
+#endif /* _LINK_H_ */