Browse Source

Merge remote-tracking branch 'origin/maint-0.2.2'

Conflicts:
	src/common/compat.h
	src/or/circuitlist.c
	src/or/circuituse.c
	src/or/or.h
	src/or/rephist.c
Nick Mathewson 13 years ago
parent
commit
ee871e7a0e

+ 7 - 0
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.
+

+ 4 - 0
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.)

+ 3 - 0
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.

+ 4 - 4
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>],

+ 41 - 6
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);

+ 2 - 2
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));
   }

+ 54 - 37
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 */

+ 1 - 1
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);

+ 3 - 1
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.