servlib/contacts/Link.h
changeset 0 2b3e5ec03512
--- /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_ */