瀏覽代碼

Fix packet buffer enqueue logic error

The size of the contiguous window should be prioritized over the size of
the contiguous window if padding were added.

For example, given the following packet buffer:

  1   2     3
|---|----|------|

If 2 is used and 1 and 3 are empty, enqueing a buffer of size 4 should
be placed in contiguous window 3 and the size of 1 should not cause
any issues in enqueue.

Closes: #247
Approved by: whitequark
Dan Robertson 6 年之前
父節點
當前提交
682fc30782
共有 1 個文件被更改,包括 22 次插入6 次删除
  1. 22 6
      src/storage/packet_buffer.rs

+ 22 - 6
src/storage/packet_buffer.rs

@@ -84,13 +84,21 @@ impl<'a, 'b, H> PacketBuffer<'a, 'b, H> {
         let window = self.payload_ring.window();
         let contig_window = self.payload_ring.contiguous_window();
 
-        if window < size || (window != contig_window && window - contig_window < size) {
+        if window < size {
             return Err(Error::Exhausted)
-        }
-
-        if contig_window < size {
-            *self.metadata_ring.enqueue_one()? = PacketMetadata::padding(size);
-            self.payload_ring.enqueue_many(size);
+        } else if contig_window < size {
+            if window - contig_window < size {
+                // The buffer length is larger than the current contiguous window
+                // and is larger than the contiguous window will be after adding
+                // the padding necessary to circle around to the beginning of the
+                // ring buffer.
+                return Err(Error::Exhausted)
+            } else {
+                // Add padding to the end of the ring buffer so that the
+                // contiguous window is at the beginning of the ring buffer.
+                *self.metadata_ring.enqueue_one()? = PacketMetadata::padding(size);
+                self.payload_ring.enqueue_many(size);
+            }
         }
 
         *self.metadata_ring.enqueue_one()? = PacketMetadata::packet(size, header);
@@ -244,4 +252,12 @@ mod test {
         let mut buffer = buffer();
         assert_eq!(buffer.enqueue(32, ()), Err(Error::Truncated));
     }
+
+    #[test]
+    fn test_contig_window_prioritized() {
+        let mut buffer = buffer();
+        assert!(buffer.enqueue(4, ()).is_ok());
+        assert!(buffer.dequeue().is_ok());
+        assert!(buffer.enqueue(5, ()).is_ok());
+    }
 }