servlib/bundling/BPQCacheEntry.cc
changeset 57 bb780f1beb9b
child 58 574358af597b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlib/bundling/BPQCacheEntry.cc	Wed Oct 05 13:57:27 2011 +0100
@@ -0,0 +1,160 @@
+/*
+ *    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.
+ */
+
+#include "BPQCacheEntry.h"
+#include "BPQBlock.h"
+
+namespace dtn {
+
+int
+BPQCacheEntry::add_response(Bundle* bundle)
+{
+	if ( ! bundle->is_fragment() ) {
+		log_debug("add complete response to cache entry");
+		bundle_ = bundle;
+		is_complete_ = true;
+
+	} else if ( bundle->is_fragment() && ! is_complete_ ) {
+		log_debug("add response fragment to cache entry");
+		fragments_.insert_sorted(bundle, BundleList::SORT_FRAG_OFFSET);
+		is_complete_ = check_complete();
+
+	} else if ( bundle->is_fragment() && is_complete_ ) {
+		log_debug("ignoring response fragment as cache entry is complete");
+
+	}
+
+	return BP_SUCCESS;
+}
+
+//----------------------------------------------------------------------
+int
+BPQCacheEntry::reassemble_fragments(){
+	//TODO: implement this
+	NOTIMPLEMENTED;
+	return BP_FAIL;
+}
+
+//----------------------------------------------------------------------
+bool
+BPQCacheEntry::check_complete() const
+{
+    Bundle* fragment;
+    BundleList::iterator iter;
+    oasys::ScopeLock l(fragments_.lock(),
+                       "BPQCacheEntry::check_complete");
+
+    size_t done_up_to = 0;  // running total of completed reassembly
+    size_t f_len;
+    size_t f_offset;
+    size_t f_origlen;
+
+    size_t total_len = bundle_->payload().length();
+
+    int fragi = 0;
+    int fragn = fragments_.size();
+    (void)fragn; // in case NDEBUG is defined
+
+    for (iter = fragments_.begin();
+         iter != fragments_.end();
+         ++iter, ++fragi)
+    {
+        fragment = *iter;
+
+        f_len = fragment->payload().length();
+        f_offset = fragment->frag_offset();
+        f_origlen = fragment->orig_length();
+
+        ASSERT(fragment->is_fragment());
+
+        if (f_origlen != total_len) {
+            PANIC("check_completed: error fragment orig len %zu != total %zu",
+                  f_origlen, total_len);
+            // XXX/demmer deal with this
+        }
+
+        if (done_up_to == f_offset) {
+            /*
+             * fragment is adjacent to the bytes so far
+             * bbbbbbbbbb
+             *           fff
+             */
+            log_debug("check_completed fragment %d/%d: "
+                      "offset %zu len %zu total %zu done_up_to %zu: "
+                      "(perfect fit)",
+                      fragi, fragn, f_offset, f_len, f_origlen, done_up_to);
+            done_up_to += f_len;
+        }
+
+        else if (done_up_to < f_offset) {
+            /*
+             * there's a gap
+             * bbbbbbb ffff
+             */
+            log_debug("check_completed fragment %d/%d: "
+                      "offset %zu len %zu total %zu done_up_to %zu: "
+                      "(found a hole)",
+                      fragi, fragn, f_offset, f_len, f_origlen, done_up_to);
+            return false;
+
+        }
+
+        else if (done_up_to > (f_offset + f_len)) {
+            /* fragment is completely redundant, skip
+             * bbbbbbbbbb
+             *      fffff
+             */
+            log_debug("check_completed fragment %d/%d: "
+                      "offset %zu len %zu total %zu done_up_to %zu: "
+                      "(redundant fragment)",
+                      fragi, fragn, f_offset, f_len, f_origlen, done_up_to);
+            continue;
+        }
+
+        else if (done_up_to > f_offset) {
+            /*
+             * there's some overlap, so reduce f_len accordingly
+             * bbbbbbbbbb
+             *      fffffff
+             */
+            log_debug("check_completed fragment %d/%d: "
+                      "offset %zu len %zu total %zu done_up_to %zu: "
+                      "(overlapping fragment, reducing len to %zu)",
+                      fragi, fragn, f_offset, f_len, f_origlen, done_up_to,
+                      (f_len - (done_up_to - f_offset)));
+
+            f_len -= (done_up_to - f_offset);
+            done_up_to += f_len;
+        }
+
+        else {
+            // all cases should be covered above
+            NOTREACHED;
+        }
+    }
+
+    if (done_up_to == total_len) {
+        log_debug("check_completed reassembly complete!");
+        return true;
+    } else {
+        log_debug("check_completed reassembly not done (got %zu/%zu)",
+                  done_up_to, total_len);
+        return false;
+    }
+}
+
+
+} // namespace dtn