Browse Source

channel: Remove unused write cell functions

The channel_write_cell() and channel_write_var_cell() can't be possibly called
nor are used by tor. We only write on the connection outbuf packed cell coming
from the scheduler that takes them from the circuit queue.

This makes channel_write_packed_cell() the only usable function. It is
simplify and now returns a code value. The reason for this is that in the next
commit(s), we'll re-queue the cell onto the circuit queue if the write fails.

Finally, channel unit tests are being removed with this commit because they do
not match the new semantic. They will be re-written in future commits.

Signed-off-by: David Goulet <dgoulet@torproject.org>
David Goulet 6 years ago
parent
commit
6d1ea7766b
3 changed files with 44 additions and 319 deletions
  1. 36 172
      src/or/channel.c
  2. 1 3
      src/or/channel.h
  3. 7 144
      src/test/test_channel.c

+ 36 - 172
src/or/channel.c

@@ -148,9 +148,6 @@ HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
 HT_GENERATE2(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
              channel_idmap_eq, 0.5,  tor_reallocarray_, tor_free_)
 
-static int is_destroy_cell(channel_t *chan,
-                           const cell_queue_entry_t *q, circid_t *circid_out);
-
 /* Functions to maintain the digest map */
 static void channel_add_to_digest_map(channel_t *chan);
 static void channel_remove_from_digest_map(channel_t *chan);
@@ -161,10 +158,6 @@ channel_free_list(smartlist_t *channels, int mark_for_close);
 static void
 channel_listener_free_list(smartlist_t *channels, int mark_for_close);
 static void channel_listener_force_free(channel_listener_t *chan_l);
-static size_t channel_get_cell_queue_entry_size(channel_t *chan,
-                                                cell_queue_entry_t *q);
-static void
-channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q);
 
 /***********************************
  * Channel state utility functions *
@@ -1628,186 +1621,82 @@ channel_set_remote_end(channel_t *chan,
     channel_add_to_digest_map(chan);
 }
 
-/**
- * Ask how big the cell contained in a cell_queue_entry_t is
- */
-
-static size_t
-channel_get_cell_queue_entry_size(channel_t *chan, cell_queue_entry_t *q)
-{
-  size_t rv = 0;
-
-  tor_assert(chan);
-  tor_assert(q);
-
-  switch (q->type) {
-    case CELL_QUEUE_FIXED:
-      rv = get_cell_network_size(chan->wide_circ_ids);
-      break;
-    case CELL_QUEUE_VAR:
-      rv = get_var_cell_header_size(chan->wide_circ_ids) +
-           (q->u.var.var_cell ? q->u.var.var_cell->payload_len : 0);
-      break;
-    case CELL_QUEUE_PACKED:
-      rv = get_cell_network_size(chan->wide_circ_ids);
-      break;
-    default:
-      tor_assert_nonfatal_unreached_once();
-  }
-
-  return rv;
-}
-
 /**
  * Write to a channel based on a cell_queue_entry_t
  *
  * Given a cell_queue_entry_t filled out by the caller, try to send the cell
  * and queue it if we can't.
  */
-
-static void
-channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
+static int
+write_packed_cell(channel_t *chan, packed_cell_t *cell)
 {
-  int result = 0;
+  int ret = -1;
   size_t cell_bytes;
 
   tor_assert(chan);
-  tor_assert(q);
+  tor_assert(cell);
 
   /* Assert that the state makes sense for a cell write */
   tor_assert(CHANNEL_CAN_HANDLE_CELLS(chan));
 
   {
     circid_t circ_id;
-    if (is_destroy_cell(chan, q, &circ_id)) {
+    if (packed_cell_is_destroy(chan, cell, &circ_id)) {
       channel_note_destroy_not_pending(chan, circ_id);
     }
   }
 
   /* For statistical purposes, figure out how big this cell is */
-  cell_bytes = channel_get_cell_queue_entry_size(chan, q);
+  cell_bytes = get_cell_network_size(chan->wide_circ_ids);
 
   /* Can we send it right out?  If so, try */
-  if (CHANNEL_IS_OPEN(chan)) {
-    /* Pick the right write function for this cell type and save the result */
-    switch (q->type) {
-      case CELL_QUEUE_FIXED:
-        tor_assert(chan->write_cell);
-        tor_assert(q->u.fixed.cell);
-        result = chan->write_cell(chan, q->u.fixed.cell);
-        break;
-      case CELL_QUEUE_PACKED:
-        tor_assert(chan->write_packed_cell);
-        tor_assert(q->u.packed.packed_cell);
-        result = chan->write_packed_cell(chan, q->u.packed.packed_cell);
-        break;
-      case CELL_QUEUE_VAR:
-        tor_assert(chan->write_var_cell);
-        tor_assert(q->u.var.var_cell);
-        result = chan->write_var_cell(chan, q->u.var.var_cell);
-        break;
-      default:
-        tor_assert(1);
-    }
+  if (!CHANNEL_IS_OPEN(chan)) {
+    goto done;
+  }
 
-    /* Check if we got it out */
-    if (result > 0) {
-      /* Timestamp for transmission */
-      channel_timestamp_xmit(chan);
-      /* If we're here the queue is empty, so it's drained too */
-      channel_timestamp_drained(chan);
-      /* Update the counter */
-      ++(chan->n_cells_xmitted);
-      chan->n_bytes_xmitted += cell_bytes;
-    }
+  /* Write the cell on the connection's outbuf. */
+  if (chan->write_packed_cell(chan, cell) < 0) {
+    goto done;
   }
+  /* Timestamp for transmission */
+  channel_timestamp_xmit(chan);
+  /* If we're here the queue is empty, so it's drained too */
+  channel_timestamp_drained(chan);
+  /* Update the counter */
+  ++(chan->n_cells_xmitted);
+  chan->n_bytes_xmitted += cell_bytes;
+  /* Successfully sent the cell. */
+  ret = 0;
 
-  /* XXX: If the cell wasn't sent, we need to propagate the error back so we
-   * can put it back in the circuit queue. */
+ done:
+  return ret;
 }
 
-/** Write a generic cell type to a channel
+/**
+ * Write a packed cell to a channel
  *
- * Write a generic cell to a channel. It is called by channel_write_cell(),
- * channel_write_var_cell() and channel_write_packed_cell() in order to reduce
- * code duplication. Notice that it takes cell as pointer of type void,
- * this can be dangerous because no type check is performed.
+ * Write a packed cell to a channel using the write_cell() method.  This is
+ * called by the transport-independent code to deliver a packed cell to a
+ * channel for transmission.
  */
-
-void
-channel_write_cell_generic_(channel_t *chan, const char *cell_type,
-                            void *cell, cell_queue_entry_t *q)
+int
+channel_write_packed_cell(channel_t *chan, packed_cell_t *cell)
 {
-
   tor_assert(chan);
   tor_assert(cell);
 
   if (CHANNEL_IS_CLOSING(chan)) {
-    log_debug(LD_CHANNEL, "Discarding %c %p on closing channel %p with "
-              "global ID "U64_FORMAT, *cell_type, cell, chan,
+    log_debug(LD_CHANNEL, "Discarding %p on closing channel %p with "
+              "global ID "U64_FORMAT, cell, chan,
               U64_PRINTF_ARG(chan->global_identifier));
     tor_free(cell);
-    return;
+    return -1;
   }
   log_debug(LD_CHANNEL,
-            "Writing %c %p to channel %p with global ID "
-            U64_FORMAT, *cell_type,
-            cell, chan, U64_PRINTF_ARG(chan->global_identifier));
+            "Writing %p to channel %p with global ID "
+            U64_FORMAT, cell, chan, U64_PRINTF_ARG(chan->global_identifier));
 
-  channel_write_cell_queue_entry(chan, q);
-}
-
-/**
- * Write a cell to a channel
- *
- * Write a fixed-length cell to a channel using the write_cell() method.
- * This is equivalent to the pre-channels connection_or_write_cell_to_buf();
- * it is called by the transport-independent code to deliver a cell to a
- * channel for transmission.
- */
-
-void
-channel_write_cell(channel_t *chan, cell_t *cell)
-{
-  cell_queue_entry_t q;
-  q.type = CELL_QUEUE_FIXED;
-  q.u.fixed.cell = cell;
-  channel_write_cell_generic_(chan, "cell_t", cell, &q);
-}
-
-/**
- * Write a packed cell to a channel
- *
- * Write a packed cell to a channel using the write_cell() method.  This is
- * called by the transport-independent code to deliver a packed cell to a
- * channel for transmission.
- */
-
-void
-channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell)
-{
-  cell_queue_entry_t q;
-  q.type = CELL_QUEUE_PACKED;
-  q.u.packed.packed_cell = packed_cell;
-  channel_write_cell_generic_(chan, "packed_cell_t", packed_cell, &q);
-}
-
-/**
- * Write a variable-length cell to a channel
- *
- * Write a variable-length cell to a channel using the write_cell() method.
- * This is equivalent to the pre-channels
- * connection_or_write_var_cell_to_buf(); it's called by the transport-
- * independent code to deliver a var_cell to a channel for transmission.
- */
-
-void
-channel_write_var_cell(channel_t *chan, var_cell_t *var_cell)
-{
-  cell_queue_entry_t q;
-  q.type = CELL_QUEUE_VAR;
-  q.u.var.var_cell = var_cell;
-  channel_write_cell_generic_(chan, "var_cell_t", var_cell, &q);
+  return write_packed_cell(chan, cell);
 }
 
 /**
@@ -2352,31 +2241,6 @@ packed_cell_is_destroy(channel_t *chan,
   return 0;
 }
 
-/* DOCDOC */
-static int
-is_destroy_cell(channel_t *chan,
-                const cell_queue_entry_t *q, circid_t *circid_out)
-{
-  *circid_out = 0;
-  switch (q->type) {
-    case CELL_QUEUE_FIXED:
-      if (q->u.fixed.cell->command == CELL_DESTROY) {
-        *circid_out = q->u.fixed.cell->circ_id;
-        return 1;
-      }
-      break;
-    case CELL_QUEUE_VAR:
-      if (q->u.var.var_cell->command == CELL_DESTROY) {
-        *circid_out = q->u.var.var_cell->circ_id;
-        return 1;
-      }
-      break;
-    case CELL_QUEUE_PACKED:
-      return packed_cell_is_destroy(chan, q->u.packed.packed_cell, circid_out);
-  }
-  return 0;
-}
-
 /**
  * Send destroy cell on a channel
  *

+ 1 - 3
src/or/channel.h

@@ -406,9 +406,7 @@ channel_listener_state_to_string(channel_listener_state_t state);
 /* Abstract channel operations */
 
 void channel_mark_for_close(channel_t *chan);
-void channel_write_cell(channel_t *chan, cell_t *cell);
-void channel_write_packed_cell(channel_t *chan, packed_cell_t *cell);
-void channel_write_var_cell(channel_t *chan, var_cell_t *cell);
+int channel_write_packed_cell(channel_t *chan, packed_cell_t *cell);
 
 void channel_listener_mark_for_close(channel_listener_t *chan_l);
 

+ 7 - 144
src/test/test_channel.c

@@ -26,7 +26,6 @@ static cell_t * test_chan_last_seen_fixed_cell_ptr = NULL;
 static int test_chan_var_cells_recved = 0;
 static var_cell_t * test_chan_last_seen_var_cell_ptr = NULL;
 static int test_cells_written = 0;
-static int test_destroy_not_pending_calls = 0;
 static int test_doesnt_want_writes_count = 0;
 static int test_dumpstats_calls = 0;
 static int test_has_waiting_cells_count = 0;
@@ -37,8 +36,6 @@ static int dump_statistics_mock_matches = 0;
 
 static void chan_test_channel_dump_statistics_mock(
     channel_t *chan, int severity);
-static void channel_note_destroy_not_pending_mock(channel_t *ch,
-                                                  circid_t circid);
 static void chan_test_cell_handler(channel_t *ch,
                                    cell_t *cell);
 static const char * chan_test_describe_transport(channel_t *ch);
@@ -61,17 +58,6 @@ static void scheduler_channel_doesnt_want_writes_mock(channel_t *ch);
 static void test_channel_dumpstats(void *arg);
 static void test_channel_incoming(void *arg);
 static void test_channel_lifecycle(void *arg);
-static void test_channel_write(void *arg);
-
-static void
-channel_note_destroy_not_pending_mock(channel_t *ch,
-                                      circid_t circid)
-{
-  (void)ch;
-  (void)circid;
-
-  ++test_destroy_not_pending_calls;
-}
 
 static const char *
 chan_test_describe_transport(channel_t *ch)
@@ -447,7 +433,7 @@ static void
 test_channel_dumpstats(void *arg)
 {
   channel_t *ch = NULL;
-  cell_t *cell = NULL;
+  packed_cell_t *p_cell = NULL;
   int old_count;
 
   (void)arg;
@@ -513,12 +499,10 @@ test_channel_dumpstats(void *arg)
   tt_assert(time(NULL) > ch->timestamp_created);
 
   /* Put cells through it both ways to make the counters non-zero */
-  cell = tor_malloc_zero(sizeof(*cell));
-  make_fake_cell(cell);
+  p_cell = packed_cell_new();
   test_chan_accept_cells = 1;
   old_count = test_cells_written;
-  channel_write_cell(ch, cell);
-  cell = NULL;
+  channel_write_packed_cell(ch, p_cell);
   tt_int_op(test_cells_written, OP_EQ, old_count + 1);
   tt_assert(ch->n_bytes_xmitted > 0);
   tt_assert(ch->n_cells_xmitted > 0);
@@ -530,10 +514,8 @@ test_channel_dumpstats(void *arg)
   tt_ptr_op(channel_get_cell_handler(ch), OP_EQ, chan_test_cell_handler);
   tt_ptr_op(channel_get_var_cell_handler(ch), OP_EQ,
             chan_test_var_cell_handler);
-  cell = tor_malloc_zero(sizeof(cell_t));
-  make_fake_cell(cell);
+  p_cell = packed_cell_new();
   old_count = test_chan_fixed_cells_recved;
-  tor_free(cell);
   tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count + 1);
   tt_assert(ch->n_bytes_recved > 0);
   tt_assert(ch->n_cells_recved > 0);
@@ -555,7 +537,6 @@ test_channel_dumpstats(void *arg)
   ch = NULL;
 
  done:
-  tor_free(cell);
   free_fake_channel(ch);
 
   UNMOCK(scheduler_channel_doesnt_want_writes);
@@ -652,7 +633,7 @@ static void
 test_channel_lifecycle(void *arg)
 {
   channel_t *ch1 = NULL, *ch2 = NULL;
-  cell_t *cell = NULL;
+  packed_cell_t *p_cell = NULL;
   int old_count, init_doesnt_want_writes_count;
   int init_releases_count;
 
@@ -685,10 +666,9 @@ test_channel_lifecycle(void *arg)
   tt_assert(ch1->registered);
 
   /* Try to write a cell through (should queue) */
-  cell = tor_malloc_zero(sizeof(cell_t));
-  make_fake_cell(cell);
+  p_cell = packed_cell_new();
   old_count = test_cells_written;
-  channel_write_cell(ch1, cell);
+  channel_write_packed_cell(ch1, p_cell);
   tt_int_op(old_count, OP_EQ, test_cells_written);
 
   /* Move it to OPEN and flush */
@@ -915,122 +895,6 @@ test_channel_lifecycle_2(void *arg)
   return;
 }
 
-static void
-test_channel_write(void *arg)
-{
-  channel_t *ch = NULL;
-  cell_t *cell = tor_malloc_zero(sizeof(cell_t));
-  packed_cell_t *packed_cell = NULL;
-  var_cell_t *var_cell =
-    tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
-  int old_count;
-
-  (void)arg;
-
-  packed_cell = packed_cell_new();
-  tt_assert(packed_cell);
-
-  ch = new_fake_channel();
-  tt_assert(ch);
-  make_fake_cell(cell);
-  make_fake_var_cell(var_cell);
-
-  /* Tell it to accept cells */
-  test_chan_accept_cells = 1;
-
-  old_count = test_cells_written;
-  channel_write_cell(ch, cell);
-  cell = NULL;
-  tt_assert(test_cells_written == old_count + 1);
-
-  channel_write_var_cell(ch, var_cell);
-  var_cell = NULL;
-  tt_assert(test_cells_written == old_count + 2);
-
-  channel_write_packed_cell(ch, packed_cell);
-  packed_cell = NULL;
-  tt_assert(test_cells_written == old_count + 3);
-
-  /* Now we test queueing; tell it not to accept cells */
-  test_chan_accept_cells = 0;
-  /* ...and keep it from trying to flush the queue */
-  ch->state = CHANNEL_STATE_MAINT;
-
-  /* Get a fresh cell */
-  cell = tor_malloc_zero(sizeof(cell_t));
-  make_fake_cell(cell);
-
-  old_count = test_cells_written;
-  channel_write_cell(ch, cell);
-  tt_assert(test_cells_written == old_count);
-
-  /*
-   * Now change back to open with channel_change_state() and assert that it
-   * gets drained from the queue.
-   */
-  test_chan_accept_cells = 1;
-  channel_change_state_open(ch);
-  tt_assert(test_cells_written == old_count + 1);
-
-  /*
-   * Check the note destroy case
-   */
-  cell = tor_malloc_zero(sizeof(cell_t));
-  make_fake_cell(cell);
-  cell->command = CELL_DESTROY;
-
-  /* Set up the mock */
-  MOCK(channel_note_destroy_not_pending,
-       channel_note_destroy_not_pending_mock);
-
-  old_count = test_destroy_not_pending_calls;
-  channel_write_cell(ch, cell);
-  tt_assert(test_destroy_not_pending_calls == old_count + 1);
-
-  /* Now send a non-destroy and check we don't call it */
-  cell = tor_malloc_zero(sizeof(cell_t));
-  make_fake_cell(cell);
-  channel_write_cell(ch, cell);
-  tt_assert(test_destroy_not_pending_calls == old_count + 1);
-
-  UNMOCK(channel_note_destroy_not_pending);
-
-  /*
-   * Now switch it to CLOSING so we can test the discard-cells case
-   * in the channel_write_*() functions.
-   */
-  MOCK(scheduler_release_channel, scheduler_release_channel_mock);
-  channel_mark_for_close(ch);
-  UNMOCK(scheduler_release_channel);
-
-  /* Send cells that will drop in the closing state */
-  old_count = test_cells_written;
-
-  cell = tor_malloc_zero(sizeof(cell_t));
-  make_fake_cell(cell);
-  channel_write_cell(ch, cell);
-  cell = NULL;
-  tt_assert(test_cells_written == old_count);
-
-  var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
-  make_fake_var_cell(var_cell);
-  channel_write_var_cell(ch, var_cell);
-  var_cell = NULL;
-  tt_assert(test_cells_written == old_count);
-
-  packed_cell = packed_cell_new();
-  channel_write_packed_cell(ch, packed_cell);
-  packed_cell = NULL;
-  tt_assert(test_cells_written == old_count);
-
- done:
-  free_fake_channel(ch);
-  tor_free(var_cell);
-  tor_free(cell);
-  packed_cell_free(packed_cell);
-  return;
-}
-
 static void
 test_channel_id_map(void *arg)
 {
@@ -1142,7 +1006,6 @@ struct testcase_t channel_tests[] = {
   { "incoming", test_channel_incoming, TT_FORK, NULL, NULL },
   { "lifecycle", test_channel_lifecycle, TT_FORK, NULL, NULL },
   { "lifecycle_2", test_channel_lifecycle_2, TT_FORK, NULL, NULL },
-  { "write", test_channel_write, TT_FORK, NULL, NULL },
   { "id_map", test_channel_id_map, TT_FORK, NULL, NULL },
   END_OF_TESTCASES
 };