示例#1
0
static void
test_virtaddrmap(void *data)
{
  /* Let's start with a bunch of random addresses. */
  int ipv6, bits, iter, b;
  virtual_addr_conf_t cfg[2];
  uint8_t bytes[16];

  (void)data;

  tor_addr_parse(&cfg[0].addr, "64.65.0.0");
  tor_addr_parse(&cfg[1].addr, "3491:c0c0::");

  for (ipv6 = 0; ipv6 <= 1; ++ipv6) {
    for (bits = 0; bits < 18; ++bits) {
      tor_addr_t last_a;
      cfg[ipv6].bits = bits;
      memset(bytes, 0, sizeof(bytes));
      tor_addr_copy(&last_a, &cfg[ipv6].addr);
      /* Generate 128 addresses with each addr/bits combination. */
      for (iter = 0; iter < 128; ++iter) {
        tor_addr_t a;

        get_random_virtual_addr(&cfg[ipv6], &a);
        //printf("%s\n", fmt_addr(&a));
        /* Make sure that the first b bits match the configured network */
        tt_int_op(0, OP_EQ, tor_addr_compare_masked(&a, &cfg[ipv6].addr,
                                                 bits, CMP_EXACT));

        /* And track which bits have been different between pairs of
         * addresses */
        update_difference(ipv6, bytes, &last_a, &a);
      }

      /* Now make sure all but the first 'bits' bits of bytes are true */
      for (b = bits+1; b < (ipv6?128:32); ++b) {
        tt_assert(1 & (bytes[b/8] >> (7-(b&7))));
      }
    }
  }

 done:
  ;
}
示例#2
0
文件: test_pubsub.c 项目: 1234max/tor
static void
test_pubsub_basic(void *arg)
{
  (void)arg;
  foobar_subscriber_data_t subdata1 = { "hi", 0 };
  foobar_subscriber_data_t subdata2 = { "wow", 0 };
  const foobar_subscriber_t *sub1;
  const foobar_subscriber_t *sub2;
  foobar_event_data_t ed = { 0, "x" };
  foobar_event_data_t ed2 = { 0, "y" };
  sub1 = foobar_subscribe(foobar_sub1, &subdata1, SUBSCRIBE_ATSTART, 100);
  tt_assert(sub1);

  foobar_notify(&ed, 0);
  tt_int_op(subdata1.l, OP_EQ, 100);
  tt_int_op(subdata2.l, OP_EQ, 0);
  tt_int_op(ed.u, OP_EQ, 10);

  sub2 = foobar_subscribe(foobar_sub2, &subdata2, 0, 5);
  tt_assert(sub2);

  foobar_notify(&ed2, 0);
  tt_int_op(subdata1.l, OP_EQ, 200);
  tt_int_op(subdata2.l, OP_EQ, 50);
  tt_int_op(ed2.u, OP_EQ, 15);

  foobar_unsubscribe(sub1);

  foobar_notify(&ed, 0);
  tt_int_op(subdata1.l, OP_EQ, 200);
  tt_int_op(subdata2.l, OP_EQ, 100);
  tt_int_op(ed.u, OP_EQ, 15);

 done:
  foobar_clear();
}
示例#3
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = NULL;
  routerset_t **setp = &set;
  int r;
  (void)arg;

  NS_MOCK(geoip_get_country);

  r = routerset_add_unknown_ccs(setp, 0);

  tt_ptr_op(*setp, OP_NE, NULL);
  tt_int_op(r, OP_EQ, 0);

  done:
    if (set != NULL)
      routerset_free(set);
}
示例#4
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = routerset_new();
  routerinfo_t ri;
  country_t country = 1;
  int r;
  const char *nickname = "foo";
  (void)arg;

  memset(&ri, 0, sizeof(ri));
  strmap_set_lc(set->names, nickname, (void *)1);
  ri.nickname = (char *)nickname;

  r = routerset_contains_router(set, &ri, country);

  tt_int_op(r, OP_EQ, 4);
  done:
    routerset_free(set);
}
示例#5
0
static void
test_address_tor_addr_to_ipv4n(void *ignored)
{
  (void)ignored;
  tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t));
  uint32_t res;

  a->family = AF_INET6;
  res = tor_addr_to_ipv4n(a);
  tt_assert(!res);

  a->family = AF_INET;
  a->addr.in_addr.s_addr = 43;
  res = tor_addr_to_ipv4n(a);
  tt_assert(res);
  tt_int_op(res, OP_EQ, 43);

 done:
  tor_free(a);
}
示例#6
0
static void
test_address_tor_addr_to_in(void *ignored)
{
  (void)ignored;
  tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t));
  const struct in_addr *res;

  a->family = AF_INET6;
  res = tor_addr_to_in(a);
  tt_assert(!res);

  a->family = AF_INET;
  a->addr.in_addr.s_addr = 44;
  res = tor_addr_to_in(a);
  tt_assert(res);
  tt_int_op(res->s_addr, OP_EQ, 44);

 done:
  tor_free(a);
}
示例#7
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = routerset_new();
  extend_info_t ei;
  int r;
  const char *nickname = "foo";
  (void)arg;

  memset(&ei, 0, sizeof(ei));
  strmap_set_lc(set->names, nickname, (void *)1);
  strncpy(ei.nickname, nickname, sizeof(ei.nickname) - 1);
  ei.nickname[sizeof(ei.nickname) - 1] = '\0';

  r = routerset_contains_extendinfo(set, &ei);

  tt_int_op(r, OP_EQ, 4);
  done:
    routerset_free(set);
}
示例#8
0
static void
test_util_format_base64_decode(void *ignored)
{
  (void)ignored;
  int res;
  int i;
  char *src;
  char *dst, *real_dst;
  uint8_t expected[] = {0x65, 0x78, 0x61, 0x6D, 0x70, 0x6C, 0x65};
  char real_src[] = "ZXhhbXBsZQ==";

  src = tor_malloc_zero(256);
  dst = tor_malloc_zero(1000);
  real_dst = tor_malloc_zero(10);

  for (i=0;i<256;i++) {
    src[i] = (char)i;
  }

  res = base64_decode(dst, 1, src, SIZE_T_CEILING);
  tt_int_op(res, OP_EQ, -1);

  res = base64_decode(dst, SIZE_T_CEILING+1, src, 10);
  tt_int_op(res, OP_EQ, -1);

  const char *s = "T3BhIG11bmRv";
  res = base64_decode(dst, 9, s, strlen(s));
  tt_int_op(res, OP_EQ, 9);
  tt_mem_op(dst, OP_EQ, "Opa mundo", 9);

  memset(dst, 0, 1000);
  res = base64_decode(dst, 100, s, strlen(s));
  tt_int_op(res, OP_EQ, 9);
  tt_mem_op(dst, OP_EQ, "Opa mundo", 9);

  s = "SGVsbG8gd29ybGQ=";
  res = base64_decode(dst, 100, s, strlen(s));
  tt_int_op(res, OP_EQ, 11);
  tt_mem_op(dst, OP_EQ, "Hello world", 11);

  res = base64_decode(real_dst, 10, real_src, 10);
  tt_int_op(res, OP_EQ, 7);
  tt_mem_op(real_dst, OP_EQ, expected, 7);

 done:
  tor_free(src);
  tor_free(dst);
  tor_free(real_dst);
}
示例#9
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = routerset_new();
  routerstatus_t rs;
  country_t country = 1;
  int r;
  const char *nickname = "foo";
  (void)arg;

  memset(&rs, 0, sizeof(rs));
  strmap_set_lc(set->names, nickname, (void *)1);
  strncpy(rs.nickname, nickname, sizeof(rs.nickname) - 1);
  rs.nickname[sizeof(rs.nickname) - 1] = '\0';

  r = routerset_contains_routerstatus(set, &rs, country);

  tt_int_op(r, OP_EQ, 4);
  done:
    routerset_free(set);
}
示例#10
0
static void
test_rend_cache_lookup_entry(void *data)
{
  int ret;
  rend_data_t *mock_rend_query = NULL;
  char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
  rend_cache_entry_t *entry = NULL;
  rend_encoded_v2_service_descriptor_t *desc_holder = NULL;
  char *service_id = NULL;
  (void)data;

  rend_cache_init();

  generate_desc(RECENT_TIME, &desc_holder, &service_id, 3);

  ret = rend_cache_lookup_entry("abababababababab", 0, NULL);
  tt_int_op(ret, OP_EQ, -ENOENT);

  ret = rend_cache_lookup_entry("invalid query", 2, NULL);
  tt_int_op(ret, OP_EQ, -EINVAL);

  ret = rend_cache_lookup_entry("abababababababab", 2, NULL);
  tt_int_op(ret, OP_EQ, -ENOENT);

  ret = rend_cache_lookup_entry("abababababababab", 4224, NULL);
  tt_int_op(ret, OP_EQ, -ENOENT);

  mock_rend_query = mock_rend_data(service_id);
  base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_holder->desc_id,
                DIGEST_LEN);
  rend_cache_store_v2_desc_as_client(desc_holder->desc_str, desc_id_base32,
                                     mock_rend_query, NULL);

  ret = rend_cache_lookup_entry(service_id, 2, NULL);
  tt_int_op(ret, OP_EQ, 0);

  ret = rend_cache_lookup_entry(service_id, 2, &entry);
  tt_assert(entry);
  tt_int_op(entry->len, OP_EQ, strlen(desc_holder->desc_str));
  tt_str_op(entry->desc, OP_EQ, desc_holder->desc_str);

 done:
  rend_encoded_v2_service_descriptor_free(desc_holder);
  tor_free(service_id);
  rend_cache_free_all();
  rend_data_free(mock_rend_query);
}
示例#11
0
/** Helper to conduct tests for populate_live_entry_guards().

   This test adds some entry guards to our list, and then tests
   populate_live_entry_guards() to mke sure it filters them correctly.

   <b>num_needed</b> is the number of guard nodes we support. It's
   configurable to make sure we function properly with 1 or 3 guard
   nodes configured.
*/
static void
populate_live_entry_guards_test_helper(int num_needed)
{
  smartlist_t *our_nodelist = NULL;
  smartlist_t *live_entry_guards = smartlist_new();
  const smartlist_t *all_entry_guards = get_entry_guards();
  or_options_t *options = get_options_mutable();
  int retval;

  /* Set NumEntryGuards to the provided number. */
  options->NumEntryGuards = num_needed;
  tt_int_op(num_needed, OP_EQ, decide_num_guards(options, 0));

  /* The global entry guards smartlist should be empty now. */
  tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 0);

  /* Walk the nodelist and add all nodes as entry guards. */
  our_nodelist = nodelist_get_list();
  tt_int_op(smartlist_len(our_nodelist), OP_EQ, NUMBER_OF_DESCRIPTORS);

  SMARTLIST_FOREACH_BEGIN(our_nodelist, const node_t *, node) {
    const node_t *node_tmp;
    node_tmp = add_an_entry_guard(node, 0, 1, 0, 0);
    tt_assert(node_tmp);
  } SMARTLIST_FOREACH_END(node);

  /* Make sure the nodes were added as entry guards. */
  tt_int_op(smartlist_len(all_entry_guards), OP_EQ, NUMBER_OF_DESCRIPTORS);

  /* Ensure that all the possible entry guards are enough to satisfy us. */
  tt_int_op(smartlist_len(all_entry_guards), OP_GE, num_needed);

  /* Walk the entry guard list for some sanity checking */
  SMARTLIST_FOREACH_BEGIN(all_entry_guards, const entry_guard_t *, entry) {
    /* Since we called add_an_entry_guard() with 'for_discovery' being
       False, all guards should have made_contact enabled. */
    tt_int_op(entry->made_contact, OP_EQ, 1);

    /* Since we don't have a routerstatus, all of the entry guards are
       not directory servers. */
    tt_int_op(entry->is_dir_cache, OP_EQ, 0);
  } SMARTLIST_FOREACH_END(entry);
示例#12
0
static void
test_cntev_bucket_millis_empty(void *arg)
{
  struct timeval tvnow;
  (void)arg;

  /* 1970-01-02 00:00:42.200000 */
  tvnow.tv_sec = 86400 + 42;
  tvnow.tv_usec = 200000;

  /* Bucket has not been refilled. */
  tt_int_op(0, OP_EQ, bucket_millis_empty(0, 42120, 0, 100, &tvnow));
  tt_int_op(0, OP_EQ, bucket_millis_empty(-10, 42120, -10, 100, &tvnow));

  /* Bucket was not empty. */
  tt_int_op(0, OP_EQ, bucket_millis_empty(10, 42120, 20, 100, &tvnow));

  /* Bucket has been emptied 80 msec ago and has just been refilled. */
  tt_int_op(80, OP_EQ, bucket_millis_empty(-20, 42120, -10, 100, &tvnow));
  tt_int_op(80, OP_EQ, bucket_millis_empty(-10, 42120, 0, 100, &tvnow));
  tt_int_op(80, OP_EQ, bucket_millis_empty(0, 42120, 10, 100, &tvnow));

  /* Bucket has been emptied 180 msec ago, last refill was 100 msec ago
   * which was insufficient to make it positive, so cap msec at 100. */
  tt_int_op(100, OP_EQ, bucket_millis_empty(0, 42020, 1, 100, &tvnow));

  /* 1970-01-02 00:00:00:050000 */
  tvnow.tv_sec = 86400;
  tvnow.tv_usec = 50000;

  /* Last emptied 30 msec before midnight, tvnow is 50 msec after
   * midnight, that's 80 msec in total. */
  tt_int_op(80, OP_EQ, bucket_millis_empty(0, 86400000 - 30, 1, 100, &tvnow));

 done:
  ;
}
示例#13
0
static void
test_util_format_base16_decode(void *ignored)
{
  (void)ignored;
  int res;
  int i;
  char *src;
  char *dst;

  src = tor_malloc_zero(256);
  dst = tor_malloc_zero(1000);

  for (i=0;i<256;i++) {
    src[i] = (char)i;
  }

  res = base16_decode(dst, 3, src, 3);
  tt_int_op(res, OP_EQ, -1);

  res = base16_decode(dst, 1, src, 10);
  tt_int_op(res, OP_EQ, -1);

  res = base16_decode(dst, SIZE_T_CEILING+2, src, 10);
  tt_int_op(res, OP_EQ, -1);

  res = base16_decode(dst, 1000, "", 0);
  tt_int_op(res, OP_EQ, 0);

  res = base16_decode(dst, 1000, "aabc", 4);
  tt_int_op(res, OP_EQ, 0);
  tt_mem_op(dst, OP_EQ, "\xaa\xbc", 2);

  res = base16_decode(dst, 1000, "aabcd", 6);
  tt_int_op(res, OP_EQ, -1);

  res = base16_decode(dst, 1000, "axxx", 4);
  tt_int_op(res, OP_EQ, -1);

 done:
  tor_free(src);
  tor_free(dst);
}
示例#14
0
static void
test_address_tor_addr_to_mapped_ipv4h(void *ignored)
{
  (void)ignored;
  tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t));
  uint32_t res;
  uint8_t toset[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 0, 42};

  a->family = AF_INET;
  res = tor_addr_to_mapped_ipv4h(a);
  tt_assert(!res);

  a->family = AF_INET6;

  memcpy(a->addr.in6_addr.s6_addr, toset, 16);
  res = tor_addr_to_mapped_ipv4h(a);
  tt_assert(res);
  tt_int_op(res, OP_EQ, 42);

 done:
  tor_free(a);
}
示例#15
0
/** Run unit tests for digest set code (implemented as a hashtable or as a
 * bloom filter) */
static void
test_container_digestset(void *arg)
{
  smartlist_t *included = smartlist_new();
  char d[DIGEST_LEN];
  int i;
  int ok = 1;
  int false_positives = 0;
  digestset_t *set = NULL;

  (void)arg;
  for (i = 0; i < 1000; ++i) {
    crypto_rand(d, DIGEST_LEN);
    smartlist_add(included, tor_memdup(d, DIGEST_LEN));
  }
  set = digestset_new(1000);
  SMARTLIST_FOREACH(included, const char *, cp,
                    if (digestset_contains(set, cp))
                      ok = 0);
  tt_assert(ok);
  SMARTLIST_FOREACH(included, const char *, cp,
                    digestset_add(set, cp));
  SMARTLIST_FOREACH(included, const char *, cp,
                    if (!digestset_contains(set, cp))
                      ok = 0);
  tt_assert(ok);
  for (i = 0; i < 1000; ++i) {
    crypto_rand(d, DIGEST_LEN);
    if (digestset_contains(set, d))
      ++false_positives;
  }
  tt_int_op(50, OP_GT, false_positives); /* Should be far lower. */

 done:
  if (set)
    digestset_free(set);
  SMARTLIST_FOREACH(included, char *, cp, tor_free(cp));
  smartlist_free(included);
}
示例#16
0
static void
test_storagedir_save_labeled(void *arg)
{
  (void)arg;
  char *dirname = tor_strdup(get_fname_rnd("store_dir"));
  storage_dir_t *d = NULL;
  uint8_t *inp = tor_malloc_zero(8192);
  config_line_t *labels = NULL;
  char *fname = NULL;
  uint8_t *saved = NULL;

  d = storage_dir_new(dirname, 10);
  tt_assert(d);

  crypto_rand((char *)inp, 8192);

  config_line_append(&labels, "Foo", "bar baz");
  config_line_append(&labels, "quux", "quuzXxz");
  const char expected[] =
    "Foo bar baz\n"
    "quux quuzXxz\n";

  int r = storage_dir_save_labeled_to_file(d, labels, inp, 8192, &fname);
  tt_int_op(r, OP_EQ, 0);

  size_t n = 0;
  saved = storage_dir_read(d, fname, 1, &n);
  tt_assert(memchr(saved, '\0', n));
  tt_str_op((char*)saved, OP_EQ, expected); /* NUL guarantees strcmp works */
  tt_mem_op(saved+strlen(expected)+1, OP_EQ, inp, 8192);

 done:
  storage_dir_free(d);
  tor_free(dirname);
  tor_free(inp);
  tor_free(fname);
  config_free_lines(labels);
  tor_free(saved);
}
示例#17
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = routerset_new();
  int r;
  const char *nickname = "foo";
  routerstatus_t rs;
  (void)arg;

  strmap_set_lc(set->names, nickname, (void *)1);

  strncpy(rs.nickname, nickname, sizeof(rs.nickname) - 1);
  rs.nickname[sizeof(rs.nickname) - 1] = '\0';
  NS(mock_node).ri = NULL;
  NS(mock_node).rs = &rs;

  r = routerset_contains_node(set, &NS(mock_node));

  tt_int_op(r, OP_EQ, 4);
  done:
    routerset_free(set);
}
示例#18
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = routerset_new();
  int r;
  const char *nickname = "foo";
  routerinfo_t ri;
  node_t mock_node;
  (void)arg;

  strmap_set_lc(set->names, nickname, (void *)1);

  ri.nickname = (char *)nickname;
  mock_node.ri = &ri;
  mock_node.rs = NULL;

  r = routerset_contains_node(set, &mock_node);

  tt_int_op(r, OP_EQ, 4);
  done:
    routerset_free(set);
}
示例#19
0
static void
test_rend_cache_increment_allocation(void *data)
{
  (void)data;

  // Test when the cache is not overflowing
  rend_cache_total_allocation = 5;
  rend_cache_increment_allocation(3);
  tt_int_op(rend_cache_total_allocation, OP_EQ, 8);

  // Test when there are too many allocations
  rend_cache_total_allocation = SIZE_MAX-1;
  rend_cache_increment_allocation(2);
  tt_u64_op(rend_cache_total_allocation, OP_EQ, SIZE_MAX);

  // And again
  rend_cache_increment_allocation(2);
  tt_u64_op(rend_cache_total_allocation, OP_EQ, SIZE_MAX);

 done:
  (void)0;
}
示例#20
0
static void
NS(test_main)(void *arg)
{
  int expected, actual;
  (void)arg;

  NS_MOCK(tls_get_write_overhead_ratio);
  NS_MOCK(we_are_hibernating);
  NS_MOCK(public_server_mode);
  NS_MOCK(router_get_my_routerinfo);

  expected = -1;
  actual = log_heartbeat(0);

  tt_int_op(actual, OP_EQ, expected);

  done:
    NS_UNMOCK(tls_get_write_overhead_ratio);
    NS_UNMOCK(we_are_hibernating);
    NS_UNMOCK(public_server_mode);
    NS_UNMOCK(router_get_my_routerinfo);
}
示例#21
0
/* Send an empty ESTABLISH_INTRO cell. Should fail. */
static void
test_establish_intro_wrong_keytype(void *arg)
{
  int retval;
  or_circuit_t *intro_circ = or_circuit_new(0,NULL);
  char circ_nonce[DIGEST_LEN] = {0};

  (void) arg;

  /* Get the auth key of the intro point */
  crypto_rand(circ_nonce, sizeof(circ_nonce));
  helper_prepare_circ_for_intro(intro_circ, circ_nonce);

  /* Receive the cell. Should fail. */
  setup_full_capture_of_logs(LOG_INFO);
  retval = hs_intro_received_establish_intro(intro_circ, (uint8_t *) "", 0);
  expect_log_msg_containing("Empty ESTABLISH_INTRO cell.");
  teardown_capture_of_logs();
  tt_int_op(retval, OP_EQ, -1);

 done:
  circuit_free_(TO_CIRCUIT(intro_circ));
}
示例#22
0
/**
 * Calling bridge_get_addrport() should give me the address and port
 * of the bridge.  In this case, we sort the smartlist of bridges on
 * fingerprints and choose the first one.
 */
static void
test_bridges_bridge_get_addrport(void *arg)
{
  smartlist_t *bridgelist;
  const bridge_info_t *bridge;
  const tor_addr_port_t *addrport;

  helper_add_bridges_to_bridgelist(arg);
  bridgelist = (smartlist_t*)bridge_list_get();
  tt_ptr_op(bridgelist, OP_NE, NULL);

  // This should be the bridge at 6.6.6.6:6666 with fingerprint
  // 0000000000000000000000000000000000000000
  bridge = smartlist_get(bridgelist, 0);
  tt_ptr_op(bridge, OP_NE, NULL);

  addrport = bridge_get_addr_port(bridge);
  tt_int_op(addrport->port, OP_EQ, 6666);

 done:
  mark_bridge_list();
  sweep_bridge_list();
}
示例#23
0
static void
test_replaycache_badalloc(void *arg)
{
  replaycache_t *r = NULL;

  /* Negative horizon should fail */
  (void)arg;
  r = replaycache_new(-600, 300);
  tt_assert(r == NULL);
  /* Negative interval should get adjusted to zero */
  r = replaycache_new(600, -300);
  tt_assert(r != NULL);
  tt_int_op(r->scrub_interval,OP_EQ, 0);
  replaycache_free(r);
  /* Negative horizon and negative interval should still fail */
  r = replaycache_new(-600, -300);
  tt_assert(r == NULL);

 done:
  if (r) replaycache_free(r);

  return;
}
示例#24
0
static void
test_replaycache_future(void *arg)
{
  replaycache_t *r = NULL;
  int result;
  time_t elapsed = 0;

  (void)arg;
  r = replaycache_new(600, 300);
  tt_assert(r != NULL);

  /* Set up like in test_replaycache_hit() */
  result =
    replaycache_add_and_test_internal(100, r, test_buffer,
        strlen(test_buffer), &elapsed);
  tt_int_op(result,OP_EQ, 0);
  /* elapsed should still be 0, since it wasn't written */
  tt_int_op(elapsed,OP_EQ, 0);

  result =
    replaycache_add_and_test_internal(200, r, test_buffer,
        strlen(test_buffer), &elapsed);
  tt_int_op(result,OP_EQ, 1);
  /* elapsed should be the time since the last hit */
  tt_int_op(elapsed,OP_EQ, 100);

  /*
   * Now let's turn the clock back to get coverage on the cache entry from the
   * future not-supposed-to-happen case.
   */
  result =
    replaycache_add_and_test_internal(150, r, test_buffer,
        strlen(test_buffer), &elapsed);
  /* We should still get a hit */
  tt_int_op(result,OP_EQ, 1);
  /* ...but it shouldn't let us see a negative elapsed time */
  tt_int_op(elapsed,OP_EQ, 0);

 done:
  if (r) replaycache_free(r);

  return;
}
示例#25
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);
}
示例#26
0
static void
test_pick_circid(void *arg)
{
  bitarray_t *ba = NULL;
  channel_t *chan1, *chan2;
  circid_t circid;
  int i;
  (void) arg;

  chan1 = tor_malloc_zero(sizeof(channel_t));
  chan2 = tor_malloc_zero(sizeof(channel_t));
  chan2->wide_circ_ids = 1;

  chan1->circ_id_type = CIRC_ID_TYPE_NEITHER;
  tt_int_op(0, OP_EQ, get_unique_circ_id_by_chan(chan1));

  /* Basic tests, with no collisions */
  chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
  for (i = 0; i < 50; ++i) {
    circid = get_unique_circ_id_by_chan(chan1);
    tt_uint_op(0, OP_LT, circid);
    tt_uint_op(circid, OP_LT, (1<<15));
  }
  chan1->circ_id_type = CIRC_ID_TYPE_HIGHER;
  for (i = 0; i < 50; ++i) {
    circid = get_unique_circ_id_by_chan(chan1);
    tt_uint_op((1<<15), OP_LT, circid);
    tt_uint_op(circid, OP_LT, (1<<16));
  }

  chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
  for (i = 0; i < 50; ++i) {
    circid = get_unique_circ_id_by_chan(chan2);
    tt_uint_op(0, OP_LT, circid);
    tt_uint_op(circid, OP_LT, (1u<<31));
  }
  chan2->circ_id_type = CIRC_ID_TYPE_HIGHER;
  for (i = 0; i < 50; ++i) {
    circid = get_unique_circ_id_by_chan(chan2);
    tt_uint_op((1u<<31), OP_LT, circid);
  }

  /* Now make sure that we can behave well when we are full up on circuits */
  chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
  chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
  chan1->wide_circ_ids = chan2->wide_circ_ids = 0;
  ba = bitarray_init_zero((1<<15));
  for (i = 0; i < (1<<15); ++i) {
    circid = get_unique_circ_id_by_chan(chan1);
    if (circid == 0) {
      tt_int_op(i, OP_GT, (1<<14));
      break;
    }
    tt_uint_op(circid, OP_LT, (1<<15));
    tt_assert(! bitarray_is_set(ba, circid));
    bitarray_set(ba, circid);
    channel_mark_circid_unusable(chan1, circid);
  }
  tt_int_op(i, OP_LT, (1<<15));
  /* Make sure that being full on chan1 does not interfere with chan2 */
  for (i = 0; i < 100; ++i) {
    circid = get_unique_circ_id_by_chan(chan2);
    tt_uint_op(circid, OP_GT, 0);
    tt_uint_op(circid, OP_LT, (1<<15));
    channel_mark_circid_unusable(chan2, circid);
  }

 done:
  tor_free(chan1);
  tor_free(chan2);
  bitarray_free(ba);
  circuit_free_all();
}
示例#27
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));
}
示例#28
0
文件: test_oom.c 项目: 1234max/tor
/** 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_);
}
示例#29
0
文件: test_oom.c 项目: 1234max/tor
/** 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_);
}
示例#30
0
static void
test_util_format_base64_encode(void *ignored)
{
  (void)ignored;
  int res;
  int i;
  char *src;
  char *dst;

  src = tor_malloc_zero(256);
  dst = tor_malloc_zero(1000);

  for (i=0;i<256;i++) {
    src[i] = (char)i;
  }

  res = base64_encode(NULL, 1, src, 1, 0);
  tt_int_op(res, OP_EQ, -1);

  res = base64_encode(dst, 1, NULL, 1, 0);
  tt_int_op(res, OP_EQ, -1);

  res = base64_encode(dst, 1, src, 10, 0);
  tt_int_op(res, OP_EQ, -1);

  res = base64_encode(dst, SSIZE_MAX-1, src, 1, 0);
  tt_int_op(res, OP_EQ, -1);

  res = base64_encode(dst, SSIZE_MAX-1, src, 10, 0);
  tt_int_op(res, OP_EQ, -1);

  res = base64_encode(dst, 1000, src, 256, 0);
  tt_int_op(res, OP_EQ, 344);
  tt_str_op(dst, OP_EQ, "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh"
            "8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH"
            "SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3"
            "BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeY"
            "mZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wM"
            "HCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp"
            "6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==");

  res = base64_encode(dst, 1000, src, 256, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 350);
  tt_str_op(dst, OP_EQ,
          "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v\n"
          "MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f\n"
          "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P\n"
          "kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/\n"
          "wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v\n"
          "8PHy8/T19vf4+fr7/P3+/w==\n");

  res = base64_encode(dst, 1000, src+1, 255, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 346);

  for (i = 0;i<50;i++) {
    src[i] = 0;
  }
  src[50] = 255;
  src[51] = 255;
  src[52] = 255;
  src[53] = 255;

  res = base64_encode(dst, 1000, src, 54, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 74);

  res = base64_encode(dst, 1000, src+1, 53, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 74);

  res = base64_encode(dst, 1000, src+2, 52, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 74);

  res = base64_encode(dst, 1000, src+3, 51, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 70);

  res = base64_encode(dst, 1000, src+4, 50, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 70);

  res = base64_encode(dst, 1000, src+5, 49, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 70);

  res = base64_encode(dst, 1000, src+6, 48, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 65);

  res = base64_encode(dst, 1000, src+7, 47, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 65);

  res = base64_encode(dst, 1000, src+8, 46, BASE64_ENCODE_MULTILINE);
  tt_int_op(res, OP_EQ, 65);

 done:
  tor_free(src);
  tor_free(dst);
}