Exemplo n.º 1
0
Arquivo: RT1.C Projeto: g8bpq/BPQ32
static void link_drop(CIRCUIT *circuit)
{
	USER *user;
	CN   *cn;

// So we don't try and send anything on this circuit.

	circuit->u.link->flags = p_nil;
	circuit->flags = p_nil;

// Users connected on the dropped link are no longer connected.

	for (user = user_hd; user; user = user->next) if (user->circuit == circuit)
	{
		circuit->refcnt--;
		node_dec(user->node);
		text_tellu(user, rtleave, NULL, o_all);
		user_tell(user, id_leave);
		user_leave(user);
	}

// Any node known from the dropped link is no longer known.

	for (cn = circuit->hnode; cn; cn = cn->next)
	{
		node_tell(cn->node, id_unlink);
		node_dec(cn->node);
	}

// The circuit is no longer used.

	circuit_free(circuit);
}
Exemplo n.º 2
0
/** Run unit tests for the onion queues. */
static void
test_onion_queues(void *arg)
{
  uint8_t buf1[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
  uint8_t buf2[NTOR_ONIONSKIN_LEN] = {0};

  or_circuit_t *circ1 = or_circuit_new(0, NULL);
  or_circuit_t *circ2 = or_circuit_new(0, NULL);

  create_cell_t *onionskin = NULL, *create2_ptr;
  create_cell_t *create1 = tor_malloc_zero(sizeof(create_cell_t));
  create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t));
  (void)arg;
  create2_ptr = create2; /* remember, but do not free */

  create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
                   TAP_ONIONSKIN_CHALLENGE_LEN, buf1);
  create_cell_init(create2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
                   NTOR_ONIONSKIN_LEN, buf2);

  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
  tt_int_op(0,OP_EQ, onion_pending_add(circ1, create1));
  create1 = NULL;
  tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));

  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
  tt_int_op(0,OP_EQ, onion_pending_add(circ2, create2));
  create2 = NULL;
  tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));

  tt_ptr_op(circ2,OP_EQ, onion_next_task(&onionskin));
  tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
  tt_ptr_op(onionskin, OP_EQ, create2_ptr);

  clear_pending_onions();
  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
  tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));

 done:
  circuit_free(TO_CIRCUIT(circ1));
  circuit_free(TO_CIRCUIT(circ2));
  tor_free(create1);
  tor_free(create2);
  tor_free(onionskin);
}
Exemplo n.º 3
0
Arquivo: RT1.C Projeto: g8bpq/BPQ32
static void logout(CIRCUIT *circuit)
{
	USER *user;

	circuit->flags = p_nil;
	user = circuit->u.user;
	if (log_rt) tlogp("RT Logout");
	user_tell(user, id_leave);
	text_tellu(user, rtleave, NULL, o_all);
	cn_dec(circuit, user->node);
	user_leave(user);
	circuit_free(circuit);
}
Exemplo n.º 4
0
/** Detach from the global circuit list, and deallocate, all
 * circuits that have been marked for close.
 */
void
circuit_close_all_marked(void)
{
  circuit_t *tmp,*m;

  while (global_circuitlist && global_circuitlist->marked_for_close) {
    tmp = global_circuitlist->next;
    circuit_free(global_circuitlist);
    global_circuitlist = tmp;
  }

  tmp = global_circuitlist;
  while (tmp && tmp->next) {
    if (tmp->next->marked_for_close) {
      m = tmp->next->next;
      circuit_free(tmp->next);
      tmp->next = m;
      /* Need to check new tmp->next; don't advance tmp. */
    } else {
      /* Advance tmp. */
      tmp = tmp->next;
    }
  }
}
Exemplo n.º 5
0
/** Release all storage held by circuits. */
void
circuit_free_all(void)
{
  circuit_t *next;
  while (global_circuitlist) {
    next = global_circuitlist->next;
    if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) {
      or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist);
      while (or_circ->resolving_streams) {
        edge_connection_t *next_conn;
        next_conn = or_circ->resolving_streams->next_stream;
        connection_free(TO_CONN(or_circ->resolving_streams));
        or_circ->resolving_streams = next_conn;
      }
    }
    circuit_free(global_circuitlist);
    global_circuitlist = next;
  }
  if (circuits_pending_or_conns) {
    smartlist_free(circuits_pending_or_conns);
    circuits_pending_or_conns = NULL;
  }
  HT_CLEAR(orconn_circid_map, &orconn_circid_circuit_map);
}
Exemplo n.º 6
0
static void
test_clist_maps(void *arg)
{
  channel_t *ch1 = new_fake_channel();
  channel_t *ch2 = new_fake_channel();
  channel_t *ch3 = new_fake_channel();
  or_circuit_t *or_c1=NULL, *or_c2=NULL;

  (void) arg;

  MOCK(circuitmux_attach_circuit, circuitmux_attach_mock);
  MOCK(circuitmux_detach_circuit, circuitmux_detach_mock);
  memset(&cam, 0, sizeof(cam));
  memset(&cdm, 0, sizeof(cdm));

  tt_assert(ch1);
  tt_assert(ch2);
  tt_assert(ch3);

  ch1->cmux = tor_malloc(1);
  ch2->cmux = tor_malloc(1);
  ch3->cmux = tor_malloc(1);

  or_c1 = or_circuit_new(100, ch2);
  tt_assert(or_c1);
  GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN);
  tt_int_op(or_c1->p_circ_id, OP_EQ, 100);
  tt_ptr_op(or_c1->p_chan, OP_EQ, ch2);

  or_c2 = or_circuit_new(100, ch1);
  tt_assert(or_c2);
  GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN);
  tt_int_op(or_c2->p_circ_id, OP_EQ, 100);
  tt_ptr_op(or_c2->p_chan, OP_EQ, ch1);

  circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1);
  GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT);

  circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2);
  GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT);

  tt_ptr_op(circuit_get_by_circid_channel(200, ch1), OP_EQ, TO_CIRCUIT(or_c1));
  tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
  tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
  /* Try the same thing again, to test the "fast" path. */
  tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
  tt_assert(circuit_id_in_use_on_channel(100, ch2));
  tt_assert(! circuit_id_in_use_on_channel(101, ch2));

  /* Try changing the circuitid and channel of that circuit. */
  circuit_set_p_circid_chan(or_c1, 500, ch3);
  GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1));
  GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN);
  tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, NULL);
  tt_assert(! circuit_id_in_use_on_channel(100, ch2));
  tt_ptr_op(circuit_get_by_circid_channel(500, ch3), OP_EQ, TO_CIRCUIT(or_c1));

  /* Now let's see about destroy handling. */
  tt_assert(! circuit_id_in_use_on_channel(205, ch2));
  tt_assert(circuit_id_in_use_on_channel(200, ch2));
  channel_note_destroy_pending(ch2, 200);
  channel_note_destroy_pending(ch2, 205);
  channel_note_destroy_pending(ch1, 100);
  tt_assert(circuit_id_in_use_on_channel(205, ch2))
  tt_assert(circuit_id_in_use_on_channel(200, ch2));
  tt_assert(circuit_id_in_use_on_channel(100, ch1));

  tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0);
  tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
  tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, TO_CIRCUIT(or_c2));

  /* Okay, now free ch2 and make sure that the circuit ID is STILL not
   * usable, because we haven't declared the destroy to be nonpending */
  tt_int_op(cdm.ncalls, OP_EQ, 0);
  circuit_free(TO_CIRCUIT(or_c2));
  or_c2 = NULL; /* prevent free */
  tt_int_op(cdm.ncalls, OP_EQ, 2);
  memset(&cdm, 0, sizeof(cdm));
  tt_assert(circuit_id_in_use_on_channel(200, ch2));
  tt_assert(circuit_id_in_use_on_channel(100, ch1));
  tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
  tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);

  /* Now say that the destroy is nonpending */
  channel_note_destroy_not_pending(ch2, 200);
  tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
  channel_note_destroy_not_pending(ch1, 100);
  tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);
  tt_assert(! circuit_id_in_use_on_channel(200, ch2));
  tt_assert(! circuit_id_in_use_on_channel(100, ch1));

 done:
  if (or_c1)
    circuit_free(TO_CIRCUIT(or_c1));
  if (or_c2)
    circuit_free(TO_CIRCUIT(or_c2));
  if (ch1)
    tor_free(ch1->cmux);
  if (ch2)
    tor_free(ch2->cmux);
  if (ch3)
    tor_free(ch3->cmux);
  tor_free(ch1);
  tor_free(ch2);
  tor_free(ch3);
  UNMOCK(circuitmux_attach_circuit);
  UNMOCK(circuitmux_detach_circuit);
}
Exemplo n.º 7
0
static void
test_rend_token_maps(void *arg)
{
  or_circuit_t *c1, *c2, *c3, *c4;
  const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y";
  const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it ";
  const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care.";
  /* -- Adapted from a quote by Fredrik Lundh. */

  (void)arg;
  (void)tok1; //xxxx
  c1 = or_circuit_new(0, NULL);
  c2 = or_circuit_new(0, NULL);
  c3 = or_circuit_new(0, NULL);
  c4 = or_circuit_new(0, NULL);

  /* Make sure we really filled up the tok* variables */
  tt_int_op(tok1[REND_TOKEN_LEN-1], OP_EQ, 'y');
  tt_int_op(tok2[REND_TOKEN_LEN-1], OP_EQ, ' ');
  tt_int_op(tok3[REND_TOKEN_LEN-1], OP_EQ, '.');

  /* No maps; nothing there. */
  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1));
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1));

  circuit_set_rendezvous_cookie(c1, tok1);
  circuit_set_intro_point_digest(c2, tok2);

  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok3));
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3));
  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2));
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1));

  /* Without purpose set, we don't get the circuits */
  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1));
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2));

  c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
  c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;

  /* Okay, make sure they show up now. */
  tt_ptr_op(c1, OP_EQ, circuit_get_rendezvous(tok1));
  tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2));

  /* Two items at the same place with the same token. */
  c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
  circuit_set_rendezvous_cookie(c3, tok2);
  tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2));
  tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2));

  /* Marking a circuit makes it not get returned any more */
  circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED);
  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1));
  circuit_free(TO_CIRCUIT(c1));
  c1 = NULL;

  /* Freeing a circuit makes it not get returned any more. */
  circuit_free(TO_CIRCUIT(c2));
  c2 = NULL;
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2));

  /* c3 -- are you still there? */
  tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2));
  /* Change its cookie.  This never happens in Tor per se, but hey. */
  c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  circuit_set_intro_point_digest(c3, tok3);

  tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2));
  tt_ptr_op(c3, OP_EQ, circuit_get_intro_point(tok3));

  /* Now replace c3 with c4. */
  c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
  circuit_set_intro_point_digest(c4, tok3);

  tt_ptr_op(c4, OP_EQ, circuit_get_intro_point(tok3));

  tt_ptr_op(c3->rendinfo, OP_EQ, NULL);
  tt_ptr_op(c4->rendinfo, OP_NE, NULL);
  tt_mem_op(c4->rendinfo, OP_EQ, tok3, REND_TOKEN_LEN);

  /* Now clear c4's cookie. */
  circuit_set_intro_point_digest(c4, NULL);
  tt_ptr_op(c4->rendinfo, OP_EQ, NULL);
  tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3));

 done:
  if (c1)
    circuit_free(TO_CIRCUIT(c1));
  if (c2)
    circuit_free(TO_CIRCUIT(c2));
  if (c3)
    circuit_free(TO_CIRCUIT(c3));
  if (c4)
    circuit_free(TO_CIRCUIT(c4));
}
Exemplo n.º 8
0
/** Run unit tests for buffers.c */
static void
test_oom_streambuf(void *arg)
{
  or_options_t *options = get_options_mutable();
  circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL, *c5 = NULL;
  struct timeval tv = { 1389641159, 0 };
  uint32_t tvms;
  int i;
  smartlist_t *edgeconns = smartlist_new();

  (void) arg;

  MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_);

  /* Far too low for real life. */
  options->MaxMemInQueues = 81*packed_cell_mem_cost() + 4096 * 34;
  options->CellStatistics = 0;

  tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We don't start out OOM. */
  tt_int_op(cell_queues_get_total_allocation(), OP_EQ, 0);
  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);

  /* Start all circuits with a bit of data queued in cells */
  tv.tv_usec = 500*1000; /* go halfway into the second. */
  tor_gettimeofday_cache_set(&tv);
  c1 = dummy_or_circuit_new(10,10);
  tv.tv_usec = 510*1000;
  tor_gettimeofday_cache_set(&tv);
  c2 = dummy_origin_circuit_new(20);
  tv.tv_usec = 520*1000;
  tor_gettimeofday_cache_set(&tv);
  c3 = dummy_or_circuit_new(20,20);
  tv.tv_usec = 530*1000;
  tor_gettimeofday_cache_set(&tv);
  c4 = dummy_or_circuit_new(0,0);
  tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
            packed_cell_mem_cost() * 80);

  tv.tv_usec = 600*1000;
  tor_gettimeofday_cache_set(&tv);

  /* Add some connections to c1...c4. */
  for (i = 0; i < 4; ++i) {
    edge_connection_t *ec;
    /* link it to a circuit */
    tv.tv_usec += 10*1000;
    tor_gettimeofday_cache_set(&tv);
    ec = dummy_edge_conn_new(c1, CONN_TYPE_EXIT, 1000, 1000);
    tt_assert(ec);
    smartlist_add(edgeconns, ec);
    tv.tv_usec += 10*1000;
    tor_gettimeofday_cache_set(&tv);
    ec = dummy_edge_conn_new(c2, CONN_TYPE_AP, 1000, 1000);
    tt_assert(ec);
    smartlist_add(edgeconns, ec);
    tv.tv_usec += 10*1000;
    tor_gettimeofday_cache_set(&tv);
    ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000); /* Yes, 4 twice*/
    tt_assert(ec);
    smartlist_add(edgeconns, ec);
    tv.tv_usec += 10*1000;
    tor_gettimeofday_cache_set(&tv);
    ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000);
    smartlist_add(edgeconns, ec);
    tt_assert(ec);
  }

  tv.tv_sec += 1;
  tv.tv_usec = 0;
  tvms = (uint32_t) tv_to_msec(&tv);

  tt_int_op(circuit_max_queued_cell_age(c1, tvms), OP_EQ, 500);
  tt_int_op(circuit_max_queued_cell_age(c2, tvms), OP_EQ, 490);
  tt_int_op(circuit_max_queued_cell_age(c3, tvms), OP_EQ, 480);
  tt_int_op(circuit_max_queued_cell_age(c4, tvms), OP_EQ, 0);

  tt_int_op(circuit_max_queued_data_age(c1, tvms), OP_EQ, 390);
  tt_int_op(circuit_max_queued_data_age(c2, tvms), OP_EQ, 380);
  tt_int_op(circuit_max_queued_data_age(c3, tvms), OP_EQ, 0);
  tt_int_op(circuit_max_queued_data_age(c4, tvms), OP_EQ, 370);

  tt_int_op(circuit_max_queued_item_age(c1, tvms), OP_EQ, 500);
  tt_int_op(circuit_max_queued_item_age(c2, tvms), OP_EQ, 490);
  tt_int_op(circuit_max_queued_item_age(c3, tvms), OP_EQ, 480);
  tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 370);

  tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
            packed_cell_mem_cost() * 80);
  tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*16*2);

  /* Now give c4 a very old buffer of modest size */
  {
    edge_connection_t *ec;
    tv.tv_sec -= 1;
    tv.tv_usec = 0;
    tor_gettimeofday_cache_set(&tv);
    ec = dummy_edge_conn_new(c4, CONN_TYPE_EXIT, 1000, 1000);
    tt_assert(ec);
    smartlist_add(edgeconns, ec);
  }
  tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2);
  tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 1000);

  tt_int_op(cell_queues_check_size(), OP_EQ, 0);

  /* And run over the limit. */
  tv.tv_usec = 800*1000;
  tor_gettimeofday_cache_set(&tv);
  c5 = dummy_or_circuit_new(0,5);

  tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
            packed_cell_mem_cost() * 85);
  tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2);

  tt_int_op(cell_queues_check_size(), OP_EQ, 1); /* We are now OOM */

  /* C4 should have died. */
  tt_assert(! c1->marked_for_close);
  tt_assert(! c2->marked_for_close);
  tt_assert(! c3->marked_for_close);
  tt_assert(c4->marked_for_close);
  tt_assert(! c5->marked_for_close);

  tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
            packed_cell_mem_cost() * 85);
  tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*8*2);

 done:
  circuit_free(c1);
  circuit_free(c2);
  circuit_free(c3);
  circuit_free(c4);
  circuit_free(c5);

  SMARTLIST_FOREACH(edgeconns, edge_connection_t *, ec,
                    connection_free_(TO_CONN(ec)));
  smartlist_free(edgeconns);

  UNMOCK(circuit_mark_for_close_);
}
Exemplo n.º 9
0
/** Run unit tests for buffers.c */
static void
test_oom_circbuf(void *arg)
{
  or_options_t *options = get_options_mutable();
  circuit_t *c1 = NULL, *c2 = NULL, *c3 = NULL, *c4 = NULL;
  struct timeval tv = { 1389631048, 0 };

  (void) arg;

  MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_);

  /* Far too low for real life. */
  options->MaxMemInQueues = 256*packed_cell_mem_cost();
  options->CellStatistics = 0;

  tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We don't start out OOM. */
  tt_int_op(cell_queues_get_total_allocation(), OP_EQ, 0);
  tt_int_op(buf_get_total_allocation(), OP_EQ, 0);

  /* Now we're going to fake up some circuits and get them added to the global
     circuit list. */
  tv.tv_usec = 0;
  tor_gettimeofday_cache_set(&tv);
  c1 = dummy_origin_circuit_new(30);
  tv.tv_usec = 10*1000;
  tor_gettimeofday_cache_set(&tv);
  c2 = dummy_or_circuit_new(20, 20);

  tt_int_op(packed_cell_mem_cost(), OP_EQ,
            sizeof(packed_cell_t));
  tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
            packed_cell_mem_cost() * 70);
  tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We are still not OOM */

  tv.tv_usec = 20*1000;
  tor_gettimeofday_cache_set(&tv);
  c3 = dummy_or_circuit_new(100, 85);
  tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We are still not OOM */
  tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
            packed_cell_mem_cost() * 255);

  tv.tv_usec = 30*1000;
  tor_gettimeofday_cache_set(&tv);
  /* Adding this cell will trigger our OOM handler. */
  c4 = dummy_or_circuit_new(2, 0);

  tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
            packed_cell_mem_cost() * 257);

  tt_int_op(cell_queues_check_size(), OP_EQ, 1); /* We are now OOM */

  tt_assert(c1->marked_for_close);
  tt_assert(! c2->marked_for_close);
  tt_assert(! c3->marked_for_close);
  tt_assert(! c4->marked_for_close);

  tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
            packed_cell_mem_cost() * (257 - 30));

  circuit_free(c1);
  tv.tv_usec = 0;
  tor_gettimeofday_cache_set(&tv); /* go back in time */
  c1 = dummy_or_circuit_new(90, 0);

  tv.tv_usec = 40*1000; /* go back to the future */
  tor_gettimeofday_cache_set(&tv);

  tt_int_op(cell_queues_check_size(), OP_EQ, 1); /* We are now OOM */

  tt_assert(c1->marked_for_close);
  tt_assert(! c2->marked_for_close);
  tt_assert(! c3->marked_for_close);
  tt_assert(! c4->marked_for_close);

  tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
            packed_cell_mem_cost() * (257 - 30));

 done:
  circuit_free(c1);
  circuit_free(c2);
  circuit_free(c3);
  circuit_free(c4);

  UNMOCK(circuit_mark_for_close_);
}