diff options
-rw-r--r-- | src/or/control.c | 7 | ||||
-rw-r--r-- | src/or/directory.c | 2 | ||||
-rw-r--r-- | src/or/dirserv.c | 8 | ||||
-rw-r--r-- | src/or/or.h | 17 | ||||
-rw-r--r-- | src/or/router.c | 5 | ||||
-rw-r--r-- | src/or/routerlist.c | 102 | ||||
-rw-r--r-- | src/or/routerparse.c | 17 | ||||
-rw-r--r-- | src/or/test.c | 4 |
8 files changed, 119 insertions, 43 deletions
diff --git a/src/or/control.c b/src/or/control.c index 7e06ec3ef9..8e19aea94a 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -1330,14 +1330,14 @@ handle_getinfo_helper(const char *question, char **answer) if (ri) { const char *body = signed_descriptor_get_body(&ri->cache_info); if (body) - *answer = tor_strdup(body); + *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); } } else if (!strcmpstart(question, "desc/name/")) { routerinfo_t *ri = router_get_by_nickname(question+strlen("desc/name/"),1); if (ri) { const char *body = signed_descriptor_get_body(&ri->cache_info); if (body) - *answer = tor_strdup(body); + *answer = tor_strndup(body, ri->cache_info.signed_descriptor_len); } } else if (!strcmp(question, "desc/all-recent")) { routerlist_t *routerlist = router_get_routerlist(); @@ -1347,7 +1347,8 @@ handle_getinfo_helper(const char *question, char **answer) { const char *body = signed_descriptor_get_body(&ri->cache_info); if (body) - smartlist_add(sl, tor_strdup(body)); + smartlist_add(sl, + tor_strndup(body, ri->cache_info.signed_descriptor_len)); }); } *answer = smartlist_join_strings(sl, "", 0, NULL); diff --git a/src/or/directory.c b/src/or/directory.c index 3430e12c22..47af8f1504 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -1076,7 +1076,7 @@ connection_dir_client_reached_eof(connection_t *conn) if (which || (conn->requested_resource && !strcmpstart(conn->requested_resource, "all"))) { /* as we learn from them, we remove them from 'which' */ - router_load_routers_from_string(body, 0, which); + router_load_routers_from_string(body, SAVED_NOWHERE, which); directory_info_has_arrived(time(NULL), 0); } if (which) { /* mark remaining ones as failed */ diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 562fad4910..7af40e9cb6 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -481,7 +481,7 @@ dirserv_add_descriptor(const char *desc, const char **msg) *msg = NULL; /* Check: is the descriptor syntactically valid? */ - ri = router_parse_entry_from_string(desc, NULL); + ri = router_parse_entry_from_string(desc, NULL, 1); if (!ri) { log_warn(LD_DIRSERV, "Couldn't parse uploaded server descriptor"); *msg = "Rejected: Couldn't parse server descriptor."; @@ -1808,6 +1808,7 @@ connection_dirserv_add_servers_to_outbuf(connection_t *conn) while (smartlist_len(conn->fingerprint_stack) && buf_datalen(conn->outbuf) < DIRSERV_BUFFER_MIN) { + char *body; char *fp = smartlist_pop_last(conn->fingerprint_stack); signed_descriptor_t *sd = NULL; if (by_fp) { @@ -1824,13 +1825,14 @@ connection_dirserv_add_servers_to_outbuf(connection_t *conn) tor_free(fp); if (!sd) continue; + body = signed_descriptor_get_body(sd); if (conn->zlib_state) { connection_write_to_buf_zlib( conn, conn->zlib_state, - sd->signed_descriptor_body, sd->signed_descriptor_len, + body, sd->signed_descriptor_len, 0); } else { - connection_write_to_buf(sd->signed_descriptor_body, + connection_write_to_buf(body, sd->signed_descriptor_len, conn); } diff --git a/src/or/or.h b/src/or/or.h index 92742848d1..113fda026f 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -762,6 +762,10 @@ typedef struct cached_dir_t { int refcnt; /**< Reference count for this cached_dir_t. */ } cached_dir_t; +typedef enum { + SAVED_NOWHERE=0, SAVED_IN_CACHE, SAVED_IN_JOURNAL +} saved_location_t; + /** Information need to cache an onion router's descriptor. */ typedef struct signed_descriptor_t { char *signed_descriptor_body; @@ -769,7 +773,7 @@ typedef struct signed_descriptor_t { char signed_descriptor_digest[DIGEST_LEN]; char identity_digest[DIGEST_LEN]; time_t published_on; - enum { SAVED_NOWHERE=0, SAVED_IN_CACHE, SAVED_IN_JOURNAL } saved_location; + saved_location_t saved_location; off_t saved_offset; } signed_descriptor_t; @@ -933,6 +937,9 @@ typedef struct { /** List of signed_descriptor_t for older router descriptors we're * caching. */ smartlist_t *old_routers; + /** DOCDOC */ + const char *mmap_descriptors; + size_t mmap_descriptors_len; } routerlist_t; /** Information on router used when extending a circuit. (We don't need a @@ -2367,7 +2374,8 @@ int router_add_to_routerlist(routerinfo_t *router, const char **msg, int from_cache, int from_fetch); int router_load_single_router(const char *s, uint8_t purpose, const char **msg); -void router_load_routers_from_string(const char *s, int from_cache, +void router_load_routers_from_string(const char *s, + saved_location_t saved_location, smartlist_t *requested_fingerprints); typedef enum { NS_FROM_CACHE, NS_FROM_DIR, NS_GENERATED @@ -2440,7 +2448,7 @@ int router_append_dirobj_signature(char *buf, size_t buf_len, crypto_pk_env_t *private_key); int router_parse_list_from_string(const char **s, smartlist_t *dest, - int from_cache); + saved_location_t saved_location); int router_parse_routerlist_from_directory(const char *s, routerlist_t **dest, crypto_pk_env_t *pkey, @@ -2448,7 +2456,8 @@ int router_parse_routerlist_from_directory(const char *s, int write_to_cache); int router_parse_runningrouters(const char *str); int router_parse_directory(const char *str); -routerinfo_t *router_parse_entry_from_string(const char *s, const char *end); +routerinfo_t *router_parse_entry_from_string(const char *s, const char *end, + int cache_copy); addr_policy_t *router_parse_addr_policy_from_string(const char *s, int assume_action); version_status_t tor_version_is_obsolete(const char *myversion, diff --git a/src/or/router.c b/src/or/router.c index 47224de14b..43a1834dd0 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -777,7 +777,10 @@ router_get_my_descriptor(void) const char *body; if (!router_get_my_routerinfo()) return NULL; + /* Make sure this is nul-terminated. */ + tor_assert(desc_routerinfo->cache_info.saved_location == SAVED_NOWHERE); body = signed_descriptor_get_body(&desc_routerinfo->cache_info); + tor_assert(!body[desc_routerinfo->cache_info.signed_descriptor_len]); log_debug(LD_GENERAL,"my desc is '%s'", body); return body; } @@ -1187,7 +1190,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, #ifdef DEBUG_ROUTER_DUMP_ROUTER_TO_STRING cp = s_tmp = s_dup = tor_strdup(s); - ri_tmp = router_parse_entry_from_string(cp, NULL); + ri_tmp = router_parse_entry_from_string(cp, NULL, 1); if (!ri_tmp) { log_err(LD_BUG, "We just generated a router descriptor we can't parse: <<%s>>", diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 2223e319bd..a1ad9fcd0e 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -194,6 +194,21 @@ router_append_to_journal(signed_descriptor_t *desc) return 0; } +static int +_compare_old_routers_by_age(const void **_a, const void **_b) +{ + const signed_descriptor_t *r1 = *_a, *r2 = *_b; + return r1->published_on - r2->published_on; +} + +static int +_compare_routers_by_age(const void **_a, const void **_b) +{ + const routerinfo_t *r1 = *_a, *r2 = *_b; + return r1->cache_info.published_on - r2->cache_info.published_on; +} + + /** If the journal is too long, or if <b>force</b> is true, then atomically * replace the router store with the routers currently in our routerlist, and * clear the journal. Return 0 on success, -1 on failure. @@ -223,8 +238,16 @@ router_rebuild_store(int force) chunk_list = smartlist_create(); for (i = 0; i < 2; ++i) { - smartlist_t *lst = (i == 0) ? routerlist->old_routers : - routerlist->routers; + smartlist_t *lst = smartlist_create(); + /* We sort the routers by age to enhance locality on disk. */ + if (i==0) { + smartlist_add_all(lst, routerlist->old_routers); + smartlist_sort(lst, _compare_old_routers_by_age); + } else { + smartlist_add_all(lst, routerlist->routers); + smartlist_sort(lst, _compare_routers_by_age); + } + /* Now, add the appropriate members to chunk_list */ SMARTLIST_FOREACH(lst, void *, ptr, { signed_descriptor_t *sd = (i==0) ? @@ -233,6 +256,7 @@ router_rebuild_store(int force) const char *body = signed_descriptor_get_body(sd); if (!body) { log_warn(LD_BUG, "Bug! No descriptor available for router."); + smartlist_free(lst); goto done; } c = tor_malloc(sizeof(sized_chunk_t)); @@ -240,11 +264,22 @@ router_rebuild_store(int force) c->len = sd->signed_descriptor_len; smartlist_add(chunk_list, c); }); + smartlist_free(lst); } if (write_chunks_to_file(fname, chunk_list, 0)<0) { log_warn(LD_FS, "Error writing router store to disk."); goto done; } + /* Our mmap is now invalid. */ + if (routerlist->mmap_descriptors) { + tor_munmap_file(routerlist->mmap_descriptors, + routerlist->mmap_descriptors_len); + routerlist->mmap_descriptors = + tor_mmap_file(fname, &routerlist->mmap_descriptors_len); + if (! routerlist->mmap_descriptors) + log_warn(LD_FS, "Unable to mmap new descriptor file at '%s'.",fname); + } + for (i = 0; i < 2; ++i) { smartlist_t *lst = (i == 0) ? routerlist->old_routers : routerlist->routers; @@ -256,6 +291,8 @@ router_rebuild_store(int force) sd->saved_location = SAVED_IN_CACHE; sd->saved_offset = offset; + if (routerlist->mmap_descriptors) + sd->signed_descriptor_body = NULL; offset += sd->signed_descriptor_len; }); } @@ -286,31 +323,32 @@ router_reload_router_list(void) { or_options_t *options = get_options(); size_t fname_len = strlen(options->DataDirectory)+32; - char *fname = tor_malloc(fname_len); + char *fname = tor_malloc(fname_len), *contents; struct stat st; - int j; if (!routerlist) router_get_routerlist(); /* mallocs and inits it in place */ router_journal_len = router_store_len = 0; - for (j = 0; j < 2; ++j) { - char *contents; - tor_snprintf(fname, fname_len, - (j==0)?"%s/cached-routers":"%s/cached-routers.new", - options->DataDirectory); - contents = read_file_to_str(fname, 0); - if (contents) { - stat(fname, &st); - if (j==0) - router_store_len = st.st_size; - else - router_journal_len = st.st_size; - router_load_routers_from_string(contents, 1, NULL); - tor_free(contents); - } + tor_snprintf(fname, fname_len, "%s/cached-routers", options->DataDirectory); + routerlist->mmap_descriptors = + tor_mmap_file(fname, &routerlist->mmap_descriptors_len); + if (routerlist->mmap_descriptors) { + router_store_len = routerlist->mmap_descriptors_len; + router_load_routers_from_string(routerlist->mmap_descriptors, + SAVED_IN_CACHE, NULL); } + + tor_snprintf(fname, fname_len, "%s/cached-routers.new", + options->DataDirectory); + contents = read_file_to_str(fname, 0); + if (contents) { + stat(fname, &st); + router_load_routers_from_string(contents, + SAVED_IN_JOURNAL, NULL); + } + tor_free(fname); if (router_journal_len) { @@ -1103,10 +1141,26 @@ router_get_by_descriptor_digest(const char *digest) return digestmap_get(routerlist->desc_digest_map, digest); } +/* DOCDOC Not always nul-terminated. */ const char * signed_descriptor_get_body(signed_descriptor_t *desc) { - return desc->signed_descriptor_body; + const char *r; + size_t len = desc->signed_descriptor_len; + tor_assert(len > 32); + if (desc->saved_location == SAVED_IN_CACHE && routerlist && + routerlist->mmap_descriptors) { + tor_assert(desc->saved_offset + len <= routerlist->mmap_descriptors_len); + r = routerlist->mmap_descriptors + desc->saved_offset; + } else { + r = desc->signed_descriptor_body; + } + tor_assert(r); + tor_assert(!memcmp("router ", r, 7)); + tor_assert(!memcmp("\n-----END SIGNATURE-----\n", + r + len - 25, 25)); + + return r; } /** Return the current list of all known routers. */ @@ -1887,7 +1941,7 @@ router_load_single_router(const char *s, uint8_t purpose, const char **msg) tor_assert(msg); *msg = NULL; - if (!(ri = router_parse_entry_from_string(s, NULL))) { + if (!(ri = router_parse_entry_from_string(s, NULL, 1))) { log_warn(LD_DIR, "Error parsing router descriptor; dropping."); *msg = "Couldn't parse router descriptor."; return -1; @@ -1927,16 +1981,18 @@ router_load_single_router(const char *s, uint8_t purpose, const char **msg) * uppercased identity fingerprints. Do not update any router whose * fingerprint is not on the list; after updating a router, remove its * fingerprint from the list. + * DOCDOC saved_location */ void -router_load_routers_from_string(const char *s, int from_cache, +router_load_routers_from_string(const char *s, saved_location_t saved_location, smartlist_t *requested_fingerprints) { smartlist_t *routers = smartlist_create(), *changed = smartlist_create(); char fp[HEX_DIGEST_LEN+1]; const char *msg; + int from_cache = (saved_location != SAVED_NOWHERE); - router_parse_list_from_string(&s, routers, from_cache); + router_parse_list_from_string(&s, routers, saved_location); routers_update_status_from_networkstatus(routers, !from_cache); diff --git a/src/or/routerparse.c b/src/or/routerparse.c index ab1a2ca3bf..608d156c40 100644 --- a/src/or/routerparse.c +++ b/src/or/routerparse.c @@ -635,10 +635,11 @@ check_directory_signature(const char *digest, * are marked running and valid. Advances *s to a point immediately * following the last router entry. Ignore any trailing router entries that * are not complete. Returns 0 on success and -1 on failure. + * DOCDOC saved_location */ int router_parse_list_from_string(const char **s, smartlist_t *dest, - int from_cache) + saved_location_t saved_location) { routerinfo_t *router; const char *end, *cp, *start; @@ -678,15 +679,16 @@ router_parse_list_from_string(const char **s, smartlist_t *dest, continue; } - router = router_parse_entry_from_string(*s, end); + router = router_parse_entry_from_string(*s, end, + saved_location != SAVED_IN_CACHE); *s = end; if (!router) { log_warn(LD_DIR, "Error reading router; skipping"); continue; } - if (from_cache) { - router->cache_info.saved_location = SAVED_IN_CACHE; + if (saved_location != SAVED_NOWHERE) { + router->cache_info.saved_location = saved_location; router->cache_info.saved_offset = *s - start; } smartlist_add(dest, router); @@ -698,9 +700,11 @@ router_parse_list_from_string(const char **s, smartlist_t *dest, /** Helper function: reads a single router entry from *<b>s</b> ... * *<b>end</b>. Mallocs a new router and returns it if all goes well, else * returns NULL. + * DOCDOC cache_copy */ routerinfo_t * -router_parse_entry_from_string(const char *s, const char *end) +router_parse_entry_from_string(const char *s, const char *end, + int cache_copy) { routerinfo_t *router = NULL; char signed_digest[128]; @@ -747,7 +751,8 @@ router_parse_entry_from_string(const char *s, const char *end) } router = tor_malloc_zero(sizeof(routerinfo_t)); - router->cache_info.signed_descriptor_body = tor_strndup(s, end-s); + if (cache_copy) + router->cache_info.signed_descriptor_body = tor_strndup(s, end-s); router->cache_info.signed_descriptor_len = end-s; memcpy(router->cache_info.signed_descriptor_digest, digest, DIGEST_LEN); diff --git a/src/or/test.c b/src/or/test.c index 14c9cbb62f..732456115d 100644 --- a/src/or/test.c +++ b/src/or/test.c @@ -1297,7 +1297,7 @@ test_dir_format(void) test_assert(router_dump_router_to_string(buf, 2048, &r1, pk2)>0); cp = buf; - rp1 = router_parse_entry_from_string((const char*)cp,NULL); + rp1 = router_parse_entry_from_string((const char*)cp,NULL,1); test_assert(rp1); test_streq(rp1->address, r1.address); test_eq(rp1->or_port, r1.or_port); @@ -1320,7 +1320,7 @@ test_dir_format(void) test_streq(buf, buf2); cp = buf; - rp2 = router_parse_entry_from_string(&cp); + rp2 = router_parse_entry_from_string(&cp,1); test_assert(rp2); test_streq(rp2->address, r2.address); test_eq(rp2->or_port, r2.or_port); |