|  | @@ -284,6 +284,8 @@ circuit_expire_building(time_t now)
 | 
	
		
			
				|  |  |     * decided on a customized one yet */
 | 
	
		
			
				|  |  |    time_t general_cutoff = now - lround(circ_times.timeout_ms/1000);
 | 
	
		
			
				|  |  |    time_t begindir_cutoff = now - lround(circ_times.timeout_ms/2000);
 | 
	
		
			
				|  |  | +  time_t fourhop_cutoff = now - lround(4*circ_times.timeout_ms/3000);
 | 
	
		
			
				|  |  | +  time_t cannibalize_cutoff = now - lround(circ_times.timeout_ms/2000);
 | 
	
		
			
				|  |  |    time_t close_cutoff = now - lround(circ_times.close_ms/1000);
 | 
	
		
			
				|  |  |    time_t introcirc_cutoff = begindir_cutoff;
 | 
	
		
			
				|  |  |    cpath_build_state_t *build_state;
 | 
	
	
		
			
				|  | @@ -299,6 +301,11 @@ circuit_expire_building(time_t now)
 | 
	
		
			
				|  |  |      build_state = TO_ORIGIN_CIRCUIT(victim)->build_state;
 | 
	
		
			
				|  |  |      if (build_state && build_state->onehop_tunnel)
 | 
	
		
			
				|  |  |        cutoff = begindir_cutoff;
 | 
	
		
			
				|  |  | +    else if (build_state && build_state->desired_path_len == 4
 | 
	
		
			
				|  |  | +             && !TO_ORIGIN_CIRCUIT(victim)->has_opened)
 | 
	
		
			
				|  |  | +      cutoff = fourhop_cutoff;
 | 
	
		
			
				|  |  | +    else if (TO_ORIGIN_CIRCUIT(victim)->has_opened)
 | 
	
		
			
				|  |  | +      cutoff = cannibalize_cutoff;
 | 
	
		
			
				|  |  |      else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING)
 | 
	
		
			
				|  |  |        cutoff = introcirc_cutoff;
 | 
	
		
			
				|  |  |      else if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
 | 
	
	
		
			
				|  | @@ -378,29 +385,36 @@ circuit_expire_building(time_t now)
 | 
	
		
			
				|  |  |          continue;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      /* circuits are allowed to last longer for measurement.
 | 
	
		
			
				|  |  | -       * Switch their purpose and wait. */
 | 
	
		
			
				|  |  | -      if (victim->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
 | 
	
		
			
				|  |  | -        victim->purpose = CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT;
 | 
	
		
			
				|  |  | -        circuit_build_times_count_timeout(&circ_times,
 | 
	
		
			
				|  |  | -                                          first_hop_succeeded);
 | 
	
		
			
				|  |  | -        continue;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +      if (circuit_timeout_want_to_count_circ(TO_ORIGIN_CIRCUIT(victim))) {
 | 
	
		
			
				|  |  | +        /* Circuits are allowed to last longer for measurement.
 | 
	
		
			
				|  |  | +         * Switch their purpose and wait. */
 | 
	
		
			
				|  |  | +        if (victim->purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) {
 | 
	
		
			
				|  |  | +          victim->purpose = CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT;
 | 
	
		
			
				|  |  | +          /* Record this failure to check for too many timeouts
 | 
	
		
			
				|  |  | +           * in a row. This function does not record a time value yet
 | 
	
		
			
				|  |  | +           * (we do that later); it only counts the fact that we did
 | 
	
		
			
				|  |  | +           * have a timeout. */
 | 
	
		
			
				|  |  | +          circuit_build_times_count_timeout(&circ_times,
 | 
	
		
			
				|  |  | +                                            first_hop_succeeded);
 | 
	
		
			
				|  |  | +          continue;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      /*
 | 
	
		
			
				|  |  | -       * If the circuit build time is much greater than we would have cut
 | 
	
		
			
				|  |  | -       * 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) {
 | 
	
		
			
				|  |  | -        log_notice(LD_CIRC,
 | 
	
		
			
				|  |  | -                   "Extremely large value for circuit build timeout: %lds. "
 | 
	
		
			
				|  |  | -                   "Assuming clock jump.",
 | 
	
		
			
				|  |  | -                   (long)(now - victim->timestamp_created));
 | 
	
		
			
				|  |  | -      } else if (circuit_build_times_count_close(&circ_times,
 | 
	
		
			
				|  |  | -                                          first_hop_succeeded,
 | 
	
		
			
				|  |  | -                                          victim->timestamp_created)) {
 | 
	
		
			
				|  |  | -        circuit_build_times_set_timeout(&circ_times);
 | 
	
		
			
				|  |  | +        /*
 | 
	
		
			
				|  |  | +         * If the circuit build time is much greater than we would have cut
 | 
	
		
			
				|  |  | +         * 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) {
 | 
	
		
			
				|  |  | +          log_notice(LD_CIRC,
 | 
	
		
			
				|  |  | +                     "Extremely large value for circuit build timeout: %lds. "
 | 
	
		
			
				|  |  | +                     "Assuming clock jump. Purpose %d",
 | 
	
		
			
				|  |  | +                     (long)(now - victim->timestamp_created),
 | 
	
		
			
				|  |  | +                      victim->purpose);
 | 
	
		
			
				|  |  | +        } else if (circuit_build_times_count_close(&circ_times,
 | 
	
		
			
				|  |  | +                                            first_hop_succeeded,
 | 
	
		
			
				|  |  | +                                            victim->timestamp_created)) {
 | 
	
		
			
				|  |  | +          circuit_build_times_set_timeout(&circ_times);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -903,6 +917,11 @@ circuit_has_opened(origin_circuit_t *circ)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    control_event_circuit_status(circ, CIRC_EVENT_BUILT, 0);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  /* Remember that this circuit has finished building. Now if we start
 | 
	
		
			
				|  |  | +   * it building again later (e.g. by extending it), we will know not
 | 
	
		
			
				|  |  | +   * to consider its build time. */
 | 
	
		
			
				|  |  | +  circ->has_opened = 1;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    switch (TO_CIRCUIT(circ)->purpose) {
 | 
	
		
			
				|  |  |      case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
 | 
	
		
			
				|  |  |        rend_client_rendcirc_has_opened(circ);
 |