1 /* Copyright (c) 2009-2013, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
5 #include "circuitbuild.h"
9 #include "entrynodes.h"
10 #include "microdesc.h"
11 #include "networkstatus.h"
15 #include "routerlist.h"
16 #include "routerparse.h"
18 /** A data structure to hold a bunch of cached microdescriptors. There are
19 * two active files in the cache: a "cache file" that we mmap, and a "journal
20 * file" that we append to. Periodically, we rebuild the cache file to hold
21 * only the microdescriptors that we want to keep */
22 struct microdesc_cache_t
{
23 /** Map from sha256-digest to microdesc_t for every microdesc_t in the
25 HT_HEAD(microdesc_map
, microdesc_t
) map
;
27 /** Name of the cache file. */
29 /** Name of the journal file. */
31 /** Mmap'd contents of the cache file, or NULL if there is none. */
32 tor_mmap_t
*cache_content
;
33 /** Number of bytes used in the journal file. */
35 /** Number of bytes in descriptors removed as too old. */
38 /** Total bytes of microdescriptor bodies we have added to this cache */
39 uint64_t total_len_seen
;
40 /** Total number of microdescriptors we have added to this cache */
44 /** Helper: computes a hash of <b>md</b> to place it in a hash table. */
45 static INLINE
unsigned int
46 microdesc_hash_(microdesc_t
*md
)
48 unsigned *d
= (unsigned*)md
->digest
;
50 return d
[0] ^ d
[1] ^ d
[2] ^ d
[3] ^ d
[4] ^ d
[5] ^ d
[6] ^ d
[7];
52 return d
[0] ^ d
[1] ^ d
[2] ^ d
[3];
56 /** Helper: compares <b>a</b> and </b> for equality for hash-table purposes. */
58 microdesc_eq_(microdesc_t
*a
, microdesc_t
*b
)
60 return tor_memeq(a
->digest
, b
->digest
, DIGEST256_LEN
);
63 HT_PROTOTYPE(microdesc_map
, microdesc_t
, node
,
64 microdesc_hash_
, microdesc_eq_
);
65 HT_GENERATE(microdesc_map
, microdesc_t
, node
,
66 microdesc_hash_
, microdesc_eq_
, 0.6,
67 malloc
, realloc
, free
);
69 /** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations.
70 * On success, return the total number of bytes written, and set
71 * *<b>annotation_len_out</b> to the number of bytes written as
74 dump_microdescriptor(FILE *f
, microdesc_t
*md
, size_t *annotation_len_out
)
78 /* XXXX drops unknown annotations. */
79 if (md
->last_listed
) {
80 char buf
[ISO_TIME_LEN
+1];
81 char annotation
[ISO_TIME_LEN
+32];
82 format_iso_time(buf
, md
->last_listed
);
83 tor_snprintf(annotation
, sizeof(annotation
), "@last-listed %s\n", buf
);
84 if (fputs(annotation
, f
) < 0) {
86 "Couldn't write microdescriptor annotation: %s",
90 r
+= strlen(annotation
);
91 *annotation_len_out
= r
;
93 *annotation_len_out
= 0;
96 md
->off
= (off_t
) ftell(f
);
97 written
= fwrite(md
->body
, 1, md
->bodylen
, f
);
98 if (written
!= md
->bodylen
) {
100 "Couldn't dump microdescriptor (wrote %lu out of %lu): %s",
101 (unsigned long)written
, (unsigned long)md
->bodylen
,
102 strerror(ferror(f
)));
109 /** Holds a pointer to the current microdesc_cache_t object, or NULL if no
110 * such object has been allocated. */
111 static microdesc_cache_t
*the_microdesc_cache
= NULL
;
113 /** Return a pointer to the microdescriptor cache, loading it if necessary. */
115 get_microdesc_cache(void)
117 if (PREDICT_UNLIKELY(the_microdesc_cache
==NULL
)) {
118 microdesc_cache_t
*cache
= tor_malloc_zero(sizeof(microdesc_cache_t
));
119 HT_INIT(microdesc_map
, &cache
->map
);
120 cache
->cache_fname
= get_datadir_fname("cached-microdescs");
121 cache
->journal_fname
= get_datadir_fname("cached-microdescs.new");
122 microdesc_cache_reload(cache
);
123 the_microdesc_cache
= cache
;
125 return the_microdesc_cache
;
128 /* There are three sources of microdescriptors:
129 1) Generated by us while acting as a directory authority.
130 2) Loaded from the cache on disk.
134 /** Decode the microdescriptors from the string starting at <b>s</b> and
135 * ending at <b>eos</b>, and store them in <b>cache</b>. If <b>no_save</b>,
136 * mark them as non-writable to disk. If <b>where</b> is SAVED_IN_CACHE,
137 * leave their bodies as pointers to the mmap'd cache. If where is
138 * <b>SAVED_NOWHERE</b>, do not allow annotations. If listed_at is positive,
139 * set the last_listed field of every microdesc to listed_at. If
140 * requested_digests is non-null, then it contains a list of digests we mean
141 * to allow, so we should reject any non-requested microdesc with a different
142 * digest, and alter the list to contain only the digests of those microdescs
144 * Return a newly allocated list of the added microdescriptors, or NULL */
146 microdescs_add_to_cache(microdesc_cache_t
*cache
,
147 const char *s
, const char *eos
, saved_location_t where
,
148 int no_save
, time_t listed_at
,
149 smartlist_t
*requested_digests256
)
151 smartlist_t
*descriptors
, *added
;
152 const int allow_annotations
= (where
!= SAVED_NOWHERE
);
153 const int copy_body
= (where
!= SAVED_IN_CACHE
);
155 descriptors
= microdescs_parse_from_string(s
, eos
,
159 SMARTLIST_FOREACH(descriptors
, microdesc_t
*, md
,
160 md
->last_listed
= listed_at
);
162 if (requested_digests256
) {
163 digestmap_t
*requested
; /* XXXX actually we should just use a
165 requested
= digestmap_new();
166 SMARTLIST_FOREACH(requested_digests256
, const char *, cp
,
167 digestmap_set(requested
, cp
, (void*)1));
168 SMARTLIST_FOREACH_BEGIN(descriptors
, microdesc_t
*, md
) {
169 if (digestmap_get(requested
, md
->digest
)) {
170 digestmap_set(requested
, md
->digest
, (void*)2);
172 log_fn(LOG_PROTOCOL_WARN
, LD_DIR
, "Received non-requested microdesc");
174 SMARTLIST_DEL_CURRENT(descriptors
, md
);
176 } SMARTLIST_FOREACH_END(md
);
177 SMARTLIST_FOREACH_BEGIN(requested_digests256
, char *, cp
) {
178 if (digestmap_get(requested
, cp
) == (void*)2) {
180 SMARTLIST_DEL_CURRENT(requested_digests256
, cp
);
182 } SMARTLIST_FOREACH_END(cp
);
183 digestmap_free(requested
, NULL
);
186 added
= microdescs_add_list_to_cache(cache
, descriptors
, where
, no_save
);
187 smartlist_free(descriptors
);
191 /** As microdescs_add_to_cache, but takes a list of microdescriptors instead of
192 * a string to decode. Frees any members of <b>descriptors</b> that it does
195 microdescs_add_list_to_cache(microdesc_cache_t
*cache
,
196 smartlist_t
*descriptors
, saved_location_t where
,
200 open_file_t
*open_file
= NULL
;
205 if (where
== SAVED_NOWHERE
&& !no_save
) {
206 f
= start_writing_to_stdio_file(cache
->journal_fname
,
207 OPEN_FLAGS_APPEND
|O_BINARY
,
210 log_warn(LD_DIR
, "Couldn't append to journal in %s: %s",
211 cache
->journal_fname
, strerror(errno
));
216 added
= smartlist_new();
217 SMARTLIST_FOREACH_BEGIN(descriptors
, microdesc_t
*, md
) {
219 md2
= HT_FIND(microdesc_map
, &cache
->map
, md
);
221 /* We already had this one. */
222 if (md2
->last_listed
< md
->last_listed
)
223 md2
->last_listed
= md
->last_listed
;
225 if (where
!= SAVED_NOWHERE
)
226 cache
->bytes_dropped
+= size
;
230 /* Okay, it's a new one. */
232 size_t annotation_len
;
233 size
= dump_microdescriptor(f
, md
, &annotation_len
);
235 /* we already warned in dump_microdescriptor */
236 abort_writing_to_file(open_file
);
237 smartlist_clear(added
);
240 md
->saved_location
= SAVED_IN_JOURNAL
;
241 cache
->journal_len
+= size
;
243 md
->saved_location
= where
;
246 md
->no_save
= no_save
;
248 HT_INSERT(microdesc_map
, &cache
->map
, md
);
250 smartlist_add(added
, md
);
252 cache
->total_len_seen
+= md
->bodylen
;
253 } SMARTLIST_FOREACH_END(md
);
256 finish_writing_to_file(open_file
); /*XXX Check me.*/
259 networkstatus_t
*ns
= networkstatus_get_latest_consensus();
260 if (ns
&& ns
->flavor
== FLAV_MICRODESC
)
261 SMARTLIST_FOREACH(added
, microdesc_t
*, md
, nodelist_add_microdesc(md
));
264 if (smartlist_len(added
))
265 router_dir_info_changed();
270 /** Remove every microdescriptor in <b>cache</b>. */
272 microdesc_cache_clear(microdesc_cache_t
*cache
)
274 microdesc_t
**entry
, **next
;
275 for (entry
= HT_START(microdesc_map
, &cache
->map
); entry
; entry
= next
) {
276 microdesc_t
*md
= *entry
;
277 next
= HT_NEXT_RMV(microdesc_map
, &cache
->map
, entry
);
281 HT_CLEAR(microdesc_map
, &cache
->map
);
282 if (cache
->cache_content
) {
283 tor_munmap_file(cache
->cache_content
);
284 cache
->cache_content
= NULL
;
286 cache
->total_len_seen
= 0;
288 cache
->bytes_dropped
= 0;
291 /** Reload the contents of <b>cache</b> from disk. If it is empty, load it
292 * for the first time. Return 0 on success, -1 on failure. */
294 microdesc_cache_reload(microdesc_cache_t
*cache
)
297 char *journal_content
;
302 microdesc_cache_clear(cache
);
304 mm
= cache
->cache_content
= tor_mmap_file(cache
->cache_fname
);
306 added
= microdescs_add_to_cache(cache
, mm
->data
, mm
->data
+mm
->size
,
307 SAVED_IN_CACHE
, 0, -1, NULL
);
309 total
+= smartlist_len(added
);
310 smartlist_free(added
);
314 journal_content
= read_file_to_str(cache
->journal_fname
,
315 RFTS_IGNORE_MISSING
, &st
);
316 if (journal_content
) {
317 cache
->journal_len
= (size_t) st
.st_size
;
318 added
= microdescs_add_to_cache(cache
, journal_content
,
319 journal_content
+st
.st_size
,
320 SAVED_IN_JOURNAL
, 0, -1, NULL
);
322 total
+= smartlist_len(added
);
323 smartlist_free(added
);
325 tor_free(journal_content
);
327 log_info(LD_DIR
, "Reloaded microdescriptor cache. Found %d descriptors.",
330 microdesc_cache_rebuild(cache
, 0 /* don't force */);
335 /** By default, we remove any microdescriptors that have gone at least this
336 * long without appearing in a current consensus. */
337 #define TOLERATE_MICRODESC_AGE (7*24*60*60)
339 /** Remove all microdescriptors from <b>cache</b> that haven't been listed for
340 * a long time. Does not rebuild the cache on disk. If <b>cutoff</b> is
341 * positive, specifically remove microdescriptors that have been unlisted
342 * since <b>cutoff</b>. If <b>force</b> is true, remove microdescriptors even
343 * if we have no current live microdescriptor consensus.
346 microdesc_cache_clean(microdesc_cache_t
*cache
, time_t cutoff
, int force
)
348 microdesc_t
**mdp
, *victim
;
349 int dropped
=0, kept
=0;
350 size_t bytes_dropped
= 0;
351 time_t now
= time(NULL
);
353 /* If we don't know a live consensus, don't believe last_listed values: we
354 * might be starting up after being down for a while. */
356 ! networkstatus_get_reasonably_live_consensus(now
, FLAV_MICRODESC
))
360 cutoff
= now
- TOLERATE_MICRODESC_AGE
;
362 for (mdp
= HT_START(microdesc_map
, &cache
->map
); mdp
!= NULL
; ) {
363 if ((*mdp
)->last_listed
< cutoff
) {
366 mdp
= HT_NEXT_RMV(microdesc_map
, &cache
->map
, mdp
);
367 victim
->held_in_map
= 0;
368 bytes_dropped
+= victim
->bodylen
;
369 microdesc_free(victim
);
372 mdp
= HT_NEXT(microdesc_map
, &cache
->map
, mdp
);
377 log_info(LD_DIR
, "Removed %d/%d microdescriptors as old.",
378 dropped
,dropped
+kept
);
379 cache
->bytes_dropped
+= bytes_dropped
;
384 should_rebuild_md_cache(microdesc_cache_t
*cache
)
386 const size_t old_len
=
387 cache
->cache_content
? cache
->cache_content
->size
: 0;
388 const size_t journal_len
= cache
->journal_len
;
389 const size_t dropped
= cache
->bytes_dropped
;
391 if (journal_len
< 16384)
392 return 0; /* Don't bother, not enough has happened yet. */
393 if (dropped
> (journal_len
+ old_len
) / 3)
394 return 1; /* We could save 1/3 or more of the currently used space. */
395 if (journal_len
> old_len
/ 2)
396 return 1; /* We should append to the regular file */
401 /** Regenerate the main cache file for <b>cache</b>, clear the journal file,
402 * and update every microdesc_t in the cache with pointers to its new
403 * location. If <b>force</b> is true, do this unconditionally. If
404 * <b>force</b> is false, do it only if we expect to save space on disk. */
406 microdesc_cache_rebuild(microdesc_cache_t
*cache
, int force
)
408 open_file_t
*open_file
;
414 int orig_size
, new_size
;
417 cache
= the_microdesc_cache
;
422 /* Remove dead descriptors */
423 microdesc_cache_clean(cache
, 0/*cutoff*/, 0/*force*/);
425 if (!force
&& !should_rebuild_md_cache(cache
))
428 log_info(LD_DIR
, "Rebuilding the microdescriptor cache...");
430 orig_size
= (int)(cache
->cache_content
? cache
->cache_content
->size
: 0);
431 orig_size
+= (int)cache
->journal_len
;
433 f
= start_writing_to_stdio_file(cache
->cache_fname
,
434 OPEN_FLAGS_REPLACE
|O_BINARY
,
439 wrote
= smartlist_new();
441 HT_FOREACH(mdp
, microdesc_map
, &cache
->map
) {
442 microdesc_t
*md
= *mdp
;
443 size_t annotation_len
;
447 size
= dump_microdescriptor(f
, md
, &annotation_len
);
449 /* XXX handle errors from dump_microdescriptor() */
450 /* log? return -1? die? coredump the universe? */
453 tor_assert(((size_t)size
) == annotation_len
+ md
->bodylen
);
454 md
->off
= off
+ annotation_len
;
456 if (md
->saved_location
!= SAVED_IN_CACHE
) {
458 md
->saved_location
= SAVED_IN_CACHE
;
460 smartlist_add(wrote
, md
);
463 if (cache
->cache_content
)
464 tor_munmap_file(cache
->cache_content
);
466 finish_writing_to_file(open_file
); /*XXX Check me.*/
468 cache
->cache_content
= tor_mmap_file(cache
->cache_fname
);
470 if (!cache
->cache_content
&& smartlist_len(wrote
)) {
471 log_err(LD_DIR
, "Couldn't map file that we just wrote to %s!",
473 smartlist_free(wrote
);
476 SMARTLIST_FOREACH_BEGIN(wrote
, microdesc_t
*, md
) {
477 tor_assert(md
->saved_location
== SAVED_IN_CACHE
);
478 md
->body
= (char*)cache
->cache_content
->data
+ md
->off
;
479 if (PREDICT_UNLIKELY(
480 md
->bodylen
< 9 || fast_memneq(md
->body
, "onion-key", 9) != 0)) {
481 /* XXXX once bug 2022 is solved, we can kill this block and turn it
482 * into just the tor_assert(fast_memeq) */
483 off_t avail
= cache
->cache_content
->size
- md
->off
;
485 tor_assert(avail
>= 0);
486 bad_str
= tor_strndup(md
->body
, MIN(128, (size_t)avail
));
487 log_err(LD_BUG
, "After rebuilding microdesc cache, offsets seem wrong. "
488 " At offset %d, I expected to find a microdescriptor starting "
489 " with \"onion-key\". Instead I got %s.",
490 (int)md
->off
, escaped(bad_str
));
492 tor_assert(fast_memeq(md
->body
, "onion-key", 9));
494 } SMARTLIST_FOREACH_END(md
);
496 smartlist_free(wrote
);
498 write_str_to_file(cache
->journal_fname
, "", 1);
499 cache
->journal_len
= 0;
500 cache
->bytes_dropped
= 0;
502 new_size
= cache
->cache_content
? (int)cache
->cache_content
->size
: 0;
503 log_info(LD_DIR
, "Done rebuilding microdesc cache. "
504 "Saved %d bytes; %d still used.",
505 orig_size
-new_size
, new_size
);
510 /** Make sure that the reference count of every microdescriptor in cache is
513 microdesc_check_counts(void)
516 if (!the_microdesc_cache
)
519 HT_FOREACH(mdp
, microdesc_map
, &the_microdesc_cache
->map
) {
520 microdesc_t
*md
= *mdp
;
521 unsigned int found
=0;
522 const smartlist_t
*nodes
= nodelist_get_list();
523 SMARTLIST_FOREACH(nodes
, node_t
*, node
, {
524 if (node
->md
== md
) {
528 tor_assert(found
== md
->held_by_nodes
);
532 /** Deallocate a single microdescriptor. Note: the microdescriptor MUST have
533 * previously been removed from the cache if it had ever been inserted. */
535 microdesc_free_(microdesc_t
*md
, const char *fname
, int lineno
)
540 /* Make sure that the microdesc was really removed from the appropriate data
542 if (md
->held_in_map
) {
543 microdesc_cache_t
*cache
= get_microdesc_cache();
544 microdesc_t
*md2
= HT_FIND(microdesc_map
, &cache
->map
, md
);
546 log_warn(LD_BUG
, "microdesc_free() called from %s:%d, but md was still "
547 "in microdesc_map", fname
, lineno
);
548 HT_REMOVE(microdesc_map
, &cache
->map
, md
);
550 log_warn(LD_BUG
, "microdesc_free() called from %s:%d with held_in_map "
551 "set, but microdesc was not in the map.", fname
, lineno
);
553 tor_fragile_assert();
555 if (md
->held_by_nodes
) {
557 const smartlist_t
*nodes
= nodelist_get_list();
558 SMARTLIST_FOREACH(nodes
, node_t
*, node
, {
559 if (node
->md
== md
) {
565 log_warn(LD_BUG
, "microdesc_free() called from %s:%d, but md was still "
566 "referenced %d node(s); held_by_nodes == %u",
567 fname
, lineno
, found
, md
->held_by_nodes
);
569 log_warn(LD_BUG
, "microdesc_free() called from %s:%d with held_by_nodes "
570 "set to %u, but md was not referenced by any nodes",
571 fname
, lineno
, md
->held_by_nodes
);
573 tor_fragile_assert();
575 //tor_assert(md->held_in_map == 0);
576 //tor_assert(md->held_by_nodes == 0);
579 crypto_pk_free(md
->onion_pkey
);
580 tor_free(md
->onion_curve25519_pkey
);
581 if (md
->body
&& md
->saved_location
!= SAVED_IN_CACHE
)
585 SMARTLIST_FOREACH(md
->family
, char *, cp
, tor_free(cp
));
586 smartlist_free(md
->family
);
588 short_policy_free(md
->exit_policy
);
589 short_policy_free(md
->ipv6_exit_policy
);
594 /** Free all storage held in the microdesc.c module. */
596 microdesc_free_all(void)
598 if (the_microdesc_cache
) {
599 microdesc_cache_clear(the_microdesc_cache
);
600 tor_free(the_microdesc_cache
->cache_fname
);
601 tor_free(the_microdesc_cache
->journal_fname
);
602 tor_free(the_microdesc_cache
);
606 /** If there is a microdescriptor in <b>cache</b> whose sha256 digest is
607 * <b>d</b>, return it. Otherwise return NULL. */
609 microdesc_cache_lookup_by_digest256(microdesc_cache_t
*cache
, const char *d
)
611 microdesc_t
*md
, search
;
613 cache
= get_microdesc_cache();
614 memcpy(search
.digest
, d
, DIGEST256_LEN
);
615 md
= HT_FIND(microdesc_map
, &cache
->map
, &search
);
619 /** Return the mean size of decriptors added to <b>cache</b> since it was last
620 * cleared. Used to estimate the size of large downloads. */
622 microdesc_average_size(microdesc_cache_t
*cache
)
625 cache
= get_microdesc_cache();
628 return (size_t)(cache
->total_len_seen
/ cache
->n_seen
);
631 /** Return a smartlist of all the sha256 digest of the microdescriptors that
632 * are listed in <b>ns</b> but not present in <b>cache</b>. Returns pointers
633 * to internals of <b>ns</b>; you should not free the members of the resulting
634 * smartlist. Omit all microdescriptors whose digest appear in <b>skip</b>. */
636 microdesc_list_missing_digest256(networkstatus_t
*ns
, microdesc_cache_t
*cache
,
637 int downloadable_only
, digestmap_t
*skip
)
639 smartlist_t
*result
= smartlist_new();
640 time_t now
= time(NULL
);
641 tor_assert(ns
->flavor
== FLAV_MICRODESC
);
642 SMARTLIST_FOREACH_BEGIN(ns
->routerstatus_list
, routerstatus_t
*, rs
) {
643 if (microdesc_cache_lookup_by_digest256(cache
, rs
->descriptor_digest
))
645 if (downloadable_only
&&
646 !download_status_is_ready(&rs
->dl_status
, now
,
647 MAX_MICRODESC_DOWNLOAD_FAILURES
))
649 if (skip
&& digestmap_get(skip
, rs
->descriptor_digest
))
651 if (tor_mem_is_zero(rs
->descriptor_digest
, DIGEST256_LEN
))
653 /* XXXX Also skip if we're a noncache and wouldn't use this router.
656 smartlist_add(result
, rs
->descriptor_digest
);
657 } SMARTLIST_FOREACH_END(rs
);
661 /** Launch download requests for microdescriptors as appropriate.
663 * Specifically, we should launch download requests if we are configured to
664 * download mirodescriptors, and there are some microdescriptors listed the
665 * current microdesc consensus that we don't have, and either we never asked
666 * for them, or we failed to download them but we're willing to retry.
669 update_microdesc_downloads(time_t now
)
671 const or_options_t
*options
= get_options();
672 networkstatus_t
*consensus
;
673 smartlist_t
*missing
;
674 digestmap_t
*pending
;
676 if (should_delay_dir_fetches(options
))
678 if (directory_too_idle_to_fetch_descriptors(options
, now
))
681 consensus
= networkstatus_get_reasonably_live_consensus(now
, FLAV_MICRODESC
);
685 if (!we_fetch_microdescriptors(options
))
688 pending
= digestmap_new();
689 list_pending_microdesc_downloads(pending
);
691 missing
= microdesc_list_missing_digest256(consensus
,
692 get_microdesc_cache(),
695 digestmap_free(pending
, NULL
);
697 launch_descriptor_downloads(DIR_PURPOSE_FETCH_MICRODESC
,
700 smartlist_free(missing
);
703 /** For every microdescriptor listed in the current microdecriptor consensus,
704 * update its last_listed field to be at least as recent as the publication
705 * time of the current microdescriptor consensus.
708 update_microdescs_from_networkstatus(time_t now
)
710 microdesc_cache_t
*cache
= get_microdesc_cache();
712 networkstatus_t
*ns
=
713 networkstatus_get_reasonably_live_consensus(now
, FLAV_MICRODESC
);
718 tor_assert(ns
->flavor
== FLAV_MICRODESC
);
720 SMARTLIST_FOREACH_BEGIN(ns
->routerstatus_list
, routerstatus_t
*, rs
) {
721 md
= microdesc_cache_lookup_by_digest256(cache
, rs
->descriptor_digest
);
722 if (md
&& ns
->valid_after
> md
->last_listed
)
723 md
->last_listed
= ns
->valid_after
;
724 } SMARTLIST_FOREACH_END(rs
);
727 /** Return true iff we should prefer to use microdescriptors rather than
728 * routerdescs for building circuits. */
730 we_use_microdescriptors_for_circuits(const or_options_t
*options
)
732 int ret
= options
->UseMicrodescriptors
;
734 /* UseMicrodescriptors is "auto"; we need to decide: */
735 /* If we are configured to use bridges and none of our bridges
736 * know what a microdescriptor is, the answer is no. */
737 if (options
->UseBridges
&& !any_bridge_supports_microdescriptors())
739 /* Otherwise, we decide that we'll use microdescriptors iff we are
740 * not a server, and we're not autofetching everything. */
741 /* XXX023 what does not being a server have to do with it? also there's
742 * a partitioning issue here where bridges differ from clients. */
743 ret
= !server_mode(options
) && !options
->FetchUselessDescriptors
;
748 /** Return true iff we should try to download microdescriptors at all. */
750 we_fetch_microdescriptors(const or_options_t
*options
)
752 if (directory_caches_dir_info(options
))
754 if (options
->FetchUselessDescriptors
)
756 return we_use_microdescriptors_for_circuits(options
);
759 /** Return true iff we should try to download router descriptors at all. */
761 we_fetch_router_descriptors(const or_options_t
*options
)
763 if (directory_caches_dir_info(options
))
765 if (options
->FetchUselessDescriptors
)
767 return ! we_use_microdescriptors_for_circuits(options
);
770 /** Return the consensus flavor we actually want to use to build circuits. */
772 usable_consensus_flavor(void)
774 if (we_use_microdescriptors_for_circuits(get_options())) {
775 return FLAV_MICRODESC
;