servlib/prophet/TLVCreator.h
changeset 0 2b3e5ec03512
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlib/prophet/TLVCreator.h	Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,230 @@
+/*
+ *    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_TLV_CREATOR_H_
+#define _PROPHET_TLV_CREATOR_H_
+
+#include "Table.h"
+#include "BundleCore.h"
+#include "BundleList.h"
+#include "Dictionary.h"
+#include "RIBDTLV.h"
+#include "RIBTLV.h"
+#include "OfferTLV.h"
+#include "BundleTLVEntryList.h"
+#include "BundleOffer.h"
+#include "Oracle.h"
+#include <string>
+
+namespace prophet
+{
+
+struct TLVCreator
+{
+    static RIBDTLV* ribd(BundleCore* core,
+                         const Table* nodes,
+                         const std::string& sender,
+                         const std::string& receiver)
+    {
+        // reject the oddball
+        if (core == NULL || nodes == NULL) return NULL;
+
+        Dictionary ribd(sender,receiver);
+        for (Table::const_iterator i = nodes->begin(); i != nodes->end(); i++)
+        {
+            // grab the route from the iterator
+            std::string dest = i->first;
+            std::string eid = core->get_route(dest);
+            // attempt to insert, fail out if unsuccessful
+            if (ribd.insert(eid) == Dictionary::INVALID_SID &&
+                ribd.find(eid) == Dictionary::INVALID_SID) return NULL;
+        }
+
+        ribd.dump(core,__FILE__,__LINE__);
+        return new RIBDTLV(ribd);
+    }
+
+    static RIBTLV* rib(Oracle* oracle,
+                       const Dictionary& ribd,
+                       bool relay_node,
+                       bool accept_custody,
+                       bool internet_gw = false)
+    {
+        // reject the oddball
+        if (oracle == NULL) return NULL;
+
+        const Table* nodes = oracle->nodes();
+        std::string sender = ribd.find(0);
+        std::string receiver = ribd.find(1);
+
+        RIBNodeList list;
+        for (Table::const_iterator i = nodes->begin(); i != nodes->end(); i++)
+        {
+            const std::string eid = i->first;
+            if (eid == sender || eid == receiver) continue;
+            const Node* n = i->second;
+            u_int16_t sid = ribd.find(eid);
+            if (sid == Dictionary::INVALID_SID)
+                return NULL; // log error?
+            oracle->core()->print_log("rib",BundleCore::LOG_DEBUG,
+                    "%s (%u) -> %.2f",eid.c_str(),sid,n->p_value());
+            list.push_back(new RIBNode(n,sid));
+        }
+
+        ribd.dump(oracle->core(),__FILE__,__LINE__);
+        return new RIBTLV(list,relay_node,accept_custody,internet_gw);
+    }
+
+    static OfferTLV* offer(Oracle* oracle,
+                           const Link* nexthop,
+                           const Dictionary& ribd,
+                           const Table& remote)
+    {
+        // reject the oddball
+        if (oracle == NULL) return NULL;
+
+        // create comp
+        FwdStrategyComp* comp = FwdStrategy::strategy(
+                oracle->params()->fs(),
+                oracle->nodes(),
+                &remote);
+
+        // create decider
+        Decider* d = Decider::decider(
+                oracle->params()->fs(),
+                nexthop,
+                oracle->core(),
+                oracle->nodes(),
+                &remote,
+                oracle->stats(),
+                oracle->params()->max_forward(),
+                oracle->params()->relay_node());
+
+        // offer's destructor will clean up comp and d
+        BundleOffer offer(oracle->core(),oracle->core()->bundles(),comp,d);
+
+        // Create a reduced list of ACKs by only tacking on those that 
+        // haven't already been sent
+
+        PointerList<Ack> acklist; // list of clones from oracle's ACKs
+        AckList acks; // reduced list to send to get_bundle_offer
+        AckList* link_acks = const_cast<Link*>(nexthop)->acks();
+
+        oracle->acks()->clone(acklist);
+        for(PointerList<Ack>::iterator i = acklist.begin();
+                i != acklist.end(); i++)
+        {
+            // returns false if already exists in list (meaning, already sent)
+            if (link_acks->insert(*i))
+                acks.insert(*i);
+        }
+
+        BundleOfferList list = offer.get_bundle_offer(ribd,&acks);
+        
+        if (list.empty())
+            oracle->core()->print_log("offer",BundleCore::LOG_DEBUG,
+                    "empty bundle offer");
+        else
+        {
+            for (BundleOfferList::const_iterator i = list.begin(); 
+                    i != list.end(); i++)
+            {
+                oracle->core()->print_log("offer",BundleCore::LOG_DEBUG,
+                        "%u %u %u %s%s%s",
+                        (*i)->creation_ts(),
+                        (*i)->seqno(),
+                        (*i)->sid(),
+                        (*i)->custody() ? "C" : "-",
+                        (*i)->accept() ? "A" : "-",
+                        (*i)->ack() ? "K" : "-");
+            }
+        }
+
+        return new OfferTLV(list);
+    }
+
+    static ResponseTLV* response(Oracle* oracle,
+                                 const BundleOfferList& offers,
+                                 BundleResponseList& list,
+                                 const Dictionary& ribd)
+    {
+        // reject the oddball
+        if (oracle == NULL) return NULL;
+
+        ribd.dump(oracle->core(),__FILE__,__LINE__);
+
+        for (BundleOfferList::const_iterator i = offers.begin();
+                i != offers.end(); i++)
+        {
+            // pull out the three-way tuple that uniquely identifies bundles
+            u_int32_t cts = (*i)->creation_ts();
+            u_int32_t seq = (*i)->seqno();
+            u_int16_t sid = (*i)->sid();
+            std::string eid = ribd.find(sid);
+
+            // First delete any ACK'd bundles, and store the ACK
+            const Bundle* b = oracle->core()->find(
+                    oracle->core()->bundles(),eid,cts,seq);
+            if ((*i)->ack())
+            {
+                oracle->core()->print_log("response",BundleCore::LOG_DEBUG,
+                        "ACK %s %u:%u",eid.c_str(),cts,seq);
+
+                if (b != NULL)
+                    oracle->ack(b);
+                else
+                    oracle->acks()->insert(eid,cts,seq);
+
+                // also remember that it came from this link, so as not 
+                // to propagate this ACK over this link again
+
+            }
+            else
+            // only request the bundle if not already present in host storage
+            // and if no ACK exists for the bundle
+            if (b == NULL)
+            {
+                // no need to request bundles that have already been delivered
+                if (oracle->acks()->is_ackd(eid,cts,seq))
+                {
+                    oracle->core()->print_log("response",BundleCore::LOG_DEBUG,
+                        "not requesting ACK'd bundle: %s %u %u",
+                        eid.c_str(),cts,seq);
+                    continue;
+                }
+
+                // Logically AND local settings for custody accept with
+                // remote's request for custody transfer
+                bool custody = (*i)->custody() &&
+                               oracle->core()->custody_accepted();
+                if (list.add_response(cts,seq,sid,custody))
+                {
+                    const BundleResponseEntry* bre = list.back();
+                    oracle->core()->print_log("response",BundleCore::LOG_DEBUG,
+                        "%s (%u) %u %u",eid.c_str(),bre->sid(),
+                        bre->creation_ts(),bre->seqno());
+                }
+            }
+        }
+
+        return new ResponseTLV(list);
+    }
+
+}; // struct TLVCreator
+
+}; // namespace prophet
+
+#endif // _PROPHET_TLV_CREATOR_H_