aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/TODO2
-rw-r--r--src/or/circuit.c17
-rw-r--r--src/or/or.h3
-rw-r--r--src/or/rendservice.c38
4 files changed, 57 insertions, 3 deletions
diff --git a/doc/TODO b/doc/TODO
index 49d313cdf..7119feea7 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -161,7 +161,7 @@ Rendezvous service:
- cannibalize general circs?
D how to set up multiple locations for a hidden service?
o make bob publish only established intro circs?
- - when bob tries to connect to alice's chosen rend point, but
+ o when bob tries to connect to alice's chosen rend point, but
can't, but it's not the fault of the last hop in the rend
circ, then he should retry?
diff --git a/src/or/circuit.c b/src/or/circuit.c
index d0fc81fec..6099a8360 100644
--- a/src/or/circuit.c
+++ b/src/or/circuit.c
@@ -1253,7 +1253,14 @@ static void circuit_build_failed(circuit_t *circ) {
/* we should examine circ and see if it failed because of
* the last hop or an earlier hop. then use this info below.
*/
- //int failed_at_last_hop;
+ int failed_at_last_hop = 0;
+ /* If the last hop isn't open, and the second-to-last is, we failed
+ * at the last hop. */
+ if (circ->cpath &&
+ circ->cpath->prev->state != CPATH_STATE_OPEN &&
+ circ->cpath->prev->prev->state == CPATH_STATE_OPEN) {
+ failed_at_last_hop = 1;
+ }
switch(circ->purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
@@ -1291,7 +1298,13 @@ static void circuit_build_failed(circuit_t *circ) {
/* at Bob, connecting to rend point */
/* Don't increment failure count, since Alice may have picked
* the rendezvous point maliciously */
- log_fn(LOG_INFO,"Couldn't connect to Alice's chosen rend point %s. Sucks to be Alice.", circ->build_state->chosen_exit);
+ if (failed_at_last_hop) {
+ log_fn(LOG_INFO,"Couldn't connect to Alice's chosen rend point %s. Sucks to be Alice.", circ->build_state->chosen_exit);
+ } else {
+ log_fn(LOG_INFO,"Couldn't connect to Alice's chosen rend point %s, because an earlier node failed.",
+ circ->build_state->chosen_exit);
+ rend_service_relaunch_rendezvous(circ);
+ }
break;
default:
/* Other cases are impossible, since this function is only called with
diff --git a/src/or/or.h b/src/or/or.h
index d91cd1207..8bb41f6d9 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -500,6 +500,8 @@ typedef struct {
char *chosen_exit;
/* cpath to append after rendezvous. */
struct crypt_path_t *pending_final_cpath;
+ /* How many times has building a circuit for this task failed? */
+ int failure_count;
} cpath_build_state_t;
/* struct for a path (circuit) through the network */
@@ -1095,6 +1097,7 @@ void rend_service_intro_is_ready(circuit_t *circuit);
int rend_service_intro_established(circuit_t *circuit, const char *request, int request_len);
void rend_service_rendezvous_is_ready(circuit_t *circuit);
int rend_service_introduce(circuit_t *circuit, const char *request, int request_len);
+void rend_service_relaunch_rendezvous(circuit_t *oldcirc);
int rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ);
void rend_service_dump_stats(int severity);
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index e7f787e4c..0c92d1d91 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -457,6 +457,44 @@ rend_service_introduce(circuit_t *circuit, const char *request, int request_len)
return -1;
}
+#define MAX_REND_FAILURES 3
+void
+rend_service_relaunch_rendezvous(circuit_t *oldcirc)
+{
+ circuit_t *newcirc;
+ cpath_build_state_t *newstate, *oldstate;
+
+ /* XXXX assert type and build_state */
+
+ if (!oldcirc->build_state ||
+ oldcirc->build_state->failure_count > MAX_REND_FAILURES) {
+ log_fn(LOG_INFO,"Attempt to build circuit to %s for rendezvous has failed too many times; giving up.",
+ oldcirc->build_state->chosen_exit);
+ return;
+ }
+
+ log_fn(LOG_INFO,"Reattempting rendezvous circuit to %s",
+ oldcirc->build_state->chosen_exit);
+
+ newcirc = circuit_launch_new(CIRCUIT_PURPOSE_S_CONNECT_REND,
+ oldcirc->build_state->chosen_exit);
+ if (!newcirc) {
+ log_fn(LOG_WARN,"Couldn't relaunch rendezvous circuit to %s",
+ oldcirc->build_state->chosen_exit);
+ return;
+ }
+ oldstate = oldcirc->build_state;
+ newstate = newcirc->build_state;
+ assert(newstate && oldstate);
+ newstate->failure_count = oldstate->failure_count+1;
+ newstate->pending_final_cpath = oldstate->pending_final_cpath;
+ oldstate->pending_final_cpath = NULL;
+
+ memcpy(newcirc->rend_query, oldcirc->rend_query, REND_SERVICE_ID_LEN+1);
+ memcpy(newcirc->rend_pk_digest, oldcirc->rend_pk_digest, DIGEST_LEN);
+ memcpy(newcirc->rend_splice, oldcirc->rend_splice, REND_COOKIE_LEN);
+}
+
/* Launch a circuit to serve as an introduction point.
*/
static int