diff options
-rw-r--r-- | changes/cbt_hi_res | 7 | ||||
-rw-r--r-- | changes/cbt_parallel_intro | 4 | ||||
-rw-r--r-- | changes/zlib_aint_openssl | 3 | ||||
-rw-r--r-- | configure.in | 8 | ||||
-rw-r--r-- | src/common/compat.h | 47 | ||||
-rw-r--r-- | src/or/circuitlist.c | 4 | ||||
-rw-r--r-- | src/or/circuituse.c | 91 | ||||
-rw-r--r-- | src/or/circuituse.h | 2 | ||||
-rw-r--r-- | src/or/main.c | 4 |
9 files changed, 119 insertions, 51 deletions
diff --git a/changes/cbt_hi_res b/changes/cbt_hi_res new file mode 100644 index 0000000000..c0df1183cb --- /dev/null +++ b/changes/cbt_hi_res @@ -0,0 +1,7 @@ + o Minor features + - When expiring circuits, use microsecond timers rather than one-second + timers. This can avoid an unpleasant situation where a circuit is + launched near the end of one second and expired right near the + beginning of the next, and prevent fluctuations in circuit timeout + values. + diff --git a/changes/cbt_parallel_intro b/changes/cbt_parallel_intro new file mode 100644 index 0000000000..44e377fb3f --- /dev/null +++ b/changes/cbt_parallel_intro @@ -0,0 +1,4 @@ + o Minor features + - Use computed circuit-build timeouts to decide when to launch + parallel introdution circuits. (Previously, we would retry + after 15 seconds.) diff --git a/changes/zlib_aint_openssl b/changes/zlib_aint_openssl new file mode 100644 index 0000000000..dd8e10a328 --- /dev/null +++ b/changes/zlib_aint_openssl @@ -0,0 +1,3 @@ + o Minor bugfixes + - When warning about missing zlib development packages, give the + correct package names. Bugfix on 0.2.0.1-alpha. diff --git a/configure.in b/configure.in index 5b9f093697..83fd0449b9 100644 --- a/configure.in +++ b/configure.in @@ -492,10 +492,10 @@ AC_SUBST(TOR_OPENSSL_LIBS) dnl ------------------------------------------------------ dnl Where do you live, zlib? And how do we call you? -tor_openssl_pkg_redhat="zlib" -tor_openssl_pkg_debian="zlib1g" -tor_openssl_devpkg_redhat="zlib-devel" -tor_openssl_devpkg_debian="zlib1g-dev" +tor_zlib_pkg_redhat="zlib" +tor_zlib_pkg_debian="zlib1g" +tor_zlib_devpkg_redhat="zlib-devel" +tor_zlib_devpkg_debian="zlib1g-dev" TOR_SEARCH_LIBRARY(zlib, $tryzlibdir, [-lz], [#include <zlib.h>], diff --git a/src/common/compat.h b/src/common/compat.h index db352de9ee..6d2565ac19 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -335,12 +335,47 @@ struct tm *tor_localtime_r(const time_t *timep, struct tm *result); struct tm *tor_gmtime_r(const time_t *timep, struct tm *result); #endif -/** Return true iff the tvp is related to uvp according to the relational - * operator cmp. Recognized values for cmp are ==, <=, <, >=, and >. */ -#define tor_timercmp(tvp, uvp, cmp) \ - (((tvp)->tv_sec == (uvp)->tv_sec) ? \ - ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ - ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#ifndef timeradd +/** Replacement for timeradd on platforms that do not have it: sets tvout to + * the sum of tv1 and tv2. */ +#define timeradd(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ + (tvout)->tv_usec = (tv2)->tv_usec + (tv2)->tv_usec; \ + if ((tvout)->tv_usec >= 1000000) { \ + (tvout)->tv_usec -= 1000000; \ + (tvout)->tv_sec++; \ + } \ + } while (0) +#endif + +#ifndef timersub +/** Replacement for timersub on platforms that do not have it: sets tvout to + * tv1 minus tv2. */ +#define timersub(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \ + (tvout)->tv_usec = (tv2)->tv_usec - (tv2)->tv_usec; \ + if ((tvout)->tv_usec < 0) { \ + (tvout)->tv_usec += 1000000; \ + (tvout)->tv_sec--; \ + } \ + } while (0) +#endif + +#ifndef timercmp +/** Replacement for timersub on platforms that do not have it: returns true + * iff the relational operator "op" makes the expression tv1 op tv2 true. + * + * Note that while this definition should work for all boolean opeators, some + * platforms' native timercmp definitions do not support >=, <=, or ==. So + * don't use those. + */ +#define timercmp(tv1,tv2,op) \ + (((tv1)->tv_sec == (tv2)->tv_sec) ? \ + ((tv1)->tv_usec op (tv2)->tv_usec) : \ + ((tv1)->tv_sec op (tv2)->tv_sec)) +#endif /* ===== File compatibility */ int tor_open_cloexec(const char *path, int flags, unsigned mode); diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index d5c74ee7b6..a0359dbdce 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -606,10 +606,10 @@ circuit_dump_details(int severity, circuit_t *circ, int conn_array_index, const char *type, int this_circid, int other_circid) { log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), " - "state %d (%s), born %d:", + "state %d (%s), born %ld:", conn_array_index, type, this_circid, other_circid, circ->state, circuit_state_to_string(circ->state), - (int)circ->timestamp_created.tv_sec); + (long)circ->timestamp_created.tv_sec); if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */ circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ)); } diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 3beb267ea7..faad49c4e5 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -32,7 +32,7 @@ extern circuit_t *global_circuitlist; /* from circuitlist.c */ /********* END VARIABLES ************/ -static void circuit_expire_old_circuits_clientside(time_t now); +static void circuit_expire_old_circuits_clientside(void); static void circuit_increment_failure_count(void); /** Return 1 if <b>circ</b> could be returned by circuit_get_best(). @@ -163,7 +163,7 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose) return 1; } else { if (a->timestamp_dirty || - tor_timercmp(&a->timestamp_created, &b->timestamp_created, >)) + timercmp(&a->timestamp_created, &b->timestamp_created, >)) return 1; if (CIRCUIT_IS_ORIGIN(b) && TO_ORIGIN_CIRCUIT(b)->build_state->is_internal) @@ -205,7 +205,7 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose, int need_uptime, int need_internal) { circuit_t *circ, *best=NULL; - time_t now = time(NULL); + struct timeval now; int intro_going_on_but_too_old = 0; tor_assert(conn); @@ -214,17 +214,16 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose, purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT || purpose == CIRCUIT_PURPOSE_C_REND_JOINED); + tor_gettimeofday(&now); + for (circ=global_circuitlist;circ;circ = circ->next) { if (!circuit_is_acceptable(circ,conn,must_be_open,purpose, - need_uptime,need_internal,now)) + need_uptime,need_internal,now.tv_sec)) continue; -/* XXX022 make this 15 be a function of circuit finishing times we've - * seen lately, a la Fallon Chen's GSoC work -RD */ -#define REND_PARALLEL_INTRO_DELAY 15 if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT && !must_be_open && circ->state != CIRCUIT_STATE_OPEN && - circ->timestamp_created.tv_sec + REND_PARALLEL_INTRO_DELAY < now) { + tv_mdiff(&now, &circ->timestamp_created) > circ_times.timeout_ms) { intro_going_on_but_too_old = 1; continue; } @@ -276,22 +275,38 @@ circuit_conforms_to_options(const origin_circuit_t *circ, * at least CircuitBuildTimeout seconds ago. */ void -circuit_expire_building(time_t now) +circuit_expire_building(void) { circuit_t *victim, *next_circ = global_circuitlist; /* circ_times.timeout_ms and circ_times.close_ms are from * circuit_build_times_get_initial_timeout() if we haven't computed * custom timeouts yet */ - time_t general_cutoff = now - tor_lround(circ_times.timeout_ms/1000); - time_t begindir_cutoff = now - tor_lround(circ_times.timeout_ms/2000); - time_t fourhop_cutoff = now - tor_lround(4*circ_times.timeout_ms/3000); - time_t cannibalize_cutoff = now - tor_lround(circ_times.timeout_ms/2000); - time_t close_cutoff = now - tor_lround(circ_times.close_ms/1000); - time_t introcirc_cutoff = begindir_cutoff; + struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff, + cannibalize_cutoff, close_cutoff, extremely_old_cutoff; + struct timeval now; + struct timeval introcirc_cutoff; cpath_build_state_t *build_state; + tor_gettimeofday(&now); +#define SET_CUTOFF(target, msec) do { \ + long ms = tor_lround(msec); \ + struct timeval diff; \ + diff.tv_sec = ms / 1000; \ + diff.tv_usec = (ms % 1000) * 1000; \ + timersub(&now, &diff, &target); \ + } while (0) + + SET_CUTOFF(general_cutoff, circ_times.timeout_ms); + SET_CUTOFF(begindir_cutoff, circ_times.timeout_ms / 2.0); + SET_CUTOFF(fourhop_cutoff, circ_times.timeout_ms * (4/3.0)); + SET_CUTOFF(cannibalize_cutoff, circ_times.timeout_ms / 2.0); + SET_CUTOFF(close_cutoff, circ_times.close_ms); + SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000); + + introcirc_cutoff = begindir_cutoff; + while (next_circ) { - time_t cutoff; + struct timeval cutoff; victim = next_circ; next_circ = next_circ->next; if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */ @@ -313,7 +328,7 @@ circuit_expire_building(time_t now) else cutoff = general_cutoff; - if (victim->timestamp_created.tv_sec > cutoff) + if (timercmp(&victim->timestamp_created, &cutoff, >)) continue; /* it's still young, leave it alone */ #if 0 @@ -359,7 +374,7 @@ circuit_expire_building(time_t now) * because that's set when they switch purposes */ if (TO_ORIGIN_CIRCUIT(victim)->rend_data || - victim->timestamp_dirty > cutoff) + victim->timestamp_dirty > cutoff.tv_sec) continue; break; case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: @@ -368,7 +383,7 @@ circuit_expire_building(time_t now) * make an introduction attempt. so timestamp_dirty * will reflect the time since the last attempt. */ - if (victim->timestamp_dirty > cutoff) + if (victim->timestamp_dirty > cutoff.tv_sec) continue; break; } @@ -408,16 +423,15 @@ circuit_expire_building(time_t now) * it off at, we probably had a suspend event along this codepath, * and we should discard the value. */ - if (now - victim->timestamp_created.tv_sec > - 2*circ_times.close_ms/1000+1) { + if (timercmp(&victim->timestamp_created, &extremely_old_cutoff, <)) { log_notice(LD_CIRC, "Extremely large value for circuit build timeout: %lds. " "Assuming clock jump. Purpose %d", - (long)(now - victim->timestamp_created.tv_sec), + (long)(now.tv_sec - victim->timestamp_created.tv_sec), victim->purpose); } else if (circuit_build_times_count_close(&circ_times, - first_hop_succeeded, - victim->timestamp_created.tv_sec)) { + first_hop_succeeded, + victim->timestamp_created.tv_sec)) { circuit_build_times_set_timeout(&circ_times); } } @@ -638,7 +652,7 @@ circuit_build_needed_circs(time_t now) time_to_new_circuit = now + options->NewCircuitPeriod; if (proxy_mode(get_options())) addressmap_clean(now); - circuit_expire_old_circuits_clientside(now); + circuit_expire_old_circuits_clientside(); #if 0 /* disable for now, until predict-and-launch-new can cull leftovers */ circ = circuit_get_youngest_clean_open(CIRCUIT_PURPOSE_C_GENERAL); @@ -727,17 +741,20 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn) * for too long and has no streams on it: mark it for close. */ static void -circuit_expire_old_circuits_clientside(time_t now) +circuit_expire_old_circuits_clientside(void) { circuit_t *circ; - time_t cutoff; + struct timeval cutoff, now; + + tor_gettimeofday(&now); + cutoff = now; if (circuit_build_times_needs_circuits(&circ_times)) { /* Circuits should be shorter lived if we need more of them * for learning a good build timeout */ - cutoff = now - IDLE_TIMEOUT_WHILE_LEARNING; + cutoff.tv_sec -= IDLE_TIMEOUT_WHILE_LEARNING; } else { - cutoff = now - get_options()->CircuitIdleTimeout; + cutoff.tv_sec -= get_options()->CircuitIdleTimeout; } for (circ = global_circuitlist; circ; circ = circ->next) { @@ -747,15 +764,15 @@ circuit_expire_old_circuits_clientside(time_t now) * on it, mark it for close. */ if (circ->timestamp_dirty && - circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now && + circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now.tv_sec && !TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) { - log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %d secs ago, " + log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %ld sec ago, " "purpose %d)", - circ->n_circ_id, (int)(now - circ->timestamp_dirty), + circ->n_circ_id, (long)(now.tv_sec - circ->timestamp_dirty), circ->purpose); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) { - if (circ->timestamp_created.tv_sec < cutoff) { + if (timercmp(&circ->timestamp_created, &cutoff, <)) { if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL || circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT || circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || @@ -764,8 +781,8 @@ circuit_expire_old_circuits_clientside(time_t now) circ->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) || circ->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { log_debug(LD_CIRC, - "Closing circuit that has been unused for %ld seconds.", - (long)(now - circ->timestamp_created.tv_sec)); + "Closing circuit that has been unused for %ld msec.", + tv_mdiff(&circ->timestamp_created, &now)); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } else if (!TO_ORIGIN_CIRCUIT(circ)->is_ancient) { /* Server-side rend joined circuits can end up really old, because @@ -777,9 +794,9 @@ circuit_expire_old_circuits_clientside(time_t now) circ->purpose != CIRCUIT_PURPOSE_S_INTRO) { log_notice(LD_CIRC, "Ancient non-dirty circuit %d is still around after " - "%ld seconds. Purpose: %d", + "%ld milliseconds. Purpose: %d", TO_ORIGIN_CIRCUIT(circ)->global_identifier, - (long)(now - circ->timestamp_created.tv_sec), + tv_mdiff(&circ->timestamp_created, &now), circ->purpose); /* FFFF implement a new circuit_purpose_to_string() so we don't * just print out a number for circ->purpose */ diff --git a/src/or/circuituse.h b/src/or/circuituse.h index 9f0e9d575f..c81d6da23f 100644 --- a/src/or/circuituse.h +++ b/src/or/circuituse.h @@ -12,7 +12,7 @@ #ifndef _TOR_CIRCUITUSE_H #define _TOR_CIRCUITUSE_H -void circuit_expire_building(time_t now); +void circuit_expire_building(void); void circuit_remove_handled_ports(smartlist_t *needed_ports); int circuit_stream_is_being_handled(edge_connection_t *conn, uint16_t port, int min); diff --git a/src/or/main.c b/src/or/main.c index 9c19485990..a9d1c9150e 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1344,7 +1344,9 @@ run_scheduled_events(time_t now) * We do this before step 4, so it can try building more if * it's not comfortable with the number of available circuits. */ - circuit_expire_building(now); + /* XXXX022 If our circuit build timeout is much lower than a second, maybe + we should do this more often? */ + circuit_expire_building(); /** 3b. Also look at pending streams and prune the ones that 'began' * a long time ago but haven't gotten a 'connected' yet. |