Exemple #1
0
static void
test_rend_cache_free_all(void *data)
{
  rend_cache_failure_t *failure;
  rend_cache_entry_t *one;
  rend_service_descriptor_t *desc_one;

  (void)data;

  rend_cache_init();

  failure = rend_cache_failure_entry_new();
  strmap_set_lc(rend_cache_failure, "foo1", failure);

  one = tor_malloc_zero(sizeof(rend_cache_entry_t));
  desc_one = tor_malloc_zero(sizeof(rend_service_descriptor_t));
  one->parsed = desc_one;
  desc_one->timestamp = time(NULL) + TIME_IN_THE_PAST;
  desc_one->pk = pk_generate(0);
  strmap_set_lc(rend_cache, "foo1", one);

  rend_cache_free_all();

  tt_assert(!rend_cache);
  tt_assert(!rend_cache_v2_dir);
  tt_assert(!rend_cache_failure);
  tt_assert(!rend_cache_total_allocation);

 done:
  rend_cache_free_all();
}
Exemple #2
0
static void
test_rend_cache_failure_clean(void *data)
{
  rend_cache_failure_t *failure;
  rend_cache_failure_intro_t *ip_one, *ip_two;

  const char key_one[DIGEST_LEN] = "ip1";
  const char key_two[DIGEST_LEN] = "ip2";

  (void)data;

  rend_cache_init();

  // Test with empty failure cache
  rend_cache_failure_clean(time(NULL));
  tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0);

  // Test with one empty failure entry
  failure = rend_cache_failure_entry_new();
  strmap_set_lc(rend_cache_failure, "foo1", failure);
  rend_cache_failure_clean(time(NULL));
  tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0);

  // Test with one new intro point
  failure = rend_cache_failure_entry_new();
  ip_one = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
  digestmap_set(failure->intro_failures, key_one, ip_one);
  strmap_set_lc(rend_cache_failure, "foo1", failure);
  rend_cache_failure_clean(time(NULL));
  tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 1);

  // Test with one old intro point
  rend_cache_failure_purge();
  failure = rend_cache_failure_entry_new();
  ip_one = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
  ip_one->created_ts = time(NULL) - 7*60;
  digestmap_set(failure->intro_failures, key_one, ip_one);
  strmap_set_lc(rend_cache_failure, "foo1", failure);
  rend_cache_failure_clean(time(NULL));
  tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 0);

  // Test with one old intro point and one new one
  rend_cache_failure_purge();
  failure = rend_cache_failure_entry_new();
  ip_one = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
  ip_one->created_ts = time(NULL) - 7*60;
  digestmap_set(failure->intro_failures, key_one, ip_one);
  ip_two = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
  ip_two->created_ts = time(NULL) - 2*60;
  digestmap_set(failure->intro_failures, key_two, ip_two);
  strmap_set_lc(rend_cache_failure, "foo1", failure);
  rend_cache_failure_clean(time(NULL));
  tt_int_op(strmap_size(rend_cache_failure), OP_EQ, 1);
  tt_int_op(digestmap_size(failure->intro_failures), OP_EQ, 1);

 done:
  rend_cache_free_all();
}
Exemple #3
0
static void
test_rend_cache_validate_intro_point_failure(void *data)
{
  (void)data;
  rend_service_descriptor_t *desc = NULL;
  char *service_id = NULL;
  rend_intro_point_t *intro = NULL;
  const char *identity = NULL;
  rend_cache_failure_t *failure;
  rend_cache_failure_intro_t *ip;

  rend_cache_init();

  create_descriptor(&desc, &service_id, 3);
  desc->timestamp = time(NULL) + RECENT_TIME;

  intro = (rend_intro_point_t *)smartlist_get(desc->intro_nodes, 0);
  identity = intro->extend_info->identity_digest;

  failure = rend_cache_failure_entry_new();
  ip = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
  digestmap_set(failure->intro_failures, identity, ip);
  strmap_set_lc(rend_cache_failure, service_id, failure);

  // Test when we have an intro point in our cache
  validate_intro_point_failure(desc, service_id);
  tt_int_op(smartlist_len(desc->intro_nodes), OP_EQ, 2);

 done:
  rend_cache_free_all();
  rend_service_descriptor_free(desc);
  tor_free(service_id);
}
Exemple #4
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = routerset_new();
  smartlist_t *list = smartlist_new();
  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.rs = NULL;
  mock_node.ri = &ri;
  smartlist_add(list, (void *)&mock_node);

  tt_int_op(smartlist_len(list), !=, 0);
  routerset_subtract_nodes(list, set);

  tt_int_op(smartlist_len(list), ==, 0);
  done:
    routerset_free(set);
    smartlist_free(list);
}
Exemple #5
0
/** Add an entry to the GeoIP table, mapping all IPs between <b>low</b> and
 * <b>high</b>, inclusive, to the 2-letter country code <b>country</b>.
 */
static void
geoip_add_entry(uint32_t low, uint32_t high, const char *country)
{
  intptr_t idx;
  geoip_entry_t *ent;
  void *idxplus1_;

  if (high < low)
    return;

  idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country);

  if (!idxplus1_) {
    geoip_country_t *c = tor_malloc_zero(sizeof(geoip_country_t));
    strlcpy(c->countrycode, country, sizeof(c->countrycode));
    tor_strlower(c->countrycode);
    smartlist_add(geoip_countries, c);
    idx = smartlist_len(geoip_countries) - 1;
    strmap_set_lc(country_idxplus1_by_lc_code, country, (void*)(idx+1));
  } else {
    idx = ((uintptr_t)idxplus1_)-1;
  }
  {
    geoip_country_t *c = smartlist_get(geoip_countries, idx);
    tor_assert(!strcasecmp(c->countrycode, country));
  }
  ent = tor_malloc_zero(sizeof(geoip_entry_t));
  ent->ip_low = low;
  ent->ip_high = high;
  ent->country = idx;
  smartlist_add(geoip_entries, ent);
}
Exemple #6
0
/** Parse the string <b>s</b> to create a set of routerset entries, and add
 * them to <b>target</b>.  In log messages, refer to the string as
 * <b>description</b>.  Return 0 on success, -1 on failure.
 *
 * Three kinds of elements are allowed in routersets: nicknames, IP address
 * patterns, and fingerprints.  They may be surrounded by optional space, and
 * must be separated by commas.
 */
int
routerset_parse(routerset_t *target, const char *s, const char *description)
{
  int r = 0;
  int added_countries = 0;
  char *countryname;
  smartlist_t *list = smartlist_new();
  int malformed_list;
  smartlist_split_string(list, s, ",",
                         SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0);
  SMARTLIST_FOREACH_BEGIN(list, char *, nick) {
      addr_policy_t *p;
      /* if it doesn't pass our validation, assume it's malformed */
      malformed_list = 1;
      if (is_legal_hexdigest(nick)) {
        char d[DIGEST_LEN];
        if (*nick == '$')
          ++nick;
        log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description);
        base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN);
        digestmap_set(target->digests, d, (void*)1);
      } else if (is_legal_nickname(nick)) {
        log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description);
        strmap_set_lc(target->names, nick, (void*)1);
      } else if ((countryname = routerset_get_countryname(nick)) != NULL) {
        log_debug(LD_CONFIG, "Adding country %s to %s", nick,
                  description);
        smartlist_add(target->country_names, countryname);
        added_countries = 1;
      } else if ((strchr(nick,'.') || strchr(nick, ':') ||  strchr(nick, '*'))
                 && (p = router_parse_addr_policy_item_from_string(
                                     nick, ADDR_POLICY_REJECT,
                                     &malformed_list))) {
        /* IPv4 addresses contain '.', IPv6 addresses contain ':',
         * and wildcard addresses contain '*'. */
        log_debug(LD_CONFIG, "Adding address %s to %s", nick, description);
        smartlist_add(target->policies, p);
      } else if (malformed_list) {
        log_warn(LD_CONFIG, "Entry '%s' in %s is malformed. Discarding entire"
                 " list.", nick, description);
        r = -1;
        tor_free(nick);
        SMARTLIST_DEL_CURRENT(list, nick);
      } else {
        log_notice(LD_CONFIG, "Entry '%s' in %s is ignored. Using the"
                   " remainder of the list.", nick, description);
        tor_free(nick);
        SMARTLIST_DEL_CURRENT(list, nick);
      }
  } SMARTLIST_FOREACH_END(nick);
Exemple #7
0
/** Set up a new list of geoip countries with no countries (yet) set in it,
 * except for the unknown country.
 */
static void
init_geoip_countries(void)
{
  geoip_country_t *geoip_unresolved;
  geoip_countries = smartlist_new();
  /* Add a geoip_country_t for requests that could not be resolved to a
   * country as first element (index 0) to geoip_countries. */
  geoip_unresolved = tor_malloc_zero(sizeof(geoip_country_t));
  strlcpy(geoip_unresolved->countrycode, "??",
          sizeof(geoip_unresolved->countrycode));
  smartlist_add(geoip_countries, geoip_unresolved);
  country_idxplus1_by_lc_code = strmap_new();
  strmap_set_lc(country_idxplus1_by_lc_code, "??", (void*)(1));
}
Exemple #8
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = routerset_new();
  int contains;
  (void)arg;

  strmap_set_lc(set->names, "bar", (void *)1);
  contains = routerset_contains(set, NULL, 0, "foo", NULL, 0);
  routerset_free(set);

  tt_int_op(contains, ==, 0);
  done:
    ;
}
Exemple #9
0
static void
NS(test_main)(void *arg)
{
  routerset_t *set = routerset_new();
  const char *nickname;
  int contains;
  (void)arg;

  nickname = "Foo";  /* This tests the lowercase comparison as well. */
  strmap_set_lc(set->names, nickname, (void *)1);
  contains = routerset_contains(set, NULL, 0, nickname, NULL, 0);
  routerset_free(set);

  tt_int_op(contains, ==, 4);
  done:
    ;
}
Exemple #10
0
/** Add an entry to a GeoIP table, mapping all IP addresses between <b>low</b>
 * and <b>high</b>, inclusive, to the 2-letter country code <b>country</b>. */
static void
geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high,
                const char *country)
{
  intptr_t idx;
  void *idxplus1_;

  if (tor_addr_family(low) != tor_addr_family(high))
    return;
  if (tor_addr_compare(high, low, CMP_EXACT) < 0)
    return;

  idxplus1_ = strmap_get_lc(country_idxplus1_by_lc_code, country);

  if (!idxplus1_) {
    geoip_country_t *c = tor_malloc_zero(sizeof(geoip_country_t));
    strlcpy(c->countrycode, country, sizeof(c->countrycode));
    tor_strlower(c->countrycode);
    smartlist_add(geoip_countries, c);
    idx = smartlist_len(geoip_countries) - 1;
    strmap_set_lc(country_idxplus1_by_lc_code, country, (void*)(idx+1));
  } else {
    idx = ((uintptr_t)idxplus1_)-1;
  }
  {
    geoip_country_t *c = smartlist_get(geoip_countries, idx);
    tor_assert(!strcasecmp(c->countrycode, country));
  }

  if (tor_addr_family(low) == AF_INET) {
    geoip_ipv4_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv4_entry_t));
    ent->ip_low = tor_addr_to_ipv4h(low);
    ent->ip_high = tor_addr_to_ipv4h(high);
    ent->country = idx;
    smartlist_add(geoip_ipv4_entries, ent);
  } else if (tor_addr_family(low) == AF_INET6) {
    geoip_ipv6_entry_t *ent = tor_malloc_zero(sizeof(geoip_ipv6_entry_t));
    ent->ip_low = *tor_addr_to_in6(low);
    ent->ip_high = *tor_addr_to_in6(high);
    ent->country = idx;
    smartlist_add(geoip_ipv6_entries, ent);
  }
}
Exemple #11
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, ==, 4);
  done:
    routerset_free(set);
}
Exemple #12
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, ==, 4);
  done:
    routerset_free(set);
}
Exemple #13
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, ==, 4);
  done:
    routerset_free(set);
}
Exemple #14
0
static void
test_rend_cache_failure_intro_lookup(void *data)
{
  (void)data;
  int ret;
  rend_cache_failure_t *failure;
  rend_cache_failure_intro_t *ip;
  rend_cache_failure_intro_t *entry;
  const char key_ip_one[DIGEST_LEN] = "ip1";
  const char key_ip_two[DIGEST_LEN] = "ip2";
  const char key_foo[DIGEST_LEN] = "foo1";

  rend_cache_init();

  failure = rend_cache_failure_entry_new();
  ip = rend_cache_failure_intro_entry_new(INTRO_POINT_FAILURE_TIMEOUT);
  digestmap_set(failure->intro_failures, key_ip_one, ip);
  strmap_set_lc(rend_cache_failure, "foo1", failure);

  // Test not found
  ret = cache_failure_intro_lookup((const uint8_t *) key_foo, "foo2", NULL);
  tt_int_op(ret, OP_EQ, 0);

  // Test found with no intro failures in it
  ret = cache_failure_intro_lookup((const uint8_t *) key_ip_two, "foo1", NULL);
  tt_int_op(ret, OP_EQ, 0);

  // Test found
  ret = cache_failure_intro_lookup((const uint8_t *) key_ip_one, "foo1", NULL);
  tt_int_op(ret, OP_EQ, 1);

  // Test found and asking for entry
  cache_failure_intro_lookup((const uint8_t *) key_ip_one, "foo1", &entry);
  tt_assert(entry);
  tt_assert(entry == ip);

 done:
  rend_cache_free_all();
}
Exemple #15
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, ==, 4);
  done:
    routerset_free(set);
}
Exemple #16
0
/** Parse the string <b>s</b> to create a set of routerset entries, and add
 * them to <b>target</b>.  In log messages, refer to the string as
 * <b>description</b>.  Return 0 on success, -1 on failure.
 *
 * Three kinds of elements are allowed in routersets: nicknames, IP address
 * patterns, and fingerprints.  They may be surrounded by optional space, and
 * must be separated by commas.
 */
int
routerset_parse(routerset_t *target, const char *s, const char *description)
{
  int r = 0;
  int added_countries = 0;
  char *countryname;
  smartlist_t *list = smartlist_new();
  smartlist_split_string(list, s, ",",
                         SPLIT_SKIP_SPACE | SPLIT_IGNORE_BLANK, 0);
  SMARTLIST_FOREACH_BEGIN(list, char *, nick) {
      addr_policy_t *p;
      if (is_legal_hexdigest(nick)) {
        char d[DIGEST_LEN];
        if (*nick == '$')
          ++nick;
        log_debug(LD_CONFIG, "Adding identity %s to %s", nick, description);
        base16_decode(d, sizeof(d), nick, HEX_DIGEST_LEN);
        digestmap_set(target->digests, d, (void*)1);
      } else if (is_legal_nickname(nick)) {
        log_debug(LD_CONFIG, "Adding nickname %s to %s", nick, description);
        strmap_set_lc(target->names, nick, (void*)1);
      } else if ((countryname = routerset_get_countryname(nick)) != NULL) {
        log_debug(LD_CONFIG, "Adding country %s to %s", nick,
                  description);
        smartlist_add(target->country_names, countryname);
        added_countries = 1;
      } else if ((strchr(nick,'.') || strchr(nick, '*')) &&
                 (p = router_parse_addr_policy_item_from_string(
                                     nick, ADDR_POLICY_REJECT))) {
        log_debug(LD_CONFIG, "Adding address %s to %s", nick, description);
        smartlist_add(target->policies, p);
      } else {
        log_warn(LD_CONFIG, "Entry '%s' in %s is malformed.", nick,
                 description);
        r = -1;
        tor_free(nick);
        SMARTLIST_DEL_CURRENT(list, nick);
      }
  } SMARTLIST_FOREACH_END(nick);
Exemple #17
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, ==, 4);
  done:
    routerset_free(set);
}
Exemple #18
0
static void
test_rend_cache_clean(void *data)
{
  rend_cache_entry_t *one, *two;
  rend_service_descriptor_t *desc_one, *desc_two;
  strmap_iter_t *iter = NULL;
  const char *key;
  void *val;

  (void)data;

  rend_cache_init();

  // Test with empty rendcache
  rend_cache_clean(time(NULL), REND_CACHE_TYPE_CLIENT);
  tt_int_op(strmap_size(rend_cache), OP_EQ, 0);

  // Test with two old entries
  one = tor_malloc_zero(sizeof(rend_cache_entry_t));
  two = tor_malloc_zero(sizeof(rend_cache_entry_t));
  desc_one = tor_malloc_zero(sizeof(rend_service_descriptor_t));
  desc_two = tor_malloc_zero(sizeof(rend_service_descriptor_t));
  one->parsed = desc_one;
  two->parsed = desc_two;

  desc_one->timestamp = time(NULL) + TIME_IN_THE_PAST;
  desc_two->timestamp = (time(NULL) + TIME_IN_THE_PAST) - 10;
  desc_one->pk = pk_generate(0);
  desc_two->pk = pk_generate(1);

  strmap_set_lc(rend_cache, "foo1", one);
  strmap_set_lc(rend_cache, "foo2", two);

  rend_cache_clean(time(NULL), REND_CACHE_TYPE_CLIENT);
  tt_int_op(strmap_size(rend_cache), OP_EQ, 0);

  // Test with one old entry and one newer entry
  one = tor_malloc_zero(sizeof(rend_cache_entry_t));
  two = tor_malloc_zero(sizeof(rend_cache_entry_t));
  desc_one = tor_malloc_zero(sizeof(rend_service_descriptor_t));
  desc_two = tor_malloc_zero(sizeof(rend_service_descriptor_t));
  one->parsed = desc_one;
  two->parsed = desc_two;

  desc_one->timestamp = (time(NULL) + TIME_IN_THE_PAST) - 10;
  desc_two->timestamp = time(NULL) - 100;
  desc_one->pk = pk_generate(0);
  desc_two->pk = pk_generate(1);

  strmap_set_lc(rend_cache, "foo1", one);
  strmap_set_lc(rend_cache, "foo2", two);

  rend_cache_clean(time(NULL), REND_CACHE_TYPE_CLIENT);
  tt_int_op(strmap_size(rend_cache), OP_EQ, 1);

  iter = strmap_iter_init(rend_cache);
  strmap_iter_get(iter, &key, &val);
  tt_str_op(key, OP_EQ, "foo2");

 done:
  rend_cache_free_all();
}
Exemple #19
0
/** Run unit tests for string-to-void* map functions */
static void
test_container_strmap(void)
{
  strmap_t *map;
  strmap_iter_t *iter;
  const char *k;
  void *v;
  char *visited = NULL;
  smartlist_t *found_keys = NULL;

  map = strmap_new();
  test_assert(map);
  test_eq(strmap_size(map), 0);
  test_assert(strmap_isempty(map));
  v = strmap_set(map, "K1", (void*)99);
  test_eq_ptr(v, NULL);
  test_assert(!strmap_isempty(map));
  v = strmap_set(map, "K2", (void*)101);
  test_eq_ptr(v, NULL);
  v = strmap_set(map, "K1", (void*)100);
  test_eq_ptr(v, (void*)99);
  test_eq_ptr(strmap_get(map,"K1"), (void*)100);
  test_eq_ptr(strmap_get(map,"K2"), (void*)101);
  test_eq_ptr(strmap_get(map,"K-not-there"), NULL);
  strmap_assert_ok(map);

  v = strmap_remove(map,"K2");
  strmap_assert_ok(map);
  test_eq_ptr(v, (void*)101);
  test_eq_ptr(strmap_get(map,"K2"), NULL);
  test_eq_ptr(strmap_remove(map,"K2"), NULL);

  strmap_set(map, "K2", (void*)101);
  strmap_set(map, "K3", (void*)102);
  strmap_set(map, "K4", (void*)103);
  test_eq(strmap_size(map), 4);
  strmap_assert_ok(map);
  strmap_set(map, "K5", (void*)104);
  strmap_set(map, "K6", (void*)105);
  strmap_assert_ok(map);

  /* Test iterator. */
  iter = strmap_iter_init(map);
  found_keys = smartlist_new();
  while (!strmap_iter_done(iter)) {
    strmap_iter_get(iter,&k,&v);
    smartlist_add(found_keys, tor_strdup(k));
    test_eq_ptr(v, strmap_get(map, k));

    if (!strcmp(k, "K2")) {
      iter = strmap_iter_next_rmv(map,iter);
    } else {
      iter = strmap_iter_next(map,iter);
    }
  }

  /* Make sure we removed K2, but not the others. */
  test_eq_ptr(strmap_get(map, "K2"), NULL);
  test_eq_ptr(strmap_get(map, "K5"), (void*)104);
  /* Make sure we visited everyone once */
  smartlist_sort_strings(found_keys);
  visited = smartlist_join_strings(found_keys, ":", 0, NULL);
  test_streq(visited, "K1:K2:K3:K4:K5:K6");

  strmap_assert_ok(map);
  /* Clean up after ourselves. */
  strmap_free(map, NULL);
  map = NULL;

  /* Now try some lc functions. */
  map = strmap_new();
  strmap_set_lc(map,"Ab.C", (void*)1);
  test_eq_ptr(strmap_get(map,"ab.c"), (void*)1);
  strmap_assert_ok(map);
  test_eq_ptr(strmap_get_lc(map,"AB.C"), (void*)1);
  test_eq_ptr(strmap_get(map,"AB.C"), NULL);
  test_eq_ptr(strmap_remove_lc(map,"aB.C"), (void*)1);
  strmap_assert_ok(map);
  test_eq_ptr(strmap_get_lc(map,"AB.C"), NULL);

 done:
  if (map)
    strmap_free(map,NULL);
  if (found_keys) {
    SMARTLIST_FOREACH(found_keys, char *, cp, tor_free(cp));
    smartlist_free(found_keys);
  }
  tor_free(visited);
}