From 3a7cee9d2984126ef8378657d6200f711eb58517 Mon Sep 17 00:00:00 2001 From: Erinn Clark Date: Tue, 15 Feb 2011 02:15:42 +0100 Subject: [PATCH 1/4] Fix configure.in zlib package names. --- changes/zlib_aint_openssl | 3 +++ configure.in | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 changes/zlib_aint_openssl 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 7cdb330b42..1fddacaada 100644 --- a/configure.in +++ b/configure.in @@ -336,10 +336,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 ], From 5eaba5ac2128eebf095441e23b6b7516ce35dd5d Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 30 Mar 2011 14:29:57 -0400 Subject: [PATCH 2/4] Implement replacements for timer(add,cmp,sub) on platforms lacking them. --- src/common/compat.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/common/compat.h b/src/common/compat.h index 35829e18b4..550c08b533 100644 --- a/src/common/compat.h +++ b/src/common/compat.h @@ -333,6 +333,48 @@ 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 +#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 replace_file(const char *from, const char *to); int touch_file(const char *fname); From aa950e6c48471f00ff9497fa4e9fad1c71e75868 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 26 Mar 2011 01:34:42 -0400 Subject: [PATCH 3/4] Use timevals, not time_t, when expiring circuits. We've got millisecond timers now, we might as well use them. This change won't actually make circuits get expiered with microsecond precision, since we only call the expiry functions once per second. Still, it should avoid the situation where we have a circuit get expired too early because of rounding. A couple of the expiry functions now call tor_gettimeofday: this should be cheap since we're only doing it once per second. If it gets to be called more often, though, we should onsider having the current time be an argument again. --- changes/cbt_hi_res | 7 ++++ src/or/circuitbuild.c | 2 +- src/or/circuitlist.c | 8 ++--- src/or/circuituse.c | 81 ++++++++++++++++++++++++++----------------- src/or/circuituse.h | 2 +- src/or/main.c | 4 ++- src/or/or.h | 3 +- src/or/rephist.c | 4 +-- 8 files changed, 69 insertions(+), 42 deletions(-) create mode 100644 changes/cbt_hi_res 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/src/or/circuitbuild.c b/src/or/circuitbuild.c index 83ac7a5a19..37b761f99b 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -2041,7 +2041,7 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) struct timeval end; long timediff; tor_gettimeofday(&end); - timediff = tv_mdiff(&circ->_base.highres_created, &end); + timediff = tv_mdiff(&circ->_base.timestamp_created, &end); /* * If the circuit build time is much greater than we would have cut diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index b4f5f45615..d1fea37c25 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -398,8 +398,7 @@ circuit_initial_package_window(void) static void init_circuit_base(circuit_t *circ) { - circ->timestamp_created = time(NULL); - tor_gettimeofday(&circ->highres_created); + tor_gettimeofday(&circ->timestamp_created); circ->package_window = circuit_initial_package_window(); circ->deliver_window = CIRCWINDOW_START; @@ -609,9 +608,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); + circuit_state_to_string(circ->state), + (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 8d9d115863..ac4bba51f8 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -31,7 +31,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 circ could be returned by circuit_get_best(). @@ -162,7 +162,7 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose) return 1; } else { if (a->timestamp_dirty || - 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) @@ -223,7 +223,7 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose, #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 + REND_PARALLEL_INTRO_DELAY < now) { + circ->timestamp_created.tv_sec + REND_PARALLEL_INTRO_DELAY < now) { intro_going_on_but_too_old = 1; continue; } @@ -275,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 */ @@ -312,7 +328,7 @@ circuit_expire_building(time_t now) else cutoff = general_cutoff; - if (victim->timestamp_created > cutoff) + if (timercmp(&victim->timestamp_created, &cutoff, >)) continue; /* it's still young, leave it alone */ #if 0 @@ -358,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: @@ -367,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; } @@ -407,15 +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 > 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), + (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)) { + victim->timestamp_created.tv_sec)) { circuit_build_times_set_timeout(&circ_times); } } @@ -636,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); @@ -725,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) { @@ -745,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 < 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 || @@ -762,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)); + "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 @@ -775,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_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 */ @@ -1123,7 +1142,7 @@ circuit_launch_by_extend_info(uint8_t purpose, /* reset the birth date of this circ, else expire_building * will see it and think it's been trying to build since it * began. */ - circ->_base.timestamp_created = time(NULL); + tor_gettimeofday(&circ->_base.timestamp_created); switch (purpose) { case CIRCUIT_PURPOSE_C_ESTABLISH_REND: case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: diff --git a/src/or/circuituse.h b/src/or/circuituse.h index 1a604b415f..a121099aca 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 214a4fad5d..83d1e1e517 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1150,7 +1150,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. diff --git a/src/or/or.h b/src/or/or.h index e3e01cff55..3cadd3173e 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -2126,10 +2126,9 @@ typedef struct circuit_t { * length ONIONSKIN_CHALLENGE_LEN. */ char *n_conn_onionskin; - time_t timestamp_created; /**< When was this circuit created? */ + struct timeval timestamp_created; /**< When was the circuit created? */ time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the * circuit is clean. */ - struct timeval highres_created; /**< When exactly was the circuit created? */ uint16_t marked_for_close; /**< Should we close this circuit at the end of * the main loop? (If true, holds the line number diff --git a/src/or/rephist.c b/src/or/rephist.c index 58e8ff0a05..06704cf817 100644 --- a/src/or/rephist.c +++ b/src/or/rephist.c @@ -2356,9 +2356,9 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval) return; if (!circuits_for_buffer_stats) circuits_for_buffer_stats = smartlist_create(); - start_of_interval = circ->timestamp_created > + start_of_interval = circ->timestamp_created.tv_sec > start_of_buffer_stats_interval ? - circ->timestamp_created : + circ->timestamp_created.tv_sec : start_of_buffer_stats_interval; interval_length = (int) (end_of_interval - start_of_interval); stat = tor_malloc_zero(sizeof(circ_buffer_stats_t)); From 65eb0e41ac05fd65bf8bef87426886fec45f7ca4 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 26 Mar 2011 01:39:11 -0400 Subject: [PATCH 4/4] Use cbt to tell when to launch parallel intro circuit Implement feature from trac #2799 --- changes/cbt_parallel_intro | 4 ++++ src/or/circuituse.c | 13 ++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 changes/cbt_parallel_intro 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/src/or/circuituse.c b/src/or/circuituse.c index ac4bba51f8..447ec8412d 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -204,7 +204,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); @@ -213,17 +213,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) { + !must_be_open && circ->state != CIRCUIT_STATE_OPEN && + tv_mdiff(&now, &circ->timestamp_created) > circ_times.timeout_ms) { intro_going_on_but_too_old = 1; continue; }