[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r12390: Initial code for variable-length cells. CERT and VERSIONS ne (in tor/trunk: . doc src/or)



Author: nickm
Date: 2007-11-05 16:46:35 -0500 (Mon, 05 Nov 2007)
New Revision: 12390

Modified:
   tor/trunk/
   tor/trunk/doc/TODO
   tor/trunk/src/or/buffers.c
   tor/trunk/src/or/command.c
   tor/trunk/src/or/connection_or.c
   tor/trunk/src/or/or.h
Log:
 r16438@catbus:  nickm | 2007-11-05 16:45:45 -0500
 Initial code for variable-length cells. CERT and VERSIONS  need to use them.



Property changes on: tor/trunk
___________________________________________________________________
 svk:merge ticket from /tor/trunk [r16438] on 8246c3cf-6607-4228-993b-4d95d33730f1

Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO	2007-11-05 21:10:22 UTC (rev 12389)
+++ tor/trunk/doc/TODO	2007-11-05 21:46:35 UTC (rev 12390)
@@ -30,8 +30,8 @@
         act-on-netinfo logic separate so it can get called _after_
         negotiation.
       - Variable-length cells
-        - Add structure
-        - Add parse logic
+        o Add structure
+        o Add parse logic
         - Make CERT and VERSIONS variable.
       - CERT cells
         - functions to parse x509 certs

Modified: tor/trunk/src/or/buffers.c
===================================================================
--- tor/trunk/src/or/buffers.c	2007-11-05 21:10:22 UTC (rev 12389)
+++ tor/trunk/src/or/buffers.c	2007-11-05 21:46:35 UTC (rev 12390)
@@ -993,6 +993,42 @@
   return buf->datalen;
 }
 
+/** DOCDOC Returns 0 on "not a var-length cell."; 1 whether it's all here
+ * yet or not. */
+int
+fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out)
+{
+  char hdr[VAR_CELL_HEADER_SIZE];
+  var_cell_t *result;
+  uint8_t command;
+  uint16_t length;
+  check();
+  *out = NULL;
+  if (buf->datalen < VAR_CELL_HEADER_SIZE)
+    return 0;
+  peek_from_buf(hdr, sizeof(hdr), buf);
+
+  command = *(uint8_t*)(hdr+2);
+  if (!(CELL_COMMAND_IS_VAR_LENGTH(command)))
+    return 0;
+
+  length = ntohs(get_uint16(hdr+3));
+  if (buf->datalen < (size_t)(VAR_CELL_HEADER_SIZE+length))
+    return 1;
+  result = tor_malloc(sizeof(var_cell_t)+length-1);
+  result->command = command;
+  result->payload_len = length;
+  result->circ_id = ntohs(*(uint16_t*)hdr);
+
+  buf_remove_from_front(buf, VAR_CELL_HEADER_SIZE);
+  peek_from_buf(result->payload, length, buf);
+  buf_remove_from_front(buf, length);
+  check();
+
+  *out = result;
+  return 1;
+}
+
 /** Move up to *<b>buf_flushlen</b> bytes from <b>buf_in</b> to
  * <b>buf_out</b>, and modify *<b>buf_flushlen</b> appropriately.
  * Return the number of bytes actually copied.

Modified: tor/trunk/src/or/command.c
===================================================================
--- tor/trunk/src/or/command.c	2007-11-05 21:10:22 UTC (rev 12389)
+++ tor/trunk/src/or/command.c	2007-11-05 21:46:35 UTC (rev 12390)
@@ -35,9 +35,10 @@
 static void command_process_created_cell(cell_t *cell, or_connection_t *conn);
 static void command_process_relay_cell(cell_t *cell, or_connection_t *conn);
 static void command_process_destroy_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_versions_cell(cell_t *cell, or_connection_t *conn);
+static void command_process_versions_cell(var_cell_t *cell,
+                                          or_connection_t *conn);
 static void command_process_netinfo_cell(cell_t *cell, or_connection_t *conn);
-static void command_process_cert_cell(cell_t *cell, or_connection_t *conn);
+static void command_process_cert_cell(var_cell_t *cell, or_connection_t *conn);
 static void command_process_link_auth_cell(cell_t *cell,or_connection_t *conn);
 
 #ifdef KEEP_TIMING_STATS
@@ -143,16 +144,14 @@
       PROCESS_CELL(destroy, cell, conn);
       break;
     case CELL_VERSIONS:
-      ++stats_n_versions_cells_processed;
-      PROCESS_CELL(versions, cell, conn);
+      tor_fragile_assert();
       break;
     case CELL_NETINFO:
       ++stats_n_netinfo_cells_processed;
       PROCESS_CELL(netinfo, cell, conn);
       break;
     case CELL_CERT:
-      ++stats_n_cert_cells_processed;
-      PROCESS_CELL(cert, cell, conn);
+      tor_fragile_assert();
       break;
     case CELL_LINK_AUTH:
       ++stats_n_link_auth_cells_processed;
@@ -165,6 +164,55 @@
   }
 }
 
+/** Process a <b>cell</b> that was just received on <b>conn</b>. Keep internal
+ * statistics about how many of each cell we've processed so far
+ * this second, and the total number of microseconds it took to
+ * process each type of cell.
+ */
+void
+command_process_var_cell(var_cell_t *cell, or_connection_t *conn)
+{
+#ifdef KEEP_TIMING_STATS
+  /* how many of each cell have we seen so far this second? needs better
+   * name. */
+  static int num_versions=0, num_cert=0;
+
+  time_t now = time(NULL);
+
+  if (now > current_second) { /* the second has rolled over */
+    /* print stats */
+    log_info(LD_OR,
+             "At end of second: %d versions (%d ms), %d cert (%d ms)",
+             num_versions, versions_time/1000,
+             cert, cert_time/1000);
+
+    num_versions = num_cert = 0;
+    versions_time = cert_time = 0;
+
+    /* remember which second it is, for next time */
+    current_second = now;
+  }
+#endif
+
+  /*XXXX020 reject all when not handshaking. */
+  switch (cell->command) {
+    case CELL_VERSIONS:
+      ++stats_n_versions_cells_processed;
+      PROCESS_CELL(versions, cell, conn);
+      break;
+    case CELL_CERT:
+      ++stats_n_cert_cells_processed;
+      PROCESS_CELL(cert, cell, conn);
+      break;
+    default:
+      log_warn(LD_BUG,
+               "Variable-length cell of unknown type (%d) received.",
+               cell->command);
+      tor_fragile_assert();
+      break;
+  }
+}
+
 /** Process a 'create' <b>cell</b> that just arrived from <b>conn</b>. Make a
  * new circuit with the p_circ_id specified in cell. Put the circuit in state
  * onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
@@ -404,7 +452,7 @@
 /** Process a 'versions' cell.  The current link protocol version must be 0
  * to indicate that no version has yet been negotiated. DOCDOC say more. */
 static void
-command_process_versions_cell(cell_t *cell, or_connection_t *conn)
+command_process_versions_cell(var_cell_t *cell, or_connection_t *conn)
 {
   uint16_t versionslen;
   int highest_supported_version = 0;
@@ -560,7 +608,7 @@
 }
 
 static void
-command_process_cert_cell(cell_t *cell, or_connection_t *conn)
+command_process_cert_cell(var_cell_t *cell, or_connection_t *conn)
 {
   (void) cell;
   (void) conn;

Modified: tor/trunk/src/or/connection_or.c
===================================================================
--- tor/trunk/src/or/connection_or.c	2007-11-05 21:10:22 UTC (rev 12389)
+++ tor/trunk/src/or/connection_or.c	2007-11-05 21:46:35 UTC (rev 12390)
@@ -147,6 +147,22 @@
   memcpy(dest->payload, src+3, CELL_PAYLOAD_SIZE);
 }
 
+/** DOCDOC */
+void
+var_cell_pack_header(var_cell_t *cell, char *hdr_out)
+{
+  *(uint16_t*)(hdr_out) = htons(cell->circ_id);
+  *(uint8_t*)(hdr_out+2) = cell->command;
+  set_uint16(hdr_out+3, htons(cell->payload_len));
+}
+
+/** DOCDOC */
+void
+var_cell_free(var_cell_t *cell)
+{
+  tor_free(cell);
+}
+
 int
 connection_or_reached_eof(or_connection_t *conn)
 {
@@ -825,6 +841,13 @@
   connection_write_to_buf(networkcell.body, CELL_NETWORK_SIZE, TO_CONN(conn));
 }
 
+/** DOCDOC */
+static int
+connection_fetch_var_cell_from_buf(or_connection_t *conn, var_cell_t **out)
+{
+  return fetch_var_cell_from_buf(conn->_base.inbuf, out);
+}
+
 /** Process cells from <b>conn</b>'s inbuf.
  *
  * Loop: while inbuf contains a cell, pull it off the inbuf, unpack it,
@@ -835,27 +858,34 @@
 static int
 connection_or_process_cells_from_inbuf(or_connection_t *conn)
 {
-  char buf[CELL_NETWORK_SIZE];
-  cell_t cell;
+  var_cell_t *var_cell;
 
- loop:
-  log_debug(LD_OR,
-            "%d: starting, inbuf_datalen %d (%d pending in tls object).",
-            conn->_base.s,(int)buf_datalen(conn->_base.inbuf),
-            tor_tls_get_pending_bytes(conn->tls));
-  if (buf_datalen(conn->_base.inbuf) < CELL_NETWORK_SIZE) /* whole response
-                                                             available? */
-    return 0; /* not yet */
+  while (1) {
+    log_debug(LD_OR,
+              "%d: starting, inbuf_datalen %d (%d pending in tls object).",
+              conn->_base.s,(int)buf_datalen(conn->_base.inbuf),
+              tor_tls_get_pending_bytes(conn->tls));
+    if (connection_fetch_var_cell_from_buf(conn, &var_cell)) {
+      if (!var_cell)
+        return 0; /* not yet. */
+      command_process_var_cell(var_cell, conn);
+      var_cell_free(var_cell);
+    } else {
+      char buf[CELL_NETWORK_SIZE];
+      cell_t cell;
+      if (buf_datalen(conn->_base.inbuf) < CELL_NETWORK_SIZE) /* whole response
+                                                                 available? */
+        return 0; /* not yet */
 
-  connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
+      connection_fetch_from_buf(buf, CELL_NETWORK_SIZE, TO_CONN(conn));
 
-  /* retrieve cell info from buf (create the host-order struct from the
-   * network-order string) */
-  cell_unpack(&cell, buf);
+      /* retrieve cell info from buf (create the host-order struct from the
+       * network-order string) */
+      cell_unpack(&cell, buf);
 
-  command_process_cell(&cell, conn);
-
-  goto loop; /* process the remainder of the buffer */
+      command_process_cell(&cell, conn);
+    }
+  }
 }
 
 /** Write a destroy cell with circ ID <b>circ_id</b> and reason <b>reason</b>

Modified: tor/trunk/src/or/or.h
===================================================================
--- tor/trunk/src/or/or.h	2007-11-05 21:10:22 UTC (rev 12389)
+++ tor/trunk/src/or/or.h	2007-11-05 21:46:35 UTC (rev 12390)
@@ -660,6 +660,9 @@
 #define CELL_CERT 9
 #define CELL_LINK_AUTH 10
 
+#define CELL_COMMAND_IS_VAR_LENGTH(x) \
+  ((x) == CELL_CERT || (x) == CELL_VERSIONS)
+
 /** How long to test reachability before complaining to the user. */
 #define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60)
 
@@ -701,28 +704,36 @@
 /** Number of bytes in a cell transmitted over the network. */
 #define CELL_NETWORK_SIZE 512
 
+#define VAR_CELL_HEADER_SIZE 5
+
 /** Number of bytes in a relay cell's header (not including general cell
  * header). */
 #define RELAY_HEADER_SIZE (1+2+2+4+2)
 /** Largest number of bytes that can fit in a relay cell payload. */
 #define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE)
 
-typedef struct cell_t cell_t;
 /** Parsed onion routing cell.  All communication between nodes
  * is via cells. */
-struct cell_t {
+typedef struct cell_t {
   uint16_t circ_id; /**< Circuit which received the cell. */
-  uint8_t command; /**< Type of the cell: one of PADDING, CREATE, RELAY,
-                    * or DESTROY. */
+  uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE,
+                    * CELL_DESTROY, etc */
   char payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */
-};
+} cell_t;
 
-typedef struct packed_cell_t packed_cell_t;
+/** Parsed variable-length onion routing cell. */
+typedef struct var_cell_t {
+  uint8_t command;
+  uint16_t circ_id;
+  uint16_t payload_len;
+  char payload[1];
+} var_cell_t;
+
 /** A cell as packed for writing to the network. */
-struct packed_cell_t {
+typedef struct packed_cell_t {
   struct packed_cell_t *next; /**< Next cell queued on this circuit. */
   char body[CELL_NETWORK_SIZE]; /**< Cell as packed for network. */
-};
+} packed_cell_t;
 
 /** A queue of cells on a circuit, waiting to be added to the
  * or_connection_t's outbuf. */
@@ -2387,6 +2398,7 @@
                       const char *data, size_t data_len, int done);
 int move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
 int fetch_from_buf(char *string, size_t string_len, buf_t *buf);
+int fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out);
 int fetch_from_buf_http(buf_t *buf,
                         char **headers_out, size_t max_headerlen,
                         char **body_out, size_t *body_used, size_t max_bodylen,
@@ -2546,6 +2558,7 @@
 /********************************* command.c ***************************/
 
 void command_process_cell(cell_t *cell, or_connection_t *conn);
+void command_process_var_cell(var_cell_t *cell, or_connection_t *conn);
 void connection_or_act_on_netinfo(or_connection_t *conn);
 
 extern uint64_t stats_n_padding_cells_processed;
@@ -2786,6 +2799,8 @@
                                          char *hmac_out);
 
 void cell_pack(packed_cell_t *dest, const cell_t *src);
+void var_cell_pack_header(var_cell_t *cell, char *hdr_out);
+void var_cell_free(var_cell_t *cell);
 
 /********************************* control.c ***************************/