Browse Source

Retry non-final-hop rendezvous failures

svn:r1625
Nick Mathewson 21 years ago
parent
commit
37255d24bc
4 changed files with 57 additions and 3 deletions
  1. 1 1
      doc/TODO
  2. 15 2
      src/or/circuit.c
  3. 3 0
      src/or/or.h
  4. 38 0
      src/or/rendservice.c

+ 1 - 1
doc/TODO

@@ -161,7 +161,7 @@ Rendezvous service:
         - cannibalize general circs?
         - cannibalize general circs?
         D how to set up multiple locations for a hidden service?
         D how to set up multiple locations for a hidden service?
         o make bob publish only established intro circs?
         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
           can't, but it's not the fault of the last hop in the rend
           circ, then he should retry?
           circ, then he should retry?
 
 

+ 15 - 2
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
   /* we should examine circ and see if it failed because of
    * the last hop or an earlier hop. then use this info below.
    * 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) {
   switch(circ->purpose) {
     case CIRCUIT_PURPOSE_C_GENERAL:
     case CIRCUIT_PURPOSE_C_GENERAL:
@@ -1291,7 +1298,13 @@ static void circuit_build_failed(circuit_t *circ) {
       /* at Bob, connecting to rend point */
       /* at Bob, connecting to rend point */
       /* Don't increment failure count, since Alice may have picked
       /* Don't increment failure count, since Alice may have picked
        * the rendezvous point maliciously */
        * 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;
       break;
     default:
     default:
       /* Other cases are impossible, since this function is only called with
       /* Other cases are impossible, since this function is only called with

+ 3 - 0
src/or/or.h

@@ -500,6 +500,8 @@ typedef struct {
   char *chosen_exit;
   char *chosen_exit;
   /* cpath to append after rendezvous. */
   /* cpath to append after rendezvous. */
   struct crypt_path_t *pending_final_cpath;
   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;
 } cpath_build_state_t;
 
 
 /* struct for a path (circuit) through the network */
 /* 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);
 int rend_service_intro_established(circuit_t *circuit, const char *request, int request_len);
 void rend_service_rendezvous_is_ready(circuit_t *circuit);
 void rend_service_rendezvous_is_ready(circuit_t *circuit);
 int rend_service_introduce(circuit_t *circuit, const char *request, int request_len);
 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);
 int rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ);
 void rend_service_dump_stats(int severity);
 void rend_service_dump_stats(int severity);
 
 

+ 38 - 0
src/or/rendservice.c

@@ -457,6 +457,44 @@ rend_service_introduce(circuit_t *circuit, const char *request, int request_len)
   return -1;
   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.
 /* Launch a circuit to serve as an introduction point.
  */
  */
 static int
 static int