Tor 0.4.9.0-alpha-dev
dirserv.c
Go to the documentation of this file.
1/* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4/* See LICENSE for licensing information */
5
6#include "core/or/or.h"
7
8#include "app/config/config.h"
19
26
28
29/**
30 * \file dirserv.c
31 * \brief Directory server core implementation. Manages directory
32 * contents and generates directory documents.
33 *
34 * This module implements most of directory cache functionality, and some of
35 * the directory authority functionality. The directory.c module delegates
36 * here in order to handle incoming requests from clients, via
37 * connection_dirserv_flushed_some() and its kin. In order to save RAM, this
38 * module is responsible for spooling directory objects (in whole or in part)
39 * onto buf_t instances, and then closing the dir_connection_t once the
40 * objects are totally flushed.
41 *
42 * The directory.c module also delegates here for handling descriptor uploads
43 * via dirserv_add_multiple_descriptors().
44 *
45 * Additionally, this module handles some aspects of voting, including:
46 * deciding how to vote on individual flags (based on decisions reached in
47 * rephist.c), of formatting routerstatus lines, and deciding what relays to
48 * include in an authority's vote. (TODO: Those functions could profitably be
49 * split off. They only live in this file because historically they were
50 * shared among the v1, v2, and v3 directory code.)
51 */
52
53static void clear_cached_dir(cached_dir_t *d);
55 const uint8_t *fp,
56 int extrainfo);
57
58static int spooled_resource_lookup_body(const spooled_resource_t *spooled,
59 int conn_is_encrypted,
60 const uint8_t **body_out,
61 size_t *size_out,
62 time_t *published_out);
64 const spooled_resource_t *spooled,
65 time_t *published_out);
66static cached_dir_t *lookup_cached_dir_by_fp(const uint8_t *fp);
67
68/********************************************************************/
69
70/* A set of functions to answer questions about how we'd like to behave
71 * as a directory mirror */
72
73/** Return true iff we want to serve certificates for authorities
74 * that we don't acknowledge as authorities ourself.
75 * Use we_want_to_fetch_unknown_auth_certs to check if we want to fetch
76 * and keep these certificates.
77 */
78int
80{
81 return dir_server_mode(options) || options->BridgeRelay;
82}
83
84/** Return 1 if we want to fetch and serve descriptors, networkstatuses, etc
85 * Else return 0.
86 * Check options->DirPort_set and directory_permits_begindir_requests()
87 * to see if we are willing to serve these directory documents to others via
88 * the DirPort and begindir-over-ORPort, respectively.
89 *
90 * To check if we should fetch documents, use we_want_to_fetch_flavor and
91 * we_want_to_fetch_unknown_auth_certs instead of this function.
92 */
93int
95{
96 if (options->BridgeRelay || dir_server_mode(options))
97 return 1;
98 if (!server_mode(options) || !advertised_server_mode())
99 return 0;
100 /* We need an up-to-date view of network info if we're going to try to
101 * block exit attempts from unknown relays. */
104}
105
106/** Return 1 if we want to allow remote clients to ask us directory
107 * requests via the "begin_dir" interface, which doesn't require
108 * having any separate port open. */
109int
111{
112 return options->BridgeRelay != 0 || dir_server_mode(options);
113}
114
115/********************************************************************/
116
117/** Map from flavor name to the cached_dir_t for the v3 consensuses that we're
118 * currently serving. */
119static strmap_t *cached_consensuses = NULL;
120
121/** Decrement the reference count on <b>d</b>, and free it if it no longer has
122 * any references. */
123void
125{
126 if (!d || --d->refcnt > 0)
127 return;
129 tor_free(d);
130}
131
132/** Allocate and return a new cached_dir_t containing the string <b>s</b>,
133 * published at <b>published</b>. */
135new_cached_dir(char *s, time_t published)
136{
137 cached_dir_t *d = tor_malloc_zero(sizeof(cached_dir_t));
138 d->refcnt = 1;
139 d->dir = s;
140 d->dir_len = strlen(s);
141 d->published = published;
143 d->dir, d->dir_len, ZLIB_METHOD)) {
144 log_warn(LD_BUG, "Error compressing directory");
145 }
146 return d;
147}
148
149/** Remove all storage held in <b>d</b>, but do not free <b>d</b> itself. */
150static void
152{
153 tor_free(d->dir);
155 memset(d, 0, sizeof(cached_dir_t));
156}
157
158/** Free all storage held by the cached_dir_t in <b>d</b>. */
159static void
161{
162 cached_dir_t *d;
163 if (!_d)
164 return;
165
166 d = (cached_dir_t *)_d;
168}
169
170/** Replace the v3 consensus networkstatus of type <b>flavor_name</b> that
171 * we're serving with <b>networkstatus</b>, published at <b>published</b>. No
172 * validation is performed. */
173void
175 size_t networkstatus_len,
176 const char *flavor_name,
177 const common_digests_t *digests,
178 const uint8_t *sha3_as_signed,
179 time_t published)
180{
181 cached_dir_t *new_networkstatus;
182 cached_dir_t *old_networkstatus;
184 cached_consensuses = strmap_new();
185
186 new_networkstatus =
187 new_cached_dir(tor_memdup_nulterm(networkstatus, networkstatus_len),
188 published);
189 memcpy(&new_networkstatus->digests, digests, sizeof(common_digests_t));
190 memcpy(&new_networkstatus->digest_sha3_as_signed, sha3_as_signed,
192 old_networkstatus = strmap_set(cached_consensuses, flavor_name,
193 new_networkstatus);
194 if (old_networkstatus)
195 cached_dir_decref(old_networkstatus);
196}
197
198/** Return the latest downloaded consensus networkstatus in encoded, signed,
199 * optionally compressed format, suitable for sending to clients. */
201dirserv_get_consensus,(const char *flavor_name))
202{
204 return NULL;
205 return strmap_get(cached_consensuses, flavor_name);
206}
207
208/** As dir_split_resource_into_fingerprints, but instead fills
209 * <b>spool_out</b> with a list of spoolable_resource_t for the resource
210 * identified through <b>source</b>. */
211int
213 dir_spool_source_t source,
214 smartlist_t *spool_out,
215 int *compressed_out,
216 int flags)
217{
218 smartlist_t *fingerprints = smartlist_new();
219
220 tor_assert(flags & (DSR_HEX|DSR_BASE64));
221 const size_t digest_len =
222 (flags & DSR_DIGEST256) ? DIGEST256_LEN : DIGEST_LEN;
223
224 int r = dir_split_resource_into_fingerprints(resource, fingerprints,
225 compressed_out, flags);
226 /* This is not a very efficient implementation XXXX */
227 SMARTLIST_FOREACH_BEGIN(fingerprints, uint8_t *, digest) {
228 spooled_resource_t *spooled =
229 spooled_resource_new(source, digest, digest_len);
230 if (spooled)
231 smartlist_add(spool_out, spooled);
232 tor_free(digest);
233 } SMARTLIST_FOREACH_END(digest);
234
235 smartlist_free(fingerprints);
236 return r;
237}
238
239/** As dirserv_get_routerdescs(), but instead of getting signed_descriptor_t
240 * pointers, adds copies of digests to fps_out, and doesn't use the
241 * /tor/server/ prefix. For a /d/ request, adds descriptor digests; for other
242 * requests, adds identity digests.
243 */
244int
246 const char *key,
247 dir_spool_source_t source,
248 int conn_is_encrypted,
249 const char **msg_out)
250{
251 *msg_out = NULL;
252
253 if (!strcmp(key, "all")) {
256 spooled_resource_t *spooled;
257 spooled = spooled_resource_new(source,
258 (const uint8_t *)r->cache_info.identity_digest,
259 DIGEST_LEN);
260 /* Treat "all" requests as if they were unencrypted */
261 conn_is_encrypted = 0;
262 smartlist_add(spool_out, spooled);
263 } SMARTLIST_FOREACH_END(r);
264 } else if (!strcmp(key, "authority")) {
266 if (ri)
267 smartlist_add(spool_out,
268 spooled_resource_new(source,
269 (const uint8_t *)ri->cache_info.identity_digest,
270 DIGEST_LEN));
271 } else if (!strcmpstart(key, "d/")) {
272 key += strlen("d/");
273 dir_split_resource_into_spoolable(key, source, spool_out, NULL,
274 DSR_HEX|DSR_SORT_UNIQ);
275 } else if (!strcmpstart(key, "fp/")) {
276 key += strlen("fp/");
277 dir_split_resource_into_spoolable(key, source, spool_out, NULL,
278 DSR_HEX|DSR_SORT_UNIQ);
279 } else {
280 *msg_out = "Not found";
281 return -1;
282 }
283
284 if (! conn_is_encrypted) {
285 /* Remove anything that insists it not be sent unencrypted. */
286 SMARTLIST_FOREACH_BEGIN(spool_out, spooled_resource_t *, spooled) {
287 const uint8_t *body = NULL;
288 size_t bodylen = 0;
289 int r = spooled_resource_lookup_body(spooled, conn_is_encrypted,
290 &body, &bodylen, NULL);
291 if (r < 0 || body == NULL || bodylen == 0) {
292 SMARTLIST_DEL_CURRENT(spool_out, spooled);
293 spooled_resource_free(spooled);
294 }
295 } SMARTLIST_FOREACH_END(spooled);
296 }
297
298 if (!smartlist_len(spool_out)) {
299 *msg_out = "Servers unavailable";
300 return -1;
301 }
302 return 0;
303}
304
305/* ==========
306 * Spooling code.
307 * ========== */
308
310spooled_resource_new(dir_spool_source_t source,
311 const uint8_t *digest, size_t digestlen)
312{
313 spooled_resource_t *spooled = tor_malloc_zero(sizeof(spooled_resource_t));
314 spooled->spool_source = source;
315 switch (source) {
316 case DIR_SPOOL_NETWORKSTATUS:
317 spooled->spool_eagerly = 0;
318 break;
319 case DIR_SPOOL_SERVER_BY_DIGEST:
320 case DIR_SPOOL_SERVER_BY_FP:
321 case DIR_SPOOL_EXTRA_BY_DIGEST:
322 case DIR_SPOOL_EXTRA_BY_FP:
323 case DIR_SPOOL_MICRODESC:
324 default:
325 spooled->spool_eagerly = 1;
326 break;
327 case DIR_SPOOL_CONSENSUS_CACHE_ENTRY:
328 tor_assert_unreached();
329 break;
330 }
331 tor_assert(digestlen <= sizeof(spooled->digest));
332 if (digest)
333 memcpy(spooled->digest, digest, digestlen);
334 return spooled;
335}
336
337/**
338 * Create a new spooled_resource_t to spool the contents of <b>entry</b> to
339 * the user. Return the spooled object on success, or NULL on failure (which
340 * is probably caused by a failure to map the body of the item from disk).
341 *
342 * Adds a reference to entry's reference counter.
343 */
346{
347 spooled_resource_t *spooled = tor_malloc_zero(sizeof(spooled_resource_t));
348 spooled->spool_source = DIR_SPOOL_CONSENSUS_CACHE_ENTRY;
349 spooled->spool_eagerly = 0;
351 spooled->consensus_cache_entry = entry;
352
353 int r = consensus_cache_entry_get_body(entry,
354 &spooled->cce_body,
355 &spooled->cce_len);
356 if (r == 0) {
357 return spooled;
358 } else {
359 spooled_resource_free(spooled);
360 return NULL;
361 }
362}
363
364/** Release all storage held by <b>spooled</b>. */
365void
367{
368 if (spooled == NULL)
369 return;
370
371 if (spooled->cached_dir_ref) {
373 }
374
375 if (spooled->consensus_cache_entry) {
377 }
378
379 tor_free(spooled);
380}
381
382/** When spooling data from a cached_dir_t object, we always add
383 * at least this much. */
384#define DIRSERV_CACHED_DIR_CHUNK_SIZE 8192
385
386/** Return an compression ratio for compressing objects from <b>source</b>.
387 */
388static double
390{
391 /* We should put in better estimates here, depending on the number of
392 objects and their type */
393 (void) source;
394 return 0.5;
395}
396
397/** Return an estimated number of bytes needed for transmitting the
398 * resource in <b>spooled</b> on <b>conn</b>
399 *
400 * As a convenient side-effect, set *<b>published_out</b> to the resource's
401 * publication time.
402 */
403static size_t
405 dir_connection_t *conn,
406 int compressed,
407 time_t *published_out)
408{
409 if (spooled->spool_eagerly) {
410 const uint8_t *body = NULL;
411 size_t bodylen = 0;
412 int r = spooled_resource_lookup_body(spooled,
414 &body, &bodylen,
415 published_out);
416 if (r == -1 || body == NULL || bodylen == 0)
417 return 0;
418 if (compressed) {
419 double ratio = estimate_compression_ratio(spooled->spool_source);
420 bodylen = (size_t)(bodylen * ratio);
421 }
422 return bodylen;
423 } else {
424 cached_dir_t *cached;
425 if (spooled->consensus_cache_entry) {
426 if (published_out) {
428 spooled->consensus_cache_entry, published_out);
429 }
430
431 return spooled->cce_len;
432 }
433 if (spooled->cached_dir_ref) {
434 cached = spooled->cached_dir_ref;
435 } else {
436 cached = spooled_resource_lookup_cached_dir(spooled,
437 published_out);
438 }
439 if (cached == NULL) {
440 return 0;
441 }
442 size_t result = compressed ? cached->dir_compressed_len : cached->dir_len;
443 return result;
444 }
445}
446
447/** Return code for spooled_resource_flush_some */
448typedef enum {
449 SRFS_ERR = -1,
450 SRFS_MORE = 0,
451 SRFS_DONE
453
454/** Flush some or all of the bytes from <b>spooled</b> onto <b>conn</b>.
455 * Return SRFS_ERR on error, SRFS_MORE if there are more bytes to flush from
456 * this spooled resource, or SRFS_DONE if we are done flushing this spooled
457 * resource.
458 */
461 dir_connection_t *conn)
462{
463 if (spooled->spool_eagerly) {
464 /* Spool_eagerly resources are sent all-at-once. */
465 const uint8_t *body = NULL;
466 size_t bodylen = 0;
467 int r = spooled_resource_lookup_body(spooled,
469 &body, &bodylen, NULL);
470 if (r == -1 || body == NULL || bodylen == 0) {
471 /* Absent objects count as "done". */
472 return SRFS_DONE;
473 }
474
475 connection_dir_buf_add((const char*)body, bodylen, conn, 0);
476
477 return SRFS_DONE;
478 } else {
479 cached_dir_t *cached = spooled->cached_dir_ref;
481 if (cached == NULL && cce == NULL) {
482 /* The cached_dir_t hasn't been materialized yet. So let's look it up. */
483 cached = spooled->cached_dir_ref =
485 if (!cached) {
486 /* Absent objects count as done. */
487 return SRFS_DONE;
488 }
489 ++cached->refcnt;
490 tor_assert_nonfatal(spooled->cached_dir_offset == 0);
491 }
492
493 if (BUG(!cached && !cce))
494 return SRFS_DONE;
495
496 int64_t total_len;
497 const char *ptr;
498 if (cached) {
499 total_len = cached->dir_compressed_len;
500 ptr = cached->dir_compressed;
501 } else {
502 total_len = spooled->cce_len;
503 ptr = (const char *)spooled->cce_body;
504 }
505 /* How many bytes left to flush? */
506 int64_t remaining;
507 remaining = total_len - spooled->cached_dir_offset;
508 if (BUG(remaining < 0))
509 return SRFS_ERR;
510 ssize_t bytes = (ssize_t) MIN(DIRSERV_CACHED_DIR_CHUNK_SIZE, remaining);
511
513 bytes, conn, 0);
514
515 spooled->cached_dir_offset += bytes;
516 if (spooled->cached_dir_offset >= (off_t)total_len) {
517 return SRFS_DONE;
518 } else {
519 return SRFS_MORE;
520 }
521 }
522}
523
524/** Helper: find the cached_dir_t for a spooled_resource_t, for
525 * sending it to <b>conn</b>. Set *<b>published_out</b>, if provided,
526 * to the published time of the cached_dir_t.
527 *
528 * DOES NOT increase the reference count on the result. Callers must do that
529 * themselves if they mean to hang on to it.
530 */
531static cached_dir_t *
533 time_t *published_out)
534{
535 tor_assert(spooled->spool_eagerly == 0);
537 if (d != NULL) {
538 if (published_out)
539 *published_out = d->published;
540 }
541 return d;
542}
543
544/** Helper: Look up the body for an eagerly-served spooled_resource. If
545 * <b>conn_is_encrypted</b> is false, don't look up any resource that
546 * shouldn't be sent over an unencrypted connection. On success, set
547 * <b>body_out</b>, <b>size_out</b>, and <b>published_out</b> to refer
548 * to the resource's body, size, and publication date, and return 0.
549 * On failure return -1. */
550static int
552 int conn_is_encrypted,
553 const uint8_t **body_out,
554 size_t *size_out,
555 time_t *published_out)
556{
557 tor_assert(spooled->spool_eagerly == 1);
558
559 const signed_descriptor_t *sd = NULL;
560
561 switch (spooled->spool_source) {
562 case DIR_SPOOL_EXTRA_BY_FP: {
563 sd = get_signed_descriptor_by_fp(spooled->digest, 1);
564 break;
565 }
566 case DIR_SPOOL_SERVER_BY_FP: {
567 sd = get_signed_descriptor_by_fp(spooled->digest, 0);
568 break;
569 }
570 case DIR_SPOOL_SERVER_BY_DIGEST: {
571 sd = router_get_by_descriptor_digest((const char *)spooled->digest);
572 break;
573 }
574 case DIR_SPOOL_EXTRA_BY_DIGEST: {
575 sd = extrainfo_get_by_descriptor_digest((const char *)spooled->digest);
576 break;
577 }
578 case DIR_SPOOL_MICRODESC: {
581 (const char *)spooled->digest);
582 if (! md || ! md->body) {
583 return -1;
584 }
585 *body_out = (const uint8_t *)md->body;
586 *size_out = md->bodylen;
587 if (published_out)
588 *published_out = TIME_MAX;
589 return 0;
590 }
591 case DIR_SPOOL_NETWORKSTATUS:
592 case DIR_SPOOL_CONSENSUS_CACHE_ENTRY:
593 default:
594 /* LCOV_EXCL_START */
596 return -1;
597 /* LCOV_EXCL_STOP */
598 }
599
600 /* If we get here, then we tried to set "sd" to a signed_descriptor_t. */
601
602 if (sd == NULL) {
603 return -1;
604 }
605 if (sd->send_unencrypted == 0 && ! conn_is_encrypted) {
606 /* we did this check once before (so we could have an accurate size
607 * estimate and maybe send a 404 if somebody asked for only bridges on
608 * a connection), but we need to do it again in case a previously
609 * unknown bridge descriptor has shown up between then and now. */
610 return -1;
611 }
612 *body_out = (const uint8_t *) signed_descriptor_get_body(sd);
613 *size_out = sd->signed_descriptor_len;
614 if (published_out)
615 *published_out = sd->published_on;
616 return 0;
617}
618
619/** Given a fingerprint <b>fp</b> which is either set if we're looking for a
620 * v2 status, or zeroes if we're looking for a v3 status, or a NUL-padded
621 * flavor name if we want a flavored v3 status, return a pointer to the
622 * appropriate cached dir object, or NULL if there isn't one available. */
623static cached_dir_t *
624lookup_cached_dir_by_fp(const uint8_t *fp)
625{
626 cached_dir_t *d = NULL;
627 if (tor_digest_is_zero((const char *)fp) && cached_consensuses) {
628 d = strmap_get(cached_consensuses, "ns");
629 } else if (memchr(fp, '\0', DIGEST_LEN) && cached_consensuses) {
630 /* this here interface is a nasty hack: we're shoving a flavor into
631 * a digest field. */
632 d = strmap_get(cached_consensuses, (const char *)fp);
633 }
634 return d;
635}
636
637/** Try to guess the number of bytes that will be needed to send the
638 * spooled objects for <b>conn</b>'s outgoing spool. In the process,
639 * remove every element of the spool that refers to an absent object, or
640 * which was published earlier than <b>cutoff</b>. Set *<b>size_out</b>
641 * to the number of bytes, and *<b>n_expired_out</b> to the number of
642 * objects removed for being too old. */
643void
645 time_t cutoff,
646 int compression,
647 size_t *size_out,
648 int *n_expired_out)
649{
650 if (BUG(!conn))
651 return;
652
653 smartlist_t *spool = conn->spool;
654 if (!spool) {
655 if (size_out)
656 *size_out = 0;
657 if (n_expired_out)
658 *n_expired_out = 0;
659 return;
660 }
661 int n_expired = 0;
662 uint64_t total = 0;
664 time_t published = TIME_MAX;
665 size_t sz = spooled_resource_estimate_size(spooled, conn,
666 compression, &published);
667 if (published < cutoff) {
668 ++n_expired;
669 SMARTLIST_DEL_CURRENT(spool, spooled);
670 spooled_resource_free(spooled);
671 } else if (sz == 0) {
672 SMARTLIST_DEL_CURRENT(spool, spooled);
673 spooled_resource_free(spooled);
674 } else {
675 total += sz;
676 }
677 } SMARTLIST_FOREACH_END(spooled);
678
679 if (size_out) {
680 *size_out = (total > SIZE_MAX) ? SIZE_MAX : (size_t)total;
681 }
682 if (n_expired_out)
683 *n_expired_out = n_expired;
684}
685
686/** Helper: used to sort a connection's spool. */
687static int
688dirserv_spool_sort_comparison_(const void **a_, const void **b_)
689{
690 const spooled_resource_t *a = *a_;
691 const spooled_resource_t *b = *b_;
692 return fast_memcmp(a->digest, b->digest, sizeof(a->digest));
693}
694
695/** Sort all the entries in <b>conn</b> by digest. */
696void
698{
699 if (conn->spool == NULL)
700 return;
702}
703
704/** Return the cache-info for identity fingerprint <b>fp</b>, or
705 * its extra-info document if <b>extrainfo</b> is true. Return
706 * NULL if not found or if the descriptor is older than
707 * <b>publish_cutoff</b>. */
708static const signed_descriptor_t *
709get_signed_descriptor_by_fp(const uint8_t *fp, int extrainfo)
710{
711 if (router_digest_is_me((const char *)fp)) {
712 if (extrainfo)
713 return &(router_get_my_extrainfo()->cache_info);
714 else
715 return &(router_get_my_routerinfo()->cache_info);
716 } else {
717 const routerinfo_t *ri = router_get_by_id_digest((const char *)fp);
718 if (ri) {
719 if (extrainfo)
721 ri->cache_info.extra_info_digest);
722 else
723 return &ri->cache_info;
724 }
725 }
726 return NULL;
727}
728
729/** When we're spooling data onto our outbuf, add more whenever we dip
730 * below this threshold. */
731#define DIRSERV_BUFFER_MIN 16384
732
733/**
734 * Called whenever we have flushed some directory data in state
735 * SERVER_WRITING, or whenever we want to fill the buffer with initial
736 * directory data (so that subsequent writes will occur, and trigger this
737 * function again.)
738 *
739 * Return 0 on success, and -1 on failure.
740 */
741int
743{
745 if (conn->spool == NULL)
746 return 0;
747
748 while (connection_get_outbuf_len(TO_CONN(conn)) < DIRSERV_BUFFER_MIN &&
749 smartlist_len(conn->spool)) {
750 spooled_resource_t *spooled =
751 smartlist_get(conn->spool, smartlist_len(conn->spool)-1);
753 status = spooled_resource_flush_some(spooled, conn);
754 if (status == SRFS_ERR) {
755 return -1;
756 } else if (status == SRFS_MORE) {
757 return 0;
758 }
759 tor_assert(status == SRFS_DONE);
760
761 /* If we're here, we're done flushing this resource. */
762 tor_assert(smartlist_pop_last(conn->spool) == spooled);
763 spooled_resource_free(spooled);
764 }
765
766 if (smartlist_len(conn->spool) > 0) {
767 /* We're still spooling something. */
768 return 0;
769 }
770
771 /* If we get here, we're done. */
772 smartlist_free(conn->spool);
773 conn->spool = NULL;
774 if (conn->compress_state) {
775 /* Flush the compression state: there could be more bytes pending in there,
776 * and we don't want to omit bytes. */
777 connection_buf_add_compress("", 0, conn, 1);
778 tor_compress_free(conn->compress_state);
779 conn->compress_state = NULL;
780 }
781 return 0;
782}
783
784/** Remove every element from <b>conn</b>'s outgoing spool, and delete
785 * the spool. */
786void
788{
789 if (!conn || ! conn->spool)
790 return;
792 spooled_resource_free(s));
793 smartlist_free(conn->spool);
794 conn->spool = NULL;
795}
796
797/** Release all storage used by the directory server. */
798void
800{
802 cached_consensuses = NULL;
803}
Cached large directory object structure.
int tor_compress(char **out, size_t *out_len, const char *in, size_t in_len, compress_method_t method)
Definition: compress.c:250
Headers for compress.c.
Header file for config.c.
void connection_dir_buf_add(const char *string, size_t len, dir_connection_t *dir_conn, int done)
Definition: connection.c:4809
Header file for connection.c.
void consensus_cache_entry_incref(consensus_cache_entry_t *ent)
Definition: conscache.c:355
void consensus_cache_entry_decref(consensus_cache_entry_t *ent)
Definition: conscache.c:370
int consensus_cache_entry_get_body(const consensus_cache_entry_t *ent, const uint8_t **body_out, size_t *sz_out)
Definition: conscache.c:437
Header for conscache.c.
int consensus_cache_entry_get_valid_after(const consensus_cache_entry_t *ent, time_t *out)
Definition: consdiffmgr.c:1977
Header for consdiffmgr.c.
#define fast_memcmp(a, b, c)
Definition: di_ops.h:28
#define DIGEST_LEN
Definition: digest_sizes.h:20
#define DIGEST256_LEN
Definition: digest_sizes.h:23
Client/server directory connection structure.
int connection_dir_is_encrypted(const dir_connection_t *conn)
Definition: directory.c:180
int dir_split_resource_into_fingerprints(const char *resource, smartlist_t *fp_out, int *compressed_out, int flags)
Definition: directory.c:640
Header file for directory.c.
#define DIR_CONN_STATE_SERVER_WRITING
Definition: directory.h:30
static int dirserv_spool_sort_comparison_(const void **a_, const void **b_)
Definition: dirserv.c:688
void cached_dir_decref(cached_dir_t *d)
Definition: dirserv.c:124
void dirserv_spool_sort(dir_connection_t *conn)
Definition: dirserv.c:697
#define DIRSERV_CACHED_DIR_CHUNK_SIZE
Definition: dirserv.c:384
static void clear_cached_dir(cached_dir_t *d)
Definition: dirserv.c:151
static cached_dir_t * spooled_resource_lookup_cached_dir(const spooled_resource_t *spooled, time_t *published_out)
Definition: dirserv.c:532
void dirserv_spool_remove_missing_and_guess_size(dir_connection_t *conn, time_t cutoff, int compression, size_t *size_out, int *n_expired_out)
Definition: dirserv.c:644
static void free_cached_dir_(void *_d)
Definition: dirserv.c:160
spooled_resource_flush_status_t
Definition: dirserv.c:448
static spooled_resource_flush_status_t spooled_resource_flush_some(spooled_resource_t *spooled, dir_connection_t *conn)
Definition: dirserv.c:460
int directory_caches_dir_info(const or_options_t *options)
Definition: dirserv.c:94
int directory_caches_unknown_auth_certs(const or_options_t *options)
Definition: dirserv.c:79
void spooled_resource_free_(spooled_resource_t *spooled)
Definition: dirserv.c:366
int dirserv_get_routerdesc_spool(smartlist_t *spool_out, const char *key, dir_spool_source_t source, int conn_is_encrypted, const char **msg_out)
Definition: dirserv.c:245
#define DIRSERV_BUFFER_MIN
Definition: dirserv.c:731
int directory_permits_begindir_requests(const or_options_t *options)
Definition: dirserv.c:110
static cached_dir_t * lookup_cached_dir_by_fp(const uint8_t *fp)
Definition: dirserv.c:624
void dirserv_set_cached_consensus_networkstatus(const char *networkstatus, size_t networkstatus_len, const char *flavor_name, const common_digests_t *digests, const uint8_t *sha3_as_signed, time_t published)
Definition: dirserv.c:174
void dir_conn_clear_spool(dir_connection_t *conn)
Definition: dirserv.c:787
static double estimate_compression_ratio(dir_spool_source_t source)
Definition: dirserv.c:389
cached_dir_t * dirserv_get_consensus(const char *flavor_name)
Definition: dirserv.c:201
static int spooled_resource_lookup_body(const spooled_resource_t *spooled, int conn_is_encrypted, const uint8_t **body_out, size_t *size_out, time_t *published_out)
Definition: dirserv.c:551
spooled_resource_t * spooled_resource_new_from_cache_entry(consensus_cache_entry_t *entry)
Definition: dirserv.c:345
static size_t spooled_resource_estimate_size(const spooled_resource_t *spooled, dir_connection_t *conn, int compressed, time_t *published_out)
Definition: dirserv.c:404
static strmap_t * cached_consensuses
Definition: dirserv.c:119
void dirserv_free_all(void)
Definition: dirserv.c:799
int connection_dirserv_flushed_some(dir_connection_t *conn)
Definition: dirserv.c:742
int dir_split_resource_into_spoolable(const char *resource, dir_spool_source_t source, smartlist_t *spool_out, int *compressed_out, int flags)
Definition: dirserv.c:212
cached_dir_t * new_cached_dir(char *s, time_t published)
Definition: dirserv.c:135
static const signed_descriptor_t * get_signed_descriptor_by_fp(const uint8_t *fp, int extrainfo)
Definition: dirserv.c:709
Header file for dirserv.c.
dir_spool_source_t
Definition: dirserv.h:20
A relay's extra-info structure.
#define LD_BUG
Definition: log.h:86
#define tor_free(p)
Definition: malloc.h:56
microdesc_t * microdesc_cache_lookup_by_digest256(microdesc_cache_t *cache, const char *d)
Definition: microdesc.c:946
microdesc_cache_t * get_microdesc_cache(void)
Definition: microdesc.c:251
Header file for microdesc.c.
Microdescriptor structure.
Master header file for Tor-specific functionality.
#define TO_CONN(c)
Definition: or.h:612
Header file for predict_ports.c.
extrainfo_t * router_get_my_extrainfo(void)
Definition: router.c:1859
int router_digest_is_me(const char *digest)
Definition: router.c:1744
const routerinfo_t * router_get_my_routerinfo(void)
Definition: router.c:1806
int router_my_exit_policy_is_reject_star(void)
Definition: router.c:1732
int should_refuse_unknown_exits(const or_options_t *options)
Definition: router.c:1385
Header file for router.c.
Router descriptor structure.
const char * signed_descriptor_get_body(const signed_descriptor_t *desc)
Definition: routerlist.c:883
routerlist_t * router_get_routerlist(void)
Definition: routerlist.c:898
signed_descriptor_t * router_get_by_descriptor_digest(const char *digest)
Definition: routerlist.c:787
const routerinfo_t * router_get_by_id_digest(const char *digest)
Definition: routerlist.c:779
signed_descriptor_t * extrainfo_get_by_descriptor_digest(const char *digest)
Definition: routerlist.c:813
Header file for routerlist.c.
Router descriptor list structure.
int advertised_server_mode(void)
Definition: routermode.c:55
int dir_server_mode(const or_options_t *options)
Definition: routermode.c:23
int server_mode(const or_options_t *options)
Definition: routermode.c:34
Header file for routermode.c.
void smartlist_sort(smartlist_t *sl, int(*compare)(const void **a, const void **b))
Definition: smartlist.c:334
void * smartlist_pop_last(smartlist_t *sl)
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
#define SMARTLIST_DEL_CURRENT(sl, var)
size_t dir_len
Definition: cached_dir_st.h:20
common_digests_t digests
Definition: cached_dir_st.h:23
uint8_t digest_sha3_as_signed[DIGEST256_LEN]
Definition: cached_dir_st.h:25
char * dir_compressed
Definition: cached_dir_st.h:19
time_t published
Definition: cached_dir_st.h:22
size_t dir_compressed_len
Definition: cached_dir_st.h:21
uint8_t state
Definition: connection_st.h:49
Definition: conscache.c:32
smartlist_t * spool
struct tor_compress_state_t * compress_state
char * body
Definition: microdesc_st.h:58
size_t bodylen
Definition: microdesc_st.h:60
smartlist_t * routers
Definition: routerlist_st.h:32
char extra_info_digest[DIGEST_LEN]
char identity_digest[DIGEST_LEN]
dir_spool_source_bitfield_t spool_source
Definition: dirserv.h:51
unsigned spool_eagerly
Definition: dirserv.h:47
uint8_t digest[DIGEST256_LEN]
Definition: dirserv.h:55
off_t cached_dir_offset
Definition: dirserv.h:71
struct consensus_cache_entry_t * consensus_cache_entry
Definition: dirserv.h:65
struct cached_dir_t * cached_dir_ref
Definition: dirserv.h:60
#define MOCK_IMPL(rv, funcname, arglist)
Definition: testsupport.h:133
#define tor_assert_nonfatal_unreached()
Definition: util_bug.h:177
#define tor_assert(expr)
Definition: util_bug.h:103
int strcmpstart(const char *s1, const char *s2)
Definition: util_string.c:217
int tor_digest_is_zero(const char *digest)
Definition: util_string.c:98