Back to index

tor  0.2.3.19-rc
Defines | Functions
circuitlist.h File Reference

Header file for circuitlist.c. More...

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define circuit_mark_for_close(c, reason)   _circuit_mark_for_close((c), (reason), __LINE__, _SHORT_FILE_)

Functions

circuit_t_circuit_get_global_list (void)
 Return the head of the global linked list of circuits.
const char * circuit_state_to_string (int state)
 Function to make circ->state human-readable.
const char * circuit_purpose_to_controller_string (uint8_t purpose)
 Map a circuit purpose to a string suitable to be displayed to a controller.
const char * circuit_purpose_to_controller_hs_state_string (uint8_t purpose)
 Return a string specifying the state of the hidden-service circuit purpose purpose, or NULL if purpose is not a hidden-service-related circuit purpose.
const char * circuit_purpose_to_string (uint8_t purpose)
 Return a human-readable string for the circuit purpose purpose.
void circuit_dump_by_conn (connection_t *conn, int severity)
 Log, at severity severity, information about each circuit that is connected to conn.
void circuit_set_p_circid_orconn (or_circuit_t *circ, circid_t id, or_connection_t *conn)
 Set the p_conn field of a circuit circ, along with the corresponding circuit ID, and add the circuit as appropriate to the (orconn,id)->circuit map.
void circuit_set_n_circid_orconn (circuit_t *circ, circid_t id, or_connection_t *conn)
 Set the n_conn field of a circuit circ, along with the corresponding circuit ID, and add the circuit as appropriate to the (orconn,id)->circuit map.
void circuit_set_state (circuit_t *circ, uint8_t state)
 Change the state of circ to state, adding it to or removing it from lists as appropriate.
void circuit_close_all_marked (void)
 Detach from the global circuit list, and deallocate, all circuits that have been marked for close.
int32_t circuit_initial_package_window (void)
 Pick a reasonable package_window to start out for our circuits.
origin_circuit_torigin_circuit_new (void)
 Allocate space for a new circuit, initializing with p_circ_id and p_conn.
or_circuit_tor_circuit_new (circid_t p_circ_id, or_connection_t *p_conn)
 Allocate a new or_circuit_t, connected to p_conn as p_circ_id.
circuit_tcircuit_get_by_circid_orconn (circid_t circ_id, or_connection_t *conn)
 Return a circ such that:
int circuit_id_in_use_on_orconn (circid_t circ_id, or_connection_t *conn)
 Return true iff the circuit ID circ_id is currently used by a circuit, marked or not, on conn.
circuit_tcircuit_get_by_edge_conn (edge_connection_t *conn)
 Return the circuit that a given edge connection is using.
void circuit_unlink_all_from_or_conn (or_connection_t *conn, int reason)
 For each circuit that has conn as n_conn or p_conn, unlink the circuit from the orconn,circid map, and mark it for close if it hasn't been marked already.
origin_circuit_tcircuit_get_by_global_id (uint32_t id)
 Return the circuit whose global ID is id, or NULL if no such circuit exists.
origin_circuit_tcircuit_get_ready_rend_circ_by_rend_data (const rend_data_t *rend_data)
 Return a circ such that.
origin_circuit_tcircuit_get_next_by_pk_and_purpose (origin_circuit_t *start, const char *digest, uint8_t purpose)
 Return the first circuit originating here in global_circuitlist after start whose purpose is purpose, and where digest (if set) matches the rend_pk_digest field.
or_circuit_tcircuit_get_rendezvous (const char *cookie)
 Return the circuit waiting for a rendezvous with the provided cookie.
or_circuit_tcircuit_get_intro_point (const char *digest)
 Return the circuit waiting for intro cells of the given digest.
origin_circuit_tcircuit_find_to_cannibalize (uint8_t purpose, extend_info_t *info, int flags)
 Return a circuit that is open, is CIRCUIT_PURPOSE_C_GENERAL, has a timestamp_dirty value of 0, has flags matching the CIRCLAUNCH_* flags in flags, and if info is defined, does not already use info as any of its hops; or NULL if no circuit fits this description.
void circuit_mark_all_unused_circs (void)
 Go through the circuitlist; mark-for-close each circuit that starts at us but has not yet been used.
void circuit_expire_all_dirty_circs (void)
 Go through the circuitlist; for each circuit that starts at us and is dirty, frob its timestamp_dirty so we won't use it for any new streams.
void _circuit_mark_for_close (circuit_t *circ, int reason, int line, const char *file)
 Mark circ to be closed next time we call circuit_close_all_marked().
int circuit_get_cpath_len (origin_circuit_t *circ)
 Return the number of hops in circuit's path.
crypt_path_tcircuit_get_cpath_hop (origin_circuit_t *circ, int hopnum)
 Return the hopnumth hop in circ->cpath, or NULL if there aren't that many hops in the list.
void circuit_get_all_pending_on_or_conn (smartlist_t *out, or_connection_t *or_conn)
 Append to out all circuits in state OR_WAIT waiting for the given connection.
int circuit_count_pending_on_or_conn (or_connection_t *or_conn)
 Return the number of circuits in state OR_WAIT, waiting for the given connection.
void assert_cpath_layer_ok (const crypt_path_t *cp)
 Verify that cpath layer cp has all of its invariants correct.
void assert_circuit_ok (const circuit_t *c)
 Verify that circuit c has all of its invariants correct.
void circuit_free_all (void)
 Release all storage held by circuits.

Detailed Description

Header file for circuitlist.c.

Definition in file circuitlist.h.


Define Documentation

#define circuit_mark_for_close (   c,
  reason 
)    _circuit_mark_for_close((c), (reason), __LINE__, _SHORT_FILE_)

Definition at line 54 of file circuitlist.h.


Function Documentation

Return the head of the global linked list of circuits.

Definition at line 313 of file circuitlist.c.

{
  return global_circuitlist;
}

Here is the caller graph for this function:

void _circuit_mark_for_close ( circuit_t circ,
int  reason,
int  line,
const char *  file 
)

Mark circ to be closed next time we call circuit_close_all_marked().

Do any cleanup needed:

  • If state is onionskin_pending, remove circ from the onion_pending list.
  • If circ isn't open yet: call circuit_build_failed() if we're the origin, and in either case call circuit_rep_hist_note_result() to note stats.
  • If purpose is C_INTRODUCE_ACK_WAIT, report the intro point failure we just had to the hidden service client module.
  • If purpose is C_INTRODUCING and reason isn't TIMEOUT, report to the hidden service client module that the intro point we just tried may be unreachable.
  • Send appropriate destroys and edge_destroys for conns and streams attached to circ.
  • If circ->rend_splice is set (we are the midpoint of a joined rendezvous stream), then mark the other circuit to close as well.

Definition at line 1218 of file circuitlist.c.

{
  int orig_reason = reason; /* Passed to the controller */
  assert_circuit_ok(circ);
  tor_assert(line);
  tor_assert(file);

  if (circ->marked_for_close) {
    log(LOG_WARN,LD_BUG,
        "Duplicate call to circuit_mark_for_close at %s:%d"
        " (first at %s:%d)", file, line,
        circ->marked_for_close_file, circ->marked_for_close);
    return;
  }
  if (reason == END_CIRC_AT_ORIGIN) {
    if (!CIRCUIT_IS_ORIGIN(circ)) {
      log_warn(LD_BUG, "Specified 'at-origin' non-reason for ending circuit, "
               "but circuit was not at origin. (called %s:%d, purpose=%d)",
               file, line, circ->purpose);
    }
    reason = END_CIRC_REASON_NONE;
  }
  if (CIRCUIT_IS_ORIGIN(circ)) {
    /* We don't send reasons when closing circuits at the origin. */
    reason = END_CIRC_REASON_NONE;
  }

  if (reason & END_CIRC_REASON_FLAG_REMOTE)
    reason &= ~END_CIRC_REASON_FLAG_REMOTE;

  if (reason < _END_CIRC_REASON_MIN || reason > _END_CIRC_REASON_MAX) {
    if (!(orig_reason & END_CIRC_REASON_FLAG_REMOTE))
      log_warn(LD_BUG, "Reason %d out of range at %s:%d", reason, file, line);
    reason = END_CIRC_REASON_NONE;
  }

  if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
    onion_pending_remove(TO_OR_CIRCUIT(circ));
  }
  /* If the circuit ever became OPEN, we sent it to the reputation history
   * 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 (CIRCUIT_IS_ORIGIN(circ)) {
      origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
      circuit_build_failed(ocirc); /* take actions if necessary */
      circuit_rep_hist_note_result(ocirc);
    }
  }
  if (circ->state == CIRCUIT_STATE_OR_WAIT) {
    if (circuits_pending_or_conns)
      smartlist_remove(circuits_pending_or_conns, circ);
  }
  if (CIRCUIT_IS_ORIGIN(circ)) {
    control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
     (circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED,
     orig_reason);
  }
  if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
    origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
    int timed_out = (reason == END_CIRC_REASON_TIMEOUT);
    tor_assert(circ->state == CIRCUIT_STATE_OPEN);
    tor_assert(ocirc->build_state->chosen_exit);
    tor_assert(ocirc->rend_data);
    /* treat this like getting a nack from it */
    log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s",
           safe_str_client(ocirc->rend_data->onion_address),
           safe_str_client(build_state_get_exit_nickname(ocirc->build_state)),
           timed_out ? "Recording timeout." : "Removing from descriptor.");
    rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
                                           ocirc->rend_data,
                                           timed_out ?
                                           INTRO_POINT_FAILURE_TIMEOUT :
                                           INTRO_POINT_FAILURE_GENERIC);
  } else if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING &&
             reason != END_CIRC_REASON_TIMEOUT) {
    origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
    if (ocirc->build_state->chosen_exit && ocirc->rend_data) {
      log_info(LD_REND, "Failed intro circ %s to %s "
               "(building circuit to intro point). "
               "Marking intro point as possibly unreachable.",
               safe_str_client(ocirc->rend_data->onion_address),
           safe_str_client(build_state_get_exit_nickname(ocirc->build_state)));
      rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
                                             ocirc->rend_data,
                                             INTRO_POINT_FAILURE_UNREACHABLE);
    }
  }
  if (circ->n_conn) {
    circuit_clear_cell_queue(circ, circ->n_conn);
    connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
  }

  if (! CIRCUIT_IS_ORIGIN(circ)) {
    or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
    edge_connection_t *conn;
    for (conn=or_circ->n_streams; conn; conn=conn->next_stream)
      connection_edge_destroy(or_circ->p_circ_id, conn);
    or_circ->n_streams = NULL;

    while (or_circ->resolving_streams) {
      conn = or_circ->resolving_streams;
      or_circ->resolving_streams = conn->next_stream;
      if (!conn->_base.marked_for_close) {
        /* The client will see a DESTROY, and infer that the connections
         * are closing because the circuit is getting torn down.  No need
         * to send an end cell. */
        conn->edge_has_sent_end = 1;
        conn->end_reason = END_STREAM_REASON_DESTROY;
        conn->end_reason |= END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED;
        connection_mark_for_close(TO_CONN(conn));
      }
      conn->on_circuit = NULL;
    }

    if (or_circ->p_conn) {
      circuit_clear_cell_queue(circ, or_circ->p_conn);
      connection_or_send_destroy(or_circ->p_circ_id, or_circ->p_conn, reason);
    }
  } else {
    origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
    edge_connection_t *conn;
    for (conn=ocirc->p_streams; conn; conn=conn->next_stream)
      connection_edge_destroy(circ->n_circ_id, conn);
    ocirc->p_streams = NULL;
  }

  circ->marked_for_close = line;
  circ->marked_for_close_file = file;

  if (!CIRCUIT_IS_ORIGIN(circ)) {
    or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
    if (or_circ->rend_splice) {
      if (!or_circ->rend_splice->_base.marked_for_close) {
        /* do this after marking this circuit, to avoid infinite recursion. */
        circuit_mark_for_close(TO_CIRCUIT(or_circ->rend_splice), reason);
      }
      or_circ->rend_splice = NULL;
    }
  }
}

Here is the call graph for this function:

void assert_circuit_ok ( const circuit_t c)

Verify that circuit c has all of its invariants correct.

Trigger an assert if anything is invalid.

Definition at line 1419 of file circuitlist.c.

{
  edge_connection_t *conn;
  const or_circuit_t *or_circ = NULL;
  const origin_circuit_t *origin_circ = NULL;

  tor_assert(c);
  tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC);
  tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN &&
             c->purpose <= _CIRCUIT_PURPOSE_MAX);

  {
    /* Having a separate variable for this pleases GCC 4.2 in ways I hope I
     * never understand. -NM. */
    circuit_t *nonconst_circ = (circuit_t*) c;
    if (CIRCUIT_IS_ORIGIN(c))
      origin_circ = TO_ORIGIN_CIRCUIT(nonconst_circ);
    else
      or_circ = TO_OR_CIRCUIT(nonconst_circ);
  }

  if (c->n_conn) {
    tor_assert(!c->n_hop);

    if (c->n_circ_id) {
      /* We use the _impl variant here to make sure we don't fail on marked
       * circuits, which would not be returned by the regular function. */
      circuit_t *c2 = circuit_get_by_circid_orconn_impl(c->n_circ_id,
                                                        c->n_conn);
      tor_assert(c == c2);
    }
  }
  if (or_circ && or_circ->p_conn) {
    if (or_circ->p_circ_id) {
      /* ibid */
      circuit_t *c2 = circuit_get_by_circid_orconn_impl(or_circ->p_circ_id,
                                                        or_circ->p_conn);
      tor_assert(c == c2);
    }
  }
  if (or_circ)
    for (conn = or_circ->n_streams; conn; conn = conn->next_stream)
      tor_assert(conn->_base.type == CONN_TYPE_EXIT);

  tor_assert(c->deliver_window >= 0);
  tor_assert(c->package_window >= 0);
  if (c->state == CIRCUIT_STATE_OPEN) {
    tor_assert(!c->n_conn_onionskin);
    if (or_circ) {
      tor_assert(or_circ->n_crypto);
      tor_assert(or_circ->p_crypto);
      tor_assert(or_circ->n_digest);
      tor_assert(or_circ->p_digest);
    }
  }
  if (c->state == CIRCUIT_STATE_OR_WAIT && !c->marked_for_close) {
    tor_assert(circuits_pending_or_conns &&
               smartlist_isin(circuits_pending_or_conns, c));
  } else {
    tor_assert(!circuits_pending_or_conns ||
               !smartlist_isin(circuits_pending_or_conns, c));
  }
  if (origin_circ && origin_circ->cpath) {
    assert_cpath_ok(origin_circ->cpath);
  }
  if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) {
    tor_assert(or_circ);
    if (!c->marked_for_close) {
      tor_assert(or_circ->rend_splice);
      tor_assert(or_circ->rend_splice->rend_splice == or_circ);
    }
    tor_assert(or_circ->rend_splice != or_circ);
  } else {
    tor_assert(!or_circ || !or_circ->rend_splice);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void assert_cpath_layer_ok ( const crypt_path_t cp)

Verify that cpath layer cp has all of its invariants correct.

Trigger an assert if anything is invalid.

Definition at line 1366 of file circuitlist.c.

{
//  tor_assert(cp->addr); /* these are zero for rendezvous extra-hops */
//  tor_assert(cp->port);
  tor_assert(cp);
  tor_assert(cp->magic == CRYPT_PATH_MAGIC);
  switch (cp->state)
    {
    case CPATH_STATE_OPEN:
      tor_assert(cp->f_crypto);
      tor_assert(cp->b_crypto);
      /* fall through */
    case CPATH_STATE_CLOSED:
      tor_assert(!cp->dh_handshake_state);
      break;
    case CPATH_STATE_AWAITING_KEYS:
      /* tor_assert(cp->dh_handshake_state); */
      break;
    default:
      log_fn(LOG_ERR, LD_BUG, "Unexpected state %d", cp->state);
      tor_assert(0);
    }
  tor_assert(cp->package_window >= 0);
  tor_assert(cp->deliver_window >= 0);
}

Here is the caller graph for this function:

void circuit_close_all_marked ( void  )

Detach from the global circuit list, and deallocate, all circuits that have been marked for close.

Definition at line 287 of file circuitlist.c.

{
  circuit_t *tmp,*m;

  while (global_circuitlist && global_circuitlist->marked_for_close) {
    tmp = global_circuitlist->next;
    circuit_free(global_circuitlist);
    global_circuitlist = tmp;
  }

  tmp = global_circuitlist;
  while (tmp && tmp->next) {
    if (tmp->next->marked_for_close) {
      m = tmp->next->next;
      circuit_free(tmp->next);
      tmp->next = m;
      /* Need to check new tmp->next; don't advance tmp. */
    } else {
      /* Advance tmp. */
      tmp = tmp->next;
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return the number of circuits in state OR_WAIT, waiting for the given connection.

Definition at line 269 of file circuitlist.c.

{
  int cnt;
  smartlist_t *sl = smartlist_new();
  circuit_get_all_pending_on_or_conn(sl, or_conn);
  cnt = smartlist_len(sl);
  smartlist_free(sl);
  log_debug(LD_CIRC,"or_conn to %s at %s, %d pending circs",
            or_conn->nickname ? or_conn->nickname : "NULL",
            or_conn->_base.address,
            cnt);
  return cnt;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void circuit_dump_by_conn ( connection_t conn,
int  severity 
)

Log, at severity severity, information about each circuit that is connected to conn.

Definition at line 761 of file circuitlist.c.

{
  circuit_t *circ;
  edge_connection_t *tmpconn;

  for (circ=global_circuitlist;circ;circ = circ->next) {
    circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
    if (circ->marked_for_close)
      continue;

    if (! CIRCUIT_IS_ORIGIN(circ))
      p_circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;

    if (! CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->p_conn &&
        TO_CONN(TO_OR_CIRCUIT(circ)->p_conn) == conn)
      circuit_dump_details(severity, circ, conn->conn_array_index, "App-ward",
                           p_circ_id, n_circ_id);
    if (CIRCUIT_IS_ORIGIN(circ)) {
      for (tmpconn=TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
           tmpconn=tmpconn->next_stream) {
        if (TO_CONN(tmpconn) == conn) {
          circuit_dump_details(severity, circ, conn->conn_array_index,
                               "App-ward", p_circ_id, n_circ_id);
        }
      }
    }
    if (circ->n_conn && TO_CONN(circ->n_conn) == conn)
      circuit_dump_details(severity, circ, conn->conn_array_index, "Exit-ward",
                           n_circ_id, p_circ_id);
    if (! CIRCUIT_IS_ORIGIN(circ)) {
      for (tmpconn=TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
           tmpconn=tmpconn->next_stream) {
        if (TO_CONN(tmpconn) == conn) {
          circuit_dump_details(severity, circ, conn->conn_array_index,
                               "Exit-ward", n_circ_id, p_circ_id);
        }
      }
    }
    if (!circ->n_conn && circ->n_hop &&
        tor_addr_eq(&circ->n_hop->addr, &conn->addr) &&
        circ->n_hop->port == conn->port &&
        conn->type == CONN_TYPE_OR &&
        tor_memeq(TO_OR_CONN(conn)->identity_digest,
                circ->n_hop->identity_digest, DIGEST_LEN)) {
      circuit_dump_details(severity, circ, conn->conn_array_index,
                           (circ->state == CIRCUIT_STATE_OPEN &&
                            !CIRCUIT_IS_ORIGIN(circ)) ?
                             "Endpoint" : "Pending",
                           n_circ_id, p_circ_id);
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Go through the circuitlist; for each circuit that starts at us and is dirty, frob its timestamp_dirty so we won't use it for any new streams.

This is useful for letting the user change pseudonyms, so new streams will not be linkable to old streams.

Definition at line 1185 of file circuitlist.c.

{
  circuit_t *circ;
  const or_options_t *options = get_options();

  for (circ=global_circuitlist; circ; circ = circ->next) {
    if (CIRCUIT_IS_ORIGIN(circ) &&
        !circ->marked_for_close &&
        circ->timestamp_dirty)
      /* XXXX024 This is a screwed-up way to say "This is too dirty
       * for new circuits. */
      circ->timestamp_dirty -= options->MaxCircuitDirtiness;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

origin_circuit_t* circuit_find_to_cannibalize ( uint8_t  purpose,
extend_info_t info,
int  flags 
)

Return a circuit that is open, is CIRCUIT_PURPOSE_C_GENERAL, has a timestamp_dirty value of 0, has flags matching the CIRCLAUNCH_* flags in flags, and if info is defined, does not already use info as any of its hops; or NULL if no circuit fits this description.

The purpose argument (currently ignored) refers to the purpose of the circuit we want to create, not the purpose of the circuit we want to cannibalize.

If !CIRCLAUNCH_NEED_UPTIME, prefer returning non-uptime circuits.

Definition at line 1059 of file circuitlist.c.

{
  circuit_t *_circ;
  origin_circuit_t *best=NULL;
  int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0;
  int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0;
  int internal = (flags & CIRCLAUNCH_IS_INTERNAL) != 0;
  const or_options_t *options = get_options();

  /* Make sure we're not trying to create a onehop circ by
   * cannibalization. */
  tor_assert(!(flags & CIRCLAUNCH_ONEHOP_TUNNEL));

  log_debug(LD_CIRC,
            "Hunting for a circ to cannibalize: purpose %d, uptime %d, "
            "capacity %d, internal %d",
            purpose, need_uptime, need_capacity, internal);

  for (_circ=global_circuitlist; _circ; _circ = _circ->next) {
    if (CIRCUIT_IS_ORIGIN(_circ) &&
        _circ->state == CIRCUIT_STATE_OPEN &&
        !_circ->marked_for_close &&
        _circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
        !_circ->timestamp_dirty) {
      origin_circuit_t *circ = TO_ORIGIN_CIRCUIT(_circ);
      if ((!need_uptime || circ->build_state->need_uptime) &&
          (!need_capacity || circ->build_state->need_capacity) &&
          (internal == circ->build_state->is_internal) &&
          circ->remaining_relay_early_cells &&
          circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN &&
          !circ->build_state->onehop_tunnel &&
          !circ->isolation_values_set) {
        if (info) {
          /* need to make sure we don't duplicate hops */
          crypt_path_t *hop = circ->cpath;
          const node_t *ri1 = node_get_by_id(info->identity_digest);
          do {
            const node_t *ri2;
            if (tor_memeq(hop->extend_info->identity_digest,
                        info->identity_digest, DIGEST_LEN))
              goto next;
            if (ri1 &&
                (ri2 = node_get_by_id(hop->extend_info->identity_digest))
                && nodes_in_same_family(ri1, ri2))
              goto next;
            hop=hop->next;
          } while (hop!=circ->cpath);
        }
        if (options->ExcludeNodes) {
          /* Make sure no existing nodes in the circuit are excluded for
           * general use.  (This may be possible if StrictNodes is 0, and we
           * thought we needed to use an otherwise excluded node for, say, a
           * directory operation.) */
          crypt_path_t *hop = circ->cpath;
          do {
            if (routerset_contains_extendinfo(options->ExcludeNodes,
                                              hop->extend_info))
              goto next;
            hop = hop->next;
          } while (hop != circ->cpath);
        }
        if (!best || (best->build_state->need_uptime && !need_uptime))
          best = circ;
      next: ;
      }
    }
  }
  return best;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void circuit_free_all ( void  )

Release all storage held by circuits.

Definition at line 686 of file circuitlist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Append to out all circuits in state OR_WAIT waiting for the given connection.

Definition at line 237 of file circuitlist.c.

{
  tor_assert(out);
  tor_assert(or_conn);

  if (!circuits_pending_or_conns)
    return;

  SMARTLIST_FOREACH_BEGIN(circuits_pending_or_conns, circuit_t *, circ) {
    if (circ->marked_for_close)
      continue;
    if (!circ->n_hop)
      continue;
    tor_assert(circ->state == CIRCUIT_STATE_OR_WAIT);
    if (tor_digest_is_zero(circ->n_hop->identity_digest)) {
      /* Look at addr/port. This is an unkeyed connection. */
      if (!tor_addr_eq(&circ->n_hop->addr, &or_conn->_base.addr) ||
          circ->n_hop->port != or_conn->_base.port)
        continue;
    } else {
      /* We expected a key. See if it's the right one. */
      if (tor_memneq(or_conn->identity_digest,
                 circ->n_hop->identity_digest, DIGEST_LEN))
        continue;
    }
    smartlist_add(out, circ);
  } SMARTLIST_FOREACH_END(circ);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return a circ such that:

  • circ->n_circ_id or circ->p_circ_id is equal to circ_id, and
  • circ is attached to conn, either as p_conn or n_conn.
  • circ is not marked for close. Return NULL if no such circuit exists.

Definition at line 887 of file circuitlist.c.

{
  circuit_t *circ = circuit_get_by_circid_orconn_impl(circ_id, conn);
  if (!circ || circ->marked_for_close)
    return NULL;
  else
    return circ;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return the circuit that a given edge connection is using.

Definition at line 906 of file circuitlist.c.

{
  circuit_t *circ;

  circ = conn->on_circuit;
  tor_assert(!circ ||
             (CIRCUIT_IS_ORIGIN(circ) ? circ->magic == ORIGIN_CIRCUIT_MAGIC
                                      : circ->magic == OR_CIRCUIT_MAGIC));

  return circ;
}

Here is the caller graph for this function:

Return the circuit whose global ID is id, or NULL if no such circuit exists.

Definition at line 817 of file circuitlist.c.

{
  circuit_t *circ;
  for (circ=global_circuitlist;circ;circ = circ->next) {
    if (CIRCUIT_IS_ORIGIN(circ) &&
        TO_ORIGIN_CIRCUIT(circ)->global_identifier == id) {
      if (circ->marked_for_close)
        return NULL;
      else
        return TO_ORIGIN_CIRCUIT(circ);
    }
  }
  return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

crypt_path_t* circuit_get_cpath_hop ( origin_circuit_t circ,
int  hopnum 
)

Return the hopnumth hop in circ->cpath, or NULL if there aren't that many hops in the list.

Definition at line 1148 of file circuitlist.c.

{
  if (circ && circ->cpath && hopnum > 0) {
    crypt_path_t *cpath, *cpath_next = NULL;
    for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) {
      cpath_next = cpath->next;
      if (--hopnum <= 0)
        return cpath;
    }
  }
  return NULL;
}

Here is the caller graph for this function:

Return the number of hops in circuit's path.

Definition at line 1132 of file circuitlist.c.

{
  int n = 0;
  if (circ && circ->cpath) {
    crypt_path_t *cpath, *cpath_next = NULL;
    for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) {
      cpath_next = cpath->next;
      ++n;
    }
  }
  return n;
}

Here is the caller graph for this function:

or_circuit_t* circuit_get_intro_point ( const char *  digest)

Return the circuit waiting for intro cells of the given digest.

Return NULL if no such circuit is found.

Definition at line 1040 of file circuitlist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

origin_circuit_t* circuit_get_next_by_pk_and_purpose ( origin_circuit_t start,
const char *  digest,
uint8_t  purpose 
)

Return the first circuit originating here in global_circuitlist after start whose purpose is purpose, and where digest (if set) matches the rend_pk_digest field.

Return NULL if no circuit is found. If start is NULL, begin at the start of the list.

Definition at line 983 of file circuitlist.c.

{
  circuit_t *circ;
  tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(purpose));
  if (start == NULL)
    circ = global_circuitlist;
  else
    circ = TO_CIRCUIT(start)->next;

  for ( ; circ; circ = circ->next) {
    if (circ->marked_for_close)
      continue;
    if (circ->purpose != purpose)
      continue;
    if (!digest)
      return TO_ORIGIN_CIRCUIT(circ);
    else if (TO_ORIGIN_CIRCUIT(circ)->rend_data &&
             tor_memeq(TO_ORIGIN_CIRCUIT(circ)->rend_data->rend_pk_digest,
                     digest, DIGEST_LEN))
      return TO_ORIGIN_CIRCUIT(circ);
  }
  return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Return a circ such that.

  • circ->rend_data->onion_address is equal to rend_data->onion_address,
  • circ->rend_data->rend_cookie is equal to rend_data->rend_cookie, and
  • circ->purpose is equal to CIRCUIT_PURPOSE_C_REND_READY.

Return NULL if no such circuit exists.

Definition at line 957 of file circuitlist.c.

{
  circuit_t *circ;

  for (circ = global_circuitlist; circ; circ = circ->next) {
    if (!circ->marked_for_close &&
        circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
      origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
      if (ocirc->rend_data &&
          !rend_cmp_service_ids(rend_data->onion_address,
                                ocirc->rend_data->onion_address) &&
          tor_memeq(ocirc->rend_data->rend_cookie,
                    rend_data->rend_cookie,
                    REND_COOKIE_LEN))
        return ocirc;
    }
  }
  return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

or_circuit_t* circuit_get_rendezvous ( const char *  cookie)

Return the circuit waiting for a rendezvous with the provided cookie.

Return NULL if no such circuit is found.

Definition at line 1029 of file circuitlist.c.

Here is the call graph for this function:

Here is the caller graph for this function:

int circuit_id_in_use_on_orconn ( circid_t  circ_id,
or_connection_t conn 
)

Return true iff the circuit ID circ_id is currently used by a circuit, marked or not, on conn.

Definition at line 899 of file circuitlist.c.

{
  return circuit_get_by_circid_orconn_impl(circ_id, conn) != NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int32_t circuit_initial_package_window ( void  )

Pick a reasonable package_window to start out for our circuits.

Originally this was hard-coded at 1000, but now the consensus votes on the answer. See proposal 168.

Definition at line 499 of file circuitlist.c.

{
  int32_t num = networkstatus_get_param(NULL, "circwindow", CIRCWINDOW_START,
                                        CIRCWINDOW_START_MIN,
                                        CIRCWINDOW_START_MAX);
  /* If the consensus tells us a negative number, we'd assert. */
  if (num < 0)
    num = CIRCWINDOW_START;
  return num;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Go through the circuitlist; mark-for-close each circuit that starts at us but has not yet been used.

Definition at line 1164 of file circuitlist.c.

{
  circuit_t *circ;

  for (circ=global_circuitlist; circ; circ = circ->next) {
    if (CIRCUIT_IS_ORIGIN(circ) &&
        !circ->marked_for_close &&
        !circ->timestamp_dirty)
      circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
  }
}

Here is the caller graph for this function:

const char* circuit_purpose_to_controller_hs_state_string ( uint8_t  purpose)

Return a string specifying the state of the hidden-service circuit purpose purpose, or NULL if purpose is not a hidden-service-related circuit purpose.

Definition at line 386 of file circuitlist.c.

{
  switch (purpose)
    {
    default:
      log_fn(LOG_WARN, LD_BUG,
             "Unrecognized circuit purpose: %d",
             (int)purpose);
      tor_fragile_assert();
      /* fall through */

    case CIRCUIT_PURPOSE_OR:
    case CIRCUIT_PURPOSE_C_GENERAL:
    case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT:
    case CIRCUIT_PURPOSE_TESTING:
    case CIRCUIT_PURPOSE_CONTROLLER:
      return NULL;

    case CIRCUIT_PURPOSE_INTRO_POINT:
      return "OR_HSSI_ESTABLISHED";
    case CIRCUIT_PURPOSE_REND_POINT_WAITING:
      return "OR_HSCR_ESTABLISHED";
    case CIRCUIT_PURPOSE_REND_ESTABLISHED:
      return "OR_HS_R_JOINED";

    case CIRCUIT_PURPOSE_C_INTRODUCING:
      return "HSCI_CONNECTING";
    case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
      return "HSCI_INTRO_SENT";
    case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED:
      return "HSCI_DONE";

    case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
      return "HSCR_CONNECTING";
    case CIRCUIT_PURPOSE_C_REND_READY:
      return "HSCR_ESTABLISHED_IDLE";
    case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
      return "HSCR_ESTABLISHED_WAITING";
    case CIRCUIT_PURPOSE_C_REND_JOINED:
      return "HSCR_JOINED";

    case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
      return "HSSI_CONNECTING";
    case CIRCUIT_PURPOSE_S_INTRO:
      return "HSSI_ESTABLISHED";

    case CIRCUIT_PURPOSE_S_CONNECT_REND:
      return "HSSR_CONNECTING";
    case CIRCUIT_PURPOSE_S_REND_JOINED:
      return "HSSR_JOINED";
    }
}

Here is the caller graph for this function:

const char* circuit_purpose_to_controller_string ( uint8_t  purpose)

Map a circuit purpose to a string suitable to be displayed to a controller.

Definition at line 338 of file circuitlist.c.

{
  static char buf[32];
  switch (purpose) {
    case CIRCUIT_PURPOSE_OR:
    case CIRCUIT_PURPOSE_INTRO_POINT:
    case CIRCUIT_PURPOSE_REND_POINT_WAITING:
    case CIRCUIT_PURPOSE_REND_ESTABLISHED:
      return "SERVER"; /* A controller should never see these, actually. */

    case CIRCUIT_PURPOSE_C_GENERAL:
      return "GENERAL";
    case CIRCUIT_PURPOSE_C_INTRODUCING:
    case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
    case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED:
      return "HS_CLIENT_INTRO";

    case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
    case CIRCUIT_PURPOSE_C_REND_READY:
    case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
    case CIRCUIT_PURPOSE_C_REND_JOINED:
      return "HS_CLIENT_REND";

    case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
    case CIRCUIT_PURPOSE_S_INTRO:
      return "HS_SERVICE_INTRO";

    case CIRCUIT_PURPOSE_S_CONNECT_REND:
    case CIRCUIT_PURPOSE_S_REND_JOINED:
      return "HS_SERVICE_REND";

    case CIRCUIT_PURPOSE_TESTING:
      return "TESTING";
    case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT:
      return "MEASURE_TIMEOUT";
    case CIRCUIT_PURPOSE_CONTROLLER:
      return "CONTROLLER";

    default:
      tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose);
      return buf;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* circuit_purpose_to_string ( uint8_t  purpose)

Return a human-readable string for the circuit purpose purpose.

Definition at line 441 of file circuitlist.c.

{
  static char buf[32];

  switch (purpose)
    {
    case CIRCUIT_PURPOSE_OR:
      return "Circuit at relay";
    case CIRCUIT_PURPOSE_INTRO_POINT:
      return "Acting as intro point";
    case CIRCUIT_PURPOSE_REND_POINT_WAITING:
      return "Acting as rendevous (pending)";
    case CIRCUIT_PURPOSE_REND_ESTABLISHED:
      return "Acting as rendevous (established)";
    case CIRCUIT_PURPOSE_C_GENERAL:
      return "General-purpose client";
    case CIRCUIT_PURPOSE_C_INTRODUCING:
      return "Hidden service client: Connecting to intro point";
    case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
      return "Hidden service client: Waiting for ack from intro point";
    case CIRCUIT_PURPOSE_C_INTRODUCE_ACKED:
      return "Hidden service client: Received ack from intro point";
    case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
      return "Hidden service client: Establishing rendezvous point";
    case CIRCUIT_PURPOSE_C_REND_READY:
      return "Hidden service client: Pending rendezvous point";
    case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
      return "Hidden service client: Pending rendezvous point (ack received)";
    case CIRCUIT_PURPOSE_C_REND_JOINED:
      return "Hidden service client: Active rendezvous point";
    case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT:
      return "Measuring circuit timeout";

    case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
      return "Hidden service: Establishing introduction point";
    case CIRCUIT_PURPOSE_S_INTRO:
      return "Hidden service: Introduction point";
    case CIRCUIT_PURPOSE_S_CONNECT_REND:
      return "Hidden service: Connecting to rendezvous point";
    case CIRCUIT_PURPOSE_S_REND_JOINED:
      return "Hidden service: Active rendezvous point";

    case CIRCUIT_PURPOSE_TESTING:
      return "Testing circuit";

    case CIRCUIT_PURPOSE_CONTROLLER:
      return "Circuit made by controller";

    default:
      tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose);
      return buf;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void circuit_set_n_circid_orconn ( circuit_t circ,
circid_t  id,
or_connection_t conn 
)

Set the n_conn field of a circuit circ, along with the corresponding circuit ID, and add the circuit as appropriate to the (orconn,id)->circuit map.

Definition at line 187 of file circuitlist.c.

{
  circuit_set_circid_orconn_helper(circ, CELL_DIRECTION_OUT, id, conn);

  if (conn)
    tor_assert(bool_eq(circ->n_conn_cells.n, circ->next_active_on_n_conn));
}

Here is the caller graph for this function:

Set the p_conn field of a circuit circ, along with the corresponding circuit ID, and add the circuit as appropriate to the (orconn,id)->circuit map.

Definition at line 173 of file circuitlist.c.

{
  circuit_set_circid_orconn_helper(TO_CIRCUIT(circ), CELL_DIRECTION_IN,
                                   id, conn);

  if (conn)
    tor_assert(bool_eq(circ->p_conn_cells.n, circ->next_active_on_p_conn));
}

Here is the caller graph for this function:

void circuit_set_state ( circuit_t circ,
uint8_t  state 
)

Change the state of circ to state, adding it to or removing it from lists as appropriate.

Definition at line 199 of file circuitlist.c.

{
  tor_assert(circ);
  if (state == circ->state)
    return;
  if (!circuits_pending_or_conns)
    circuits_pending_or_conns = smartlist_new();
  if (circ->state == CIRCUIT_STATE_OR_WAIT) {
    /* remove from waiting-circuit list. */
    smartlist_remove(circuits_pending_or_conns, circ);
  }
  if (state == CIRCUIT_STATE_OR_WAIT) {
    /* add to waiting-circuit list. */
    smartlist_add(circuits_pending_or_conns, circ);
  }
  if (state == CIRCUIT_STATE_OPEN)
    tor_assert(!circ->n_conn_onionskin);
  circ->state = state;
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* circuit_state_to_string ( int  state)

Function to make circ->state human-readable.

Definition at line 320 of file circuitlist.c.

{
  static char buf[64];
  switch (state) {
    case CIRCUIT_STATE_BUILDING: return "doing handshakes";
    case CIRCUIT_STATE_ONIONSKIN_PENDING: return "processing the onion";
    case CIRCUIT_STATE_OR_WAIT: return "connecting to server";
    case CIRCUIT_STATE_OPEN: return "open";
    default:
      log_warn(LD_BUG, "Unknown circuit state %d", state);
      tor_snprintf(buf, sizeof(buf), "unknown state [%d]", state);
      return buf;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void circuit_unlink_all_from_or_conn ( or_connection_t conn,
int  reason 
)

For each circuit that has conn as n_conn or p_conn, unlink the circuit from the orconn,circid map, and mark it for close if it hasn't been marked already.

Definition at line 923 of file circuitlist.c.

{
  circuit_t *circ;

  connection_or_unlink_all_active_circs(conn);

  for (circ = global_circuitlist; circ; circ = circ->next) {
    int mark = 0;
    if (circ->n_conn == conn) {
        circuit_set_n_circid_orconn(circ, 0, NULL);
        mark = 1;
    }
    if (! CIRCUIT_IS_ORIGIN(circ)) {
      or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
      if (or_circ->p_conn == conn) {
        circuit_set_p_circid_orconn(or_circ, 0, NULL);
        mark = 1;
      }
    }
    if (mark && !circ->marked_for_close)
      circuit_mark_for_close(circ, reason);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

or_circuit_t* or_circuit_new ( circid_t  p_circ_id,
or_connection_t p_conn 
)

Allocate a new or_circuit_t, connected to p_conn as p_circ_id.

If p_conn is NULL, the circuit is unattached.

Definition at line 558 of file circuitlist.c.

{
  /* CircIDs */
  or_circuit_t *circ;

  circ = tor_malloc_zero(sizeof(or_circuit_t));
  circ->_base.magic = OR_CIRCUIT_MAGIC;

  if (p_conn)
    circuit_set_p_circid_orconn(circ, p_circ_id, p_conn);

  circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT;

  init_circuit_base(TO_CIRCUIT(circ));

  /* Initialize the cell_ewma_t structure */

  /* Initialize the cell counts to 0 */
  circ->p_cell_ewma.cell_count = 0.0;
  circ->p_cell_ewma.last_adjusted_tick = cell_ewma_get_tick();
  circ->p_cell_ewma.is_for_p_conn = 1;

  /* It's not in any heap yet. */
  circ->p_cell_ewma.heap_index = -1;

  return circ;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Allocate space for a new circuit, initializing with p_circ_id and p_conn.

Add it to the global circuit list.

Definition at line 533 of file circuitlist.c.

{
  origin_circuit_t *circ;
  /* never zero, since a global ID of 0 is treated specially by the
   * controller */
  static uint32_t n_circuits_allocated = 1;

  circ = tor_malloc_zero(sizeof(origin_circuit_t));
  circ->_base.magic = ORIGIN_CIRCUIT_MAGIC;

  circ->next_stream_id = crypto_rand_int(1<<16);
  circ->global_identifier = n_circuits_allocated++;
  circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT;
  circ->remaining_relay_early_cells -= crypto_rand_int(2);

  init_circuit_base(TO_CIRCUIT(circ));

  circ_times.last_circ_at = approx_time();

  return circ;
}

Here is the call graph for this function:

Here is the caller graph for this function: