servlib/routing/BundleRouter.cc
changeset 0 2b3e5ec03512
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlib/routing/BundleRouter.cc	Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,263 @@
+/*
+ *    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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <dtn-config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "BundleRouter.h"
+#include "bundling/BundleDaemon.h"
+#include "bundling/BundleActions.h"
+#include "bundling/BundleList.h"
+#include "storage/BundleStore.h"
+
+#include "StaticBundleRouter.h"
+#include "FloodBundleRouter.h"
+#include "ProphetRouter.h"
+#include "DTLSRRouter.h"
+#include "ExternalRouter.h"
+#include "TcaRouter.h"
+
+namespace dtn {
+
+//----------------------------------------------------------------------
+BundleRouter::Config::Config()
+    : type_("static"),
+      add_nexthop_routes_(true),
+      open_discovered_links_(true),
+      default_priority_(0),
+      max_route_to_chain_(10),
+      storage_quota_(0),
+      subscription_timeout_(600)
+{}
+
+BundleRouter::Config BundleRouter::config_;
+
+//----------------------------------------------------------------------
+BundleRouter*
+BundleRouter::create_router(const char* type)
+{
+    if (strcmp(type, "static") == 0) {
+        return new StaticBundleRouter();
+    }
+    else if (strcmp(type, "prophet") == 0) {
+        return new ProphetRouter();
+    }
+    else if (strcmp(type, "flood") == 0) {
+        return new FloodBundleRouter();
+    }
+    else if (strcmp(type, "dtlsr") == 0) {
+        return new DTLSRRouter();
+    }    
+    else if (!strcmp(type, "tca_router")) {
+        return new TcaRouter(TcaRouter::TCA_ROUTER);
+    }
+    else if (!strcmp(type, "tca_gateway")) {
+        return new TcaRouter(TcaRouter::TCA_GATEWAY);
+    }
+#if defined(XERCES_C_ENABLED) && defined(EXTERNAL_DP_ENABLED)
+    else if (strcmp(type, "external") == 0) {
+        return new ExternalRouter();
+    }    
+#endif
+    else {
+        PANIC("unknown type %s for router", type);
+    }
+}
+
+//----------------------------------------------------------------------
+BundleRouter::BundleRouter(const char* classname, const std::string& name)
+    : BundleEventHandler(classname, "/dtn/route"),
+      name_(name)
+{
+    logpathf("/dtn/route/%s", name.c_str());
+    
+    actions_ = BundleDaemon::instance()->actions();
+    
+    // XXX/demmer maybe change this?
+    pending_bundles_ = BundleDaemon::instance()->pending_bundles();
+    custody_bundles_ = BundleDaemon::instance()->custody_bundles();
+}
+
+//----------------------------------------------------------------------
+bool
+BundleRouter::should_fwd(const Bundle* bundle, const LinkRef& link,
+                         ForwardingInfo::action_t action)
+{
+    ForwardingInfo info;
+    bool found = bundle->fwdlog()->get_latest_entry(link, &info);
+
+    if (found) {
+        ASSERT(info.state() != ForwardingInfo::NONE);
+    } else {
+        ASSERT(info.state() == ForwardingInfo::NONE);
+    }
+
+    // check if we've already sent or are in the process of sending
+    // the bundle on this link
+    if (info.state() == ForwardingInfo::TRANSMITTED ||
+        info.state() == ForwardingInfo::QUEUED)
+    {
+        log_debug("should_fwd bundle %d: "
+                  "skip %s due to forwarding log entry %s",
+                  bundle->bundleid(), link->name(),
+                  ForwardingInfo::state_to_str(info.state()));
+        return false;
+    }
+
+    // check if we've already sent or are in the process of sending
+    // the bundle to the node via some other link
+    if (link->remote_eid() != EndpointID::NULL_EID())
+    {
+        size_t count = bundle->fwdlog()->get_count(
+            link->remote_eid(),
+            ForwardingInfo::TRANSMITTED | ForwardingInfo::QUEUED);
+        
+        if (count > 0)
+        {
+            log_debug("should_fwd bundle %d: "
+                      "skip %s since already sent or queued %zu times for remote eid %s",
+                      bundle->bundleid(), link->name(),
+                      count, link->remote_eid().c_str());
+            return false;
+        }
+
+        // check whether transmission was suppressed. this could be
+        // coupled with the previous one but it's better to have a
+        // separate log message
+        count = bundle->fwdlog()->get_count(
+            link->remote_eid(),
+            ForwardingInfo::SUPPRESSED);
+        
+        if (count > 0)
+        {
+            log_debug("should_fwd bundle %d: "
+                      "skip %s since transmission suppressed to remote eid %s",
+                      bundle->bundleid(), link->name(),
+                      link->remote_eid().c_str());
+            return false;
+        }
+    }
+    
+    // if the bundle has a a singleton destination endpoint, then
+    // check if we already forwarded it or are planning to forward it
+    // somewhere else. if so, we shouldn't forward it again
+    if (bundle->singleton_dest() && action == ForwardingInfo::FORWARD_ACTION)
+    {
+        size_t count = bundle->fwdlog()->get_count(
+            ForwardingInfo::TRANSMITTED |
+            ForwardingInfo::QUEUED,
+            action);
+
+        if (count > 0) {
+            log_debug("should_fwd bundle %d: "
+                      "skip %s since already transmitted or queued (count %zu)",
+                      bundle->bundleid(), link->name(), count);
+            return false;
+        } else {
+            log_debug("should_fwd bundle %d: "
+                      "link %s ok since transmission count=%zu",
+                      bundle->bundleid(), link->name(), count);
+        }
+    }
+
+    // otherwise log the reason why we should send it
+    log_debug("should_fwd bundle %d: "
+              "match %s: forwarding log entry %s",
+              bundle->bundleid(), link->name(),
+              ForwardingInfo::state_to_str(info.state()));
+
+    return true;
+}
+
+//----------------------------------------------------------------------
+void
+BundleRouter::initialize()
+{
+}
+
+//----------------------------------------------------------------------
+BundleRouter::~BundleRouter()
+{
+}
+
+//----------------------------------------------------------------------
+bool
+BundleRouter::accept_bundle(Bundle* bundle, int* errp)
+{
+    // XXX/demmer this decision should be abstracted into a
+    // StoragePolicy class of some sort. for now just use a
+    // statically-configured payload limit
+    BundleStore* bs = BundleStore::instance();
+    if (bs->payload_quota() != 0 &&
+        (bs->total_size() + bundle->payload().length() > bs->payload_quota()))
+    {
+        log_info("accept_bundle: rejecting bundle *%p since "
+                 "cur size %llu + bundle size %zu > quota %llu",
+                 bundle, U64FMT(bs->total_size()), bundle->payload().length(),
+                 U64FMT(bs->payload_quota()));
+        *errp = BundleProtocol::REASON_DEPLETED_STORAGE;
+        return false;
+    } 
+
+    *errp = 0;
+    return true;
+}
+
+//----------------------------------------------------------------------
+bool
+BundleRouter::can_delete_bundle(const BundleRef& bundle)
+{
+    size_t num_mappings = bundle->num_mappings();
+    if (num_mappings > 1) {
+        log_debug("can_delete_bundle(*%p): not deleting because "
+                  "bundle has %zu list mappings",
+                  bundle.object(), num_mappings);
+        return false;
+    }
+    
+    return true;
+}
+
+//----------------------------------------------------------------------
+void
+BundleRouter::delete_bundle(const BundleRef& bundle)
+{
+    (void)bundle;
+}
+
+//----------------------------------------------------------------------
+void
+BundleRouter::tcl_dump_state(oasys::StringBuffer* buf)
+{
+    buf->append("{}");
+}
+
+//----------------------------------------------------------------------
+void
+BundleRouter::recompute_routes()
+{
+}
+
+//----------------------------------------------------------------------
+void
+BundleRouter::shutdown()
+{
+}
+
+} // namespace dtn