Loading changes/bug1297b 0 → 100644 +12 −0 Original line number Diff line number Diff line o Minor bugfixes: - Don't close hidden service client circuits which have almost finished connecting to their destination when they reach the normal circuit-build timeout. Previously, we would close introduction circuits which are waiting for an acknowledgement from the introduction-point relay and rendezvous circuits which have been specified in an INTRODUCE1 cell sent to a hidden service after the normal CBT; now, we mark them as 'timed out', and launch another rendezvous attempt in parallel. Fixes part of bug 1297. src/or/circuituse.c +52 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,11 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; } /* If this is a timed-out hidden service circuit, skip it. */ if (origin_circ->hs_circ_has_timed_out) { return 0; } if (purpose == CIRCUIT_PURPOSE_C_GENERAL || purpose == CIRCUIT_PURPOSE_C_REND_JOINED) if (circ->timestamp_dirty && Loading Loading @@ -351,7 +356,9 @@ circuit_expire_building(void) * circuit_build_times_get_initial_timeout() if we haven't computed * custom timeouts yet */ struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff, cannibalize_cutoff, close_cutoff, extremely_old_cutoff; cannibalize_cutoff, close_cutoff, extremely_old_cutoff, hs_extremely_old_cutoff; const or_options_t *options = get_options(); struct timeval now; cpath_build_state_t *build_state; Loading @@ -371,6 +378,10 @@ circuit_expire_building(void) SET_CUTOFF(close_cutoff, circ_times.close_ms); SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000); SET_CUTOFF(hs_extremely_old_cutoff, MAX(circ_times.close_ms*2 + 1000, options->SocksTimeout * 1000)); while (next_circ) { struct timeval cutoff; victim = next_circ; Loading @@ -392,6 +403,9 @@ circuit_expire_building(void) else cutoff = general_cutoff; if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) cutoff = hs_extremely_old_cutoff; if (timercmp(&victim->timestamp_created, &cutoff, >)) continue; /* it's still young, leave it alone */ Loading Loading @@ -497,6 +511,43 @@ circuit_expire_building(void) } } /* If this is a hidden-service circuit which is far enough along * in connecting to its destination, and we haven't already * flagged it as 'timed out', flag it as 'timed out' so we'll * launch another intro or rend circ, but don't mark it for close * yet. * * (Circs flagged as 'timed out' are given a much longer timeout * period above, so we won't close them in the next call to * circuit_expire_building.) */ if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) { switch (victim->purpose) { case CIRCUIT_PURPOSE_C_REND_READY: /* We only want to spare a rend circ if it has been specified in * an INTRODUCE1 cell sent to a hidden service. A circ's * pending_final_cpath field is non-NULL iff it is a rend circ * and we have tried to send an INTRODUCE1 cell specifying it. * Thus, if the pending_final_cpath field *is* NULL, then we * want to not spare it. */ if (TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath == NULL) break; case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: /* If we have reached this line, we want to spare the circ for now. */ log_info(LD_CIRC,"Marking circ %s:%d:%d (state %d:%s, purpose %d) " "as timed-out HS circ", victim->n_conn->_base.address, victim->n_conn->_base.port, victim->n_circ_id, victim->state, circuit_state_to_string(victim->state), victim->purpose); TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1; continue; default: break; } } if (victim->n_conn) log_info(LD_CIRC,"Abandoning circ %s:%d:%d (state %d:%s, purpose %d)", victim->n_conn->_base.address, victim->n_conn->_base.port, Loading src/or/or.h +7 −0 Original line number Diff line number Diff line Loading @@ -2607,6 +2607,13 @@ typedef struct origin_circuit_t { * cannibalized circuits. */ unsigned int has_opened : 1; /** Set iff this is a hidden-service circuit which has timed out * according to our current circuit-build timeout, but which has * been kept around because it might still succeed in connecting to * its destination, and which is not a fully-connected rendezvous * circuit. */ unsigned int hs_circ_has_timed_out : 1; /** What commands were sent over this circuit that decremented the * RELAY_EARLY counter? This is for debugging task 878. */ uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT]; Loading src/or/rendclient.c +5 −0 Original line number Diff line number Diff line Loading @@ -895,6 +895,11 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request, hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; /* Now that this circuit has finished connecting to its destination, * make sure circuit_get_open_circ_or_launch is willing to return it * so we can actually use it. */ circ->hs_circ_has_timed_out = 0; onion_append_to_cpath(&circ->cpath, hop); circ->build_state->pending_final_cpath = NULL; /* prevent double-free */ Loading Loading
changes/bug1297b 0 → 100644 +12 −0 Original line number Diff line number Diff line o Minor bugfixes: - Don't close hidden service client circuits which have almost finished connecting to their destination when they reach the normal circuit-build timeout. Previously, we would close introduction circuits which are waiting for an acknowledgement from the introduction-point relay and rendezvous circuits which have been specified in an INTRODUCE1 cell sent to a hidden service after the normal CBT; now, we mark them as 'timed out', and launch another rendezvous attempt in parallel. Fixes part of bug 1297.
src/or/circuituse.c +52 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,11 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; } /* If this is a timed-out hidden service circuit, skip it. */ if (origin_circ->hs_circ_has_timed_out) { return 0; } if (purpose == CIRCUIT_PURPOSE_C_GENERAL || purpose == CIRCUIT_PURPOSE_C_REND_JOINED) if (circ->timestamp_dirty && Loading Loading @@ -351,7 +356,9 @@ circuit_expire_building(void) * circuit_build_times_get_initial_timeout() if we haven't computed * custom timeouts yet */ struct timeval general_cutoff, begindir_cutoff, fourhop_cutoff, cannibalize_cutoff, close_cutoff, extremely_old_cutoff; cannibalize_cutoff, close_cutoff, extremely_old_cutoff, hs_extremely_old_cutoff; const or_options_t *options = get_options(); struct timeval now; cpath_build_state_t *build_state; Loading @@ -371,6 +378,10 @@ circuit_expire_building(void) SET_CUTOFF(close_cutoff, circ_times.close_ms); SET_CUTOFF(extremely_old_cutoff, circ_times.close_ms*2 + 1000); SET_CUTOFF(hs_extremely_old_cutoff, MAX(circ_times.close_ms*2 + 1000, options->SocksTimeout * 1000)); while (next_circ) { struct timeval cutoff; victim = next_circ; Loading @@ -392,6 +403,9 @@ circuit_expire_building(void) else cutoff = general_cutoff; if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out) cutoff = hs_extremely_old_cutoff; if (timercmp(&victim->timestamp_created, &cutoff, >)) continue; /* it's still young, leave it alone */ Loading Loading @@ -497,6 +511,43 @@ circuit_expire_building(void) } } /* If this is a hidden-service circuit which is far enough along * in connecting to its destination, and we haven't already * flagged it as 'timed out', flag it as 'timed out' so we'll * launch another intro or rend circ, but don't mark it for close * yet. * * (Circs flagged as 'timed out' are given a much longer timeout * period above, so we won't close them in the next call to * circuit_expire_building.) */ if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) { switch (victim->purpose) { case CIRCUIT_PURPOSE_C_REND_READY: /* We only want to spare a rend circ if it has been specified in * an INTRODUCE1 cell sent to a hidden service. A circ's * pending_final_cpath field is non-NULL iff it is a rend circ * and we have tried to send an INTRODUCE1 cell specifying it. * Thus, if the pending_final_cpath field *is* NULL, then we * want to not spare it. */ if (TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath == NULL) break; case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: /* If we have reached this line, we want to spare the circ for now. */ log_info(LD_CIRC,"Marking circ %s:%d:%d (state %d:%s, purpose %d) " "as timed-out HS circ", victim->n_conn->_base.address, victim->n_conn->_base.port, victim->n_circ_id, victim->state, circuit_state_to_string(victim->state), victim->purpose); TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out = 1; continue; default: break; } } if (victim->n_conn) log_info(LD_CIRC,"Abandoning circ %s:%d:%d (state %d:%s, purpose %d)", victim->n_conn->_base.address, victim->n_conn->_base.port, Loading
src/or/or.h +7 −0 Original line number Diff line number Diff line Loading @@ -2607,6 +2607,13 @@ typedef struct origin_circuit_t { * cannibalized circuits. */ unsigned int has_opened : 1; /** Set iff this is a hidden-service circuit which has timed out * according to our current circuit-build timeout, but which has * been kept around because it might still succeed in connecting to * its destination, and which is not a fully-connected rendezvous * circuit. */ unsigned int hs_circ_has_timed_out : 1; /** What commands were sent over this circuit that decremented the * RELAY_EARLY counter? This is for debugging task 878. */ uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT]; Loading
src/or/rendclient.c +5 −0 Original line number Diff line number Diff line Loading @@ -895,6 +895,11 @@ rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request, hop->package_window = circuit_initial_package_window(); hop->deliver_window = CIRCWINDOW_START; /* Now that this circuit has finished connecting to its destination, * make sure circuit_get_open_circ_or_launch is willing to return it * so we can actually use it. */ circ->hs_circ_has_timed_out = 0; onion_append_to_cpath(&circ->cpath, hop); circ->build_state->pending_final_cpath = NULL; /* prevent double-free */ Loading