diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/util.h | 5 | ||||
-rw-r--r-- | src/config/torrc.complete.in | 2 | ||||
-rw-r--r-- | src/or/buffers.c | 4 | ||||
-rw-r--r-- | src/or/circuitbuild.c | 12 | ||||
-rw-r--r-- | src/or/circuitlist.c | 8 | ||||
-rw-r--r-- | src/or/config.c | 5 | ||||
-rw-r--r-- | src/or/connection_edge.c | 42 | ||||
-rw-r--r-- | src/or/connection_edge.h | 3 | ||||
-rw-r--r-- | src/or/connection_or.c | 15 | ||||
-rw-r--r-- | src/or/control.c | 2 | ||||
-rw-r--r-- | src/or/directory.c | 73 | ||||
-rw-r--r-- | src/or/directory.h | 2 | ||||
-rw-r--r-- | src/or/dirserv.c | 55 | ||||
-rw-r--r-- | src/or/dirserv.h | 2 | ||||
-rw-r--r-- | src/or/dnsserv.c | 22 | ||||
-rw-r--r-- | src/or/eventdns.c | 7 | ||||
-rw-r--r-- | src/or/geoip.c | 1 | ||||
-rw-r--r-- | src/or/hibernate.c | 149 | ||||
-rw-r--r-- | src/or/main.c | 16 | ||||
-rw-r--r-- | src/or/main.h | 2 | ||||
-rw-r--r-- | src/or/networkstatus.c | 88 | ||||
-rw-r--r-- | src/or/or.h | 6 | ||||
-rw-r--r-- | src/or/relay.c | 177 | ||||
-rw-r--r-- | src/or/relay.h | 4 | ||||
-rw-r--r-- | src/or/routerlist.c | 93 | ||||
-rw-r--r-- | src/or/routerlist.h | 3 | ||||
-rw-r--r-- | src/test/tinytest.c | 27 | ||||
-rw-r--r-- | src/test/tinytest.h | 2 | ||||
-rw-r--r-- | src/test/tinytest_macros.h | 12 | ||||
-rw-r--r-- | src/win32/orconfig.h | 2 |
30 files changed, 646 insertions, 195 deletions
diff --git a/src/common/util.h b/src/common/util.h index 3a3a87378a..4a31c277e3 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -160,6 +160,11 @@ unsigned round_to_next_multiple_of(unsigned number, unsigned divisor); uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor); uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor); +/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b> + * and positive <b>b</b>. Works on integer types only. Not defined if a+b can + * overflow. */ +#define CEIL_DIV(a,b) (((a)+(b)-1)/(b)) + /* String manipulation */ /** Allowable characters in a hexadecimal string. */ diff --git a/src/config/torrc.complete.in b/src/config/torrc.complete.in index 6dbec2fbf9..1a1eea1548 100644 --- a/src/config/torrc.complete.in +++ b/src/config/torrc.complete.in @@ -529,6 +529,6 @@ ## Every time the specified period elapses, Tor uploads any ren- ## dezvous service descriptors to the directory servers. This ## information is also uploaded whenever it changes. -## (Default: 20 minutes) +## (Default: 1 hour) #RendPostPeriod N seconds|minutes|hours|days|weeks # diff --git a/src/or/buffers.c b/src/or/buffers.c index e8422637cd..09ccb7cb0d 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -1498,8 +1498,8 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req, return -1; } - req->port = ntohs(*(uint16_t*)(buf->head->data+2)); - destip = ntohl(*(uint32_t*)(buf->head->data+4)); + req->port = ntohs(get_uint16(buf->head->data+2)); + destip = ntohl(get_uint32(buf->head->data+4)); if ((!req->port && req->command!=SOCKS_COMMAND_RESOLVE) || !destip) { log_warn(LD_APP,"socks4: Port or DestIP is zero. Rejecting."); return -1; diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index ef1bab3206..35d8087b6f 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -1918,9 +1918,9 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) circuit_reset_failure_count(0); if (circ->build_state->onehop_tunnel) control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_STATUS, 0); - if (!has_completed_circuit && !circ->build_state->onehop_tunnel) { + if (!can_complete_circuit && !circ->build_state->onehop_tunnel) { or_options_t *options = get_options(); - has_completed_circuit=1; + can_complete_circuit=1; /* FFFF Log a count of known routers here */ log_notice(LD_GENERAL, "Tor has successfully opened a circuit. " @@ -1987,7 +1987,7 @@ circuit_note_clock_jumped(int seconds_elapsed) seconds_elapsed >=0 ? "forward" : "backward"); control_event_general_status(LOG_WARN, "CLOCK_JUMPED TIME=%d", seconds_elapsed); - has_completed_circuit=0; /* so it'll log when it works again */ + can_complete_circuit=0; /* so it'll log when it works again */ control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s", "CLOCK_JUMPED"); circuit_mark_all_unused_circs(); @@ -2308,8 +2308,8 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, const char *payload, cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2); log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.", - (unsigned int)*(uint32_t*)(keys), - (unsigned int)*(uint32_t*)(keys+20)); + (unsigned int)get_uint32(keys), + (unsigned int)get_uint32(keys+20)); if (circuit_init_cpath_crypto(tmp_cpath, keys, 0)<0) { log_warn(LD_BUG,"Circuit initialization failed"); tor_free(tmp_cpath); @@ -2448,6 +2448,8 @@ router_handles_some_port(routerinfo_t *router, smartlist_t *needed_ports) for (i = 0; i < smartlist_len(needed_ports); ++i) { addr_policy_result_t r; + /* alignment issues aren't a worry for this dereference, since + needed_ports is explicitly a smartlist of uint16_t's */ port = *(uint16_t *)smartlist_get(needed_ports, i); tor_assert(port); r = compare_addr_to_addr_policy(0, port, router->exit_policy); diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index c581365f8b..fa800db1a4 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -1124,8 +1124,10 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line, rend_client_remove_intro_point(ocirc->build_state->chosen_exit, ocirc->rend_data); } - if (circ->n_conn) + if (circ->n_conn) { + circuit_clear_cell_queue(circ, circ->n_conn); connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason); + } if (! CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); @@ -1149,8 +1151,10 @@ _circuit_mark_for_close(circuit_t *circ, int reason, int line, conn->on_circuit = NULL; } - if (or_circ->p_conn) + if (or_circ->p_conn) { + circuit_clear_cell_queue(circ, or_circ->p_conn); connection_or_send_destroy(or_circ->p_circ_id, or_circ->p_conn, reason); + } } else { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); edge_connection_t *conn; diff --git a/src/or/config.c b/src/or/config.c index 6b3bcf6da8..8febe7a56b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -428,6 +428,9 @@ static config_var_t _state_vars[] = { V(AccountingExpectedUsage, MEMUNIT, NULL), V(AccountingIntervalStart, ISOTIME, NULL), V(AccountingSecondsActive, INTERVAL, NULL), + V(AccountingSecondsToReachSoftLimit,INTERVAL, NULL), + V(AccountingSoftLimitHitAt, ISOTIME, NULL), + V(AccountingBytesAtSoftLimit, MEMUNIT, NULL), VAR("EntryGuard", LINELIST_S, EntryGuards, NULL), VAR("EntryGuardDownSince", LINELIST_S, EntryGuards, NULL), @@ -1287,7 +1290,7 @@ options_act(or_options_t *old_options) return -1; } ip_address_changed(0); - if (has_completed_circuit || !any_predicted_circuits(time(NULL))) + if (can_complete_circuit || !any_predicted_circuits(time(NULL))) inform_testing_reachability(); } cpuworkers_rotate(); diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 64f3429930..6a3a5ef0a9 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -147,7 +147,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial) return 0; case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: - if (connection_edge_package_raw_inbuf(conn, package_partial) < 0) { + if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) { /* (We already sent an end cell if possible) */ connection_mark_for_close(TO_CONN(conn)); return -1; @@ -1408,6 +1408,26 @@ consider_plaintext_ports(edge_connection_t *conn, uint16_t port) * different one? */ #define TRACKHOSTEXITS_RETRIES 5 +/** Call connection_ap_handshake_rewrite_and_attach() unless a controller + * asked us to leave streams unattached. Return 0 in that case. + * + * See connection_ap_handshake_rewrite_and_attach()'s + * documentation for arguments and return value. + */ +int +connection_ap_rewrite_and_attach_if_allowed(edge_connection_t *conn, + origin_circuit_t *circ, + crypt_path_t *cpath) +{ + or_options_t *options = get_options(); + + if (options->LeaveStreamsUnattached) { + conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT; + return 0; + } + return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath); +} + /** Connection <b>conn</b> just finished its socks handshake, or the * controller asked us to take care of it. If <b>circ</b> is defined, * then that's where we'll want to attach it. Otherwise we have to @@ -1908,11 +1928,7 @@ connection_ap_handshake_process_socks(edge_connection_t *conn) else control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE, 0); - if (options->LeaveStreamsUnattached) { - conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT; - return 0; - } - return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL); + return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } /** connection_init_accepted_conn() found a new trans AP conn. @@ -1926,7 +1942,6 @@ int connection_ap_process_transparent(edge_connection_t *conn) { socks_request_t *socks; - or_options_t *options = get_options(); tor_assert(conn); tor_assert(conn->_base.type == CONN_TYPE_AP); @@ -1950,11 +1965,7 @@ connection_ap_process_transparent(edge_connection_t *conn) control_event_stream_status(conn, STREAM_EVENT_NEW, 0); - if (options->LeaveStreamsUnattached) { - conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT; - return 0; - } - return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL); + return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } /** connection_edge_process_inbuf() found a conn in state natd_wait. See if @@ -1975,7 +1986,6 @@ connection_ap_process_natd(edge_connection_t *conn) size_t tlen = 30; int err, port_ok; socks_request_t *socks; - or_options_t *options = get_options(); tor_assert(conn); tor_assert(conn->_base.type == CONN_TYPE_AP); @@ -2031,13 +2041,9 @@ connection_ap_process_natd(edge_connection_t *conn) control_event_stream_status(conn, STREAM_EVENT_NEW, 0); - if (options->LeaveStreamsUnattached) { - conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT; - return 0; - } conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT; - return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL); + return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); } /** Iterate over the two bytes of stream_id until we get one that is not diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h index d1bce48e8f..762af5172e 100644 --- a/src/or/connection_edge.h +++ b/src/or/connection_edge.h @@ -79,6 +79,9 @@ void client_dns_set_addressmap(const char *address, uint32_t val, const char *addressmap_register_virtual_address(int type, char *new_address); void addressmap_get_mappings(smartlist_t *sl, time_t min_expires, time_t max_expires, int want_expiry); +int connection_ap_rewrite_and_attach_if_allowed(edge_connection_t *conn, + origin_circuit_t *circ, + crypt_path_t *cpath); int connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, origin_circuit_t *circ, crypt_path_t *cpath); diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 0ba1bca31f..6b648b124d 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -147,7 +147,7 @@ void cell_pack(packed_cell_t *dst, const cell_t *src) { char *dest = dst->body; - *(uint16_t*)dest = htons(src->circ_id); + set_uint16(dest, htons(src->circ_id)); *(uint8_t*)(dest+2) = src->command; memcpy(dest+3, src->payload, CELL_PAYLOAD_SIZE); } @@ -158,7 +158,7 @@ cell_pack(packed_cell_t *dst, const cell_t *src) static void cell_unpack(cell_t *dest, const char *src) { - dest->circ_id = ntohs(*(uint16_t*)(src)); + dest->circ_id = ntohs(get_uint16(src)); dest->command = *(uint8_t*)(src+2); memcpy(dest->payload, src+3, CELL_PAYLOAD_SIZE); } @@ -252,8 +252,7 @@ connection_or_flushed_some(or_connection_t *conn) /* If we're under the low water mark, add cells until we're just over the * high water mark. */ if (datalen < OR_CONN_LOWWATER) { - ssize_t n = (OR_CONN_HIGHWATER - datalen + CELL_NETWORK_SIZE-1) - / CELL_NETWORK_SIZE; + ssize_t n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, CELL_NETWORK_SIZE); time_t now = approx_time(); while (conn->active_circuits && n > 0) { int flushed; @@ -371,10 +370,10 @@ connection_or_update_token_buckets_helper(or_connection_t *conn, int reset, * bandwidth parameters in the consensus, but allow local config * options to override. */ rate = options->PerConnBWRate ? (int)options->PerConnBWRate : - (int)networkstatus_get_param(NULL, "bwconnrate", + (int)networkstatus_get_param(NULL, "perconnbwrate", (int)options->BandwidthRate); burst = options->PerConnBWBurst ? (int)options->PerConnBWBurst : - (int)networkstatus_get_param(NULL, "bwconnburst", + (int)networkstatus_get_param(NULL, "perconnbwburst", (int)options->BandwidthBurst); } @@ -1324,10 +1323,6 @@ connection_or_send_destroy(circid_t circ_id, or_connection_t *conn, int reason) cell.payload[0] = (uint8_t) reason; log_debug(LD_OR,"Sending destroy (circID %d).", circ_id); - /* XXXX It's possible that under some circumstances, we want the destroy - * to take precedence over other data waiting on the circuit's cell queue. - */ - connection_or_write_cell_to_buf(&cell, conn); return 0; } diff --git a/src/or/control.c b/src/or/control.c index 7eead0e18a..4d505a98fb 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -1726,7 +1726,7 @@ getinfo_helper_events(control_connection_t *control_conn, /* Note that status/ is not a catch-all for events; there's only supposed * to be a status GETINFO if there's a corresponding STATUS event. */ if (!strcmp(question, "status/circuit-established")) { - *answer = tor_strdup(has_completed_circuit ? "1" : "0"); + *answer = tor_strdup(can_complete_circuit ? "1" : "0"); } else if (!strcmp(question, "status/enough-dir-info")) { *answer = tor_strdup(router_have_minimum_dir_info() ? "1" : "0"); } else if (!strcmp(question, "status/good-server-descriptor") || diff --git a/src/or/directory.c b/src/or/directory.c index a3e575ac97..b109cb53a7 100644 --- a/src/or/directory.c +++ b/src/or/directory.c @@ -67,8 +67,10 @@ static void http_set_address_origin(const char *headers, connection_t *conn); static void connection_dir_download_networkstatus_failed( dir_connection_t *conn, int status_code); static void connection_dir_download_routerdesc_failed(dir_connection_t *conn); +static void connection_dir_bridge_routerdesc_failed(dir_connection_t *conn); static void connection_dir_download_cert_failed( dir_connection_t *conn, int status_code); +static void connection_dir_retry_bridges(smartlist_t *descs); static void dir_networkstatus_download_failed(smartlist_t *failed, int status_code); static void dir_routerdesc_download_failed(smartlist_t *failed, @@ -124,7 +126,7 @@ purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose) { if (get_options()->AllDirActionsPrivate) return 1; - if (router_purpose == ROUTER_PURPOSE_BRIDGE && has_completed_circuit) + if (router_purpose == ROUTER_PURPOSE_BRIDGE && can_complete_circuit) return 1; /* if no circuits yet, we may need this info to bootstrap. */ if (dir_purpose == DIR_PURPOSE_UPLOAD_DIR || dir_purpose == DIR_PURPOSE_UPLOAD_VOTE || @@ -582,7 +584,7 @@ connection_dir_request_failed(dir_connection_t *conn) if (directory_conn_is_self_reachability_test(conn)) { return; /* this was a test fetch. don't retry. */ } - if (entry_list_is_constrained(get_options())) + if (!entry_list_is_constrained(get_options())) router_set_status(conn->identity_digest, 0); /* don't try him again */ if (conn->_base.purpose == DIR_PURPOSE_FETCH_V2_NETWORKSTATUS) { log_info(LD_DIR, "Giving up on directory server at '%s'; retrying", @@ -592,6 +594,8 @@ connection_dir_request_failed(dir_connection_t *conn) conn->_base.purpose == DIR_PURPOSE_FETCH_EXTRAINFO) { log_info(LD_DIR, "Giving up on directory server at '%s'; retrying", conn->_base.address); + if (conn->router_purpose == ROUTER_PURPOSE_BRIDGE) + connection_dir_bridge_routerdesc_failed(conn); connection_dir_download_routerdesc_failed(conn); } else if (conn->_base.purpose == DIR_PURPOSE_FETCH_CONSENSUS) { networkstatus_consensus_download_failed(0); @@ -645,6 +649,24 @@ connection_dir_download_networkstatus_failed(dir_connection_t *conn, } } +/** Helper: Attempt to fetch directly the descriptors of each bridge + * listed in <b>failed</b>. + */ +static void +connection_dir_retry_bridges(smartlist_t *descs) +{ + char digest[DIGEST_LEN]; + SMARTLIST_FOREACH(descs, const char *, cp, + { + if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) { + log_warn(LD_BUG, "Malformed fingerprint in list: %s", + escaped(cp)); + continue; + } + retry_bridge_descriptor_fetch_directly(digest); + }); +} + /** Called when an attempt to download one or more router descriptors * or extra-info documents on connection <b>conn</b> failed. */ @@ -662,6 +684,33 @@ connection_dir_download_routerdesc_failed(dir_connection_t *conn) (void) conn; } +/** Called when an attempt to download a bridge's routerdesc from + * one of the authorities failed due to a network error. If + * possible attempt to download descriptors from the bridge directly. + */ +static void +connection_dir_bridge_routerdesc_failed(dir_connection_t *conn) +{ + smartlist_t *which = NULL; + + /* Requests for bridge descriptors are in the form 'fp/', so ignore + anything else. */ + if (!conn->requested_resource || strcmpstart(conn->requested_resource,"fp/")) + return; + + which = smartlist_create(); + dir_split_resource_into_fingerprints(conn->requested_resource + + strlen("fp/"), + which, NULL, 0); + + tor_assert(conn->_base.purpose != DIR_PURPOSE_FETCH_EXTRAINFO); + if (smartlist_len(which)) { + connection_dir_retry_bridges(which); + SMARTLIST_FOREACH(which, char *, cp, tor_free(cp)); + } + smartlist_free(which); +} + /** Called when an attempt to fetch a certificate fails. */ static void connection_dir_download_cert_failed(dir_connection_t *conn, int status) @@ -3484,6 +3533,14 @@ download_status_reset(download_status_t *dls) dls->next_attempt_at = time(NULL) + schedule[0]; } +/** Return the number of failures on <b>dls</b> since the last success (if + * any). */ +int +download_status_get_n_failures(const download_status_t *dls) +{ + return dls->n_download_failures; +} + /** Called when one or more routerdesc (or extrainfo, if <b>was_extrainfo</b>) * fetches have failed (with uppercase fingerprints listed in <b>failed</b>, * either as descriptor digests or as identity digests based on @@ -3499,16 +3556,8 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code, int server = directory_fetches_from_authorities(get_options()); if (!was_descriptor_digests) { if (router_purpose == ROUTER_PURPOSE_BRIDGE) { - tor_assert(!was_extrainfo); /* not supported yet */ - SMARTLIST_FOREACH(failed, const char *, cp, - { - if (base16_decode(digest, DIGEST_LEN, cp, strlen(cp))<0) { - log_warn(LD_BUG, "Malformed fingerprint in list: %s", - escaped(cp)); - continue; - } - retry_bridge_descriptor_fetch_directly(digest); - }); + tor_assert(!was_extrainfo); + connection_dir_retry_bridges(failed); } return; /* FFFF should implement for other-than-router-purpose someday */ } diff --git a/src/or/directory.h b/src/or/directory.h index 36b4cf2b18..6fd2c0beff 100644 --- a/src/or/directory.h +++ b/src/or/directory.h @@ -104,5 +104,7 @@ download_status_mark_impossible(download_status_t *dl) dl->n_download_failures = IMPOSSIBLE_TO_DOWNLOAD; } +int download_status_get_n_failures(const download_status_t *dls); + #endif diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 86cd186111..3fcf1783d7 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -730,6 +730,10 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source) desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen); nickname = tor_strdup(ri->nickname); + /* Tell if we're about to need to launch a test if we add this. */ + ri->needs_retest_if_added = + dirserv_should_launch_reachability_test(ri, ri_old); + r = router_add_to_routerlist(ri, msg, 0, 0); if (!WRA_WAS_ADDED(r)) { /* unless the routerinfo was fine, just out-of-date */ @@ -744,7 +748,7 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source) changed = smartlist_create(); smartlist_add(changed, ri); - control_event_descriptors_changed(changed); + routerlist_descriptors_added(changed, 0); smartlist_free(changed); if (!*msg) { *msg = ri->is_valid ? "Descriptor for valid server accepted" : @@ -923,6 +927,11 @@ running_long_enough_to_decide_unreachable(void) * the directory. */ #define REACHABLE_TIMEOUT (45*60) +/** If we tested a router and found it reachable _at least this long_ after it + * declared itself hibernating, it is probably done hibernating and we just + * missed a descriptor from it. */ +#define HIBERNATION_PUBLICATION_SKEW (60*60) + /** Treat a router as alive if * - It's me, and I'm not hibernating. * or - We've found it reachable recently. */ @@ -935,11 +944,23 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now) */ int answer; - if (router_is_me(router) && !we_are_hibernating()) + if (router_is_me(router)) { + /* We always know if we are down ourselves. */ + answer = ! we_are_hibernating(); + } else if (router->is_hibernating && + (router->cache_info.published_on + + HIBERNATION_PUBLICATION_SKEW) > router->last_reachable) { + /* A hibernating router is down unless we (somehow) had contact with it + * since it declared itself to be hibernating. */ + answer = 0; + } else if (get_options()->AssumeReachable) { + /* If AssumeReachable, everybody is up unless they say they are down! */ answer = 1; - else - answer = get_options()->AssumeReachable || - now < router->last_reachable + REACHABLE_TIMEOUT; + } else { + /* Otherwise, a router counts as up if we found it reachable in the last + REACHABLE_TIMEOUT seconds. */ + answer = (now < router->last_reachable + REACHABLE_TIMEOUT); + } if (!answer && running_long_enough_to_decide_unreachable()) { /* not considered reachable. tell rephist. */ @@ -3098,6 +3119,30 @@ dirserv_orconn_tls_done(const char *address, * skip testing. */ } +/** Called when we, as an authority, receive a new router descriptor either as + * an upload or a download. Used to decide whether to relaunch reachability + * testing for the server. */ +int +dirserv_should_launch_reachability_test(routerinfo_t *ri, routerinfo_t *ri_old) +{ + if (!authdir_mode_handles_descs(get_options(), ri->purpose)) + return 0; + if (!ri_old) { + /* New router: Launch an immediate reachability test, so we will have an + * opinion soon in case we're generating a consensus soon */ + return 1; + } + if (ri_old->is_hibernating && !ri->is_hibernating) { + /* It just came out of hibernation; launch a reachability test */ + return 1; + } + if (! routers_have_same_or_addr(ri, ri_old)) { + /* Address or port changed; launch a reachability test */ + return 1; + } + return 0; +} + /** Helper function for dirserv_test_reachability(). Start a TLS * connection to <b>router</b>, and annotate it with when we started * the test. */ diff --git a/src/or/dirserv.h b/src/or/dirserv.h index 5ebcb8b2b0..94e4e811d6 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -99,6 +99,8 @@ void dirserv_orconn_tls_done(const char *address, uint16_t or_port, const char *digest_rcvd, int as_advertised); +int dirserv_should_launch_reachability_test(routerinfo_t *ri, + routerinfo_t *ri_old); void dirserv_single_reachability_test(time_t now, routerinfo_t *router); void dirserv_test_reachability(time_t now); int authdir_wants_to_reject_router(routerinfo_t *ri, const char **msg, diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c index e231b655f4..ad4f4122bc 100644 --- a/src/or/dnsserv.c +++ b/src/or/dnsserv.c @@ -141,16 +141,17 @@ evdns_server_callback(struct evdns_server_request *req, void *_data) control_event_stream_status(conn, STREAM_EVENT_NEW, 0); - /* Now, throw the connection over to get rewritten (which will answer it - * immediately if it's in the cache, or completely bogus, or automapped), - * and then attached to a circuit. */ + /* Now, unless a controller asked us to leave streams unattached, + * throw the connection over to get rewritten (which will + * answer it immediately if it's in the cache, or completely bogus, or + * automapped), and then attached to a circuit. */ log_info(LD_APP, "Passing request for %s to rewrite_and_attach.", escaped_safe_str_client(q->name)); q_name = tor_strdup(q->name); /* q could be freed in rewrite_and_attach */ - connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL); + connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); /* Now, the connection is marked if it was bad. */ - log_info(LD_APP, "Passed request for %s to rewrite_and_attach.", + log_info(LD_APP, "Passed request for %s to rewrite_and_attach_if_allowed.", escaped_safe_str_client(q_name)); tor_free(q_name); } @@ -186,16 +187,17 @@ dnsserv_launch_request(const char *name, int reverse) return -1; } - /* Now, throw the connection over to get rewritten (which will answer it - * immediately if it's in the cache, or completely bogus, or automapped), - * and then attached to a circuit. */ + /* Now, unless a controller asked us to leave streams unattached, + * throw the connection over to get rewritten (which will + * answer it immediately if it's in the cache, or completely bogus, or + * automapped), and then attached to a circuit. */ log_info(LD_APP, "Passing request for %s to rewrite_and_attach.", escaped_safe_str_client(name)); q_name = tor_strdup(name); /* q could be freed in rewrite_and_attach */ - connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL); + connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL); /* Now, the connection is marked if it was bad. */ - log_info(LD_APP, "Passed request for %s to rewrite_and_attach.", + log_info(LD_APP, "Passed request for %s to rewrite_and_attach_if_allowed.", escaped_safe_str_client(q_name)); tor_free(q_name); return 0; diff --git a/src/or/eventdns.c b/src/or/eventdns.c index 14c5d88df3..8ebfb79353 100644 --- a/src/or/eventdns.c +++ b/src/or/eventdns.c @@ -3132,7 +3132,7 @@ load_nameservers_with_getnetworkparams(void) GetNetworkParams_fn_t fn; /* XXXX Possibly, we should hardcode the location of this DLL. */ - if (!(handle = LoadLibrary(TEXT("iphlpapi.dll"))) { + if (!(handle = LoadLibrary(TEXT("iphlpapi.dll")))) { log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll"); /* right now status = 0, doesn't that mean "good" - mikec */ status = -1; @@ -3204,6 +3204,7 @@ static int config_nameserver_from_reg_key(HKEY key, const TCHAR *subkey) { char *buf; + char ansibuf[MAX_PATH] = {0}; DWORD bufsz = 0, type = 0; int status = 0; @@ -3216,7 +3217,7 @@ config_nameserver_from_reg_key(HKEY key, const TCHAR *subkey) if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz) == ERROR_SUCCESS && bufsz > 1) { wcstombs(ansibuf,(wchar_t*)buf,MAX_PATH);/*XXXX UNICODE */ - status = evdns_nameserver_ip_add_line(buf); + status = evdns_nameserver_ip_add_line(ansibuf); } mm_free(buf); @@ -3254,7 +3255,7 @@ load_nameservers_from_registry(void) log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError()); return -1; } - r = RegOpenKeyEx(nt_key, Text("Interfaces"), 0, + r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0, KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &interfaces_key); if (r != ERROR_SUCCESS) { diff --git a/src/or/geoip.c b/src/or/geoip.c index d9c8a01519..7f1052e98d 100644 --- a/src/or/geoip.c +++ b/src/or/geoip.c @@ -145,6 +145,7 @@ _geoip_compare_entries(const void **_a, const void **_b) static int _geoip_compare_key_to_entry(const void *_key, const void **_member) { + /* No alignment issue here, since _key really is a pointer to uint32_t */ const uint32_t addr = *(uint32_t *)_key; const geoip_entry_t *entry = *_member; if (addr < entry->ip_low) diff --git a/src/or/hibernate.c b/src/or/hibernate.c index d50d05ed5e..3c6a3fa033 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -95,6 +95,13 @@ static uint64_t n_bytes_read_in_interval = 0; static uint64_t n_bytes_written_in_interval = 0; /** How many seconds have we been running this interval? */ static uint32_t n_seconds_active_in_interval = 0; +/** How many seconds were we active in this interval before we hit our soft + * limit? */ +static int n_seconds_to_hit_soft_limit = 0; +/** When in this interval was the soft limit hit. */ +static time_t soft_limit_hit_at = 0; +/** How many bytes had we read/written when we hit the soft limit? */ +static uint64_t n_bytes_at_soft_limit = 0; /** When did this accounting interval start? */ static time_t interval_start_time = 0; /** When will this accounting interval end? */ @@ -341,29 +348,57 @@ start_of_accounting_period_after(time_t now) return edge_of_accounting_period_containing(now, 1); } +/** Return the length of the accounting period containing the time + * <b>now</b>. */ +static long +length_of_accounting_period_containing(time_t now) +{ + return edge_of_accounting_period_containing(now, 1) - + edge_of_accounting_period_containing(now, 0); +} + /** Initialize the accounting subsystem. */ void configure_accounting(time_t now) { + time_t s_now; /* Try to remember our recorded usage. */ if (!interval_start_time) read_bandwidth_usage(); /* If we fail, we'll leave values at zero, and * reset below.*/ - if (!interval_start_time || - start_of_accounting_period_after(interval_start_time) <= now) { - /* We didn't have recorded usage, or we don't have recorded usage - * for this interval. Start a new interval. */ + + s_now = start_of_accounting_period_containing(now); + + if (!interval_start_time) { + /* We didn't have recorded usage; Start a new interval. */ log_info(LD_ACCT, "Starting new accounting interval."); reset_accounting(now); - } else if (interval_start_time == - start_of_accounting_period_containing(interval_start_time)) { + } else if (s_now == interval_start_time) { log_info(LD_ACCT, "Continuing accounting interval."); /* We are in the interval we thought we were in. Do nothing.*/ interval_end_time = start_of_accounting_period_after(interval_start_time); } else { - log_warn(LD_ACCT, - "Mismatched accounting interval; starting a fresh one."); - reset_accounting(now); + long duration = length_of_accounting_period_containing(now); + double delta = ((double)(s_now - interval_start_time)) / duration; + if (-0.50 <= delta && delta <= 0.50) { + /* The start of the period is now a little later or earlier than we + * remembered. That's fine; we might lose some bytes we could otherwise + * have written, but better to err on the side of obeying people's + * accounting settings. */ + log_info(LD_ACCT, "Accounting interval moved by %.02f%%; " + "that's fine.", delta*100); + interval_end_time = start_of_accounting_period_after(now); + } else if (delta >= 0.99) { + /* This is the regular time-moved-forward case; don't be too noisy + * about it or people will complain */ + log_info(LD_ACCT, "Accounting interval elapsed; starting a new one"); + reset_accounting(now); + } else { + log_warn(LD_ACCT, + "Mismatched accounting interval: moved by %.02f%%. " + "Starting a fresh one.", delta*100); + reset_accounting(now); + } } accounting_set_wakeup_time(); } @@ -374,23 +409,42 @@ configure_accounting(time_t now) static void update_expected_bandwidth(void) { - uint64_t used, expected; - uint64_t max_configured = (get_options()->BandwidthRate * 60); - - if (n_seconds_active_in_interval < 1800) { + uint64_t expected; + or_options_t *options= get_options(); + uint64_t max_configured = (options->RelayBandwidthRate > 0 ? + options->RelayBandwidthRate : + options->BandwidthRate) * 60; + +#define MIN_TIME_FOR_MEASUREMENT (1800) + + if (soft_limit_hit_at > interval_start_time && n_bytes_at_soft_limit && + (soft_limit_hit_at - interval_start_time) > MIN_TIME_FOR_MEASUREMENT) { + /* If we hit our soft limit last time, only count the bytes up to that + * time. This is a better predictor of our actual bandwidth than + * considering the entirety of the last interval, since we likely started + * using bytes very slowly once we hit our soft limit. */ + expected = n_bytes_at_soft_limit / + (soft_limit_hit_at - interval_start_time); + expected /= 60; + } else if (n_seconds_active_in_interval >= MIN_TIME_FOR_MEASUREMENT) { + /* Otherwise, we either measured enough time in the last interval but + * never hit our soft limit, or we're using a state file from a Tor that + * doesn't know to store soft-limit info. Just take rate at which + * we were reading/writing in the last interval as our expected rate. + */ + uint64_t used = MAX(n_bytes_written_in_interval, + n_bytes_read_in_interval); + expected = used / (n_seconds_active_in_interval / 60); + } else { /* If we haven't gotten enough data last interval, set 'expected' * to 0. This will set our wakeup to the start of the interval. * Next interval, we'll choose our starting time based on how much * we sent this interval. */ expected = 0; - } else { - used = n_bytes_written_in_interval < n_bytes_read_in_interval ? - n_bytes_read_in_interval : n_bytes_written_in_interval; - expected = used / (n_seconds_active_in_interval / 60); - if (expected > max_configured) - expected = max_configured; } + if (expected > max_configured) + expected = max_configured; expected_bandwidth_usage = expected; } @@ -408,6 +462,9 @@ reset_accounting(time_t now) n_bytes_read_in_interval = 0; n_bytes_written_in_interval = 0; n_seconds_active_in_interval = 0; + n_bytes_at_soft_limit = 0; + soft_limit_hit_at = 0; + n_seconds_to_hit_soft_limit = 0; } /** Return true iff we should save our bandwidth usage to disk. */ @@ -568,6 +625,10 @@ accounting_record_bandwidth_usage(time_t now, or_state_t *state) state->AccountingSecondsActive = n_seconds_active_in_interval; state->AccountingExpectedUsage = expected_bandwidth_usage; + state->AccountingSecondsToReachSoftLimit = n_seconds_to_hit_soft_limit; + state->AccountingSoftLimitHitAt = soft_limit_hit_at; + state->AccountingBytesAtSoftLimit = n_bytes_at_soft_limit; + or_state_mark_dirty(state, now+(get_options()->AvoidDiskWrites ? 7200 : 60)); @@ -591,10 +652,6 @@ read_bandwidth_usage(void) if (!state) return -1; - /* Okay; it looks like the state file is more up-to-date than the - * bw_accounting file, or the bw_accounting file is nonexistent, - * or the bw_accounting file is corrupt. - */ log_info(LD_ACCT, "Reading bandwidth accounting data from state file"); n_bytes_read_in_interval = state->AccountingBytesReadInInterval; n_bytes_written_in_interval = state->AccountingBytesWrittenInInterval; @@ -602,6 +659,21 @@ read_bandwidth_usage(void) interval_start_time = state->AccountingIntervalStart; expected_bandwidth_usage = state->AccountingExpectedUsage; + /* Older versions of Tor (before 0.2.2.17-alpha or so) didn't generate these + * fields. If you switch back and forth, you might get an + * AccountingSoftLimitHitAt value from long before the most recent + * interval_start_time. If that's so, then ignore the softlimit-related + * values. */ + if (state->AccountingSoftLimitHitAt > interval_start_time) { + soft_limit_hit_at = state->AccountingSoftLimitHitAt; + n_bytes_at_soft_limit = state->AccountingBytesAtSoftLimit; + n_seconds_to_hit_soft_limit = state->AccountingSecondsToReachSoftLimit; + } else { + soft_limit_hit_at = 0; + n_bytes_at_soft_limit = 0; + n_seconds_to_hit_soft_limit = 0; + } + { char tbuf1[ISO_TIME_LEN+1]; char tbuf2[ISO_TIME_LEN+1]; @@ -641,8 +713,27 @@ hibernate_hard_limit_reached(void) static int hibernate_soft_limit_reached(void) { - uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(get_options()->AccountingMax) - * .95); + const uint64_t acct_max = get_options()->AccountingMax; +#define SOFT_LIM_PCT (.95) +#define SOFT_LIM_BYTES (500*1024*1024) +#define SOFT_LIM_MINUTES (3*60) + /* The 'soft limit' is a fair bit more complicated now than once it was. + * We want to stop accepting connections when ALL of the following are true: + * - We expect to use up the remaining bytes in under 3 hours + * - We have used up 95% of our bytes. + * - We have less than 500MB of bytes left. + */ + uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(acct_max) * SOFT_LIM_PCT); + if (acct_max > SOFT_LIM_BYTES && acct_max - SOFT_LIM_BYTES > soft_limit) { + soft_limit = acct_max - SOFT_LIM_BYTES; + } + if (expected_bandwidth_usage) { + const uint64_t expected_usage = + expected_bandwidth_usage * SOFT_LIM_MINUTES; + if (acct_max > expected_usage && acct_max - expected_usage > soft_limit) + soft_limit = acct_max - expected_usage; + } + if (!soft_limit) return 0; return n_bytes_read_in_interval >= soft_limit @@ -667,6 +758,14 @@ hibernate_begin(hibernate_state_t new_state, time_t now) exit(0); } + if (new_state == HIBERNATE_STATE_LOWBANDWIDTH && + hibernate_state == HIBERNATE_STATE_LIVE) { + soft_limit_hit_at = now; + n_seconds_to_hit_soft_limit = n_seconds_active_in_interval; + n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval, + n_bytes_written_in_interval); + } + /* close listeners. leave control listener(s). */ while ((conn = connection_get_by_type(CONN_TYPE_OR_LISTENER)) || (conn = connection_get_by_type(CONN_TYPE_AP_LISTENER)) || diff --git a/src/or/main.c b/src/or/main.c index f33dc2f6b4..477a274d54 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -119,8 +119,12 @@ static smartlist_t *active_linked_connection_lst = NULL; static int called_loop_once = 0; /** We set this to 1 when we've opened a circuit, so we can print a log - * entry to inform the user that Tor is working. */ -int has_completed_circuit=0; + * entry to inform the user that Tor is working. We set it to 0 when + * we think the fact that we once opened a circuit doesn't mean we can do so + * any longer (a big time jump happened, when we notice our directory is + * heinously out-of-date, etc. + */ +int can_complete_circuit=0; /** How often do we check for router descriptors that we should download * when we have too little directory info? */ @@ -714,7 +718,7 @@ directory_info_has_arrived(time_t now, int from_cache) } if (server_mode(options) && !we_are_hibernating() && !from_cache && - (has_completed_circuit || !any_predicted_circuits(now))) + (can_complete_circuit || !any_predicted_circuits(now))) consider_testing_reachability(1, 1); } @@ -1093,7 +1097,7 @@ run_scheduled_events(time_t now) /* also, check religiously for reachability, if it's within the first * 20 minutes of our uptime. */ if (server_mode(options) && - (has_completed_circuit || !any_predicted_circuits(now)) && + (can_complete_circuit || !any_predicted_circuits(now)) && !we_are_hibernating()) { if (stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { consider_testing_reachability(1, dirport_reachability_count==0); @@ -1192,7 +1196,7 @@ run_scheduled_events(time_t now) circuit_close_all_marked(); /** 7. And upload service descriptors if necessary. */ - if (has_completed_circuit && !we_are_hibernating()) { + if (can_complete_circuit && !we_are_hibernating()) { rend_consider_services_upload(now); rend_consider_descriptor_republication(); } @@ -1274,7 +1278,7 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg) if (server_mode(options) && !we_are_hibernating() && seconds_elapsed > 0 && - has_completed_circuit && + can_complete_circuit && stats_n_seconds_working / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT != (stats_n_seconds_working+seconds_elapsed) / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) { diff --git a/src/or/main.h b/src/or/main.h index 6eeb95449a..ef38dc9351 100644 --- a/src/or/main.h +++ b/src/or/main.h @@ -12,7 +12,7 @@ #ifndef _TOR_MAIN_H #define _TOR_MAIN_H -extern int has_completed_circuit; +extern int can_complete_circuit; int connection_add(connection_t *conn); int connection_remove(connection_t *conn); diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index c0a3a28e4b..1d8a20be11 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -464,7 +464,7 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, int warn) { int n_good = 0; - int n_missing_key = 0; + int n_missing_key = 0, n_dl_failed_key = 0; int n_bad = 0; int n_unknown = 0; int n_no_signature = 0; @@ -482,7 +482,8 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, voter) { int good_here = 0; int bad_here = 0; - int missing_key_here = 0; + int unknown_here = 0; + int missing_key_here = 0, dl_failed_key_here = 0; SMARTLIST_FOREACH_BEGIN(voter->sigs, document_signature_t *, sig) { if (!sig->good_signature && !sig->bad_signature && sig->signature) { @@ -497,16 +498,20 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, if (!is_v3_auth) { smartlist_add(unrecognized, voter); - ++n_unknown; + ++unknown_here; continue; } else if (!cert || cert->expires < now) { smartlist_add(need_certs_from, voter); ++missing_key_here; + if (authority_cert_dl_looks_uncertain(sig->identity_digest)) + ++dl_failed_key_here; continue; } if (networkstatus_check_document_signature(consensus, sig, cert) < 0) { smartlist_add(need_certs_from, voter); ++missing_key_here; + if (authority_cert_dl_looks_uncertain(sig->identity_digest)) + ++dl_failed_key_here; continue; } } @@ -519,10 +524,15 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, ++n_good; else if (bad_here) ++n_bad; - else if (missing_key_here) + else if (missing_key_here) { ++n_missing_key; - else + if (dl_failed_key_here) + ++n_dl_failed_key; + } else if (unknown_here) { + ++n_unknown; + } else { ++n_no_signature; + } } SMARTLIST_FOREACH_END(voter); /* Now see whether we're missing any voters entirely. */ @@ -534,39 +544,71 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, smartlist_add(missing_authorities, ds); }); - if (warn > 1 || (warn >= 0 && n_good < n_required)) + if (warn > 1 || (warn >= 0 && + (n_good + n_missing_key - n_dl_failed_key < n_required))) { severity = LOG_WARN; - else + } else { severity = LOG_INFO; + } if (warn >= 0) { SMARTLIST_FOREACH(unrecognized, networkstatus_voter_info_t *, voter, { - log_info(LD_DIR, "Consensus includes unrecognized authority '%s' " - "at %s:%d (contact %s; identity %s)", + log(severity, LD_DIR, "Consensus includes unrecognized authority " + "'%s' at %s:%d (contact %s; identity %s)", voter->nickname, voter->address, (int)voter->dir_port, voter->contact?voter->contact:"n/a", hex_str(voter->identity_digest, DIGEST_LEN)); }); SMARTLIST_FOREACH(need_certs_from, networkstatus_voter_info_t *, voter, { - log_info(LD_DIR, "Looks like we need to download a new certificate " - "from authority '%s' at %s:%d (contact %s; identity %s)", + log(severity, LD_DIR, "Looks like we need to download a new " + "certificate from authority '%s' at %s:%d (contact %s; " + "identity %s)", voter->nickname, voter->address, (int)voter->dir_port, voter->contact?voter->contact:"n/a", hex_str(voter->identity_digest, DIGEST_LEN)); }); SMARTLIST_FOREACH(missing_authorities, trusted_dir_server_t *, ds, { - log_info(LD_DIR, "Consensus does not include configured " + log(severity, LD_DIR, "Consensus does not include configured " "authority '%s' at %s:%d (identity %s)", ds->nickname, ds->address, (int)ds->dir_port, hex_str(ds->v3_identity_digest, DIGEST_LEN)); }); - log(severity, LD_DIR, - "%d unknown, %d missing key, %d good, %d bad, %d no signature, " - "%d required", n_unknown, n_missing_key, n_good, n_bad, - n_no_signature, n_required); + { + smartlist_t *sl = smartlist_create(); + char *cp; + tor_asprintf(&cp, "A consensus needs %d good signatures from recognized " + "authorities for us to accept it. This one has %d.", + n_required, n_good); + smartlist_add(sl,cp); + if (n_no_signature) { + tor_asprintf(&cp, "%d of the authorities we know didn't sign it.", + n_no_signature); + smartlist_add(sl,cp); + } + if (n_unknown) { + tor_asprintf(&cp, "It has %d signatures from authorities we don't " + "recognize.", n_unknown); + smartlist_add(sl,cp); + } + if (n_bad) { + tor_asprintf(&cp, "%d of the signatures on it didn't verify " + "correctly.", n_bad); + smartlist_add(sl,cp); + } + if (n_missing_key) { + tor_asprintf(&cp, "We were unable to check %d of the signatures, " + "because we were missing the keys.", n_missing_key); + smartlist_add(sl,cp); + } + cp = smartlist_join_strings(sl, " ", 0, NULL); + log(severity, LD_DIR, "%s", cp); + tor_free(cp); + SMARTLIST_FOREACH(sl, char *, c, tor_free(c)); + smartlist_free(sl); + } } smartlist_free(unrecognized); @@ -1168,14 +1210,11 @@ update_v2_networkstatus_cache_downloads(time_t now) static void update_consensus_networkstatus_downloads(time_t now) { - or_options_t *options = get_options(); int i; if (!networkstatus_get_live_consensus(now)) time_to_download_next_consensus = now; /* No live consensus? Get one now!*/ if (time_to_download_next_consensus > now) return; /* Wait until the current consensus is older. */ - if (authdir_mode_v3(options)) - return; /* Authorities never fetch a consensus */ /* XXXXNM Microdescs: may need to download more types. */ if (!download_status_is_ready(&consensus_dl_status[FLAV_NS], now, CONSENSUS_NETWORKSTATUS_MAX_DL_TRIES)) @@ -1246,7 +1285,7 @@ update_consensus_networkstatus_fetch_time(time_t now) * is no longer fresh... */ start = c->fresh_until + min_sec_before_caching; /* Some clients may need the consensus sooner than others. */ - if (options->FetchDirInfoExtraEarly) { + if (options->FetchDirInfoExtraEarly || authdir_mode_v3(options)) { dl_interval = 60; if (min_sec_before_caching + dl_interval > interval) dl_interval = interval/2; @@ -1946,6 +1985,15 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers, router->is_bad_directory = rs->is_bad_directory; router->is_bad_exit = rs->is_bad_exit; router->is_hs_dir = rs->is_hs_dir; + } else { + /* If we _are_ an authority, we should check whether this router + * is one that will cause us to need a reachability test. */ + routerinfo_t *old_router = + router_get_by_digest(router->cache_info.identity_digest); + if (old_router != router) { + router->needs_retest_if_added = + dirserv_should_launch_reachability_test(router, old_router); + } } if (router->is_running && ds) { download_status_reset(&ds->v2_ns_dl_status); diff --git a/src/or/or.h b/src/or/or.h index 48641c8115..6332de83a1 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1456,6 +1456,9 @@ typedef struct { * directory according to the authorities. */ unsigned int policy_is_reject_star:1; /**< True iff the exit policy for this * router rejects everything. */ + /** True if, after we have added this router, we should re-launch + * tests for it. */ + unsigned int needs_retest_if_added:1; /** Tor can use this router for general positions in circuits. */ #define ROUTER_PURPOSE_GENERAL 0 @@ -2828,6 +2831,9 @@ typedef struct { uint64_t AccountingBytesReadInInterval; uint64_t AccountingBytesWrittenInInterval; int AccountingSecondsActive; + int AccountingSecondsToReachSoftLimit; + time_t AccountingSoftLimitHitAt; + uint64_t AccountingBytesAtSoftLimit; uint64_t AccountingExpectedUsage; /** A list of Entry Guard-related configuration lines. */ diff --git a/src/or/relay.c b/src/or/relay.c index 0b0b7067a0..b12cef4912 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -38,20 +38,18 @@ static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t *layer_hint); -static int -connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, - edge_connection_t *conn, - crypt_path_t *layer_hint); -static void -circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint); -static void -circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint); -static int -circuit_resume_edge_reading_helper(edge_connection_t *conn, - circuit_t *circ, - crypt_path_t *layer_hint); -static int -circuit_consider_stop_edge_reading(circuit_t *circ, crypt_path_t *layer_hint); +static int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, + edge_connection_t *conn, + crypt_path_t *layer_hint); +static void circuit_consider_sending_sendme(circuit_t *circ, + crypt_path_t *layer_hint); +static void circuit_resume_edge_reading(circuit_t *circ, + crypt_path_t *layer_hint); +static int circuit_resume_edge_reading_helper(edge_connection_t *conn, + circuit_t *circ, + crypt_path_t *layer_hint); +static int circuit_consider_stop_edge_reading(circuit_t *circ, + crypt_path_t *layer_hint); static int circuit_queue_streams_are_blocked(circuit_t *circ); /** Cache the current hi-res time; the cache gets reset when libevent @@ -59,6 +57,13 @@ static int circuit_queue_streams_are_blocked(circuit_t *circ); static struct timeval cached_time_hires = {0, 0}; +/** Stop reading on edge connections when we have this many cells + * waiting on the appropriate queue. */ +#define CELL_QUEUE_HIGHWATER_SIZE 256 +/** Start reading from edge connections again when we get down to this many + * cells. */ +#define CELL_QUEUE_LOWWATER_SIZE 64 + static void tor_gettimeofday_cached(struct timeval *tv) { @@ -948,7 +953,7 @@ connection_edge_process_relay_cell_not_open( } /* handle anything that might have queued */ - if (connection_edge_package_raw_inbuf(conn, 1) < 0) { + if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) { /* (We already sent an end cell if possible) */ connection_mark_for_close(TO_CONN(conn)); return 0; @@ -1189,6 +1194,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, } if (circ->n_conn) { uint8_t trunc_reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE); + circuit_clear_cell_queue(circ, circ->n_conn); connection_or_send_destroy(circ->n_circ_id, circ->n_conn, trunc_reason); circuit_set_n_circid_orconn(circ, 0, NULL); @@ -1243,7 +1249,7 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, } connection_start_reading(TO_CONN(conn)); /* handle whatever might still be on the inbuf */ - if (connection_edge_package_raw_inbuf(conn, 1) < 0) { + if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) { /* (We already sent an end cell if possible) */ connection_mark_for_close(TO_CONN(conn)); return 0; @@ -1309,15 +1315,19 @@ uint64_t stats_n_data_cells_received = 0; * ever received were completely full of data. */ uint64_t stats_n_data_bytes_received = 0; -/** While conn->inbuf has an entire relay payload of bytes on it, - * and the appropriate package windows aren't empty, grab a cell - * and send it down the circuit. +/** If <b>conn</b> has an entire relay payload of bytes on its inbuf (or + * <b>package_partial</b> is true), and the appropriate package windows aren't + * empty, grab a cell and send it down the circuit. + * + * If *<b>max_cells</b> is given, package no more than max_cells. Decrement + * *<b>max_cells</b> by the number of cells packaged. * * Return -1 (and send a RELAY_COMMAND_END cell if necessary) if conn should * be marked for close, else return 0. */ int -connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial) +connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial, + int *max_cells) { size_t amount_to_process, length; char payload[CELL_PAYLOAD_SIZE]; @@ -1333,6 +1343,9 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial) return 0; } + if (max_cells && *max_cells <= 0) + return 0; + repeat_connection_edge_package_raw_inbuf: circ = circuit_get_by_edge_conn(conn); @@ -1394,6 +1407,12 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial) } log_debug(domain,"conn->package_window is now %d",conn->package_window); + if (max_cells) { + *max_cells -= 1; + if (*max_cells <= 0) + return 0; + } + /* handle more if there's more, or return 0 if there isn't */ goto repeat_connection_edge_package_raw_inbuf; } @@ -1460,31 +1479,100 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) * of a linked list of edge streams that should each be considered. */ static int -circuit_resume_edge_reading_helper(edge_connection_t *conn, +circuit_resume_edge_reading_helper(edge_connection_t *first_conn, circuit_t *circ, crypt_path_t *layer_hint) { - for ( ; conn; conn=conn->next_stream) { - if (conn->_base.marked_for_close) + edge_connection_t *conn; + int n_streams, n_streams_left; + int packaged_this_round; + int cells_on_queue; + int cells_per_conn; + + /* How many cells do we have space for? It will be the minimum of + * the number needed to exhaust the package window, and the minimum + * needed to fill the cell queue. */ + int max_to_package = circ->package_window; + if (CIRCUIT_IS_ORIGIN(circ)) { + cells_on_queue = circ->n_conn_cells.n; + } else { + or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); + cells_on_queue = or_circ->p_conn_cells.n; + } + if (CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue < max_to_package) + max_to_package = CELL_QUEUE_HIGHWATER_SIZE - cells_on_queue; + + /* Count how many non-marked streams there are that have anything on + * their inbuf, and enable reading on all of the connections. */ + n_streams = 0; + for (conn=first_conn; conn; conn=conn->next_stream) { + if (conn->_base.marked_for_close || conn->package_window <= 0) continue; - if ((!layer_hint && conn->package_window > 0) || - (layer_hint && conn->package_window > 0 && - conn->cpath_layer == layer_hint)) { + if (!layer_hint || conn->cpath_layer == layer_hint) { connection_start_reading(TO_CONN(conn)); + + if (buf_datalen(conn->_base.inbuf) > 0) + ++n_streams; + } + } + + if (n_streams == 0) /* avoid divide-by-zero */ + return 0; + + again: + + cells_per_conn = CEIL_DIV(max_to_package, n_streams); + + packaged_this_round = 0; + n_streams_left = 0; + + /* Iterate over all connections. Package up to cells_per_conn cells on + * each. Update packaged_this_round with the total number of cells + * packaged, and n_streams_left with the number that still have data to + * package. + */ + for (conn=first_conn; conn; conn=conn->next_stream) { + if (conn->_base.marked_for_close || conn->package_window <= 0) + continue; + if (!layer_hint || conn->cpath_layer == layer_hint) { + int n = cells_per_conn, r; /* handle whatever might still be on the inbuf */ - if (connection_edge_package_raw_inbuf(conn, 1)<0) { - /* (We already sent an end cell if possible) */ + r = connection_edge_package_raw_inbuf(conn, 1, &n); + + /* Note how many we packaged */ + packaged_this_round += (cells_per_conn-n); + + if (r<0) { + /* Problem while packaging. (We already sent an end cell if + * possible) */ connection_mark_for_close(TO_CONN(conn)); continue; } + /* If there's still data to read, we'll be coming back to this stream. */ + if (buf_datalen(conn->_base.inbuf)) + ++n_streams_left; + /* If the circuit won't accept any more data, return without looking * at any more of the streams. Any connections that should be stopped * have already been stopped by connection_edge_package_raw_inbuf. */ if (circuit_consider_stop_edge_reading(circ, layer_hint)) return -1; + /* XXXX should we also stop immediately if we fill up the cell queue? + * Probably. */ } } + + /* If we made progress, and we are willing to package more, and there are + * any streams left that want to package stuff... try again! + */ + if (packaged_this_round && packaged_this_round < max_to_package && + n_streams_left) { + max_to_package -= packaged_this_round; + n_streams = n_streams_left; + goto again; + } + return 0; } @@ -1553,13 +1641,6 @@ circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint) } } -/** Stop reading on edge connections when we have this many cells - * waiting on the appropriate queue. */ -#define CELL_QUEUE_HIGHWATER_SIZE 256 -/** Start reading from edge connections again when we get down to this many - * cells. */ -#define CELL_QUEUE_LOWWATER_SIZE 64 - #ifdef ACTIVE_CIRCUITS_PARANOIA #define assert_active_circuits_ok_paranoid(conn) \ assert_active_circuits_ok(conn) @@ -2216,7 +2297,9 @@ connection_or_flush_from_first_active_circuit(or_connection_t *conn, int max, flushed = (uint32_t)((now.tv_sec % SECONDS_IN_A_DAY) * 100L + (uint32_t)now.tv_usec / (uint32_t)10000L); if (!it_queue || !it_queue->first) { - log_warn(LD_BUG, "Cannot determine insertion time of cell."); + log_info(LD_GENERAL, "Cannot determine insertion time of cell. " + "Looks like the CellStatistics option was " + "recently enabled."); } else { or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); insertion_time_elem_t *elem = it_queue->first; @@ -2297,6 +2380,9 @@ append_cell_to_circuit_queue(circuit_t *circ, or_connection_t *orconn, { cell_queue_t *queue; int streams_blocked; + if (circ->marked_for_close) + return; + if (direction == CELL_DIRECTION_OUT) { queue = &circ->n_conn_cells; streams_blocked = circ->streams_blocked_on_n_conn; @@ -2399,6 +2485,25 @@ decode_address_from_payload(tor_addr_t *addr_out, const char *payload, return payload + 2 + (uint8_t)payload[1]; } +/** Remove all the cells queued on <b>circ</b> for <b>orconn</b>. */ +void +circuit_clear_cell_queue(circuit_t *circ, or_connection_t *orconn) +{ + cell_queue_t *queue; + if (circ->n_conn == orconn) { + queue = &circ->n_conn_cells; + } else { + or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); + tor_assert(orcirc->p_conn == orconn); + queue = &orcirc->p_conn_cells; + } + + if (queue->n) + make_circuit_inactive_on_conn(circ,orconn); + + cell_queue_clear(queue); +} + /** Fail with an assert if the active circuits ring on <b>orconn</b> is * corrupt. */ void diff --git a/src/or/relay.h b/src/or/relay.h index 0ef17b6ffd..08a1ffe789 100644 --- a/src/or/relay.h +++ b/src/or/relay.h @@ -27,7 +27,8 @@ int connection_edge_send_command(edge_connection_t *fromconn, uint8_t relay_command, const char *payload, size_t payload_len); int connection_edge_package_raw_inbuf(edge_connection_t *conn, - int package_partial); + int package_partial, + int *max_cells); void connection_edge_consider_sending_sendme(edge_connection_t *conn); extern uint64_t stats_n_data_cells_packaged; @@ -61,6 +62,7 @@ const char *decode_address_from_payload(tor_addr_t *addr_out, unsigned cell_ewma_get_tick(void); void cell_ewma_set_scale_factor(or_options_t *options, networkstatus_t *consensus); +void circuit_clear_cell_queue(circuit_t *circ, or_connection_t *orconn); #endif diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 8808f56db9..5fb4fe13c2 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -440,6 +440,23 @@ authority_cert_dl_failed(const char *id_digest, int status) download_status_failed(&cl->dl_status, status); } +/** Return true iff when we've been getting enough failures when trying to + * download the certificate with ID digest <b>id_digest</b> that we're willing + * to start bugging the user about it. */ +int +authority_cert_dl_looks_uncertain(const char *id_digest) +{ +#define N_AUTH_CERT_DL_FAILURES_TO_BUG_USER 2 + cert_list_t *cl; + int n_failures; + if (!trusted_dir_certs || + !(cl = digestmap_get(trusted_dir_certs, id_digest))) + return 0; + + n_failures = download_status_get_n_failures(&cl->dl_status); + return n_failures >= N_AUTH_CERT_DL_FAILURES_TO_BUG_USER; +} + /** How many times will we try to fetch a certificate before giving up? */ #define MAX_CERT_DL_FAILURES 8 @@ -1257,6 +1274,13 @@ mark_all_trusteddirservers_up(void) router_dir_info_changed(); } +/** Return true iff r1 and r2 have the same address and OR port. */ +int +routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2) +{ + return r1->addr == r2->addr && r1->or_port == r2->or_port; +} + /** Reset all internal variables used to count failed downloads of network * status objects. */ void @@ -3159,8 +3183,10 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, /* If we have this descriptor already and the new descriptor is a bridge * descriptor, replace it. If we had a bridge descriptor before and the * new one is not a bridge descriptor, don't replace it. */ - if (old_router && (!routerinfo_is_a_configured_bridge(router) || - routerinfo_is_a_configured_bridge(old_router))) { + tor_assert(old_router); + if (! (routerinfo_is_a_configured_bridge(router) && + (router->purpose == ROUTER_PURPOSE_BRIDGE || + old_router->purpose != ROUTER_PURPOSE_BRIDGE))) { log_info(LD_DIR, "Dropping descriptor that we already have for router '%s'", router->nickname); @@ -3251,8 +3277,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, log_debug(LD_DIR, "Replacing entry for router '%s/%s' [%s]", router->nickname, old_router->nickname, hex_str(id_digest,DIGEST_LEN)); - if (router->addr == old_router->addr && - router->or_port == old_router->or_port) { + if (routers_have_same_or_addr(router, old_router)) { /* these carry over when the address and orport are unchanged. */ router->last_reachable = old_router->last_reachable; router->testing_since = old_router->testing_since; @@ -3281,11 +3306,6 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg, * the list. */ routerlist_insert(routerlist, router); if (!from_cache) { - if (authdir) { - /* launch an immediate reachability test, so we will have an opinion - * soon in case we're generating a consensus soon */ - dirserv_single_reachability_test(time(NULL), router); - } signed_desc_append_to_journal(&router->cache_info, &routerlist->desc_store); } @@ -3605,15 +3625,19 @@ routerlist_remove_old_routers(void) /** We just added a new set of descriptors. Take whatever extra steps * we need. */ -static void +void routerlist_descriptors_added(smartlist_t *sl, int from_cache) { tor_assert(sl); control_event_descriptors_changed(sl); - SMARTLIST_FOREACH(sl, routerinfo_t *, ri, + SMARTLIST_FOREACH_BEGIN(sl, routerinfo_t *, ri) { if (ri->purpose == ROUTER_PURPOSE_BRIDGE) learned_bridge_descriptor(ri, from_cache); - ); + if (ri->needs_retest_if_added) { + ri->needs_retest_if_added = 0; + dirserv_single_reachability_test(approx_time(), ri); + } + } SMARTLIST_FOREACH_END(ri); } /** @@ -4196,7 +4220,7 @@ launch_router_descriptor_downloads(smartlist_t *downloadable, pds_flags |= PDS_NO_EXISTING_SERVERDESC_FETCH; } - n_per_request = (n_downloadable+MIN_REQUESTS-1) / MIN_REQUESTS; + n_per_request = CEIL_DIV(n_downloadable, MIN_REQUESTS); if (n_per_request > MAX_DL_PER_REQUEST) n_per_request = MAX_DL_PER_REQUEST; if (n_per_request < MIN_DL_PER_REQUEST) @@ -4209,7 +4233,7 @@ launch_router_descriptor_downloads(smartlist_t *downloadable, log_info(LD_DIR, "Launching %d request%s for %d router%s, %d at a time", - (n_downloadable+n_per_request-1)/n_per_request, + CEIL_DIV(n_downloadable, n_per_request), req_plural, n_downloadable, rtr_plural, n_per_request); smartlist_sort_digests(downloadable); for (i=0; i < n_downloadable; i += n_per_request) { @@ -4649,16 +4673,21 @@ get_dir_info_status_string(void) /** Iterate over the servers listed in <b>consensus</b>, and count how many of * them seem like ones we'd use, and how many of <em>those</em> we have * descriptors for. Store the former in *<b>num_usable</b> and the latter in - * *<b>num_present</b>. */ + * *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those + * routers in <b>in_set</b>. + */ static void count_usable_descriptors(int *num_present, int *num_usable, const networkstatus_t *consensus, - or_options_t *options, time_t now) + or_options_t *options, time_t now, + routerset_t *in_set) { *num_present = 0, *num_usable=0; SMARTLIST_FOREACH(consensus->routerstatus_list, routerstatus_t *, rs, { + if (in_set && ! routerset_contains_routerstatus(in_set, rs)) + continue; if (client_would_use_router(rs, now, options)) { ++*num_usable; /* the consensus says we want it. */ if (router_get_by_descriptor_digest(rs->descriptor_digest)) { @@ -4687,7 +4716,7 @@ count_loading_descriptors_progress(void) return 0; /* can't count descriptors if we have no list of them */ count_usable_descriptors(&num_present, &num_usable, - consensus, get_options(), now); + consensus, get_options(), now, NULL); if (num_usable == 0) return 0; /* don't div by 0 */ @@ -4731,22 +4760,39 @@ update_router_have_minimum_dir_info(void) goto done; } - count_usable_descriptors(&num_present, &num_usable, consensus, options, now); + count_usable_descriptors(&num_present, &num_usable, consensus, options, now, + NULL); if (num_present < num_usable/4) { tor_snprintf(dir_info_status, sizeof(dir_info_status), "We have only %d/%d usable descriptors.", num_present, num_usable); res = 0; control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0); + goto done; } else if (num_present < 2) { tor_snprintf(dir_info_status, sizeof(dir_info_status), "Only %d descriptor%s here and believed reachable!", num_present, num_present ? "" : "s"); res = 0; - } else { - res = 1; + goto done; } + /* Check for entry nodes. */ + if (options->EntryNodes) { + count_usable_descriptors(&num_present, &num_usable, consensus, options, + now, options->EntryNodes); + + if (num_usable && (num_present == 0)) { + tor_snprintf(dir_info_status, sizeof(dir_info_status), + "We have only %d/%d usable entry node descriptors.", + num_present, num_usable); + res = 0; + goto done; + } + } + + res = 1; + done: if (res && !have_min_dir_info) { log(LOG_NOTICE, LD_DIR, @@ -4759,6 +4805,13 @@ update_router_have_minimum_dir_info(void) log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR, "Our directory information is no longer up-to-date " "enough to build circuits: %s", dir_info_status); + + /* a) make us log when we next complete a circuit, so we know when Tor + * is back up and usable, and b) disable some activities that Tor + * should only do while circuits are working, like reachability tests + * and fetching bridge descriptors only over circuits. */ + can_complete_circuit = 0; + control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO"); } have_min_dir_info = res; diff --git a/src/or/routerlist.h b/src/or/routerlist.h index e31b07aef5..574bce7ffc 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -24,6 +24,7 @@ void authority_cert_get_all(smartlist_t *certs_out); void authority_cert_dl_failed(const char *id_digest, int status); void authority_certs_fetch_missing(networkstatus_t *status, time_t now); int router_reload_router_list(void); +int authority_cert_dl_looks_uncertain(const char *id_digest); smartlist_t *router_get_trusted_dir_servers(void); routerstatus_t *router_pick_directory_server(authority_type_t type, int flags); @@ -35,6 +36,7 @@ int router_get_my_share_of_directory_requests(double *v2_share_out, void router_reset_status_download_failures(void); void routerlist_add_family(smartlist_t *sl, routerinfo_t *router); int routers_in_same_family(routerinfo_t *r1, routerinfo_t *r2); +int routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2); void add_nickname_list_to_smartlist(smartlist_t *sl, const char *list, int must_be_running); int router_nickname_is_in_list(routerinfo_t *router, const char *list); @@ -115,6 +117,7 @@ was_router_added_t router_add_to_routerlist(routerinfo_t *router, was_router_added_t router_add_extrainfo_to_routerlist( extrainfo_t *ei, const char **msg, int from_cache, int from_fetch); +void routerlist_descriptors_added(smartlist_t *sl, int from_cache); void routerlist_remove_old_routers(void); int router_load_single_router(const char *s, uint8_t purpose, int cache, const char **msg); diff --git a/src/test/tinytest.c b/src/test/tinytest.c index b453308121..11ffc2fe56 100644 --- a/src/test/tinytest.c +++ b/src/test/tinytest.c @@ -1,4 +1,4 @@ -/* tinytest.c -- Copyright 2009 Nick Mathewson +/* tinytest.c -- Copyright 2009-2010 Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,6 +40,9 @@ #define __attribute__(x) #endif +#ifdef TINYTEST_LOCAL +#include "tinytest_local.h" +#endif #include "tinytest.h" #include "tinytest_macros.h" @@ -58,7 +61,7 @@ const char *verbosity_flag = ""; enum outcome { SKIP=2, OK=1, FAIL=0 }; static enum outcome cur_test_outcome = 0; const char *cur_test_prefix = NULL; /**< prefix of the current test group */ -/** Name of the current test, if we haven't logged is yet. Used for --quiet */ +/** Name of the current test, if we haven't logged is yet. Used for --quiet */ const char *cur_test_name = NULL; #ifdef WIN32 @@ -76,7 +79,7 @@ _testcase_run_bare(const struct testcase_t *testcase) int outcome; if (testcase->setup) { env = testcase->setup->setup_fn(testcase); - if (!env) + if (!env) return FAIL; else if (env == (void*)TT_SKIP) return SKIP; @@ -149,7 +152,7 @@ _testcase_run_forked(const struct testgroup_t *group, #else int outcome_pipe[2]; pid_t pid; - (void)group; + (void)group; if (pipe(outcome_pipe)) perror("opening pipe"); @@ -165,7 +168,7 @@ _testcase_run_forked(const struct testgroup_t *group, test_r = _testcase_run_bare(testcase); assert(0<=(int)test_r && (int)test_r<=2); b[0] = "NYS"[test_r]; - write_r = (int)write(outcome_pipe[1], b, 1); + write_r = (int)write(outcome_pipe[1], b, 1); if (write_r != 1) { perror("write outcome to pipe"); exit(1); @@ -217,7 +220,7 @@ testcase_run_one(const struct testgroup_t *group, if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) { outcome = _testcase_run_forked(group, testcase); } else { - outcome = _testcase_run_bare(testcase); + outcome = _testcase_run_bare(testcase); } if (outcome == OK) { @@ -270,6 +273,7 @@ usage(struct testgroup_t *groups, int list_groups) { puts("Options are: [--verbose|--quiet|--terse] [--no-fork]"); puts(" Specify tests by name, or using a prefix ending with '..'"); + puts(" To skip a test, list give its name prefixed with a colon."); puts(" Use --list-tests for a list of tests."); if (list_groups) { puts("Known tests are:"); @@ -310,8 +314,15 @@ tinytest_main(int c, const char **v, struct testgroup_t *groups) return -1; } } else { - ++n; - if (!_tinytest_set_flag(groups, v[i], _TT_ENABLED)) { + const char *test = v[i]; + int flag = _TT_ENABLED; + if (test[0] == ':') { + ++test; + flag = TT_SKIP; + } else { + ++n; + } + if (!_tinytest_set_flag(groups, test, flag)) { printf("No such test as %s!\n", v[i]); return -1; } diff --git a/src/test/tinytest.h b/src/test/tinytest.h index a0cb913138..cbe28b7f51 100644 --- a/src/test/tinytest.h +++ b/src/test/tinytest.h @@ -1,4 +1,4 @@ -/* tinytest.h -- Copyright 2009 Nick Mathewson +/* tinytest.h -- Copyright 2009-2010 Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/src/test/tinytest_macros.h b/src/test/tinytest_macros.h index 48c1fbdfb8..a7fa64a824 100644 --- a/src/test/tinytest_macros.h +++ b/src/test/tinytest_macros.h @@ -1,4 +1,4 @@ -/* tinytest_macros.h -- Copyright 2009 Nick Mathewson +/* tinytest_macros.h -- Copyright 2009-2010 Nick Mathewson * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,7 +28,7 @@ /* Helpers for defining statement-like macros */ #define TT_STMT_BEGIN do { -#define TT_STMT_END } while(0) +#define TT_STMT_END } while (0) /* Redefine this if your test functions want to abort with something besides * "goto end;" */ @@ -45,7 +45,7 @@ TT_STMT_END #endif -/* Announce a failure. Args are parenthesized printf args. */ +/* Announce a failure. Args are parenthesized printf args. */ #define TT_GRIPE(args) TT_DECLARE("FAIL", args) /* Announce a non-failure if we're verbose. */ @@ -80,7 +80,7 @@ #define tt_fail() TT_FAIL(("%s", "(Failed.)")) /* End the current test, and indicate we are skipping it. */ -#define tt_skip() \ +#define tt_skip() \ TT_STMT_BEGIN \ _tinytest_set_test_skipped(); \ TT_EXIT_TEST_FUNCTION; \ @@ -111,7 +111,7 @@ #define tt_assert(b) tt_assert_msg((b), "assert("#b")") #define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \ - setup_block,cleanup_block) \ + setup_block,cleanup_block) \ TT_STMT_BEGIN \ type _val1 = (type)(a); \ type _val2 = (type)(b); \ @@ -126,7 +126,7 @@ _value = _val2; \ setup_block; \ _print2 = _print; \ - TT_DECLARE(_tt_status?" OK":"FAIL", \ + TT_DECLARE(_tt_status?" OK":"FAIL", \ ("assert(%s): "printf_fmt" vs "printf_fmt, \ str_test, _print1, _print2)); \ _print = _print1; \ diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h index 427ca01ae9..cedfd20f92 100644 --- a/src/win32/orconfig.h +++ b/src/win32/orconfig.h @@ -233,5 +233,5 @@ #define USING_TWOS_COMPLEMENT /* Version number of package */ -#define VERSION "0.2.2.15-alpha-dev" +#define VERSION "0.2.2.16-alpha-dev" |