Exemplo n.º 1
0
/* Test inbound cell. The callstack is:
 *  channel_process_cell()
 *    -> chan->cell_handler()
 *
 * This test is about checking if we can process an inbound cell down to the
 * channel handler. */
static void
test_channel_inbound_cell(void *arg)
{
  channel_t *chan = NULL;
  cell_t *cell = NULL;
  int old_count;

  (void) arg;

  /* The channel will be freed so we need to hijack this so the scheduler
   * doesn't get confused. */
  MOCK(scheduler_release_channel, scheduler_release_channel_mock);

  /* Accept cells to lower layer */
  test_chan_accept_cells = 1;

  chan = new_fake_channel();
  tt_assert(chan);
  /* Start it off in OPENING */
  chan->state = CHANNEL_STATE_OPENING;

  /* Try to register it */
  channel_register(chan);
  tt_int_op(chan->registered, OP_EQ, 1);

  /* Open it */
  channel_change_state_open(chan);
  tt_int_op(chan->state, OP_EQ, CHANNEL_STATE_OPEN);
  tt_int_op(chan->has_been_open, OP_EQ, 1);

  /* Receive a cell now. */
  cell = tor_malloc_zero(sizeof(*cell));
  make_fake_cell(cell);
  old_count = test_chan_fixed_cells_recved;
  channel_process_cell(chan, cell);
  tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count);
  tt_assert(monotime_coarse_is_zero(&chan->timestamp_xfer));
  tt_u64_op(chan->timestamp_active, OP_EQ, 0);
  tt_u64_op(chan->timestamp_recv, OP_EQ, 0);

  /* Setup incoming cell handlers. We don't care about var cell, the channel
   * layers is not handling those. */
  channel_set_cell_handlers(chan, chan_test_cell_handler, NULL);
  tt_ptr_op(chan->cell_handler, OP_EQ, chan_test_cell_handler);
  /* Now process the cell, we should see it. */
  old_count = test_chan_fixed_cells_recved;
  channel_process_cell(chan, cell);
  tt_int_op(test_chan_fixed_cells_recved, OP_EQ, old_count + 1);
  /* We should have a series of timestamp set. */
  tt_assert(!monotime_coarse_is_zero(&chan->timestamp_xfer));
  tt_u64_op(chan->timestamp_active, OP_NE, 0);
  tt_u64_op(chan->timestamp_recv, OP_NE, 0);
  tt_assert(monotime_coarse_is_zero(&chan->next_padding_time));
  tt_u64_op(chan->n_cells_recved, OP_EQ, 1);
  tt_u64_op(chan->n_bytes_recved, OP_EQ, get_cell_network_size(0));

  /* Close it */
  old_count = test_close_called;
  channel_mark_for_close(chan);
  tt_int_op(chan->state, OP_EQ, CHANNEL_STATE_CLOSING);
  tt_int_op(chan->reason_for_closing, OP_EQ, CHANNEL_CLOSE_REQUESTED);
  tt_int_op(test_close_called, OP_EQ, old_count + 1);

  /* This closes the channe so it calls in the scheduler, make sure of it. */
  old_count = test_releases_count;
  chan_test_finish_close(chan);
  tt_int_op(test_releases_count, OP_EQ, old_count + 1);
  tt_int_op(chan->state, OP_EQ, CHANNEL_STATE_CLOSED);

  /* The channel will be free, lets make sure it is not accessible. */
  uint64_t chan_id = chan->global_identifier;
  tt_ptr_op(channel_find_by_global_id(chan_id), OP_EQ, chan);
  channel_run_cleanup();
  chan = channel_find_by_global_id(chan_id);
  tt_assert(chan == NULL);

 done:
  tor_free(cell);
  UNMOCK(scheduler_release_channel);
}
Exemplo n.º 2
0
/** Called when we get data from a cpuworker.  If the answer is not complete,
 * wait for a complete answer. If the answer is complete,
 * process it as appropriate.
 */
int
connection_cpu_process_inbuf(connection_t *conn)
{
  uint64_t chan_id;
  circid_t circ_id;
  channel_t *p_chan = NULL;
  circuit_t *circ;

  tor_assert(conn);
  tor_assert(conn->type == CONN_TYPE_CPUWORKER);

  if (!connection_get_inbuf_len(conn))
    return 0;

  if (conn->state == CPUWORKER_STATE_BUSY_ONION) {
    cpuworker_reply_t rpl;
    if (connection_get_inbuf_len(conn) < sizeof(cpuworker_reply_t))
      return 0; /* not yet */
    tor_assert(connection_get_inbuf_len(conn) == sizeof(cpuworker_reply_t));

    connection_fetch_from_buf((void*)&rpl,sizeof(cpuworker_reply_t),conn);

    tor_assert(rpl.magic == CPUWORKER_REPLY_MAGIC);

    if (rpl.timed && rpl.success &&
        rpl.handshake_type <= MAX_ONION_HANDSHAKE_TYPE) {
      /* Time how long this request took. The handshake_type check should be
         needless, but let's leave it in to be safe. */
      struct timeval tv_end, tv_diff;
      int64_t usec_roundtrip;
      tor_gettimeofday(&tv_end);
      timersub(&tv_end, &rpl.started_at, &tv_diff);
      usec_roundtrip = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
      if (usec_roundtrip >= 0 &&
          usec_roundtrip < MAX_BELIEVABLE_ONIONSKIN_DELAY) {
        ++onionskins_n_processed[rpl.handshake_type];
        onionskins_usec_internal[rpl.handshake_type] += rpl.n_usec;
        onionskins_usec_roundtrip[rpl.handshake_type] += usec_roundtrip;
        if (onionskins_n_processed[rpl.handshake_type] >= 500000) {
          /* Scale down every 500000 handshakes.  On a busy server, that's
           * less impressive than it sounds. */
          onionskins_n_processed[rpl.handshake_type] /= 2;
          onionskins_usec_internal[rpl.handshake_type] /= 2;
          onionskins_usec_roundtrip[rpl.handshake_type] /= 2;
        }
      }
    }
    /* parse out the circ it was talking about */
    tag_unpack(rpl.tag, &chan_id, &circ_id);
    circ = NULL;
    log_debug(LD_OR,
              "Unpacking cpuworker reply, chan_id is " U64_FORMAT
              ", circ_id is %u",
              U64_PRINTF_ARG(chan_id), (unsigned)circ_id);
    p_chan = channel_find_by_global_id(chan_id);

    if (p_chan)
      circ = circuit_get_by_circid_channel(circ_id, p_chan);

    if (rpl.success == 0) {
      log_debug(LD_OR,
                "decoding onionskin failed. "
                "(Old key or bad software.) Closing.");
      if (circ)
        circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
      goto done_processing;
    }
    if (!circ) {
      /* This happens because somebody sends us a destroy cell and the
       * circuit goes away, while the cpuworker is working. This is also
       * why our tag doesn't include a pointer to the circ, because we'd
       * never know if it's still valid.
       */
      log_debug(LD_OR,"processed onion for a circ that's gone. Dropping.");
      goto done_processing;
    }
    tor_assert(! CIRCUIT_IS_ORIGIN(circ));
    if (onionskin_answer(TO_OR_CIRCUIT(circ),
                         &rpl.created_cell,
                         (const char*)rpl.keys,
                         rpl.rend_auth_material) < 0) {
      log_warn(LD_OR,"onionskin_answer failed. Closing.");
      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
      goto done_processing;
    }
    log_debug(LD_OR,"onionskin_answer succeeded. Yay.");
  } else {
    tor_assert(0); /* don't ask me to do handshakes yet */
  }

 done_processing:
  conn->state = CPUWORKER_STATE_IDLE;
  num_cpuworkers_busy--;
  if (conn->timestamp_created < last_rotation_time) {
    connection_mark_for_close(conn);
    num_cpuworkers--;
    spawn_enough_cpuworkers();
  } else {
    process_pending_task(conn);
  }
  return 0;
}
Exemplo n.º 3
0
/** Called when we get data from a cpuworker.  If the answer is not complete,
 * wait for a complete answer. If the answer is complete,
 * process it as appropriate.
 */
int
connection_cpu_process_inbuf(connection_t *conn)
{
  char success;
  char buf[LEN_ONION_RESPONSE];
  uint64_t chan_id;
  circid_t circ_id;
  channel_t *p_chan = NULL;
  circuit_t *circ;

  tor_assert(conn);
  tor_assert(conn->type == CONN_TYPE_CPUWORKER);

  if (!connection_get_inbuf_len(conn))
    return 0;

  if (conn->state == CPUWORKER_STATE_BUSY_ONION) {
    if (connection_get_inbuf_len(conn) < LEN_ONION_RESPONSE)
      return 0; /* not yet */
    tor_assert(connection_get_inbuf_len(conn) == LEN_ONION_RESPONSE);

    connection_fetch_from_buf(&success,1,conn);
    connection_fetch_from_buf(buf,LEN_ONION_RESPONSE-1,conn);

    /* parse out the circ it was talking about */
    tag_unpack(buf, &chan_id, &circ_id);
    circ = NULL;
    log_debug(LD_OR,
              "Unpacking cpuworker reply, chan_id is " U64_FORMAT
              ", circ_id is %d",
              U64_PRINTF_ARG(chan_id), circ_id);
    p_chan = channel_find_by_global_id(chan_id);

    if (p_chan)
      circ = circuit_get_by_circid_channel(circ_id, p_chan);

    if (success == 0) {
      log_debug(LD_OR,
                "decoding onionskin failed. "
                "(Old key or bad software.) Closing.");
      if (circ)
        circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
      goto done_processing;
    }
    if (!circ) {
      /* This happens because somebody sends us a destroy cell and the
       * circuit goes away, while the cpuworker is working. This is also
       * why our tag doesn't include a pointer to the circ, because we'd
       * never know if it's still valid.
       */
      log_debug(LD_OR,"processed onion for a circ that's gone. Dropping.");
      goto done_processing;
    }
    tor_assert(! CIRCUIT_IS_ORIGIN(circ));
    if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
                         buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
      log_warn(LD_OR,"onionskin_answer failed. Closing.");
      circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
      goto done_processing;
    }
    log_debug(LD_OR,"onionskin_answer succeeded. Yay.");
  } else {
    tor_assert(0); /* don't ask me to do handshakes yet */
  }

 done_processing:
  conn->state = CPUWORKER_STATE_IDLE;
  num_cpuworkers_busy--;
  if (conn->timestamp_created < last_rotation_time) {
    connection_mark_for_close(conn);
    num_cpuworkers--;
    spawn_enough_cpuworkers();
  } else {
    process_pending_task(conn);
  }
  return 0;
}