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 return (unsigned) siphash24g(md
->digest
, sizeof(md
->digest
));
51 /** Helper: compares <b>a</b> and </b> for equality for hash-table purposes. */
53 microdesc_eq_(microdesc_t
*a
, microdesc_t
*b
)
55 return tor_memeq(a
->digest
, b
->digest
, DIGEST256_LEN
);
58 HT_PROTOTYPE(microdesc_map
, microdesc_t
, node
,
59 microdesc_hash_
, microdesc_eq_
);
60 HT_GENERATE(microdesc_map
, microdesc_t
, node
,
61 microdesc_hash_
, microdesc_eq_
, 0.6,
62 malloc
, realloc
, free
);
64 /** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations.
65 * On success, return the total number of bytes written, and set
66 * *<b>annotation_len_out</b> to the number of bytes written as
69 dump_microdescriptor(int fd
, microdesc_t
*md
, size_t *annotation_len_out
)
73 if (md
->body
== NULL
) {
74 *annotation_len_out
= 0;
77 /* XXXX drops unknown annotations. */
78 if (md
->last_listed
) {
79 char buf
[ISO_TIME_LEN
+1];
80 char annotation
[ISO_TIME_LEN
+32];
81 format_iso_time(buf
, md
->last_listed
);
82 tor_snprintf(annotation
, sizeof(annotation
), "@last-listed %s\n", buf
);
83 if (write_all(fd
, annotation
, strlen(annotation
), 0) < 0) {
85 "Couldn't write microdescriptor annotation: %s",
89 r
+= strlen(annotation
);
90 *annotation_len_out
= r
;
92 *annotation_len_out
= 0;
95 md
->off
= tor_fd_getpos(fd
);
96 written
= write_all(fd
, md
->body
, md
->bodylen
, 0);
97 if (written
!= (ssize_t
)md
->bodylen
) {
99 "Couldn't dump microdescriptor (wrote %ld out of %lu): %s",
100 (long)written
, (unsigned long)md
->bodylen
,
108 /** Holds a pointer to the current microdesc_cache_t object, or NULL if no
109 * such object has been allocated. */
110 static microdesc_cache_t
*the_microdesc_cache
= NULL
;
112 /** Return a pointer to the microdescriptor cache, loading it if necessary. */
114 get_microdesc_cache(void)
116 if (PREDICT_UNLIKELY(the_microdesc_cache
==NULL
)) {
117 microdesc_cache_t
*cache
= tor_malloc_zero(sizeof(microdesc_cache_t
));
118 HT_INIT(microdesc_map
, &cache
->map
);
119 cache
->cache_fname
= get_datadir_fname("cached-microdescs");
120 cache
->journal_fname
= get_datadir_fname("cached-microdescs.new");
121 microdesc_cache_reload(cache
);
122 the_microdesc_cache
= cache
;
124 return the_microdesc_cache
;
127 /* There are three sources of microdescriptors:
128 1) Generated by us while acting as a directory authority.
129 2) Loaded from the cache on disk.
133 /** Decode the microdescriptors from the string starting at <b>s</b> and
134 * ending at <b>eos</b>, and store them in <b>cache</b>. If <b>no_save</b>,
135 * mark them as non-writable to disk. If <b>where</b> is SAVED_IN_CACHE,
136 * leave their bodies as pointers to the mmap'd cache. If where is
137 * <b>SAVED_NOWHERE</b>, do not allow annotations. If listed_at is not -1,
138 * set the last_listed field of every microdesc to listed_at. If
139 * requested_digests is non-null, then it contains a list of digests we mean
140 * to allow, so we should reject any non-requested microdesc with a different
141 * digest, and alter the list to contain only the digests of those microdescs
143 * Return a newly allocated list of the added microdescriptors, or NULL */
145 microdescs_add_to_cache(microdesc_cache_t
*cache
,
146 const char *s
, const char *eos
, saved_location_t where
,
147 int no_save
, time_t listed_at
,
148 smartlist_t
*requested_digests256
)
150 smartlist_t
*descriptors
, *added
;
151 const int allow_annotations
= (where
!= SAVED_NOWHERE
);
153 descriptors
= microdescs_parse_from_string(s
, eos
,
156 if (listed_at
!= (time_t)-1) {
157 SMARTLIST_FOREACH(descriptors
, microdesc_t
*, md
,
158 md
->last_listed
= listed_at
);
160 if (requested_digests256
) {
161 digestmap_t
*requested
; /* XXXX actually we should just use a
163 requested
= digestmap_new();
164 SMARTLIST_FOREACH(requested_digests256
, const char *, cp
,
165 digestmap_set(requested
, cp
, (void*)1));
166 SMARTLIST_FOREACH_BEGIN(descriptors
, microdesc_t
*, md
) {
167 if (digestmap_get(requested
, md
->digest
)) {
168 digestmap_set(requested
, md
->digest
, (void*)2);
170 log_fn(LOG_PROTOCOL_WARN
, LD_DIR
, "Received non-requested microdesc");
172 SMARTLIST_DEL_CURRENT(descriptors
, md
);
174 } SMARTLIST_FOREACH_END(md
);
175 SMARTLIST_FOREACH_BEGIN(requested_digests256
, char *, cp
) {
176 if (digestmap_get(requested
, cp
) == (void*)2) {
178 SMARTLIST_DEL_CURRENT(requested_digests256
, cp
);
180 } SMARTLIST_FOREACH_END(cp
);
181 digestmap_free(requested
, NULL
);
184 added
= microdescs_add_list_to_cache(cache
, descriptors
, where
, no_save
);
185 smartlist_free(descriptors
);
189 /** As microdescs_add_to_cache, but takes a list of microdescriptors instead of
190 * a string to decode. Frees any members of <b>descriptors</b> that it does
193 microdescs_add_list_to_cache(microdesc_cache_t
*cache
,
194 smartlist_t
*descriptors
, saved_location_t where
,
198 open_file_t
*open_file
= NULL
;
203 if (where
== SAVED_NOWHERE
&& !no_save
) {
204 fd
= start_writing_to_file(cache
->journal_fname
,
205 OPEN_FLAGS_APPEND
|O_BINARY
,
208 log_warn(LD_DIR
, "Couldn't append to journal in %s: %s",
209 cache
->journal_fname
, strerror(errno
));
213 added
= smartlist_new();
214 SMARTLIST_FOREACH_BEGIN(descriptors
, microdesc_t
*, md
) {
216 md2
= HT_FIND(microdesc_map
, &cache
->map
, md
);
218 /* We already had this one. */
219 if (md2
->last_listed
< md
->last_listed
)
220 md2
->last_listed
= md
->last_listed
;
222 if (where
!= SAVED_NOWHERE
)
223 cache
->bytes_dropped
+= size
;
227 /* Okay, it's a new one. */
229 size_t annotation_len
;
230 size
= dump_microdescriptor(fd
, md
, &annotation_len
);
232 /* we already warned in dump_microdescriptor */
233 abort_writing_to_file(open_file
);
236 md
->saved_location
= SAVED_IN_JOURNAL
;
237 cache
->journal_len
+= size
;
240 md
->saved_location
= where
;
243 md
->no_save
= no_save
;
245 HT_INSERT(microdesc_map
, &cache
->map
, md
);
247 smartlist_add(added
, md
);
249 cache
->total_len_seen
+= md
->bodylen
;
250 } SMARTLIST_FOREACH_END(md
);
253 if (finish_writing_to_file(open_file
) < 0) {
254 log_warn(LD_DIR
, "Error appending to microdescriptor file: %s",
256 smartlist_clear(added
);
262 networkstatus_t
*ns
= networkstatus_get_latest_consensus();
263 if (ns
&& ns
->flavor
== FLAV_MICRODESC
)
264 SMARTLIST_FOREACH(added
, microdesc_t
*, md
, nodelist_add_microdesc(md
));
267 if (smartlist_len(added
))
268 router_dir_info_changed();
273 /** Remove every microdescriptor in <b>cache</b>. */
275 microdesc_cache_clear(microdesc_cache_t
*cache
)
277 microdesc_t
**entry
, **next
;
279 for (entry
= HT_START(microdesc_map
, &cache
->map
); entry
; entry
= next
) {
280 microdesc_t
*md
= *entry
;
281 next
= HT_NEXT_RMV(microdesc_map
, &cache
->map
, entry
);
285 HT_CLEAR(microdesc_map
, &cache
->map
);
286 if (cache
->cache_content
) {
287 int res
= tor_munmap_file(cache
->cache_content
);
290 "tor_munmap_file() failed clearing microdesc cache; "
291 "we are probably about to leak memory.");
292 /* TODO something smarter? */
294 cache
->cache_content
= NULL
;
296 cache
->total_len_seen
= 0;
298 cache
->bytes_dropped
= 0;
301 /** Reload the contents of <b>cache</b> from disk. If it is empty, load it
302 * for the first time. Return 0 on success, -1 on failure. */
304 microdesc_cache_reload(microdesc_cache_t
*cache
)
307 char *journal_content
;
312 microdesc_cache_clear(cache
);
314 mm
= cache
->cache_content
= tor_mmap_file(cache
->cache_fname
);
316 added
= microdescs_add_to_cache(cache
, mm
->data
, mm
->data
+mm
->size
,
317 SAVED_IN_CACHE
, 0, -1, NULL
);
319 total
+= smartlist_len(added
);
320 smartlist_free(added
);
324 journal_content
= read_file_to_str(cache
->journal_fname
,
325 RFTS_IGNORE_MISSING
, &st
);
326 if (journal_content
) {
327 cache
->journal_len
= (size_t) st
.st_size
;
328 added
= microdescs_add_to_cache(cache
, journal_content
,
329 journal_content
+st
.st_size
,
330 SAVED_IN_JOURNAL
, 0, -1, NULL
);
332 total
+= smartlist_len(added
);
333 smartlist_free(added
);
335 tor_free(journal_content
);
337 log_info(LD_DIR
, "Reloaded microdescriptor cache. Found %d descriptors.",
340 microdesc_cache_rebuild(cache
, 0 /* don't force */);
345 /** By default, we remove any microdescriptors that have gone at least this
346 * long without appearing in a current consensus. */
347 #define TOLERATE_MICRODESC_AGE (7*24*60*60)
349 /** Remove all microdescriptors from <b>cache</b> that haven't been listed for
350 * a long time. Does not rebuild the cache on disk. If <b>cutoff</b> is
351 * positive, specifically remove microdescriptors that have been unlisted
352 * since <b>cutoff</b>. If <b>force</b> is true, remove microdescriptors even
353 * if we have no current live microdescriptor consensus.
356 microdesc_cache_clean(microdesc_cache_t
*cache
, time_t cutoff
, int force
)
358 microdesc_t
**mdp
, *victim
;
359 int dropped
=0, kept
=0;
360 size_t bytes_dropped
= 0;
361 time_t now
= time(NULL
);
363 /* If we don't know a live consensus, don't believe last_listed values: we
364 * might be starting up after being down for a while. */
366 ! networkstatus_get_reasonably_live_consensus(now
, FLAV_MICRODESC
))
370 cutoff
= now
- TOLERATE_MICRODESC_AGE
;
372 for (mdp
= HT_START(microdesc_map
, &cache
->map
); mdp
!= NULL
; ) {
373 const int is_old
= (*mdp
)->last_listed
< cutoff
;
374 const unsigned held_by_nodes
= (*mdp
)->held_by_nodes
;
375 if (is_old
&& !held_by_nodes
) {
378 mdp
= HT_NEXT_RMV(microdesc_map
, &cache
->map
, mdp
);
379 victim
->held_in_map
= 0;
380 bytes_dropped
+= victim
->bodylen
;
381 microdesc_free(victim
);
384 /* It's old, but it has held_by_nodes set. That's not okay. */
385 /* Let's try to diagnose and fix #7164 . */
386 smartlist_t
*nodes
= nodelist_find_nodes_with_microdesc(*mdp
);
387 const networkstatus_t
*ns
= networkstatus_get_latest_consensus();
388 long networkstatus_age
= -1;
389 const int ht_badness
= HT_REP_IS_BAD_(microdesc_map
, &cache
->map
);
391 networkstatus_age
= now
- ns
->valid_after
;
393 log_warn(LD_BUG
, "Microdescriptor seemed very old "
394 "(last listed %d hours ago vs %d hour cutoff), but is still "
395 "marked as being held by %d node(s). I found %d node(s) "
396 "holding it. Current networkstatus is %ld hours old. "
397 "Hashtable badness is %d.",
398 (int)((now
- (*mdp
)->last_listed
) / 3600),
399 (int)((now
- cutoff
) / 3600),
401 smartlist_len(nodes
),
402 networkstatus_age
/ 3600,
405 SMARTLIST_FOREACH_BEGIN(nodes
, const node_t
*, node
) {
406 const char *rs_match
= "No RS";
407 const char *rs_present
= "";
409 if (tor_memeq(node
->rs
->descriptor_digest
,
410 (*mdp
)->digest
, DIGEST256_LEN
)) {
411 rs_match
= "Microdesc digest in RS matches";
413 rs_match
= "Microdesc digest in RS does match";
416 /* This should be impossible, but let's see! */
417 rs_present
= " RS not present in networkstatus.";
418 SMARTLIST_FOREACH(ns
->routerstatus_list
, routerstatus_t
*,rs
, {
419 if (rs
== node
->rs
) {
420 rs_present
= " RS okay in networkstatus.";
425 log_warn(LD_BUG
, " [%d]: ID=%s. md=%p, rs=%p, ri=%p. %s.%s",
427 hex_str(node
->identity
, DIGEST_LEN
),
428 node
->md
, node
->rs
, node
->ri
, rs_match
, rs_present
);
429 } SMARTLIST_FOREACH_END(node
);
430 smartlist_free(nodes
);
431 (*mdp
)->last_listed
= now
;
435 mdp
= HT_NEXT(microdesc_map
, &cache
->map
, mdp
);
440 log_info(LD_DIR
, "Removed %d/%d microdescriptors as old.",
441 dropped
,dropped
+kept
);
442 cache
->bytes_dropped
+= bytes_dropped
;
447 should_rebuild_md_cache(microdesc_cache_t
*cache
)
449 const size_t old_len
=
450 cache
->cache_content
? cache
->cache_content
->size
: 0;
451 const size_t journal_len
= cache
->journal_len
;
452 const size_t dropped
= cache
->bytes_dropped
;
454 if (journal_len
< 16384)
455 return 0; /* Don't bother, not enough has happened yet. */
456 if (dropped
> (journal_len
+ old_len
) / 3)
457 return 1; /* We could save 1/3 or more of the currently used space. */
458 if (journal_len
> old_len
/ 2)
459 return 1; /* We should append to the regular file */
465 * Mark <b>md</b> as having no body, and release any storage previously held
469 microdesc_wipe_body(microdesc_t
*md
)
474 if (md
->saved_location
!= SAVED_IN_CACHE
)
478 md
->saved_location
= SAVED_NOWHERE
;
484 /** Regenerate the main cache file for <b>cache</b>, clear the journal file,
485 * and update every microdesc_t in the cache with pointers to its new
486 * location. If <b>force</b> is true, do this unconditionally. If
487 * <b>force</b> is false, do it only if we expect to save space on disk. */
489 microdesc_cache_rebuild(microdesc_cache_t
*cache
, int force
)
491 open_file_t
*open_file
;
496 off_t off
= 0, off_real
;
497 int orig_size
, new_size
;
500 cache
= the_microdesc_cache
;
505 /* Remove dead descriptors */
506 microdesc_cache_clean(cache
, 0/*cutoff*/, 0/*force*/);
508 if (!force
&& !should_rebuild_md_cache(cache
))
511 log_info(LD_DIR
, "Rebuilding the microdescriptor cache...");
513 orig_size
= (int)(cache
->cache_content
? cache
->cache_content
->size
: 0);
514 orig_size
+= (int)cache
->journal_len
;
516 fd
= start_writing_to_file(cache
->cache_fname
,
517 OPEN_FLAGS_REPLACE
|O_BINARY
,
522 wrote
= smartlist_new();
524 HT_FOREACH(mdp
, microdesc_map
, &cache
->map
) {
525 microdesc_t
*md
= *mdp
;
526 size_t annotation_len
;
527 if (md
->no_save
|| !md
->body
)
530 size
= dump_microdescriptor(fd
, md
, &annotation_len
);
532 microdesc_wipe_body(md
);
534 /* rewind, in case it was a partial write. */
535 tor_fd_setpos(fd
, off
);
538 tor_assert(((size_t)size
) == annotation_len
+ md
->bodylen
);
539 md
->off
= off
+ annotation_len
;
541 off_real
= tor_fd_getpos(fd
);
542 if (off_real
!= off
) {
543 log_warn(LD_BUG
, "Discontinuity in position in microdescriptor cache."
544 "By my count, I'm at "I64_FORMAT
545 ", but I should be at "I64_FORMAT
,
546 I64_PRINTF_ARG(off
), I64_PRINTF_ARG(off_real
));
550 if (md
->saved_location
!= SAVED_IN_CACHE
) {
552 md
->saved_location
= SAVED_IN_CACHE
;
554 smartlist_add(wrote
, md
);
557 /* We must do this unmap _before_ we call finish_writing_to_file(), or
558 * windows will not actually replace the file. */
559 if (cache
->cache_content
) {
560 res
= tor_munmap_file(cache
->cache_content
);
563 "Failed to unmap old microdescriptor cache while rebuilding");
565 cache
->cache_content
= NULL
;
568 if (finish_writing_to_file(open_file
) < 0) {
569 log_warn(LD_DIR
, "Error rebuilding microdescriptor cache: %s",
571 /* Okay. Let's prevent from making things worse elsewhere. */
572 cache
->cache_content
= NULL
;
573 HT_FOREACH(mdp
, microdesc_map
, &cache
->map
) {
574 microdesc_t
*md
= *mdp
;
575 if (md
->saved_location
== SAVED_IN_CACHE
) {
576 microdesc_wipe_body(md
);
582 cache
->cache_content
= tor_mmap_file(cache
->cache_fname
);
584 if (!cache
->cache_content
&& smartlist_len(wrote
)) {
585 log_err(LD_DIR
, "Couldn't map file that we just wrote to %s!",
587 smartlist_free(wrote
);
590 SMARTLIST_FOREACH_BEGIN(wrote
, microdesc_t
*, md
) {
591 tor_assert(md
->saved_location
== SAVED_IN_CACHE
);
592 md
->body
= (char*)cache
->cache_content
->data
+ md
->off
;
593 if (PREDICT_UNLIKELY(
594 md
->bodylen
< 9 || fast_memneq(md
->body
, "onion-key", 9) != 0)) {
595 /* XXXX once bug 2022 is solved, we can kill this block and turn it
596 * into just the tor_assert(fast_memeq) */
597 off_t avail
= cache
->cache_content
->size
- md
->off
;
599 tor_assert(avail
>= 0);
600 bad_str
= tor_strndup(md
->body
, MIN(128, (size_t)avail
));
601 log_err(LD_BUG
, "After rebuilding microdesc cache, offsets seem wrong. "
602 " At offset %d, I expected to find a microdescriptor starting "
603 " with \"onion-key\". Instead I got %s.",
604 (int)md
->off
, escaped(bad_str
));
606 tor_assert(fast_memeq(md
->body
, "onion-key", 9));
608 } SMARTLIST_FOREACH_END(md
);
610 smartlist_free(wrote
);
612 write_str_to_file(cache
->journal_fname
, "", 1);
613 cache
->journal_len
= 0;
614 cache
->bytes_dropped
= 0;
616 new_size
= cache
->cache_content
? (int)cache
->cache_content
->size
: 0;
617 log_info(LD_DIR
, "Done rebuilding microdesc cache. "
618 "Saved %d bytes; %d still used.",
619 orig_size
-new_size
, new_size
);
624 /** Make sure that the reference count of every microdescriptor in cache is
627 microdesc_check_counts(void)
630 if (!the_microdesc_cache
)
633 HT_FOREACH(mdp
, microdesc_map
, &the_microdesc_cache
->map
) {
634 microdesc_t
*md
= *mdp
;
635 unsigned int found
=0;
636 const smartlist_t
*nodes
= nodelist_get_list();
637 SMARTLIST_FOREACH(nodes
, node_t
*, node
, {
638 if (node
->md
== md
) {
642 tor_assert(found
== md
->held_by_nodes
);
646 /** Deallocate a single microdescriptor. Note: the microdescriptor MUST have
647 * previously been removed from the cache if it had ever been inserted. */
649 microdesc_free_(microdesc_t
*md
, const char *fname
, int lineno
)
654 /* Make sure that the microdesc was really removed from the appropriate data
656 if (md
->held_in_map
) {
657 microdesc_cache_t
*cache
= get_microdesc_cache();
658 microdesc_t
*md2
= HT_FIND(microdesc_map
, &cache
->map
, md
);
660 log_warn(LD_BUG
, "microdesc_free() called from %s:%d, but md was still "
661 "in microdesc_map", fname
, lineno
);
662 HT_REMOVE(microdesc_map
, &cache
->map
, md
);
664 log_warn(LD_BUG
, "microdesc_free() called from %s:%d with held_in_map "
665 "set, but microdesc was not in the map.", fname
, lineno
);
667 tor_fragile_assert();
669 if (md
->held_by_nodes
) {
670 microdesc_cache_t
*cache
= get_microdesc_cache();
672 const smartlist_t
*nodes
= nodelist_get_list();
673 const int ht_badness
= HT_REP_IS_BAD_(microdesc_map
, &cache
->map
);
674 SMARTLIST_FOREACH(nodes
, node_t
*, node
, {
675 if (node
->md
== md
) {
681 log_warn(LD_BUG
, "microdesc_free() called from %s:%d, but md was still "
682 "referenced %d node(s); held_by_nodes == %u, ht_badness == %d",
683 fname
, lineno
, found
, md
->held_by_nodes
, ht_badness
);
685 log_warn(LD_BUG
, "microdesc_free() called from %s:%d with held_by_nodes "
686 "set to %u, but md was not referenced by any nodes. "
688 fname
, lineno
, md
->held_by_nodes
, ht_badness
);
690 tor_fragile_assert();
692 //tor_assert(md->held_in_map == 0);
693 //tor_assert(md->held_by_nodes == 0);
696 crypto_pk_free(md
->onion_pkey
);
697 tor_free(md
->onion_curve25519_pkey
);
698 if (md
->body
&& md
->saved_location
!= SAVED_IN_CACHE
)
702 SMARTLIST_FOREACH(md
->family
, char *, cp
, tor_free(cp
));
703 smartlist_free(md
->family
);
705 short_policy_free(md
->exit_policy
);
706 short_policy_free(md
->ipv6_exit_policy
);
711 /** Free all storage held in the microdesc.c module. */
713 microdesc_free_all(void)
715 if (the_microdesc_cache
) {
716 microdesc_cache_clear(the_microdesc_cache
);
717 tor_free(the_microdesc_cache
->cache_fname
);
718 tor_free(the_microdesc_cache
->journal_fname
);
719 tor_free(the_microdesc_cache
);
723 /** If there is a microdescriptor in <b>cache</b> whose sha256 digest is
724 * <b>d</b>, return it. Otherwise return NULL. */
726 microdesc_cache_lookup_by_digest256(microdesc_cache_t
*cache
, const char *d
)
728 microdesc_t
*md
, search
;
730 cache
= get_microdesc_cache();
731 memcpy(search
.digest
, d
, DIGEST256_LEN
);
732 md
= HT_FIND(microdesc_map
, &cache
->map
, &search
);
736 /** Return the mean size of decriptors added to <b>cache</b> since it was last
737 * cleared. Used to estimate the size of large downloads. */
739 microdesc_average_size(microdesc_cache_t
*cache
)
742 cache
= get_microdesc_cache();
745 return (size_t)(cache
->total_len_seen
/ cache
->n_seen
);
748 /** Return a smartlist of all the sha256 digest of the microdescriptors that
749 * are listed in <b>ns</b> but not present in <b>cache</b>. Returns pointers
750 * to internals of <b>ns</b>; you should not free the members of the resulting
751 * smartlist. Omit all microdescriptors whose digest appear in <b>skip</b>. */
753 microdesc_list_missing_digest256(networkstatus_t
*ns
, microdesc_cache_t
*cache
,
754 int downloadable_only
, digestmap_t
*skip
)
756 smartlist_t
*result
= smartlist_new();
757 time_t now
= time(NULL
);
758 tor_assert(ns
->flavor
== FLAV_MICRODESC
);
759 SMARTLIST_FOREACH_BEGIN(ns
->routerstatus_list
, routerstatus_t
*, rs
) {
760 if (microdesc_cache_lookup_by_digest256(cache
, rs
->descriptor_digest
))
762 if (downloadable_only
&&
763 !download_status_is_ready(&rs
->dl_status
, now
,
764 get_options()->TestingMicrodescMaxDownloadTries
))
766 if (skip
&& digestmap_get(skip
, rs
->descriptor_digest
))
768 if (tor_mem_is_zero(rs
->descriptor_digest
, DIGEST256_LEN
))
770 /* XXXX Also skip if we're a noncache and wouldn't use this router.
773 smartlist_add(result
, rs
->descriptor_digest
);
774 } SMARTLIST_FOREACH_END(rs
);
778 /** Launch download requests for microdescriptors as appropriate.
780 * Specifically, we should launch download requests if we are configured to
781 * download mirodescriptors, and there are some microdescriptors listed the
782 * current microdesc consensus that we don't have, and either we never asked
783 * for them, or we failed to download them but we're willing to retry.
786 update_microdesc_downloads(time_t now
)
788 const or_options_t
*options
= get_options();
789 networkstatus_t
*consensus
;
790 smartlist_t
*missing
;
791 digestmap_t
*pending
;
793 if (should_delay_dir_fetches(options
, NULL
))
795 if (directory_too_idle_to_fetch_descriptors(options
, now
))
798 consensus
= networkstatus_get_reasonably_live_consensus(now
, FLAV_MICRODESC
);
802 if (!we_fetch_microdescriptors(options
))
805 pending
= digestmap_new();
806 list_pending_microdesc_downloads(pending
);
808 missing
= microdesc_list_missing_digest256(consensus
,
809 get_microdesc_cache(),
812 digestmap_free(pending
, NULL
);
814 launch_descriptor_downloads(DIR_PURPOSE_FETCH_MICRODESC
,
817 smartlist_free(missing
);
820 /** For every microdescriptor listed in the current microdecriptor consensus,
821 * update its last_listed field to be at least as recent as the publication
822 * time of the current microdescriptor consensus.
825 update_microdescs_from_networkstatus(time_t now
)
827 microdesc_cache_t
*cache
= get_microdesc_cache();
829 networkstatus_t
*ns
=
830 networkstatus_get_reasonably_live_consensus(now
, FLAV_MICRODESC
);
835 tor_assert(ns
->flavor
== FLAV_MICRODESC
);
837 SMARTLIST_FOREACH_BEGIN(ns
->routerstatus_list
, routerstatus_t
*, rs
) {
838 md
= microdesc_cache_lookup_by_digest256(cache
, rs
->descriptor_digest
);
839 if (md
&& ns
->valid_after
> md
->last_listed
)
840 md
->last_listed
= ns
->valid_after
;
841 } SMARTLIST_FOREACH_END(rs
);
844 /** Return true iff we should prefer to use microdescriptors rather than
845 * routerdescs for building circuits. */
847 we_use_microdescriptors_for_circuits(const or_options_t
*options
)
849 int ret
= options
->UseMicrodescriptors
;
851 /* UseMicrodescriptors is "auto"; we need to decide: */
852 /* If we are configured to use bridges and none of our bridges
853 * know what a microdescriptor is, the answer is no. */
854 if (options
->UseBridges
&& !any_bridge_supports_microdescriptors())
856 /* Otherwise, we decide that we'll use microdescriptors iff we are
857 * not a server, and we're not autofetching everything. */
858 /* XXX023 what does not being a server have to do with it? also there's
859 * a partitioning issue here where bridges differ from clients. */
860 ret
= !server_mode(options
) && !options
->FetchUselessDescriptors
;
865 /** Return true iff we should try to download microdescriptors at all. */
867 we_fetch_microdescriptors(const or_options_t
*options
)
869 if (directory_caches_dir_info(options
))
871 if (options
->FetchUselessDescriptors
)
873 return we_use_microdescriptors_for_circuits(options
);
876 /** Return true iff we should try to download router descriptors at all. */
878 we_fetch_router_descriptors(const or_options_t
*options
)
880 if (directory_caches_dir_info(options
))
882 if (options
->FetchUselessDescriptors
)
884 return ! we_use_microdescriptors_for_circuits(options
);
887 /** Return the consensus flavor we actually want to use to build circuits. */
889 usable_consensus_flavor(void)
891 if (we_use_microdescriptors_for_circuits(get_options())) {
892 return FLAV_MICRODESC
;