[tor-commits] [stegotorus/master] Break up chop.cc in preparation for adding more control blocks.

zwol at torproject.org zwol at torproject.org
Fri Jul 20 23:17:08 UTC 2012


commit 17a1e39d73c4767bdc4c6a89a30b5378a4f0a0b9
Author: Zack Weinberg <zackw at cmu.edu>
Date:   Sun Jul 8 18:39:39 2012 +0200

    Break up chop.cc in preparation for adding more control blocks.
    
    All of the header formatting code and the reassembly queue move to their
    own file.  Some of the low-level transmission and reception code may follow.
    This will make it easier to add new types of control blocks (for retransmit,
    in-band connection close, the long-awaited rekeying and handshake logic, etc)
    and will also make it possible to unit test the separated code.
---
 Makefile.am              |    2 +
 src/protocol/chop.cc     |  292 +---------------------------------------------
 src/protocol/chop_blk.cc |  104 ++++++++++++++++
 src/protocol/chop_blk.h  |  247 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 358 insertions(+), 287 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 174e09c..b449619 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,6 +14,7 @@ bin_PROGRAMS     = stegotorus
 
 PROTOCOLS = \
 	src/protocol/chop.cc \
+	src/protocol/chop_blk.cc \
 	src/protocol/null.cc
 
 STEGANOGRAPHERS = \
@@ -78,6 +79,7 @@ noinst_HEADERS = \
 	src/socks.h \
 	src/steg.h \
 	src/util.h \
+	src/protocol/chop_blk.h \
 	src/test/tinytest.h \
 	src/test/tinytest_macros.h \
 	src/test/unittest.h
diff --git a/src/protocol/chop.cc b/src/protocol/chop.cc
index 9109295..9e3a605 100644
--- a/src/protocol/chop.cc
+++ b/src/protocol/chop.cc
@@ -1,10 +1,10 @@
-/* Copyright 2011, SRI International
+/* Copyright 2011, 2012 SRI International
  * See LICENSE for other credits and copying information
  */
 
 #include "util.h"
+#include "chop_blk.h"
 #include "connections.h"
-#include "crypt.h"
 #include "protocol.h"
 #include "rng.h"
 #include "steg.h"
@@ -14,7 +14,6 @@
 #include <vector>
 
 #include <event2/event.h>
-#include <event2/buffer.h>
 
 /* The chopper is the core StegoTorus protocol implementation.
    For its design, see doc/chopper.txt.  Note that it is still
@@ -25,286 +24,7 @@ using std::tr1::unordered_set;
 using std::vector;
 using std::make_pair;
 
-namespace
-{
-
-/* Packets on the wire have a 16-byte header, consisting of a 32-bit
-   sequence number, two 16-bit length fields ("D" and "P"), an 8-bit
-   opcode ("F"), and a 56-bit check field.  All numbers in this header
-   are serialized in network byte order.
-
-   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
-   |Sequence Number|   D   |   P   | F |           Check           |
-
-   The header is encrypted with AES in ECB mode: this is safe because
-   the header is exactly one AES block long, the sequence number is
-   never repeated, the header-encryption key is not used for anything
-   else, and the high 24 bits of the sequence number, plus the check
-   field, constitute an 80-bit MAC.  The receiver maintains a
-   256-element sliding window of acceptable sequence numbers, which
-   begins one after the highest sequence number so far _processed_
-   (not received).  If the sequence number is outside this window, or
-   the check field is not all-bits-zero, the packet is discarded.  An
-   attacker's odds of being able to manipulate the D, P, or F fields
-   or the low bits of the sequence number are therefore less than one
-   in 2^80.  Unlike TCP, our sequence numbers always start at zero on
-   a new (or freshly rekeyed) circuit, and increment by one per
-   _block_, not per byte of data.  Furthermore, they do not wrap: a
-   rekeying cycle (which resets the sequence number) is required to
-   occur before the highest-received sequence number reaches 2^32.
-
-   Following the header are two variable-length payload sections,
-   "data" and "padding", whose length in bytes are given by the D and
-   P fields, respectively.  These sections are encrypted, using a
-   different key, with AES in GCM mode.  The *encrypted* packet header
-   doubles as the GCM nonce.  The semantics of the "data" section's
-   contents, if any, are defined by the opcode F.  The "padding"
-   section SHOULD be filled with zeroes by the sender; regardless, its
-   contents MUST be ignored by the receiver.  Following these sections
-   is a 16-byte GCM authentication tag, computed over the data and
-   padding sections only, NOT the message header.  */
-
-const size_t HEADER_LEN = 16;
-const size_t TRAILER_LEN = 16;
-const size_t SECTION_LEN = UINT16_MAX;
-const size_t MIN_BLOCK_SIZE = HEADER_LEN + TRAILER_LEN;
-const size_t MAX_BLOCK_SIZE = MIN_BLOCK_SIZE + SECTION_LEN*2;
-
-const size_t HANDSHAKE_LEN = sizeof(uint32_t);
-
-enum opcode_t
-{
-  op_DAT = 0,       // Pass data section along to upstream
-  op_FIN = 1,       // No further transmissions (pass data along if any)
-  op_RST = 2,       // Protocol error, close circuit now
-  op_RESERVED0 = 3, // 3 -- 127 reserved for future definition
-  op_STEG0 = 128,   // 128 -- 255 reserved for steganography modules
-  op_LAST = 255
-};
-
-static const char *
-opname(opcode_t o, char fallbackbuf[4])
-{
-  switch (o) {
-  case op_DAT: return "DAT";
-  case op_FIN: return "FIN";
-  case op_RST: return "RST";
-  default: {
-    unsigned int x = o;
-    if (x < op_STEG0)
-      xsnprintf(fallbackbuf, sizeof fallbackbuf, "R%02x", x);
-    else
-      xsnprintf(fallbackbuf, sizeof fallbackbuf, "S%02x", x - op_STEG0);
-    return fallbackbuf;
-  }
-  }
-}
-
-class block_header
-{
-  uint8_t clear[16];
-  uint8_t ciphr[16];
-
-public:
-  block_header(uint32_t s, uint16_t d, uint16_t p, opcode_t f,
-               ecb_encryptor &ec)
-  {
-    if (f > op_LAST || (f >= op_RESERVED0 && f < op_STEG0)) {
-      memset(clear, 0xFF, sizeof clear); // invalid!
-      memset(ciphr, 0xFF, sizeof ciphr);
-      return;
-    }
-
-    // sequence number
-    clear[0] = (s >> 24) & 0xFF;
-    clear[1] = (s >> 16) & 0xFF;
-    clear[2] = (s >>  8) & 0xFF;
-    clear[3] = (s      ) & 0xFF;
-
-    // D field
-    clear[4] = (d >>  8) & 0xFF;
-    clear[5] = (d      ) & 0xFF;
-
-    // P field
-    clear[6] = (p >>  8) & 0xFF;
-    clear[7] = (p      ) & 0xFF;
-
-    // F field
-    clear[8] = uint8_t(f);
-
-    // Check field
-    memset(clear + 9, 0, 7);
-
-    ec.encrypt(ciphr, clear);
-  }
-
-  block_header(evbuffer *buf, ecb_decryptor &dc)
-  {
-    if (evbuffer_copyout(buf, ciphr, sizeof ciphr) != sizeof ciphr) {
-      memset(clear, 0xFF, sizeof clear);
-      memset(ciphr, 0xFF, sizeof ciphr);
-      return;
-    }
-    dc.decrypt(clear, ciphr);
-  }
-
-  uint32_t seqno() const
-  {
-    return ((uint32_t(clear[0]) << 24) |
-            (uint32_t(clear[1]) << 16) |
-            (uint32_t(clear[2]) <<  8) |
-            (uint32_t(clear[3])      ));
-
-  }
-
-  size_t dlen() const
-  {
-    return ((uint16_t(clear[4]) << 8) |
-            (uint16_t(clear[5])     ));
-  }
-
-  size_t plen() const
-  {
-    return ((uint16_t(clear[6]) << 8) |
-            (uint16_t(clear[7])     ));
-  }
-
-  size_t total_len() const
-  {
-    return HEADER_LEN + TRAILER_LEN + dlen() + plen();
-  }
-
-  opcode_t opcode() const
-  {
-    return opcode_t(clear[8]);
-  }
-
-  bool valid(uint64_t window) const
-  {
-    // This check must run in constant time.
-    uint8_t ck = (clear[ 9] | clear[10] | clear[11] | clear[12] |
-                  clear[13] | clear[14] | clear[15]);
-    uint32_t delta = seqno() - window;
-    ck |= !!(delta & ~uint32_t(0xFF));
-    return !ck;
-  }
-
-  const uint8_t *nonce() const
-  {
-    return ciphr;
-  }
-
-  const uint8_t *cleartext() const
-  {
-    return clear;
-  }
-};
-
-/* Most of a block's header information is processed before it reaches
-   the reassembly queue; the only things the queue needs to record are
-   the sequence number (which is stored implictly), the opcode, and an
-   evbuffer holding the data section.  Zero-data blocks still get an
-   evbuffer, for simplicity's sake: a reassembly queue element holds a
-   received block if and only if its data pointer is non-null.
-
-   The reassembly queue is a 256-element circular buffer of
-   'reassembly_elt' structs.  This corresponds to the 256-element
-   sliding window of sequence numbers which may legitimately be
-   received at any time.  */
-
-struct reassembly_elt
-{
-  evbuffer *data;
-  opcode_t op;
-};
-
-class reassembly_queue
-{
-  reassembly_elt cbuf[256];
-  uint32_t next_to_process;
-
-  reassembly_queue(const reassembly_queue&) DELETE_METHOD;
-  reassembly_queue& operator=(const reassembly_queue&) DELETE_METHOD;
-
-public:
-  reassembly_queue()
-    : next_to_process(0)
-  {
-    memset(cbuf, 0, sizeof cbuf);
-  }
-
-  ~reassembly_queue()
-  {
-    for (int i = 0; i < 256; i++)
-      if (cbuf[i].data)
-        evbuffer_free(cbuf[i].data);
-  }
-
-  // Remove the next block to be processed from the reassembly queue
-  // and return it.  If we are out of blocks or the next block to
-  // process has not yet arrived, return an empty reassembly_elt.
-  // Caller is responsible for freeing the evbuffer in the
-  // reassembly_elt, if any.
-  reassembly_elt
-  remove_next()
-  {
-    reassembly_elt rv = { 0, op_DAT };
-    uint8_t front = next_to_process & 0xFF;
-    log_debug("next_to_process=%d data=%p op=%02x",
-              next_to_process, cbuf[front].data, cbuf[front].op);
-    if (cbuf[front].data) {
-      rv = cbuf[front];
-      cbuf[front].data = 0;
-      cbuf[front].op   = op_DAT;
-      next_to_process++;
-    }
-    return rv;
-  }
-
-  // Insert a block into the reassembly queue at sequence number
-  // SEQNO, with opcode OP and data section DATA.  Returns true if the
-  // block was successfully added to the queue, false if it is either
-  // outside the acceptable window or duplicates a block already on
-  // the queue (both of these cases indicate protocol errors).
-  // DATA is consumed no matter what the return value is.
-  bool
-  insert(uint32_t seqno, opcode_t op, evbuffer *data, conn_t *conn)
-  {
-    if (seqno - window() > 255) {
-      log_info(conn, "block outside receive window");
-      evbuffer_free(data);
-      return false;
-    }
-    uint8_t front = next_to_process & 0xFF;
-    uint8_t pos = front + (seqno - window());
-    if (cbuf[pos].data) {
-      log_info(conn, "duplicate block");
-      evbuffer_free(data);
-      return false;
-    }
-
-    cbuf[pos].data = data;
-    cbuf[pos].op   = op;
-    return true;
-  }
-
-  // Return the current lowest acceptable sequence number in the
-  // receive window. This is the value to be passed to
-  // block_header::valid().
-  uint32_t window() const { return next_to_process; }
-
-  // As the last step of a rekeying cycle, the expected next sequence number
-  // is reset to zero.
-  void reset()
-  {
-    for (int i = 0; i < 256; i++) {
-      log_assert(!cbuf[i].data);
-    }
-    next_to_process = 0;
-  }
-};
-
-// Protocol objects
+using namespace chop_blk;
 
 struct chop_config_t;
 struct chop_circuit_t;
@@ -883,7 +603,7 @@ chop_circuit_t::send_targeted(chop_conn_t *conn, size_t d, size_t p, opcode_t f,
   }
   v.iov_len = blocksize;
 
-  block_header hdr(send_seq, d, p, f, *send_hdr_crypt);
+  header hdr(send_seq, d, p, f, *send_hdr_crypt);
   log_assert(hdr.valid(send_seq));
   memcpy(v.iov_base, hdr.nonce(), HEADER_LEN);
 
@@ -1335,7 +1055,7 @@ chop_conn_t::recv()
       break;
     }
 
-    block_header hdr(recv_pending, *upstream->recv_hdr_crypt);
+    header hdr(recv_pending, *upstream->recv_hdr_crypt);
     if (!hdr.valid(upstream->recv_queue.window())) {
       const uint8_t *c = hdr.cleartext();
       char fallbackbuf[4];
@@ -1543,8 +1263,6 @@ chop_conn_t::must_send_timeout(evutil_socket_t, short, void *arg)
   static_cast<chop_conn_t *>(arg)->send();
 }
 
-} // anonymous namespace
-
 PROTO_DEFINE_MODULE(chop);
 
 // Local Variables:
diff --git a/src/protocol/chop_blk.cc b/src/protocol/chop_blk.cc
new file mode 100644
index 0000000..460097d
--- /dev/null
+++ b/src/protocol/chop_blk.cc
@@ -0,0 +1,104 @@
+/* Copyright 2011, 2012 SRI International
+ * See LICENSE for other credits and copying information
+ */
+
+#include "util.h"
+#include "chop_blk.h"
+
+/* The chopper is the core StegoTorus protocol implementation.
+   For its design, see doc/chopper.txt.  Note that it is still
+   being implemented, and may change incompatibly.  */
+
+namespace chop_blk
+{
+
+const char *
+opname(opcode_t o, char fallbackbuf[4])
+{
+  switch (o) {
+  case op_DAT: return "DAT";
+  case op_FIN: return "FIN";
+  case op_RST: return "RST";
+  default: {
+    unsigned int x = o;
+    if (x < op_STEG0)
+      xsnprintf(fallbackbuf, sizeof fallbackbuf, "R%02x", x);
+    else
+      xsnprintf(fallbackbuf, sizeof fallbackbuf, "S%02x", x - op_STEG0);
+    return fallbackbuf;
+  }
+  }
+}
+
+reassembly_queue::reassembly_queue()
+  : next_to_process(0)
+{
+  memset(cbuf, 0, sizeof cbuf);
+}
+
+reassembly_queue::~reassembly_queue()
+{
+  for (int i = 0; i < 256; i++)
+    if (cbuf[i].data)
+      evbuffer_free(cbuf[i].data);
+}
+
+reassembly_elt
+reassembly_queue::remove_next()
+{
+  reassembly_elt rv = { 0, op_DAT };
+  uint8_t front = next_to_process & 0xFF;
+  char fallbackbuf[4];
+
+  log_debug("next_to_process=%d data=%p op=%s",
+            next_to_process, cbuf[front].data,
+            opname(cbuf[front].op, fallbackbuf));
+
+  if (cbuf[front].data) {
+    rv = cbuf[front];
+    cbuf[front].data = 0;
+    cbuf[front].op   = op_DAT;
+    next_to_process++;
+  }
+  return rv;
+}
+
+bool
+reassembly_queue::insert(uint32_t seqno, opcode_t op,
+                         evbuffer *data, conn_t *conn)
+{
+  if (seqno - window() > 255) {
+    log_info(conn, "block outside receive window");
+    evbuffer_free(data);
+    return false;
+  }
+  uint8_t front = next_to_process & 0xFF;
+  uint8_t pos = front + (seqno - window());
+  if (cbuf[pos].data) {
+    log_info(conn, "duplicate block");
+    evbuffer_free(data);
+    return false;
+  }
+
+  cbuf[pos].data = data;
+  cbuf[pos].op   = op;
+  return true;
+}
+
+void
+reassembly_queue::reset()
+{
+  for (int i = 0; i < 256; i++) {
+    log_assert(!cbuf[i].data);
+  }
+  next_to_process = 0;
+}
+
+} // namespace chop_blk
+
+// Local Variables:
+// mode: c++
+// c-basic-offset: 2
+// c-file-style: "gnu"
+// c-file-offsets: ((innamespace . 0) (brace-list-open . 0))
+// End:
diff --git a/src/protocol/chop_blk.h b/src/protocol/chop_blk.h
new file mode 100644
index 0000000..9776a70
--- /dev/null
+++ b/src/protocol/chop_blk.h
@@ -0,0 +1,247 @@
+/* Copyright 2011, 2012 SRI International
+ * See LICENSE for other credits and copying information
+ */
+
+#ifndef CHOP_BLK_H
+#define CHOP_BLK_H
+
+#include "crypt.h"
+#include <event2/buffer.h>
+
+namespace chop_blk
+{
+
+/* Packets on the wire have a 16-byte header, consisting of a 32-bit
+   sequence number, two 16-bit length fields ("D" and "P"), an 8-bit
+   opcode ("F"), and a 56-bit check field.  All numbers in this header
+   are serialized in network byte order.
+
+   | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
+   |Sequence Number|   D   |   P   | F |           Check           |
+
+   The header is encrypted with AES in ECB mode: this is safe because
+   the header is exactly one AES block long, the sequence number is
+   never repeated, the header-encryption key is not used for anything
+   else, and the high 24 bits of the sequence number, plus the check
+   field, constitute an 80-bit MAC.  The receiver maintains a
+   256-element sliding window of acceptable sequence numbers, which
+   begins one after the highest sequence number so far _processed_
+   (not received).  If the sequence number is outside this window, or
+   the check field is not all-bits-zero, the packet is discarded.  An
+   attacker's odds of being able to manipulate the D, P, or F fields
+   or the low bits of the sequence number are therefore less than one
+   in 2^80.  Unlike TCP, our sequence numbers always start at zero on
+   a new (or freshly rekeyed) circuit, and increment by one per
+   _block_, not per byte of data.  Furthermore, they do not wrap: a
+   rekeying cycle (which resets the sequence number) is required to
+   occur before the highest-received sequence number reaches 2^32.
+
+   Following the header are two variable-length payload sections,
+   "data" and "padding", whose length in bytes are given by the D and
+   P fields, respectively.  These sections are encrypted, using a
+   different key, with AES in GCM mode.  The *encrypted* packet header
+   doubles as the GCM nonce.  The semantics of the "data" section's
+   contents, if any, are defined by the opcode F.  The "padding"
+   section SHOULD be filled with zeroes by the sender; regardless, its
+   contents MUST be ignored by the receiver.  Following these sections
+   is a 16-byte GCM authentication tag, computed over the data and
+   padding sections only, NOT the message header.  */
+
+const size_t HEADER_LEN = 16;
+const size_t TRAILER_LEN = 16;
+const size_t SECTION_LEN = UINT16_MAX;
+const size_t MIN_BLOCK_SIZE = HEADER_LEN + TRAILER_LEN;
+const size_t MAX_BLOCK_SIZE = MIN_BLOCK_SIZE + SECTION_LEN*2;
+
+const size_t HANDSHAKE_LEN = sizeof(uint32_t);
+
+enum opcode_t
+{
+  op_DAT = 0,       // Pass data section along to upstream
+  op_FIN = 1,       // No further transmissions (pass data along if any)
+  op_RST = 2,       // Protocol error, close circuit now
+  op_RESERVED0 = 3, // 3 -- 127 reserved for future definition
+  op_STEG0 = 128,   // 128 -- 255 reserved for steganography modules
+  op_LAST = 255
+};
+
+/**
+ * Produce a human-readable codename for opcode O.
+ * FALLBACKBUF is used for opcodes that have no official assignment.
+ * Will either return FALLBACKBUF or a pointer to a string constant.
+ */
+extern const char *opname(opcode_t o, char fallbackbuf[4]);
+
+class header
+{
+  uint8_t clear[16];
+  uint8_t ciphr[16];
+
+public:
+  header(uint32_t s, uint16_t d, uint16_t p, opcode_t f, ecb_encryptor &ec)
+  {
+    if (f > op_LAST || (f >= op_RESERVED0 && f < op_STEG0)) {
+      memset(clear, 0xFF, sizeof clear); // invalid!
+      memset(ciphr, 0xFF, sizeof ciphr);
+      return;
+    }
+
+    // sequence number
+    clear[0] = (s >> 24) & 0xFF;
+    clear[1] = (s >> 16) & 0xFF;
+    clear[2] = (s >>  8) & 0xFF;
+    clear[3] = (s      ) & 0xFF;
+
+    // D field
+    clear[4] = (d >>  8) & 0xFF;
+    clear[5] = (d      ) & 0xFF;
+
+    // P field
+    clear[6] = (p >>  8) & 0xFF;
+    clear[7] = (p      ) & 0xFF;
+
+    // F field
+    clear[8] = uint8_t(f);
+
+    // Check field
+    memset(clear + 9, 0, 7);
+
+    ec.encrypt(ciphr, clear);
+  }
+
+  header(evbuffer *buf, ecb_decryptor &dc)
+  {
+    if (evbuffer_copyout(buf, ciphr, sizeof ciphr) != sizeof ciphr) {
+      memset(clear, 0xFF, sizeof clear);
+      memset(ciphr, 0xFF, sizeof ciphr);
+      return;
+    }
+    dc.decrypt(clear, ciphr);
+  }
+
+  uint32_t seqno() const
+  {
+    return ((uint32_t(clear[0]) << 24) |
+            (uint32_t(clear[1]) << 16) |
+            (uint32_t(clear[2]) <<  8) |
+            (uint32_t(clear[3])      ));
+
+  }
+
+  size_t dlen() const
+  {
+    return ((uint16_t(clear[4]) << 8) |
+            (uint16_t(clear[5])     ));
+  }
+
+  size_t plen() const
+  {
+    return ((uint16_t(clear[6]) << 8) |
+            (uint16_t(clear[7])     ));
+  }
+
+  size_t total_len() const
+  {
+    return HEADER_LEN + TRAILER_LEN + dlen() + plen();
+  }
+
+  opcode_t opcode() const
+  {
+    return opcode_t(clear[8]);
+  }
+
+  bool valid(uint64_t window) const
+  {
+    // This check must run in constant time.
+    uint8_t ck = (clear[ 9] | clear[10] | clear[11] | clear[12] |
+                  clear[13] | clear[14] | clear[15]);
+    uint32_t delta = seqno() - window;
+    ck |= !!(delta & ~uint32_t(0xFF));
+    return !ck;
+  }
+
+  const uint8_t *nonce() const
+  {
+    return ciphr;
+  }
+
+  const uint8_t *cleartext() const
+  {
+    return clear;
+  }
+};
+
+
+/* Most of a block's header information is processed before it reaches
+   the reassembly queue; the only things the queue needs to record are
+   the sequence number (which is stored implictly), the opcode, and an
+   evbuffer holding the data section.  Zero-data blocks still get an
+   evbuffer, for simplicity's sake: a reassembly queue element holds a
+   received block if and only if its data pointer is non-null.
+
+   The reassembly queue is a 256-element circular buffer of
+   'reassembly_elt' structs.  This corresponds to the 256-element
+   sliding window of sequence numbers which may legitimately be
+   received at any time.  */
+
+struct reassembly_elt
+{
+  evbuffer *data;
+  opcode_t op;
+};
+
+class reassembly_queue
+{
+  reassembly_elt cbuf[256];
+  uint32_t next_to_process;
+
+  reassembly_queue(const reassembly_queue&) DELETE_METHOD;
+  reassembly_queue& operator=(const reassembly_queue&) DELETE_METHOD;
+
+public:
+  reassembly_queue();
+  ~reassembly_queue();
+
+  /**
+   * Remove the next block to be processed from the reassembly queue
+   * and return it.  If we are out of blocks or the next block to
+   * process has not yet arrived, return an empty reassembly_elt.
+   * Caller is responsible for freeing the evbuffer in the
+   * reassembly_elt, if any.
+   */
+  reassembly_elt remove_next();
+
+  /**
+   * Insert a block into the reassembly queue at sequence number
+   * SEQNO, with opcode OP and data section DATA.  Returns true if the
+   * block was successfully added to the queue, false if it is either
+   * outside the acceptable window or duplicates a block already on
+   * the queue (both of these cases indicate protocol errors).
+   * DATA is consumed no matter what the return value is.
+   */
+  bool insert(uint32_t seqno, opcode_t op, evbuffer *data, conn_t *conn);
+
+  /**
+   * Return the current lowest acceptable sequence number in the
+   * receive window. This is the value to be passed to
+   * block_header::valid().
+   */
+  uint32_t window() const { return next_to_process; }
+
+  /**
+   * Reset the expected next sequence number to zero.  The queue must
+   * be empty.  This is done as the last step of a rekeying cycle.
+   */
+  void reset();
+};
+
+} // namespace chop_blk
+
+#endif /* chop_blk.h */
+
+// Local Variables:
+// mode: c++
+// c-basic-offset: 2
+// c-file-style: "gnu"
+// c-file-offsets: ((innamespace . 0) (brace-list-open . 0))
+// End:





More information about the tor-commits mailing list