Commit d13857a3 authored by Roger Dingledine's avatar Roger Dingledine
Browse files

put in hooks for alice and bob logic when circuits finish/fail

let you specify the purpose of circuits you launch

bugfix: we used to be declaring the first successful circuit too                               early -- when the first hop finished. now we're more accurate.


svn:r1421
parent 6c9c4a32
Loading
Loading
Loading
Loading
+88 −20
Changes for src/or/circuit.c: 88 added lines, 20 removed lines.
Original line number Diff line number Diff line
@@ -13,6 +13,10 @@ static void circuit_free_cpath_node(crypt_path_t *victim);
static uint16_t get_unique_circ_id_by_conn(connection_t *conn, int circ_id_type);
static void circuit_rep_hist_note_result(circuit_t *circ);

static void circuit_is_ready(circuit_t *circ);
static void circuit_failed(circuit_t *circ);
static int circuit_establish_circuit(uint8_t purpose);

unsigned long stats_n_relay_cells_relayed = 0;
unsigned long stats_n_relay_cells_delivered = 0;

@@ -259,6 +263,8 @@ circuit_t *circuit_get_newest(connection_t *conn,
  for (circ=global_circuitlist;circ;circ = circ->next) {
    if (!circ->cpath)
      continue; /* this circ doesn't start at us */
    if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
      continue; /* don't pick rendezvous circuits */
    if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_conn))
      continue; /* ignore non-open circs */
    if (circ->marked_for_close)
@@ -732,8 +738,10 @@ int _circuit_mark_for_close(circuit_t *circ) {
   * module then.  If it isn't OPEN, we send it there now to remember which
   * links worked and which didn't.
   */
  if (circ->state != CIRCUIT_STATE_OPEN)
  if (circ->state != CIRCUIT_STATE_OPEN) {
    circuit_failed(circ); /* take actions if necessary */
    circuit_rep_hist_note_result(circ);
  }

  if(circ->n_conn)
    connection_send_destroy(circ->n_circ_id, circ->n_conn);
@@ -745,13 +753,7 @@ int _circuit_mark_for_close(circuit_t *circ) {
  for(conn=circ->p_streams; conn; conn=conn->next_stream) {
    connection_edge_destroy(circ->p_circ_id, conn);
  }
  if (circ->state == CIRCUIT_STATE_BUILDING ||
      circ->state == CIRCUIT_STATE_OR_WAIT) {
    /* If we never built the circuit, note it as a failure. */
    /* Note that we can't just check circ->cpath here, because if
     * circuit-building failed immediately, it won't be set yet. */
    circuit_increment_failure_count();
  }

  circ->marked_for_close = 1;

  if (circ->rend_splice && !circ->rend_splice->marked_for_close) {
@@ -981,13 +983,76 @@ void circuit_expire_unused_circuits(void) {
  smartlist_free(unused_open_circs);
}

static void circuit_is_ready(circuit_t *circ) {

  /* should maybe break this into rend_circuit_is_ready() one day */
  switch(circ->purpose) {
    case CIRCUIT_PURPOSE_C_GENERAL:
      /* Tell any AP connections that have been waiting for a new
      * circuit that one is ready. */
      connection_ap_attach_pending();
      break;
    case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
      /* at Bob, waiting for introductions */
      // do nothing?
      break;
    case CIRCUIT_PURPOSE_C_INTRODUCING:
      /* at Alice, connecting to intro point */
      // alice sends introduce1 relay cell
      break;
    case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
      /* at Alice, waiting for Bob */
      // alice launches a circuit to bob's intro point
      break;
    case CIRCUIT_PURPOSE_S_RENDEZVOUSING:
      /* at Bob, connecting to rend point */
      // bob sends rend2 cell
      break;
  }
}

static void circuit_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;

  switch(circ->purpose) {
    case CIRCUIT_PURPOSE_C_GENERAL:
      if (circ->state != CIRCUIT_STATE_OPEN) {
        /* If we never built the circuit, note it as a failure. */
        /* Note that we can't just check circ->cpath here, because if
         * circuit-building failed immediately, it won't be set yet. */
        circuit_increment_failure_count();
      }
      break;
    case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
      /* at Bob, waiting for introductions */
      // remember this somewhere?
      break;
    case CIRCUIT_PURPOSE_C_INTRODUCING:
      /* at Alice, connecting to intro point */
      // alice needs to try another intro point
      break;
    case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
      /* at Alice, waiting for Bob */
      // alice needs to pick a new rend point
      break;
    case CIRCUIT_PURPOSE_S_RENDEZVOUSING:
      /* at Bob, connecting to rend point */
      // 
      break;
  }
}

/* Number of consecutive failures so far; should only be touched by
 * circuit_launch_new and circuit_*_failure_count.
 */
static int n_circuit_failures = 0;

/* Return -1 if you aren't going to try to make a circuit, 0 if you did try. */
int circuit_launch_new(void) {
int circuit_launch_new(uint8_t purpose) {

  if(!(options.SocksPort||options.RunTesting)) /* no need for circuits. */
    return -1;
@@ -998,7 +1063,7 @@ int circuit_launch_new(void) {
  }

  /* try a circ. if it fails, circuit_mark_for_close will increment n_circuit_failures */
  circuit_establish_circuit();
  circuit_establish_circuit(purpose);

  return 0;
}
@@ -1012,7 +1077,7 @@ void circuit_reset_failure_count(void) {
  n_circuit_failures = 0;
}

int circuit_establish_circuit(void) {
static int circuit_establish_circuit(uint8_t purpose) {
  routerinfo_t *firsthop;
  connection_t *n_conn;
  circuit_t *circ;
@@ -1020,7 +1085,7 @@ int circuit_establish_circuit(void) {
  circ = circuit_new(0, NULL); /* sets circ->p_circ_id and circ->p_conn */
  circ->state = CIRCUIT_STATE_OR_WAIT;
  circ->build_state = onion_new_cpath_build_state();
  circ->purpose = CIRCUIT_PURPOSE_C_GENERAL;
  circ->purpose = purpose;

  if (! circ->build_state) {
    log_fn(LOG_INFO,"Generating cpath length failed.");
@@ -1097,6 +1162,8 @@ void circuit_n_conn_open(connection_t *or_conn) {
  }
}

extern int has_completed_circuit;

int circuit_send_next_onion_skin(circuit_t *circ) {
  cell_t cell;
  crypt_path_t *hop;
@@ -1119,7 +1186,9 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
    cell.command = CELL_CREATE;
    cell.circ_id = circ->n_circ_id;

    if(onion_skin_create(circ->n_conn->onion_pkey, &(circ->cpath->handshake_state), cell.payload) < 0) {
    if(onion_skin_create(circ->n_conn->onion_pkey,
                         &(circ->cpath->handshake_state),
                         cell.payload) < 0) {
      log_fn(LOG_WARN,"onion_skin_create (first hop) failed.");
      return -1;
    }
@@ -1139,6 +1208,12 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
      circ->state = CIRCUIT_STATE_OPEN;
      log_fn(LOG_INFO,"circuit built!");
      circuit_reset_failure_count();
      if(!has_completed_circuit) {
        has_completed_circuit=1;
        log_fn(LOG_NOTICE,"Tor has successfully opened a circuit. Looks like it's working.");
      }
      circuit_rep_hist_note_result(circ);
      circuit_is_ready(circ); /* do other actions as necessary */
      /* Tell any AP connections that have been waiting for a new
       * circuit that one is ready. */
      connection_ap_attach_pending();
@@ -1233,8 +1308,6 @@ int circuit_extend(cell_t *cell, circuit_t *circ) {
  return 0;
}

extern int has_completed_circuit;

int circuit_finish_handshake(circuit_t *circ, char *reply) {
  unsigned char iv[16];
  unsigned char keys[40+32];
@@ -1286,12 +1359,7 @@ int circuit_finish_handshake(circuit_t *circ, char *reply) {

  hop->state = CPATH_STATE_OPEN;
  log_fn(LOG_INFO,"finished");
  if(!has_completed_circuit) {
    has_completed_circuit=1;
    log_fn(LOG_NOTICE,"Tor has successfully opened a circuit. Looks like it's working.");
  }
  circuit_log_path(LOG_INFO,circ);
  circuit_rep_hist_note_result(circ);
  return 0;
}

+1 −1
Changes for src/or/connection_edge.c: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -739,7 +739,7 @@ static int connection_ap_handshake_attach_circuit(connection_t *conn,
    case 0: /* no useful circuits available */
      if(!circuit_get_newest(conn, 0, must_be_clean)) {
        /* is one already on the way? */
        circuit_launch_new();
        circuit_launch_new(CIRCUIT_PURPOSE_C_GENERAL);
      }
      return 0;
    default: /* case 1, it succeeded, great */
+3 −3
Changes for src/or/main.c: 3 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -388,11 +388,11 @@ static void run_scheduled_events(time_t now) {
      circuit_reset_failure_count();
      if(circ && circ->timestamp_dirty) {
        log_fn(LOG_INFO,"Youngest circuit dirty; launching replacement.");
        circuit_launch_new(); /* make a new circuit */
        circuit_launch_new(CIRCUIT_PURPOSE_C_GENERAL); /* make a new circuit */
      } else if (options.RunTesting && circ &&
                 circ->timestamp_created + TESTING_CIRCUIT_INTERVAL < now) {
        log_fn(LOG_INFO,"Creating a new testing circuit.");
        circuit_launch_new();
        circuit_launch_new(CIRCUIT_PURPOSE_C_GENERAL);
      }
      time_to_new_circuit = now + options.NewCircuitPeriod;
    }
@@ -401,7 +401,7 @@ static void run_scheduled_events(time_t now) {
      /* if there's no open circ, and less than 3 are on the way,
       * go ahead and try another.
       */
      circuit_launch_new();
      circuit_launch_new(CIRCUIT_PURPOSE_C_GENERAL);
    }
  }

+1 −2
Changes for src/or/or.h: 1 added line, 2 removed lines.
Original line number Diff line number Diff line
@@ -689,10 +689,9 @@ void circuit_log_path(int severity, circuit_t *circ);
void circuit_dump_by_conn(connection_t *conn, int severity);

void circuit_expire_unused_circuits(void);
int circuit_launch_new(void);
int circuit_launch_new(uint8_t purpose);
void circuit_increment_failure_count(void);
void circuit_reset_failure_count(void);
int circuit_establish_circuit(void);
void circuit_n_conn_open(connection_t *or_conn);
int circuit_send_next_onion_skin(circuit_t *circ);
int circuit_extend(cell_t *cell, circuit_t *circ);