servlib/prophet/Encounter.h
changeset 0 2b3e5ec03512
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlib/prophet/Encounter.h	Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,196 @@
+/*
+ *    Copyright 2007 Baylor University
+ * 
+ *    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 _PROPHET_ENCOUNTER_H_
+#define _PROPHET_ENCOUNTER_H_
+
+#include "Link.h"
+#include "BaseTLV.h"
+#include "HelloTLV.h"
+#include "ProphetTLV.h"
+#include "Oracle.h"
+#include "Table.h"
+#include "Dictionary.h"
+#include "BundleTLVEntryList.h"
+#include "Alarm.h"
+
+namespace prophet
+{
+
+/**
+ * Section 4.4.4, p. 28
+ * The Routing Information Base lists the destinations a node knows of,
+ * and the delivery predictabilities it has associated with them.  This
+ * information is needed by the PRoPHET algorithm to make decisions on
+ * routing and forwarding.
+ *
+ * Section 4.4.3, p. 27
+ * The Routing Information Base Dictionary includes the list of addresses
+ * used in making routing decisions.  The referents remain constant for
+ * the duration of a session over a link where the instance numbers remain
+ * the same and can be used by both the Routing Information Base messages
+ * and the bundle offer messages.
+ *
+ * Track the state for the Prophet protocol throughout the duration of
+ * this encounter between the local node and this remote.
+ */
+class Encounter : public ExpirationHandler
+{
+public:
+    typedef enum {
+        UNDEFINED_STATE = 0,
+        WAIT_NB,    ///< Waiting for Neighbor
+        SYNSENT,    ///< Sent SYN, waiting for SYNACK
+        SYNRCVD,    ///< Received SYN, sent SYNACK, waiting for ACK
+        ESTAB,      ///< Prophet link established with remote
+        WAIT_DICT,  ///< Listener mode of bundle-passing phase
+        WAIT_RIB,   ///< Listener rcvd RIBD, waiting for RIB
+        OFFER,      ///< Listener sent Offer, waiting for Request
+        CREATE_DR,  ///< Initiator creates and sends RIBD and RIB
+        SEND_DR,    ///< Initiator sent RIBD and RIB, waiting for Offer
+        REQUEST,    ///< Initiator sent Request, waiting for Bundles
+        WAIT_INFO   ///< All phases now complete, waiting for timer or ACK
+    } state_t;
+
+    static const char* state_to_str(state_t st) {
+        switch(st) {
+#define CASE(_state) case _state: return # _state
+        CASE(WAIT_NB);
+        CASE(SYNSENT);
+        CASE(SYNRCVD);
+        CASE(ESTAB);
+        CASE(WAIT_DICT);
+        CASE(WAIT_RIB);
+        CASE(OFFER);
+        CASE(CREATE_DR);
+        CASE(SEND_DR);
+        CASE(REQUEST);
+        CASE(WAIT_INFO);
+#undef CASE
+        default: return "Unknown State";
+        }
+    }
+    /**
+     * Constructor
+     */
+    Encounter(const Link* nexthop, Oracle* oracle, u_int16_t instance);
+
+    /**
+     * Copy constructor
+     */
+    Encounter(const Encounter& e);
+
+    /**
+     * Destructor
+     */
+    ~Encounter();
+
+    ///@{ Operators
+    bool operator< (const Encounter& e) const
+    {
+        return remote_instance_ < e.remote_instance_;
+    }
+    ///@}
+
+    ///@{ Accessors
+    u_int16_t   remote_instance() const { return remote_instance_; }
+    u_int16_t   local_instance() const { return local_instance_; }
+    const char* remote_eid() const { return next_hop_->remote_eid(); }
+    const Link* nexthop() const { return next_hop_; }
+    state_t     state() const { return state_; }
+    const char* state_str() const { return state_to_str(state_); }
+    bool        neighbor_gone() const { return neighbor_gone_; }
+    u_int       time_remaining() const { return alarm_->time_remaining(); }
+    ///@}
+
+    /**
+     * Callback to inform this instance that the hello_interval
+     * parameter has changed
+     */
+    void hello_interval_changed();
+
+    /**
+     * Callback for this instance to receive TLVs received from peer
+     * by the host bundling system. Encounter assumes ownership of
+     * memory pointed to by tlv. Return true if message processed 
+     * successfully.  Return false upon fault (peering session died).
+     */
+    bool receive_tlv(ProphetTLV* tlv);
+
+    /**
+     * Callback for timeout handler, either due to peer failure or
+     * unacceptable delay in messaging
+     */
+    void handle_timeout();
+
+    /**
+     * Callback for tracking which Bundle requests are outstanding 
+     */
+    void handle_bundle_received(const Bundle* b);
+
+protected:
+
+    ///@{ TLV event handlers
+    bool dispatch_tlv(BaseTLV* tlv);
+    bool handle_hello_tlv(BaseTLV* hello);
+    bool handle_ribd_tlv(BaseTLV* ribd);
+    bool handle_rib_tlv(BaseTLV* rib);
+    bool handle_offer_tlv(BaseTLV* offer);
+    bool handle_response_tlv(BaseTLV* response);
+    ///@}
+
+    ///@{ Outbound message generators
+    bool send_hello(HelloTLV::hello_hf_t hf,
+                    ProphetTLV::header_result_t hr = ProphetTLV::NoSuccessAck,
+                    u_int32_t tid = 0);
+    bool send_dictionary_rib(ProphetTLV::header_result_t hr =
+                                                    ProphetTLV::NoSuccessAck,
+                             u_int32_t tid = 0);
+    bool send_offer(ProphetTLV::header_result_t hr = ProphetTLV::NoSuccessAck,
+                    u_int32_t tid = 0);
+    bool send_response(ProphetTLV::header_result_t hr =
+                                                     ProphetTLV::NoSuccessAck,
+                       u_int32_t tid = 0);
+    bool send_tlv(ProphetTLV* tlv);
+    ///@}
+
+    Oracle* const oracle_; ///< collection of Prophet information
+    u_int16_t local_instance_; ///< local's instance for remote
+    u_int16_t remote_instance_; ///< remote's instance for local 
+    u_int32_t tid_; ///< transaction id from peer's most recent TLV
+    u_int32_t next_tid_; ///< used to generate TID for outbound TLVs
+    u_int32_t timeout_; ///< most milliseconds expected between TLVs
+    const Link* next_hop_; ///< Link object for this encounter
+    ProphetTLV* tlv_; ///< most recent message received from peer
+    const bool synsender_; ///< whether active or passive during Hello phase
+    state_t state_; ///< which phase of Prophet protocol for this end
+    bool synsent_; ///< whether hello phase has sent SYN or SYNACK
+    bool estab_; ///< whether hello phase has been completed
+    volatile bool neighbor_gone_; ///< whether session has died
+    Dictionary local_ribd_; ///< 16 bit index lookup to translate routes
+    Dictionary remote_ribd_; ///< 16 bit index lookup for remote's routes
+    BundleOfferList remote_offers_; ///< in-memory rep of remote's offer
+    BundleResponseList local_response_; ///< Bundle requests sent to peer
+    Table remote_nodes_; ///< in-memory representation of remote's RIB
+    u_int hello_rate_; ///< simple flow control for Hello messages (ACK, etc)
+    u_int32_t data_sent_; ///< timestamp of last TLV sent
+    u_int32_t data_rcvd_; ///< timestamp of last TLV received
+    Alarm* alarm_; ///< callback registration for timeout handler
+}; // class Encounter
+
+}; // namespace prophet
+
+#endif // _PROPHET_ENCOUNTER_H_