Commit 3fa2925a authored by Roger Dingledine's avatar Roger Dingledine
Browse files

if an intro circ waiting for an ack dies before getting one, then

count it as a nack


svn:r1665
parent 8d86f8ab
Loading
Loading
Loading
Loading
+7 −0
Changes for src/or/circuit.c: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -997,6 +997,13 @@ int _circuit_mark_for_close(circuit_t *circ) {
      circuit_build_failed(circ); /* take actions if necessary */
    circuit_rep_hist_note_result(circ);
  }
  if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
    assert(circ->state == CIRCUIT_STATE_OPEN);
    /* treat this like getting a nack from it */
    log_fn(LOG_INFO,"Failed intro circ %s to %s (awaiting ack). Removing from descriptor.",
           circ->rend_query, circ->build_state->chosen_exit);
    rend_client_remove_intro_point(circ->build_state->chosen_exit, circ->rend_query);
  }

  if(circ->n_conn)
    connection_send_destroy(circ->n_circ_id, circ->n_conn);
+1 −8
Changes for src/or/connection_edge.c: 1 added line, 8 removed lines.
Original line number Diff line number Diff line
@@ -757,14 +757,7 @@ static int connection_ap_handshake_process_socks(connection_t *conn) {
      return connection_ap_handshake_attach_circuit(conn);
    } else {
      conn->state = AP_CONN_STATE_RENDDESC_WAIT;
      if(connection_get_by_type_rendquery(CONN_TYPE_DIR, conn->rend_query)) {
        log_fn(LOG_INFO,"Would fetch a new renddesc here (for %s), but one is already in progress.", conn->rend_query);
      } else {
        /* not one already; initiate a dir rend desc lookup */
        directory_initiate_command(router_pick_directory_server(),
                                   DIR_PURPOSE_FETCH_RENDDESC,
                                   conn->rend_query, strlen(conn->rend_query));
      }
      rend_client_refetch_renddesc(conn->rend_query);
      return 0;
    }
  }
+2 −0
Changes for src/or/or.h: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -1043,6 +1043,8 @@ void rep_hist_dump_stats(time_t now, int severity);
void rend_client_introcirc_is_open(circuit_t *circ);
void rend_client_rendcirc_is_open(circuit_t *circ);
int rend_client_introduction_acked(circuit_t *circ, const char *request, int request_len);
void rend_client_refetch_renddesc(char *query);
int rend_client_remove_intro_point(char *failed_intro, char *query);
int rend_client_rendezvous_acked(circuit_t *circ, const char *request, int request_len);
int rend_client_receive_rendezvous(circuit_t *circ, const char *request, int request_len);
void rend_client_desc_fetched(char *query, int success);
+58 −38
Changes for src/or/rendclient.c: 58 added lines, 38 removed lines.
Original line number Diff line number Diff line
@@ -147,8 +147,6 @@ int
rend_client_introduction_acked(circuit_t *circ,
                               const char *request, int request_len)
{
  int i, r;
  rend_cache_entry_t *ent;
  char *nickname;
  circuit_t *rendcirc;

@@ -177,44 +175,25 @@ rend_client_introduction_acked(circuit_t *circ,
  } else {
    /* It's a NAK; the introduction point didn't relay our request. */
    circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
    /* XXXX
     * Now become non-open, extend to another one of Bob's
     * introduction points, and try again.  Maybe mark the service as
     * non-functional at the first intro point somehow?
     *
     * Or re-fetch the service descriptor? Hm....
     */
    r = rend_cache_lookup_entry(circ->rend_query, &ent);
    if (r<0) {
      log_fn(LOG_WARN, "Malformed service ID '%s'", circ->rend_query);
      return -1;
    }
    if (r>0) {
      /* Okay, we found the right service desc.  First, remove this intro point
       * from the parsed descriptor (if it's still there!)
    /* Remove this intro point from the set of viable introduction
     * points. If any remain, extend to a new one and try again.
     * If none remain, refetch the service descriptor.
     */
      for (i=0; i < ent->parsed->n_intro_points; ++i) {
        if (!strcasecmp(ent->parsed->intro_points[i],
                        circ->build_state->chosen_exit)) {
          tor_free(ent->parsed->intro_points[i]);
          ent->parsed->intro_points[i] =
            ent->parsed->intro_points[--ent->parsed->n_intro_points];
          break;
        }
      }
      /* If there are any introduction points left, re-extend the circuit to
    if(rend_client_remove_intro_point(circ->build_state->chosen_exit,
                                      circ->rend_query) > 0) {
      /* There are introduction points left. re-extend the circuit to
       * another intro point and try again. */
      if (ent->parsed->n_intro_points) {
      nickname = rend_client_get_random_intro(circ->rend_query);
      assert(nickname);
      log_fn(LOG_INFO,"Got nack for %s from %s, extending to %s.", circ->rend_query, circ->build_state->chosen_exit, nickname);
      if (!router_get_by_nickname(nickname)) {
        log_fn(LOG_WARN, "Advertised intro point '%s' for %s is not known. Closing.",
               nickname, circ->rend_query);
        circuit_mark_for_close(circ);
        return -1;
      }
        log_fn(LOG_INFO, "Chose new intro point %s for %s (circ %d, %d choices left)",
               nickname, circ->rend_query, circ->n_circ_id, ent->parsed->n_intro_points);
      log_fn(LOG_INFO, "Chose new intro point %s for %s (circ %d)",
             nickname, circ->rend_query, circ->n_circ_id);
      circ->state = CIRCUIT_STATE_BUILDING;
      tor_free(circ->build_state->chosen_exit);
      circ->build_state->chosen_exit = tor_strdup(nickname);
@@ -224,23 +203,64 @@ rend_client_introduction_acked(circuit_t *circ,
        circuit_mark_for_close(circ);
        return -1;
      }
        return 0;
    }
  }
    /* Either we have no service desc, or all the intro points in that
     * descriptor failed. So re-fetch the descriptor and try again. */
    circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
    /* XXX anything else we need to do to circ? */
    /* Refetch descriptor */
    if(!connection_get_by_type_rendquery(CONN_TYPE_DIR, circ->rend_query)) {
  return 0;
}

void
rend_client_refetch_renddesc(char *query)
{
  if(connection_get_by_type_rendquery(CONN_TYPE_DIR, query)) {
    log_fn(LOG_INFO,"Would fetch a new renddesc here (for %s), but one is already in progress.", query);
  } else {
    /* not one already; initiate a dir rend desc lookup */
    directory_initiate_command(router_pick_directory_server(),
                               DIR_PURPOSE_FETCH_RENDDESC,
                                 circ->rend_query, strlen(circ->rend_query));
                               query, strlen(query));
  }
}

/* remove failed_intro from ent. if ent now has no intro points, or
 * service is unrecognized, then launch a new renddesc fetch.
 *
 * Return -1 if error, 0 if no intro points remain or service
 * unrecognized, 1 if recognized and some intro points remain.
 */
int
rend_client_remove_intro_point(char *failed_intro, char *query)
{
  int i, r;
  rend_cache_entry_t *ent;

  r = rend_cache_lookup_entry(query, &ent);
  if (r<0) {
    log_fn(LOG_WARN, "Malformed service ID '%s'", query);
    return -1;
  }
  if (r==0) {
    log_fn(LOG_INFO, "Unknown service %s. Re-fetching descriptor.", query);
    rend_client_refetch_renddesc(query);
    return 0;
  }

  for (i=0; i < ent->parsed->n_intro_points; ++i) {
    if (!strcasecmp(ent->parsed->intro_points[i], failed_intro)) {
      tor_free(ent->parsed->intro_points[i]);
      ent->parsed->intro_points[i] =
        ent->parsed->intro_points[--ent->parsed->n_intro_points];
      break;
    }
  }

  if(!ent->parsed->n_intro_points) {
    log_fn(LOG_INFO,"No more intro points remain for %s. Re-fetching descriptor.", query);
    rend_client_refetch_renddesc(query);
    return 0;
  }
  log_fn(LOG_INFO,"%d options left for %s.", ent->parsed->n_intro_points, query);
  return 1;
}

/* Called when we receive a RENDEZVOUS_ESTABLISHED cell; changes the state of
 * the circuit to C_REND_READY.