Back to index

tor  0.2.3.18-rc
Classes | Defines | Functions | Variables
microdesc.c File Reference
#include "or.h"
#include "circuitbuild.h"
#include "config.h"
#include "directory.h"
#include "dirserv.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "policies.h"
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"

Go to the source code of this file.

Classes

struct  microdesc_cache_t
 A data structure to hold a bunch of cached microdescriptors. More...

Defines

#define TOLERATE_MICRODESC_AGE   (7*24*60*60)
 By default, we remove any microdescriptors that have gone at least this long without appearing in a current consensus.

Functions

static INLINE unsigned int _microdesc_hash (microdesc_t *md)
 Helper: computes a hash of md to place it in a hash table.
static INLINE int _microdesc_eq (microdesc_t *a, microdesc_t *b)
 Helper: compares a and for equality for hash-table purposes.
 HT_PROTOTYPE (microdesc_map, microdesc_t, node, _microdesc_hash, _microdesc_eq)
 HT_GENERATE (microdesc_map, microdesc_t, node, _microdesc_hash, _microdesc_eq, 0.6, malloc, realloc, free)
static ssize_t dump_microdescriptor (FILE *f, microdesc_t *md, size_t *annotation_len_out)
 Write the body of md into f, with appropriate annotations.
microdesc_cache_tget_microdesc_cache (void)
 Return a pointer to the microdescriptor cache, loading it if necessary.
smartlist_tmicrodescs_add_to_cache (microdesc_cache_t *cache, const char *s, const char *eos, saved_location_t where, int no_save, time_t listed_at, smartlist_t *requested_digests256)
 Decode the microdescriptors from the string starting at s and ending at eos, and store them in cache.
smartlist_tmicrodescs_add_list_to_cache (microdesc_cache_t *cache, smartlist_t *descriptors, saved_location_t where, int no_save)
 As microdescs_add_to_cache, but takes a list of micrdescriptors instead of a string to decode.
void microdesc_cache_clear (microdesc_cache_t *cache)
 Remove every microdescriptor in cache.
int microdesc_cache_reload (microdesc_cache_t *cache)
 Reload the contents of cache from disk.
void microdesc_cache_clean (microdesc_cache_t *cache, time_t cutoff, int force)
 Remove all microdescriptors from cache that haven't been listed for a long time.
static int should_rebuild_md_cache (microdesc_cache_t *cache)
int microdesc_cache_rebuild (microdesc_cache_t *cache, int force)
 Regenerate the main cache file for cache, clear the journal file, and update every microdesc_t in the cache with pointers to its new location.
void microdesc_check_counts (void)
 Make sure that the reference count of every microdescriptor in cache is accurate.
void microdesc_free (microdesc_t *md)
 Deallocate a single microdescriptor.
void microdesc_free_all (void)
 Free all storage held in the microdesc.c module.
microdesc_tmicrodesc_cache_lookup_by_digest256 (microdesc_cache_t *cache, const char *d)
 If there is a microdescriptor in cache whose sha256 digest is d, return it.
size_t microdesc_average_size (microdesc_cache_t *cache)
 Return the mean size of decriptors added to cache since it was last cleared.
smartlist_tmicrodesc_list_missing_digest256 (networkstatus_t *ns, microdesc_cache_t *cache, int downloadable_only, digestmap_t *skip)
 Return a smartlist of all the sha256 digest of the microdescriptors that are listed in ns but not present in cache.
void update_microdesc_downloads (time_t now)
 Launch download requests for mircodescriptors as appropriate.
void update_microdescs_from_networkstatus (time_t now)
 For every microdescriptor listed in the current microdecriptor consensus, update its last_listed field to be at least as recent as the publication time of the current microdescriptor consensus.
int we_use_microdescriptors_for_circuits (const or_options_t *options)
 Return true iff we should prefer to use microdescriptors rather than routerdescs for building circuits.
int we_fetch_microdescriptors (const or_options_t *options)
 Return true iff we should try to download microdescriptors at all.
int we_fetch_router_descriptors (const or_options_t *options)
 Return true iff we should try to download router descriptors at all.
int usable_consensus_flavor (void)
 Return the consensus flavor we actually want to use to build circuits.

Variables

static microdesc_cache_tthe_microdesc_cache = NULL
 Holds a pointer to the current microdesc_cache_t object, or NULL if no such object has been allocated.

Class Documentation

struct microdesc_cache_t

A data structure to hold a bunch of cached microdescriptors.

There are two active files in the cache: a "cache file" that we mmap, and a "journal file" that we append to. Periodically, we rebuild the cache file to hold only the microdescriptors that we want to keep

Definition at line 21 of file microdesc.c.


Define Documentation

#define TOLERATE_MICRODESC_AGE   (7*24*60*60)

By default, we remove any microdescriptors that have gone at least this long without appearing in a current consensus.

Definition at line 336 of file microdesc.c.


Function Documentation

static INLINE int _microdesc_eq ( microdesc_t a,
microdesc_t b 
) [static]

Helper: compares a and for equality for hash-table purposes.

Definition at line 57 of file microdesc.c.

{
  return tor_memeq(a->digest, b->digest, DIGEST256_LEN);
}

Here is the call graph for this function:

static INLINE unsigned int _microdesc_hash ( microdesc_t md) [static]

Helper: computes a hash of md to place it in a hash table.

Definition at line 45 of file microdesc.c.

{
  unsigned *d = (unsigned*)md->digest;
#if SIZEOF_INT == 4
  return d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7];
#else
  return d[0] ^ d[1] ^ d[2] ^ d[3];
#endif
}
static ssize_t dump_microdescriptor ( FILE *  f,
microdesc_t md,
size_t *  annotation_len_out 
) [static]

Write the body of md into f, with appropriate annotations.

On success, return the total number of bytes written, and set *annotation_len_out to the number of bytes written as annotations.

Definition at line 73 of file microdesc.c.

{
  ssize_t r = 0;
  size_t written;
  /* XXXX drops unkown annotations. */
  if (md->last_listed) {
    char buf[ISO_TIME_LEN+1];
    char annotation[ISO_TIME_LEN+32];
    format_iso_time(buf, md->last_listed);
    tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf);
    if (fputs(annotation, f) < 0) {
      log_warn(LD_DIR,
               "Couldn't write microdescriptor annotation: %s",
               strerror(ferror(f)));
      return -1;
    }
    r += strlen(annotation);
    *annotation_len_out = r;
  } else {
    *annotation_len_out = 0;
  }

  md->off = (off_t) ftell(f);
  written = fwrite(md->body, 1, md->bodylen, f);
  if (written != md->bodylen) {
    log_warn(LD_DIR,
             "Couldn't dump microdescriptor (wrote %lu out of %lu): %s",
             (unsigned long)written, (unsigned long)md->bodylen,
             strerror(ferror(f)));
    return -1;
  }
  r += md->bodylen;
  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return a pointer to the microdescriptor cache, loading it if necessary.

Definition at line 114 of file microdesc.c.

{
  if (PREDICT_UNLIKELY(the_microdesc_cache==NULL)) {
    microdesc_cache_t *cache = tor_malloc_zero(sizeof(microdesc_cache_t));
    HT_INIT(microdesc_map, &cache->map);
    cache->cache_fname = get_datadir_fname("cached-microdescs");
    cache->journal_fname = get_datadir_fname("cached-microdescs.new");
    microdesc_cache_reload(cache);
    the_microdesc_cache = cache;
  }
  return the_microdesc_cache;
}

Here is the call graph for this function:

Here is the caller graph for this function:

HT_GENERATE ( microdesc_map  ,
microdesc_t  ,
node  ,
_microdesc_hash  ,
_microdesc_eq  ,
0.  6,
malloc  ,
realloc  ,
free   
)
HT_PROTOTYPE ( microdesc_map  ,
microdesc_t  ,
node  ,
_microdesc_hash  ,
_microdesc_eq   
)

Return the mean size of decriptors added to cache since it was last cleared.

Used to estimate the size of large downloads.

Definition at line 617 of file microdesc.c.

{
  if (!cache)
    cache = get_microdesc_cache();
  if (!cache->n_seen)
    return 512;
  return (size_t)(cache->total_len_seen / cache->n_seen);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void microdesc_cache_clean ( microdesc_cache_t cache,
time_t  cutoff,
int  force 
)

Remove all microdescriptors from cache that haven't been listed for a long time.

Does not rebuild the cache on disk. If cutoff is positive, specifically remove microdescriptors that have been unlisted since cutoff. If force is true, remove microdescriptors even if we have no current live microdescriptor consensus.

Definition at line 345 of file microdesc.c.

{
  microdesc_t **mdp, *victim;
  int dropped=0, kept=0;
  size_t bytes_dropped = 0;
  time_t now = time(NULL);

  /* If we don't know a live consensus, don't believe last_listed values: we
   * might be starting up after being down for a while. */
  if (! force &&
      ! networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC))
      return;

  if (cutoff <= 0)
    cutoff = now - TOLERATE_MICRODESC_AGE;

  for (mdp = HT_START(microdesc_map, &cache->map); mdp != NULL; ) {
    if ((*mdp)->last_listed < cutoff) {
      ++dropped;
      victim = *mdp;
      mdp = HT_NEXT_RMV(microdesc_map, &cache->map, mdp);
      victim->held_in_map = 0;
      bytes_dropped += victim->bodylen;
      microdesc_free(victim);
    } else {
      ++kept;
      mdp = HT_NEXT(microdesc_map, &cache->map, mdp);
    }
  }

  if (dropped) {
    log_info(LD_DIR, "Removed %d/%d microdescriptors as old.",
             dropped,dropped+kept);
    cache->bytes_dropped += bytes_dropped;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Remove every microdescriptor in cache.

Definition at line 271 of file microdesc.c.

{
  microdesc_t **entry, **next;
  for (entry = HT_START(microdesc_map, &cache->map); entry; entry = next) {
    microdesc_t *md = *entry;
    next = HT_NEXT_RMV(microdesc_map, &cache->map, entry);
    md->held_in_map = 0;
    microdesc_free(md);
  }
  HT_CLEAR(microdesc_map, &cache->map);
  if (cache->cache_content) {
    tor_munmap_file(cache->cache_content);
    cache->cache_content = NULL;
  }
  cache->total_len_seen = 0;
  cache->n_seen = 0;
  cache->bytes_dropped = 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

If there is a microdescriptor in cache whose sha256 digest is d, return it.

Otherwise return NULL.

Definition at line 604 of file microdesc.c.

{
  microdesc_t *md, search;
  if (!cache)
    cache = get_microdesc_cache();
  memcpy(search.digest, d, DIGEST256_LEN);
  md = HT_FIND(microdesc_map, &cache->map, &search);
  return md;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int microdesc_cache_rebuild ( microdesc_cache_t cache,
int  force 
)

Regenerate the main cache file for cache, clear the journal file, and update every microdesc_t in the cache with pointers to its new location.

If force is true, do this unconditionally. If force is false, do it only if we expect to save space on disk.

Definition at line 405 of file microdesc.c.

{
  open_file_t *open_file;
  FILE *f;
  microdesc_t **mdp;
  smartlist_t *wrote;
  ssize_t size;
  off_t off = 0;
  int orig_size, new_size;

  if (cache == NULL) {
    cache = the_microdesc_cache;
    if (cache == NULL)
      return 0;
  }

  /* Remove dead descriptors */
  microdesc_cache_clean(cache, 0/*cutoff*/, 0/*force*/);

  if (!force && !should_rebuild_md_cache(cache))
    return 0;

  log_info(LD_DIR, "Rebuilding the microdescriptor cache...");

  orig_size = (int)(cache->cache_content ? cache->cache_content->size : 0);
  orig_size += (int)cache->journal_len;

  f = start_writing_to_stdio_file(cache->cache_fname,
                                  OPEN_FLAGS_REPLACE|O_BINARY,
                                  0600, &open_file);
  if (!f)
    return -1;

  wrote = smartlist_new();

  HT_FOREACH(mdp, microdesc_map, &cache->map) {
    microdesc_t *md = *mdp;
    size_t annotation_len;
    if (md->no_save)
      continue;

    size = dump_microdescriptor(f, md, &annotation_len);
    if (size < 0) {
      /* XXX handle errors from dump_microdescriptor() */
      /* log?  return -1?  die?  coredump the universe? */
      continue;
    }
    tor_assert(((size_t)size) == annotation_len + md->bodylen);
    md->off = off + annotation_len;
    off += size;
    if (md->saved_location != SAVED_IN_CACHE) {
      tor_free(md->body);
      md->saved_location = SAVED_IN_CACHE;
    }
    smartlist_add(wrote, md);
  }

  if (cache->cache_content)
    tor_munmap_file(cache->cache_content);

  finish_writing_to_file(open_file); /*XXX Check me.*/

  cache->cache_content = tor_mmap_file(cache->cache_fname);

  if (!cache->cache_content && smartlist_len(wrote)) {
    log_err(LD_DIR, "Couldn't map file that we just wrote to %s!",
            cache->cache_fname);
    smartlist_free(wrote);
    return -1;
  }
  SMARTLIST_FOREACH_BEGIN(wrote, microdesc_t *, md) {
    tor_assert(md->saved_location == SAVED_IN_CACHE);
    md->body = (char*)cache->cache_content->data + md->off;
    if (PREDICT_UNLIKELY(
             md->bodylen < 9 || fast_memneq(md->body, "onion-key", 9) != 0)) {
      /* XXXX once bug 2022 is solved, we can kill this block and turn it
       * into just the tor_assert(!memcmp) */
      off_t avail = cache->cache_content->size - md->off;
      char *bad_str;
      tor_assert(avail >= 0);
      bad_str = tor_strndup(md->body, MIN(128, (size_t)avail));
      log_err(LD_BUG, "After rebuilding microdesc cache, offsets seem wrong. "
              " At offset %d, I expected to find a microdescriptor starting "
              " with \"onion-key\".  Instead I got %s.",
              (int)md->off, escaped(bad_str));
      tor_free(bad_str);
      tor_assert(fast_memeq(md->body, "onion-key", 9));
    }
  } SMARTLIST_FOREACH_END(md);

  smartlist_free(wrote);

  write_str_to_file(cache->journal_fname, "", 1);
  cache->journal_len = 0;
  cache->bytes_dropped = 0;

  new_size = cache->cache_content ? (int)cache->cache_content->size : 0;
  log_info(LD_DIR, "Done rebuilding microdesc cache. "
           "Saved %d bytes; %d still used.",
           orig_size-new_size, new_size);

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Reload the contents of cache from disk.

If it is empty, load it for the first time. Return 0 on success, -1 on failure.

Definition at line 293 of file microdesc.c.

{
  struct stat st;
  char *journal_content;
  smartlist_t *added;
  tor_mmap_t *mm;
  int total = 0;

  microdesc_cache_clear(cache);

  mm = cache->cache_content = tor_mmap_file(cache->cache_fname);
  if (mm) {
    added = microdescs_add_to_cache(cache, mm->data, mm->data+mm->size,
                                    SAVED_IN_CACHE, 0, -1, NULL);
    if (added) {
      total += smartlist_len(added);
      smartlist_free(added);
    }
  }

  journal_content = read_file_to_str(cache->journal_fname,
                                     RFTS_IGNORE_MISSING, &st);
  if (journal_content) {
    cache->journal_len = (size_t) st.st_size;
    added = microdescs_add_to_cache(cache, journal_content,
                                    journal_content+st.st_size,
                                    SAVED_IN_JOURNAL, 0, -1, NULL);
    if (added) {
      total += smartlist_len(added);
      smartlist_free(added);
    }
    tor_free(journal_content);
  }
  log_notice(LD_DIR, "Reloaded microdescriptor cache.  Found %d descriptors.",
             total);

  microdesc_cache_rebuild(cache, 0 /* don't force */);

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void microdesc_check_counts ( void  )

Make sure that the reference count of every microdescriptor in cache is accurate.

Definition at line 512 of file microdesc.c.

{
  microdesc_t **mdp;
  if (!the_microdesc_cache)
    return;

  HT_FOREACH(mdp, microdesc_map, &the_microdesc_cache->map) {
    microdesc_t *md = *mdp;
    unsigned int found=0;
    const smartlist_t *nodes = nodelist_get_list();
    SMARTLIST_FOREACH(nodes, node_t *, node, {
        if (node->md == md) {
          ++found;
        }
      });
    tor_assert(found == md->held_by_nodes);
  }
}

Here is the call graph for this function:

void microdesc_free ( microdesc_t md)

Deallocate a single microdescriptor.

Note: the microdescriptor MUST have previously been removed from the cache if it had ever been inserted.

Definition at line 534 of file microdesc.c.

{
  if (!md)
    return;

  /* Make sure that the microdesc was really removed from the appropriate data
     structures. */
  if (md->held_in_map) {
    microdesc_cache_t *cache = get_microdesc_cache();
    microdesc_t *md2 = HT_FIND(microdesc_map, &cache->map, md);
    if (md2 == md) {
      log_warn(LD_BUG, "microdesc_free() called, but md was still in "
               "microdesc_map");
      HT_REMOVE(microdesc_map, &cache->map, md);
    } else {
      log_warn(LD_BUG, "microdesc_free() called with held_in_map set, but "
               "microdesc was not in the map.");
    }
    tor_fragile_assert();
  }
  if (md->held_by_nodes) {
    int found=0;
    const smartlist_t *nodes = nodelist_get_list();
    SMARTLIST_FOREACH(nodes, node_t *, node, {
        if (node->md == md) {
          ++found;
          node->md = NULL;
        }
      });
    if (found) {
      log_warn(LD_BUG, "microdesc_free() called, but md was still referenced "
               "%d node(s); held_by_nodes == %u", found, md->held_by_nodes);
    } else {
      log_warn(LD_BUG, "microdesc_free() called with held_by_nodes set to %u, "
               "but md was not referenced by any nodes", md->held_by_nodes);
    }
    tor_fragile_assert();
  }
  //tor_assert(md->held_in_map == 0);
  //tor_assert(md->held_by_nodes == 0);

  if (md->onion_pkey)
    crypto_pk_free(md->onion_pkey);
  if (md->body && md->saved_location != SAVED_IN_CACHE)
    tor_free(md->body);

  if (md->family) {
    SMARTLIST_FOREACH(md->family, char *, cp, tor_free(cp));
    smartlist_free(md->family);
  }
  short_policy_free(md->exit_policy);

  tor_free(md);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void microdesc_free_all ( void  )

Free all storage held in the microdesc.c module.

Definition at line 591 of file microdesc.c.

Here is the call graph for this function:

Here is the caller graph for this function:

smartlist_t* microdesc_list_missing_digest256 ( networkstatus_t ns,
microdesc_cache_t cache,
int  downloadable_only,
digestmap_t *  skip 
)

Return a smartlist of all the sha256 digest of the microdescriptors that are listed in ns but not present in cache.

Returns pointers to internals of ns; you should not free the members of the resulting smartlist. Omit all microdescriptors whose digest appear in skip.

Definition at line 631 of file microdesc.c.

{
  smartlist_t *result = smartlist_new();
  time_t now = time(NULL);
  tor_assert(ns->flavor == FLAV_MICRODESC);
  SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
    if (microdesc_cache_lookup_by_digest256(cache, rs->descriptor_digest))
      continue;
    if (downloadable_only &&
        !download_status_is_ready(&rs->dl_status, now,
                                  MAX_MICRODESC_DOWNLOAD_FAILURES))
      continue;
    if (skip && digestmap_get(skip, rs->descriptor_digest))
      continue;
    if (tor_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN)) {
      log_info(LD_BUG, "Found an entry in networkstatus with no "
               "microdescriptor digest. (Router %s=%s at %s:%d.)",
               rs->nickname, hex_str(rs->identity_digest, DIGEST_LEN),
               fmt_addr32(rs->addr), rs->or_port);
      continue;
    }
    /* XXXX Also skip if we're a noncache and wouldn't use this router.
     * XXXX NM Microdesc
     */
    smartlist_add(result, rs->descriptor_digest);
  } SMARTLIST_FOREACH_END(rs);
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

smartlist_t* microdescs_add_list_to_cache ( microdesc_cache_t cache,
smartlist_t descriptors,
saved_location_t  where,
int  no_save 
)

As microdescs_add_to_cache, but takes a list of micrdescriptors instead of a string to decode.

Frees any members of descriptors that it does not add.

Definition at line 194 of file microdesc.c.

{
  smartlist_t *added;
  open_file_t *open_file = NULL;
  FILE *f = NULL;
  //  int n_added = 0;
  ssize_t size = 0;

  if (where == SAVED_NOWHERE && !no_save) {
    f = start_writing_to_stdio_file(cache->journal_fname,
                                    OPEN_FLAGS_APPEND|O_BINARY,
                                    0600, &open_file);
    if (!f) {
      log_warn(LD_DIR, "Couldn't append to journal in %s: %s",
               cache->journal_fname, strerror(errno));
      return NULL;
    }
  }

  added = smartlist_new();
  SMARTLIST_FOREACH_BEGIN(descriptors, microdesc_t *, md) {
    microdesc_t *md2;
    md2 = HT_FIND(microdesc_map, &cache->map, md);
    if (md2) {
      /* We already had this one. */
      if (md2->last_listed < md->last_listed)
        md2->last_listed = md->last_listed;
      microdesc_free(md);
      if (where != SAVED_NOWHERE)
        cache->bytes_dropped += size;
      continue;
    }

    /* Okay, it's a new one. */
    if (f) {
      size_t annotation_len;
      size = dump_microdescriptor(f, md, &annotation_len);
      if (size < 0) {
        /* we already warned in dump_microdescriptor; */
        abort_writing_to_file(open_file);
        smartlist_clear(added);
        return added;
      }
      md->saved_location = SAVED_IN_JOURNAL;
      cache->journal_len += size;
    } else {
      md->saved_location = where;
    }

    md->no_save = no_save;

    HT_INSERT(microdesc_map, &cache->map, md);
    md->held_in_map = 1;
    smartlist_add(added, md);
    ++cache->n_seen;
    cache->total_len_seen += md->bodylen;
  } SMARTLIST_FOREACH_END(md);

  if (f)
    finish_writing_to_file(open_file); /*XXX Check me.*/

  {
    networkstatus_t *ns = networkstatus_get_latest_consensus();
    if (ns && ns->flavor == FLAV_MICRODESC)
      SMARTLIST_FOREACH(added, microdesc_t *, md, nodelist_add_microdesc(md));
  }

  if (smartlist_len(added))
    router_dir_info_changed();

  return added;
}

Here is the call graph for this function:

Here is the caller graph for this function:

smartlist_t* microdescs_add_to_cache ( microdesc_cache_t cache,
const char *  s,
const char *  eos,
saved_location_t  where,
int  no_save,
time_t  listed_at,
smartlist_t requested_digests256 
)

Decode the microdescriptors from the string starting at s and ending at eos, and store them in cache.

If no-save, mark them as non-writable to disk. If where is SAVED_IN_CACHE, leave their bodies as pointers to the mmap'd cache. If where is SAVED_NOWHERE, do not allow annotations. If listed_at is positive, set the last_listed field of every microdesc to listed_at. If requested_digests is non-null, then it contains a list of digests we mean to allow, so we should reject any non-requested microdesc with a different digest, and alter the list to contain only the digests of those microdescs we didn't find. Return a newly allocated list of the added microdescriptors, or NULL

Definition at line 145 of file microdesc.c.

{
  smartlist_t *descriptors, *added;
  const int allow_annotations = (where != SAVED_NOWHERE);
  const int copy_body = (where != SAVED_IN_CACHE);

  descriptors = microdescs_parse_from_string(s, eos,
                                             allow_annotations,
                                             copy_body);
  if (listed_at > 0) {
    SMARTLIST_FOREACH(descriptors, microdesc_t *, md,
                      md->last_listed = listed_at);
  }
  if (requested_digests256) {
    digestmap_t *requested; /* XXXX actuqlly we should just use a
                               digest256map */
    requested = digestmap_new();
    SMARTLIST_FOREACH(requested_digests256, const char *, cp,
      digestmap_set(requested, cp, (void*)1));
    SMARTLIST_FOREACH_BEGIN(descriptors, microdesc_t *, md) {
      if (digestmap_get(requested, md->digest)) {
        digestmap_set(requested, md->digest, (void*)2);
      } else {
        log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Received non-requested microcdesc");
        microdesc_free(md);
        SMARTLIST_DEL_CURRENT(descriptors, md);
      }
    } SMARTLIST_FOREACH_END(md);
    SMARTLIST_FOREACH_BEGIN(requested_digests256, char *, cp) {
      if (digestmap_get(requested, cp) == (void*)2) {
        tor_free(cp);
        SMARTLIST_DEL_CURRENT(requested_digests256, cp);
      }
    } SMARTLIST_FOREACH_END(cp);
    digestmap_free(requested, NULL);
  }

  added = microdescs_add_list_to_cache(cache, descriptors, where, no_save);
  smartlist_free(descriptors);
  return added;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int should_rebuild_md_cache ( microdesc_cache_t cache) [static]

Definition at line 383 of file microdesc.c.

{
    const size_t old_len =
      cache->cache_content ? cache->cache_content->size : 0;
    const size_t journal_len = cache->journal_len;
    const size_t dropped = cache->bytes_dropped;

    if (journal_len < 16384)
      return 0; /* Don't bother, not enough has happened yet. */
    if (dropped > (journal_len + old_len) / 3)
      return 1; /* We could save 1/3 or more of the currently used space. */
    if (journal_len > old_len / 2)
      return 1; /* We should append to the regular file */

    return 0;
}

Here is the caller graph for this function:

void update_microdesc_downloads ( time_t  now)

Launch download requests for mircodescriptors as appropriate.

Specifically, we should launch download requests if we are configured to download mirodescriptors, and there are some microdescriptors listed the current microdesc consensus that we don't have, and either we never asked for them, or we failed to download them but we're willing to retry.

Definition at line 669 of file microdesc.c.

{
  const or_options_t *options = get_options();
  networkstatus_t *consensus;
  smartlist_t *missing;
  digestmap_t *pending;

  if (should_delay_dir_fetches(options))
    return;
  if (directory_too_idle_to_fetch_descriptors(options, now))
    return;

  consensus = networkstatus_get_reasonably_live_consensus(now, FLAV_MICRODESC);
  if (!consensus)
    return;

  if (!we_fetch_microdescriptors(options))
    return;

  pending = digestmap_new();
  list_pending_microdesc_downloads(pending);

  missing = microdesc_list_missing_digest256(consensus,
                                             get_microdesc_cache(),
                                             1,
                                             pending);
  digestmap_free(pending, NULL);

  launch_descriptor_downloads(DIR_PURPOSE_FETCH_MICRODESC,
                              missing, NULL, now);

  smartlist_free(missing);
}

Here is the call graph for this function:

Here is the caller graph for this function:

For every microdescriptor listed in the current microdecriptor consensus, update its last_listed field to be at least as recent as the publication time of the current microdescriptor consensus.

Definition at line 708 of file microdesc.c.

Here is the call graph for this function:

Here is the caller graph for this function:

int usable_consensus_flavor ( void  )

Return the consensus flavor we actually want to use to build circuits.

Definition at line 772 of file microdesc.c.

Here is the call graph for this function:

Here is the caller graph for this function:

int we_fetch_microdescriptors ( const or_options_t options)

Return true iff we should try to download microdescriptors at all.

Definition at line 750 of file microdesc.c.

{
  if (directory_caches_dir_info(options))
    return 1;
  if (options->FetchUselessDescriptors)
    return 1;
  return we_use_microdescriptors_for_circuits(options);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int we_fetch_router_descriptors ( const or_options_t options)

Return true iff we should try to download router descriptors at all.

Definition at line 761 of file microdesc.c.

{
  if (directory_caches_dir_info(options))
    return 1;
  if (options->FetchUselessDescriptors)
    return 1;
  return ! we_use_microdescriptors_for_circuits(options);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return true iff we should prefer to use microdescriptors rather than routerdescs for building circuits.

Definition at line 730 of file microdesc.c.

{
  int ret = options->UseMicrodescriptors;
  if (ret == -1) {
    /* UseMicrodescriptors is "auto"; we need to decide: */
    /* If we are configured to use bridges and one of our bridges doesn't
     * know what a microdescriptor is, the answer is no. */
    if (options->UseBridges && any_bridges_dont_support_microdescriptors())
      return 0;
    /* Otherwise, we decide that we'll use microdescriptors iff we are
     * not a server, and we're not autofetching everything. */
    /* XXX023 what does not being a server have to do with it? also there's
     * a partitioning issue here where bridges differ from clients. */
    ret = !server_mode(options) && !options->FetchUselessDescriptors;
  }
  return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Holds a pointer to the current microdesc_cache_t object, or NULL if no such object has been allocated.

Definition at line 110 of file microdesc.c.