static int circuit_deliver_create_cell(circuit_t *circ,
uint8_t cell_type, char *payload);
-static int onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit);
+static int onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit);
static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
static int onion_extend_cpath(uint8_t purpose, crypt_path_t **head_ptr,
cpath_build_state_t *state);
* a more verbose format using spaces.
*/
char *
-circuit_list_path(circuit_t *circ, int verbose)
+circuit_list_path(origin_circuit_t *circ, int verbose)
{
crypt_path_t *hop;
smartlist_t *elements;
const char *states[] = {"closed", "waiting for keys", "open"};
char buf[128];
char *s;
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
elements = smartlist_create();
circ->build_state->is_internal ? "internal" : "exit",
circ->build_state->need_uptime ? " (high-uptime)" : "",
circ->build_state->desired_path_len,
- circ->state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
- circ->state == CIRCUIT_STATE_OPEN ? "" :
+ circ->_base.state == CIRCUIT_STATE_OPEN ? "" : ", exit ",
+ circ->_base.state == CIRCUIT_STATE_OPEN ? "" :
(nickname?nickname:"*unnamed*"));
smartlist_add(elements, tor_strdup(buf));
}
* exit point.
*/
void
-circuit_log_path(int severity, unsigned int domain, circuit_t *circ)
+circuit_log_path(int severity, unsigned int domain, origin_circuit_t *circ)
{
char *s = circuit_list_path(circ,1);
log(severity,domain,"%s",s);
* unable to extend.
*/
void
-circuit_rep_hist_note_result(circuit_t *circ)
+circuit_rep_hist_note_result(origin_circuit_t *circ)
{
crypt_path_t *hop;
char *prev_digest = NULL;
} while (hop!=circ->cpath);
}
-/** A helper function for circuit_dump_by_conn() below. Log a bunch
- * of information about circuit <b>circ</b>.
- */
-static void
-circuit_dump_details(int severity, circuit_t *circ, int poll_index,
- const char *type, int this_circid, int other_circid)
-{
- log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
- "state %d (%s), born %d:",
- poll_index, type, this_circid, other_circid, circ->state,
- circuit_state_to_string(circ->state), (int)circ->timestamp_created);
- if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
- circuit_log_path(severity, LD_CIRC, circ);
- }
-}
-
-/** Log, at severity <b>severity</b>, information about each circuit
- * that is connected to <b>conn</b>.
- */
-void
-circuit_dump_by_conn(connection_t *conn, int severity)
-{
- circuit_t *circ;
- connection_t *tmpconn;
-
- for (circ=global_circuitlist;circ;circ = circ->next) {
- if (circ->marked_for_close)
- continue;
- if (circ->p_conn == conn)
- circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
- circ->p_circ_id, circ->n_circ_id);
- for (tmpconn=circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) {
- if (tmpconn == conn) {
- circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
- circ->p_circ_id, circ->n_circ_id);
- }
- }
- if (circ->n_conn == conn)
- circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
- circ->n_circ_id, circ->p_circ_id);
- for (tmpconn=circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) {
- if (tmpconn == conn) {
- circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
- circ->n_circ_id, circ->p_circ_id);
- }
- }
- if (!circ->n_conn && circ->n_addr && circ->n_port &&
- circ->n_addr == conn->addr &&
- circ->n_port == conn->port &&
- !memcmp(conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) {
- circuit_dump_details(severity, circ, conn->poll_index,
- (circ->state == CIRCUIT_STATE_OPEN &&
- !CIRCUIT_IS_ORIGIN(circ)) ?
- "Endpoint" : "Pending",
- circ->n_circ_id, circ->p_circ_id);
- }
- }
-}
-
/** Pick all the entries in our cpath. Stop and return 0 when we're
* happy, or return -1 if an error occurs. */
static int
-onion_populate_cpath(circuit_t *circ)
+onion_populate_cpath(origin_circuit_t *circ)
{
int r;
again:
- r = onion_extend_cpath(circ->purpose, &circ->cpath, circ->build_state);
-// || !CIRCUIT_IS_ORIGIN(circ)) { // wtf? -rd
+ r = onion_extend_cpath(circ->_base.purpose, &circ->cpath, circ->build_state);
if (r < 0) {
log_info(LD_CIRC,"Generating cpath hop failed.");
return -1;
return 0; /* if r == 1 */
}
-/** Create and return a new circuit. Initialize its purpose and
+/** Create and return a new origin circuit. Initialize its purpose and
* build-state based on our arguments. */
-circuit_t *
-circuit_init(uint8_t purpose, int need_uptime, int need_capacity, int internal)
+origin_circuit_t *
+origin_circuit_init(uint8_t purpose, int need_uptime, int need_capacity,
+ int internal)
{
/* sets circ->p_circ_id and circ->p_conn */
- circuit_t *circ = circuit_new(0, NULL);
- circuit_set_state(circ, CIRCUIT_STATE_OR_WAIT);
+ origin_circuit_t *circ = origin_circuit_new();
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OR_WAIT);
circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
circ->build_state->need_uptime = need_uptime;
circ->build_state->need_capacity = need_capacity;
circ->build_state->is_internal = internal;
- circ->purpose = purpose;
+ circ->_base.purpose = purpose;
return circ;
}
* Also launch a connection to the first OR in the chosen path, if
* it's not open already.
*/
-circuit_t *
+origin_circuit_t *
circuit_establish_circuit(uint8_t purpose, extend_info_t *info,
int need_uptime, int need_capacity, int internal)
{
- circuit_t *circ;
+ origin_circuit_t *circ;
- circ = circuit_init(purpose, need_uptime, need_capacity, internal);
+ circ = origin_circuit_init(purpose, need_uptime, need_capacity, internal);
if (onion_pick_cpath_exit(circ, info) < 0 ||
onion_populate_cpath(circ) < 0) {
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return NULL;
}
control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
if (circuit_handle_first_hop(circ) < 0) {
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return NULL;
}
return circ;
* it. If we're already connected, then send the 'create' cell.
* Return 0 for ok, -1 if circ should be marked-for-close. */
int
-circuit_handle_first_hop(circuit_t *circ)
+circuit_handle_first_hop(origin_circuit_t *circ)
{
crypt_path_t *firsthop;
connection_t *n_conn;
log_debug(LD_CIRC,"Looking for firsthop '%s:%u'",tmpbuf,
firsthop->extend_info->port);
/* imprint the circuit with its future n_conn->id */
- memcpy(circ->n_conn_id_digest, firsthop->extend_info->identity_digest,
+ memcpy(circ->_base.n_conn_id_digest, firsthop->extend_info->identity_digest,
DIGEST_LEN);
n_conn = connection_or_get_by_identity_digest(
firsthop->extend_info->identity_digest);
router_digest_version_as_new_as(firsthop->extend_info->identity_digest,
"0.1.1.9-alpha-cvs"))) {
/* not currently connected */
- circ->n_addr = firsthop->extend_info->addr;
- circ->n_port = firsthop->extend_info->port;
+ circ->_base.n_addr = firsthop->extend_info->addr;
+ circ->_base.n_port = firsthop->extend_info->port;
if (!n_conn || n_conn->is_obsolete) { /* launch the connection */
n_conn = connection_or_connect(firsthop->extend_info->addr,
*/
return 0;
} else { /* it's already open. use it. */
- circ->n_addr = n_conn->addr;
- circ->n_port = n_conn->port;
- circ->n_conn = n_conn;
+ circ->_base.n_addr = n_conn->addr;
+ circ->_base.n_port = n_conn->port;
+ circ->_base.n_conn = n_conn;
log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
if (circuit_send_next_onion_skin(circ) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
* set_circid_orconn here. */
circ->n_conn = or_conn;
if (CIRCUIT_IS_ORIGIN(circ)) {
- if (circuit_send_next_onion_skin(circ) < 0) {
+ if (circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)) < 0) {
log_info(LD_CIRC,
"send_next_onion_skin failed; circuit marked for closing.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
* Return -1 if we failed to find a suitable circid, else return 0.
*/
static int
-circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type, char *payload)
+circuit_deliver_create_cell(circuit_t *circ, uint8_t cell_type,
+ char *payload)
{
cell_t cell;
uint16_t id;
return -1;
}
log_debug(LD_CIRC,"Chosen circID %u.", id);
- circuit_set_circid_orconn(circ, id, circ->n_conn, N_CONN_CHANGED);
+ circuit_set_n_circid_orconn(circ, id, circ->n_conn);
memset(&cell, 0, sizeof(cell_t));
cell.command = cell_type;
* Return -reason if we want to tear down circ, else return 0.
*/
int
-circuit_send_next_onion_skin(circuit_t *circ)
+circuit_send_next_onion_skin(origin_circuit_t *circ)
{
crypt_path_t *hop;
routerinfo_t *router;
size_t payload_len;
tor_assert(circ);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (circ->cpath->state == CPATH_STATE_CLOSED) {
int fast;
uint8_t cell_type;
log_debug(LD_CIRC,"First skin; sending create cell.");
- router = router_get_by_digest(circ->n_conn->identity_digest);
+ router = router_get_by_digest(circ->_base.n_conn->identity_digest);
fast = should_use_create_fast_for_router(router);
if (! fast) {
/* We are an OR, or we are connecting to an old Tor: we should
sizeof(circ->cpath->fast_handshake_state));
}
- if (circuit_deliver_create_cell(circ, cell_type, payload) < 0)
+ if (circuit_deliver_create_cell(TO_CIRCUIT(circ), cell_type, payload) < 0)
return - END_CIRC_REASON_RESOURCELIMIT;
circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
- circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
log_info(LD_CIRC,"First hop: finished sending %s cell to '%s'",
fast ? "CREATE_FAST" : "CREATE",
router ? router->nickname : "<unnamed>");
} else {
tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
- tor_assert(circ->state == CIRCUIT_STATE_BUILDING);
+ tor_assert(circ->_base.state == CIRCUIT_STATE_BUILDING);
log_debug(LD_CIRC,"starting to send subsequent skin.");
hop = onion_next_hop_in_cpath(circ->cpath);
if (!hop) {
/* done building the circuit. whew. */
- circuit_set_state(circ, CIRCUIT_STATE_OPEN);
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
log_info(LD_CIRC,"circuit built!");
circuit_reset_failure_count(0);
if (!has_completed_circuit) {
log_debug(LD_CIRC,"Sending extend relay cell.");
/* send it to hop->prev, because it will transfer
* it to a create cell and then send to hop */
- if (connection_edge_send_command(NULL, circ, RELAY_COMMAND_EXTEND,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(circ),
+ RELAY_COMMAND_EXTEND,
payload, payload_len, hop->prev) < 0)
return 0; /* circuit is closed */
* Return - reason if we want to mark circ for close, else return 0.
*/
int
-circuit_finish_handshake(circuit_t *circ, uint8_t reply_type, char *reply)
+circuit_finish_handshake(origin_circuit_t *circ, uint8_t reply_type,
+ char *reply)
{
char keys[CPATH_KEY_MATERIAL_LEN];
crypt_path_t *hop;
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
hop = circ->cpath;
else {
* just give up: for circ to close, and return 0.
*/
int
-circuit_truncated(circuit_t *circ, crypt_path_t *layer)
+circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer)
{
// crypt_path_t *victim;
// connection_t *stream;
tor_assert(circ);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
tor_assert(layer);
/* XXX Since we don't ask for truncates currently, getting a truncated
* means that a connection broke or an extend failed. For now,
* just give up.
*/
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return 0;
#if 0
* cell back.
*/
int
-onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload, char *keys)
+onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
+ char *keys)
{
cell_t cell;
crypt_path_t *tmp_cpath;
cell.command = cell_type;
cell.circ_id = circ->p_circ_id;
- circuit_set_state(circ, CIRCUIT_STATE_OPEN);
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN);
memcpy(cell.payload, payload,
cell_type == CELL_CREATED ? ONIONSKIN_REPLY_LEN : DIGEST_LEN*2);
* router (or use <b>exit</b> if provided). Store these in the
* cpath. Return 0 if ok, -1 if circuit should be closed. */
static int
-onion_pick_cpath_exit(circuit_t *circ, extend_info_t *exit)
+onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
{
cpath_build_state_t *state = circ->build_state;
routerlist_t *rl = router_get_routerlist();
int r;
- r = new_route_len(get_options()->PathlenCoinWeight, circ->purpose,
+ r = new_route_len(get_options()->PathlenCoinWeight, circ->_base.purpose,
exit, rl->routers);
if (r < 1) /* must be at least 1 */
return -1;
exit = extend_info_dup(exit);
} else { /* we have to decide one */
routerinfo_t *router =
- choose_good_exit_server(circ->purpose, rl, state->need_uptime,
- state->need_capacity, state->is_internal);
+ choose_good_exit_server(circ->_base.purpose, rl, state->need_uptime,
+ state->need_capacity, state->is_internal);
if (!router) {
log_warn(LD_CIRC,"failed to choose an exit server");
return -1;
* the caller will do this if it wants to.
*/
int
-circuit_append_new_exit(circuit_t *circ, extend_info_t *info)
+circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info)
{
cpath_build_state_t *state;
tor_assert(info);
- tor_assert(circ && CIRCUIT_IS_ORIGIN(circ));
+ tor_assert(circ);
state = circ->build_state;
tor_assert(state);
* send the next extend cell to begin connecting to that hop.
*/
int
-circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info)
+circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info)
{
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
circuit_append_new_exit(circ, info);
- circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
if (circuit_send_next_onion_skin(circ)<0) {
log_warn(LD_CIRC, "Couldn't extend circuit to new point '%s'.",
info->nickname);
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
return 0;
*/
orconn_circid_circuit_map_t *_last_circid_orconn_ent = NULL;
-/** Set the p_conn or n_conn field of a circuit <b>circ</b>, along
- * with the corresponding circuit ID, and add the circuit as appropriate
- * to the (orconn,id)-\>circuit map. */
-void
-circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
- connection_t *conn,
- enum which_conn_changed_t which)
+static void
+circuit_set_circid_orconn_helper(circuit_t *circ, uint16_t id,
+ connection_t *conn,
+ uint16_t old_id, connection_t *old_conn)
{
- uint16_t old_id;
- connection_t *old_conn;
orconn_circid_circuit_map_t search;
orconn_circid_circuit_map_t *found;
- tor_assert(!conn || conn->type == CONN_TYPE_OR);
-
- if (which == P_CONN_CHANGED) {
- old_id = circ->p_circ_id;
- old_conn = circ->p_conn;
- circ->p_circ_id = id;
- circ->p_conn = conn;
- } else {
- old_id = circ->n_circ_id;
- old_conn = circ->n_conn;
- circ->n_circ_id = id;
- circ->n_conn = conn;
- }
- if (conn == old_conn && old_id == id)
- return;
-
if (_last_circid_orconn_ent &&
((old_id == _last_circid_orconn_ent->circ_id &&
old_conn == _last_circid_orconn_ent->or_conn) ||
++conn->n_circuits;
}
+/** Set the p_conn field of a circuit <b>circ</b>, along
+ * with the corresponding circuit ID, and add the circuit as appropriate
+ * to the (orconn,id)-\>circuit map. */
+void
+circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
+ connection_t *conn)
+{
+ uint16_t old_id;
+ connection_t *old_conn;
+
+ old_id = circ->p_circ_id;
+ old_conn = circ->p_conn;
+ circ->p_circ_id = id;
+ circ->p_conn = conn;
+
+ if (id == old_id && conn == old_conn)
+ return;
+ circuit_set_circid_orconn_helper(TO_CIRCUIT(circ), id, conn,
+ old_id, old_conn);
+}
+
+/** Set the n_conn field of a circuit <b>circ</b>, 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, uint16_t id,
+ connection_t *conn)
+{
+ uint16_t old_id;
+ connection_t *old_conn;
+
+ old_id = circ->n_circ_id;
+ old_conn = circ->n_conn;
+ circ->n_circ_id = id;
+ circ->n_conn = conn;
+
+ if (id == old_id && conn == old_conn)
+ return;
+ circuit_set_circid_orconn_helper(circ, id, conn, old_id, old_conn);
+}
+
/** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
* it from lists as appropriate. */
void
}
}
-/** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
- * and <b>p_conn</b>. Add it to the global circuit list.
- */
-circuit_t *
-circuit_new(uint16_t p_circ_id, connection_t *p_conn)
+/* DOCDOC */
+static void
+init_circuit_base(circuit_t *circ)
{
- circuit_t *circ;
static uint32_t n_circuits_allocated = 1;
/* never zero, since a global ID of 0 is treated specially by the
* controller */
-
- circ = tor_malloc_zero(sizeof(circuit_t));
- circ->magic = CIRCUIT_MAGIC;
-
circ->timestamp_created = time(NULL);
- /* CircIDs */
- if (p_conn) {
- circuit_set_circid_orconn(circ, p_circ_id, p_conn, P_CONN_CHANGED);
- }
- /* circ->n_circ_id remains 0 because we haven't identified the next hop
- * yet */
-
circ->package_window = CIRCWINDOW_START;
circ->deliver_window = CIRCWINDOW_START;
-
- circ->next_stream_id = crypto_rand_int(1<<16);
circ->global_identifier = n_circuits_allocated++;
circuit_add(circ);
+}
+
+/** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
+ * and <b>p_conn</b>. Add it to the global circuit list.
+ */
+origin_circuit_t *
+origin_circuit_new(void)
+{
+ origin_circuit_t *circ;
+
+ circ = tor_malloc_zero(sizeof(origin_circuit_t));
+ circ->_base.magic = ORIGIN_CIRCUIT_MAGIC;
+
+ circ->next_stream_id = crypto_rand_int(1<<16);
+
+ init_circuit_base(TO_CIRCUIT(circ));
+
+ return circ;
+}
+
+or_circuit_t *
+or_circuit_new(uint16_t p_circ_id, connection_t *p_conn)
+{
+ /* 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);
+
+ init_circuit_base(TO_CIRCUIT(circ));
return circ;
}
static void
circuit_free(circuit_t *circ)
{
+ void *mem;
tor_assert(circ);
- tor_assert(circ->magic == CIRCUIT_MAGIC);
- if (circ->n_crypto)
- crypto_free_cipher_env(circ->n_crypto);
- if (circ->p_crypto)
- crypto_free_cipher_env(circ->p_crypto);
- if (circ->n_digest)
- crypto_free_digest_env(circ->n_digest);
- if (circ->p_digest)
- crypto_free_digest_env(circ->p_digest);
- if (circ->build_state) {
- if (circ->build_state->chosen_exit)
- extend_info_free(circ->build_state->chosen_exit);
- if (circ->build_state->pending_final_cpath)
- circuit_free_cpath_node(circ->build_state->pending_final_cpath);
- }
- tor_free(circ->build_state);
- tor_free(circ->onionskin);
- circuit_free_cpath(circ->cpath);
- if (circ->rend_splice) {
- tor_assert(circ->rend_splice->magic == CIRCUIT_MAGIC);
- circ->rend_splice->rend_splice = NULL;
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ mem = ocirc;
+ tor_assert(circ->magic == ORIGIN_CIRCUIT_MAGIC);
+ if (ocirc->build_state) {
+ if (ocirc->build_state->chosen_exit)
+ extend_info_free(ocirc->build_state->chosen_exit);
+ if (ocirc->build_state->pending_final_cpath)
+ circuit_free_cpath_node(ocirc->build_state->pending_final_cpath);
+ }
+ tor_free(ocirc->build_state);
+
+ circuit_free_cpath(ocirc->cpath);
+
+ } else {
+ or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
+ mem = ocirc;
+ tor_assert(circ->magic == OR_CIRCUIT_MAGIC);
+
+ if (ocirc->p_crypto)
+ crypto_free_cipher_env(ocirc->p_crypto);
+ if (ocirc->p_digest)
+ crypto_free_digest_env(ocirc->p_digest);
+ if (ocirc->n_crypto)
+ crypto_free_cipher_env(ocirc->n_crypto);
+ if (ocirc->n_digest)
+ crypto_free_digest_env(ocirc->n_digest);
+
+ if (ocirc->rend_splice) {
+ or_circuit_t *other = ocirc->rend_splice;
+ tor_assert(other->_base.magic == OR_CIRCUIT_MAGIC);
+ other->rend_splice = NULL;
+ }
+
+ tor_free(circ->onionskin);
+
+ /* remove from map. */
+ circuit_set_p_circid_orconn(ocirc, 0, NULL);
}
+
/* Remove from map. */
- circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
- circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
+ circuit_set_n_circid_orconn(circ, 0, NULL);
memset(circ, 0xAA, sizeof(circuit_t)); /* poison memory */
- tor_free(circ);
+ tor_free(mem);
}
/** Deallocate space associated with the linked list <b>cpath</b>. */
circuit_t *next;
while (global_circuitlist) {
next = global_circuitlist->next;
- while (global_circuitlist->resolving_streams) {
- connection_t *next;
- next = global_circuitlist->resolving_streams->next_stream;
- connection_free(global_circuitlist->resolving_streams);
- global_circuitlist->resolving_streams = next;
+ if (! CIRCUIT_IS_ORIGIN(global_circuitlist)) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(global_circuitlist);
+ while (or_circ->resolving_streams) {
+ connection_t *next;
+ next = or_circ->resolving_streams->next_stream;
+ connection_free(or_circ->resolving_streams);
+ or_circ->resolving_streams = next;
+ }
}
circuit_free(global_circuitlist);
global_circuitlist = next;
tor_free(victim);
}
+/** A helper function for circuit_dump_by_conn() below. Log a bunch
+ * of information about circuit <b>circ</b>.
+ */
+static void
+circuit_dump_details(int severity, circuit_t *circ, int poll_index,
+ const char *type, int this_circid, int other_circid)
+{
+ log(severity, LD_CIRC, "Conn %d has %s circuit: circID %d (other side %d), "
+ "state %d (%s), born %d:",
+ poll_index, type, this_circid, other_circid, circ->state,
+ circuit_state_to_string(circ->state), (int)circ->timestamp_created);
+ if (CIRCUIT_IS_ORIGIN(circ)) { /* circ starts at this node */
+ circuit_log_path(severity, LD_CIRC, TO_ORIGIN_CIRCUIT(circ));
+ }
+}
+
+/** Log, at severity <b>severity</b>, information about each circuit
+ * that is connected to <b>conn</b>.
+ */
+void
+circuit_dump_by_conn(connection_t *conn, int severity)
+{
+ circuit_t *circ;
+ 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 == conn)
+ circuit_dump_details(severity, circ, conn->poll_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 (tmpconn == conn) {
+ circuit_dump_details(severity, circ, conn->poll_index, "App-ward",
+ p_circ_id, n_circ_id);
+ }
+ }
+ }
+ if (circ->n_conn == conn)
+ circuit_dump_details(severity, circ, conn->poll_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 (tmpconn == conn) {
+ circuit_dump_details(severity, circ, conn->poll_index, "Exit-ward",
+ n_circ_id, p_circ_id);
+ }
+ }
+ }
+ if (!circ->n_conn && circ->n_addr && circ->n_port &&
+ circ->n_addr == conn->addr &&
+ circ->n_port == conn->port &&
+ !memcmp(conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) {
+ circuit_dump_details(severity, circ, conn->poll_index,
+ (circ->state == CIRCUIT_STATE_OPEN &&
+ !CIRCUIT_IS_ORIGIN(circ)) ?
+ "Endpoint" : "Pending",
+ n_circ_id, p_circ_id);
+ }
+ }
+}
+
/** Return the circuit whose global ID is <b>id</b>, or NULL if no
* such circuit exists. */
circuit_t *
{
circuit_t *circ;
for (circ=global_circuitlist;circ;circ = circ->next) {
- if (circ->p_conn == conn && circ->p_circ_id == circ_id) {
- log_warn(LD_BUG,
- "circuit matches p_conn, but not in hash table (Bug!)");
- return circ;
+ if (! CIRCUIT_IS_ORIGIN(circ)) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ if (or_circ->p_conn == conn && or_circ->p_circ_id == circ_id) {
+ log_warn(LD_BUG,
+ "circuit matches p_conn, but not in hash table (Bug!)");
+ return circ;
+ }
}
if (circ->n_conn == conn && circ->n_circ_id == circ_id) {
log_warn(LD_BUG,
tor_assert(CONN_IS_EDGE(conn));
circ = conn->on_circuit;
- tor_assert(!circ || circ->magic == CIRCUIT_MAGIC);
+ tor_assert(!circ ||
+ (CIRCUIT_IS_ORIGIN(circ) ? circ->magic == ORIGIN_CIRCUIT_MAGIC
+ : circ->magic == OR_CIRCUIT_MAGIC));
return circ;
}
{
circuit_t *circ;
for (circ = global_circuitlist; circ; circ = circ->next) {
- if (circ->n_conn == conn || circ->p_conn == conn) {
- if (circ->n_conn == conn)
- circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
- if (circ->p_conn == conn)
- circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
- if (!circ->marked_for_close)
- circuit_mark_for_close(circ, reason);
+ 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);
}
}
/** Return the circuit waiting for a rendezvous with the provided cookie.
* Return NULL if no such circuit is found.
*/
-circuit_t *
+or_circuit_t *
circuit_get_rendezvous(const char *cookie)
{
circuit_t *circ;
if (! circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_REND_POINT_WAITING &&
! memcmp(circ->rend_cookie, cookie, REND_COOKIE_LEN) )
- return circ;
+ return TO_OR_CIRCUIT(circ);
}
return NULL;
}
*
* Only return internal circuits if that is requested.
*/
-circuit_t *
+origin_circuit_t *
circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
int need_uptime,
int need_capacity, int internal)
{
- circuit_t *circ;
- circuit_t *best=NULL;
+ circuit_t *_circ;
+ origin_circuit_t *best=NULL;
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 == purpose &&
- !circ->timestamp_dirty &&
- (!need_uptime || circ->build_state->need_uptime) &&
- (!need_capacity || circ->build_state->need_capacity) &&
- (internal == circ->build_state->is_internal)) {
- if (info) {
- /* need to make sure we don't duplicate hops */
- crypt_path_t *hop = circ->cpath;
- do {
- if (!memcmp(hop->extend_info->identity_digest,
- info->identity_digest, DIGEST_LEN))
- goto next;
- hop=hop->next;
- } while (hop!=circ->cpath);
- }
- if (!best || (best->build_state->need_uptime && !need_uptime))
- best = circ;
+ for (_circ=global_circuitlist; _circ; _circ = _circ->next) {
+ if (CIRCUIT_IS_ORIGIN(_circ) &&
+ _circ->state == CIRCUIT_STATE_OPEN &&
+ !_circ->marked_for_close &&
+ _circ->purpose == purpose &&
+ !_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)) {
+ if (info) {
+ /* need to make sure we don't duplicate hops */
+ crypt_path_t *hop = circ->cpath;
+ do {
+ if (!memcmp(hop->extend_info->identity_digest,
+ info->identity_digest, DIGEST_LEN))
+ goto next;
+ hop=hop->next;
+ } while (hop!=circ->cpath);
+ }
+ if (!best || (best->build_state->need_uptime && !need_uptime))
+ best = circ;
next: ;
+ }
}
}
return best;
}
if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
- onion_pending_remove(circ);
+ 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
*/
if (circ->state != CIRCUIT_STATE_OPEN) {
if (CIRCUIT_IS_ORIGIN(circ)) {
- circuit_build_failed(circ); /* take actions if necessary */
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
+ circuit_build_failed(ocirc); /* take actions if necessary */
+ circuit_rep_hist_note_result(ocirc);
}
- circuit_rep_hist_note_result(circ);
}
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(circ,
+ control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
(circ->state == CIRCUIT_STATE_OPEN)?CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED);
}
if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
+ origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
tor_assert(circ->state == CIRCUIT_STATE_OPEN);
- tor_assert(circ->build_state->chosen_exit);
+ tor_assert(ocirc->build_state->chosen_exit);
/* treat this like getting a nack from it */
log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). "
"Removing from descriptor.",
safe_str(circ->rend_query),
- safe_str(build_state_get_exit_nickname(circ->build_state)));
- rend_client_remove_intro_point(circ->build_state->chosen_exit,
+ safe_str(build_state_get_exit_nickname(ocirc->build_state)));
+ rend_client_remove_intro_point(ocirc->build_state->chosen_exit,
circ->rend_query);
}
-
if (circ->n_conn)
connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
- for (conn=circ->n_streams; conn; conn=conn->next_stream)
- connection_edge_destroy(circ->n_circ_id, conn);
- while (circ->resolving_streams) {
- conn = circ->resolving_streams;
- circ->resolving_streams = conn->next_stream;
- if (!conn->marked_for_close) {
- /* The other side 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->has_sent_end = 1;
- connection_mark_for_close(conn);
+
+ if (! CIRCUIT_IS_ORIGIN(circ)) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ for (conn=or_circ->n_streams; conn; conn=conn->next_stream)
+ connection_edge_destroy(or_circ->p_circ_id, conn);
+
+ while (or_circ->resolving_streams) {
+ conn = or_circ->resolving_streams;
+ or_circ->resolving_streams = conn->next_stream;
+ if (!conn->marked_for_close) {
+ /* The other side 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->has_sent_end = 1;
+ connection_mark_for_close(conn);
+ }
+ conn->on_circuit = NULL;
}
- conn->on_circuit = NULL;
+
+ if (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);
+ for (conn=ocirc->p_streams; conn; conn=conn->next_stream)
+ connection_edge_destroy(circ->n_circ_id, conn);
}
- if (circ->p_conn)
- connection_or_send_destroy(circ->p_circ_id, circ->p_conn, reason);
- for (conn=circ->p_streams; conn; conn=conn->next_stream)
- connection_edge_destroy(circ->p_circ_id, conn);
circ->marked_for_close = line;
circ->marked_for_close_file = file;
- if (circ->rend_splice) {
- if (!circ->rend_splice->marked_for_close) {
- /* do this after marking this circuit, to avoid infinite recursion. */
- circuit_mark_for_close(circ->rend_splice, reason);
+ 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;
}
- circ->rend_splice = NULL;
}
}
assert_circuit_ok(const circuit_t *c)
{
connection_t *conn;
+ const or_circuit_t *or_circ = NULL;
+ const origin_circuit_t *origin_circ = NULL;
tor_assert(c);
- tor_assert(c->magic == CIRCUIT_MAGIC);
+ tor_assert(c->magic == ORIGIN_CIRCUIT_MAGIC || c->magic == OR_CIRCUIT_MAGIC);
tor_assert(c->purpose >= _CIRCUIT_PURPOSE_MIN &&
c->purpose <= _CIRCUIT_PURPOSE_MAX);
+ if (CIRCUIT_IS_ORIGIN(c))
+ origin_circ = TO_ORIGIN_CIRCUIT((circuit_t*)c);
+ else
+ or_circ = TO_OR_CIRCUIT((circuit_t*)c);
+
if (c->n_conn) {
tor_assert(c->n_conn->type == CONN_TYPE_OR);
tor_assert(!memcmp(c->n_conn->identity_digest, c->n_conn_id_digest,
if (c->n_circ_id)
tor_assert(c == circuit_get_by_circid_orconn(c->n_circ_id, c->n_conn));
}
- if (c->p_conn) {
- tor_assert(c->p_conn->type == CONN_TYPE_OR);
- if (c->p_circ_id)
- tor_assert(c == circuit_get_by_circid_orconn(c->p_circ_id, c->p_conn));
+ if (or_circ && or_circ->p_conn) {
+ tor_assert(or_circ->p_conn->type == CONN_TYPE_OR);
+ if (or_circ->p_circ_id)
+ tor_assert(c == circuit_get_by_circid_orconn(or_circ->p_circ_id,
+ or_circ->p_conn));
}
- for (conn = c->p_streams; conn; conn = conn->next_stream)
- tor_assert(conn->type == CONN_TYPE_AP);
- for (conn = c->n_streams; conn; conn = conn->next_stream)
- tor_assert(conn->type == CONN_TYPE_EXIT);
+ if (origin_circ)
+ for (conn = origin_circ->p_streams; conn; conn = conn->next_stream)
+ tor_assert(conn->type == CONN_TYPE_AP);
+ if (or_circ)
+ for (conn = or_circ->n_streams; conn; conn = conn->next_stream)
+ tor_assert(conn->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->onionskin);
- if (c->cpath) {
- tor_assert(CIRCUIT_IS_ORIGIN(c));
- tor_assert(!c->n_crypto);
- tor_assert(!c->p_crypto);
- tor_assert(!c->n_digest);
- tor_assert(!c->p_digest);
- } else {
- tor_assert(!CIRCUIT_IS_ORIGIN(c));
- tor_assert(c->n_crypto);
- tor_assert(c->p_crypto);
- tor_assert(c->n_digest);
- tor_assert(c->p_digest);
+ 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));
}
- if (c->cpath) {
- assert_cpath_ok(c->cpath);
+ if (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(c->rend_splice);
- tor_assert(c->rend_splice->rend_splice == c);
+ tor_assert(or_circ->rend_splice);
+ tor_assert(or_circ->rend_splice->rend_splice == or_circ);
}
- tor_assert(c->rend_splice != c);
+ tor_assert(or_circ->rend_splice != or_circ);
} else {
- tor_assert(!c->rend_splice);
+ tor_assert(!or_circ || !or_circ->rend_splice);
}
}
time_t now)
{
routerinfo_t *exitrouter;
+ cpath_build_state_t *build_state;
tor_assert(circ);
tor_assert(conn);
tor_assert(conn->socks_request);
* circuit, it's the magical extra bob hop. so just check the nickname
* of the one we meant to finish at.
*/
- exitrouter = build_state_get_exit_router(circ->build_state);
+ build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ exitrouter = build_state_get_exit_router(build_state);
- if (need_uptime && !circ->build_state->need_uptime)
+ if (need_uptime && !build_state->need_uptime)
return 0;
- if (need_internal != circ->build_state->is_internal)
+ if (need_internal != build_state->is_internal)
return 0;
if (purpose == CIRCUIT_PURPOSE_C_GENERAL) {
return 1;
} else {
if (a->timestamp_dirty ||
- b->build_state->is_internal ||
a->timestamp_created > b->timestamp_created)
return 1;
+ if (CIRCUIT_IS_ORIGIN(b) &&
+ TO_ORIGIN_CIRCUIT(b)->build_state->is_internal)
+ return 1;
}
break;
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
* If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the
* closest introduce-purposed circuit that you can find.
*/
-static circuit_t *
+static origin_circuit_t *
circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose,
int need_uptime, int need_internal)
{
purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
for (circ=global_circuitlist;circ;circ = circ->next) {
+ if (!CIRCUIT_IS_ORIGIN(circ))
+ continue;
if (!circuit_is_acceptable(circ,conn,must_be_open,purpose,
need_uptime,need_internal,now))
continue;
best = circ;
}
- return best;
+ return best ? TO_ORIGIN_CIRCUIT(best) : NULL;
}
/** Close all circuits that start at us, aren't open, and were born
victim->n_circ_id, victim->state,
circuit_state_to_string(victim->state), victim->purpose);
- circuit_log_path(LOG_INFO,LD_CIRC,victim);
+ circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim));
circuit_mark_for_close(victim, END_CIRC_AT_ORIGIN);
}
}
if (CIRCUIT_IS_ORIGIN(circ) &&
!circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
- !circ->build_state->is_internal &&
(!circ->timestamp_dirty ||
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness > now)) {
- exitrouter = build_state_get_exit_router(circ->build_state);
- if (exitrouter &&
- (!need_uptime || circ->build_state->need_uptime)) {
+ cpath_build_state_t *build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ if (build_state->is_internal)
+ continue;
+
+ exitrouter = build_state_get_exit_router(build_state);
+ if (exitrouter && (!need_uptime || build_state->need_uptime)) {
int ok;
if (conn) {
ok = connection_ap_can_use_exit(conn, exitrouter);
/* First, count how many of each type of circuit we have already. */
for (circ=global_circuitlist;circ;circ = circ->next) {
+ cpath_build_state_t *build_state;
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
if (circ->marked_for_close)
if (circ->purpose != CIRCUIT_PURPOSE_C_GENERAL)
continue; /* only pay attention to general-purpose circs */
num++;
- if (circ->build_state->is_internal)
+ build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ if (build_state->is_internal)
num_internal++;
- if (circ->build_state->need_uptime && circ->build_state->is_internal)
+ if (build_state->need_uptime && build_state->is_internal)
num_uptime_internal++;
}
conn->cpath_layer = NULL; /* make sure we don't keep a stale pointer */
conn->on_circuit = NULL;
- if (conn == circ->p_streams) {
- circ->p_streams = conn->next_stream;
- return;
- }
- if (conn == circ->n_streams) {
- circ->n_streams = conn->next_stream;
- return;
- }
- if (conn == circ->resolving_streams) {
- circ->resolving_streams = conn->next_stream;
- return;
- }
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
+ if (conn == origin_circ->p_streams) {
+ origin_circ->p_streams = conn->next_stream;
+ return;
+ }
- for (prevconn = circ->p_streams;
- prevconn && prevconn->next_stream && prevconn->next_stream != conn;
- prevconn = prevconn->next_stream)
- ;
- if (prevconn && prevconn->next_stream) {
- prevconn->next_stream = conn->next_stream;
- return;
- }
+ for (prevconn = origin_circ->p_streams;
+ prevconn && prevconn->next_stream && prevconn->next_stream != conn;
+ prevconn = prevconn->next_stream)
+ ;
+ if (prevconn && prevconn->next_stream) {
+ prevconn->next_stream = conn->next_stream;
+ return;
+ }
+ } else {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
+ if (conn == or_circ->n_streams) {
+ or_circ->n_streams = conn->next_stream;
+ return;
+ }
+ if (conn == or_circ->resolving_streams) {
+ or_circ->resolving_streams = conn->next_stream;
+ return;
+ }
- for (prevconn = circ->n_streams;
- prevconn && prevconn->next_stream && prevconn->next_stream != conn;
- prevconn = prevconn->next_stream)
- ;
- if (prevconn && prevconn->next_stream) {
- prevconn->next_stream = conn->next_stream;
- return;
- }
+ for (prevconn = or_circ->n_streams;
+ prevconn && prevconn->next_stream && prevconn->next_stream != conn;
+ prevconn = prevconn->next_stream)
+ ;
+ if (prevconn && prevconn->next_stream) {
+ prevconn->next_stream = conn->next_stream;
+ return;
+ }
- for (prevconn = circ->resolving_streams;
- prevconn && prevconn->next_stream && prevconn->next_stream != conn;
- prevconn = prevconn->next_stream)
- ;
- if (prevconn && prevconn->next_stream) {
- prevconn->next_stream = conn->next_stream;
- return;
+ for (prevconn = or_circ->resolving_streams;
+ prevconn && prevconn->next_stream && prevconn->next_stream != conn;
+ prevconn = prevconn->next_stream)
+ ;
+ if (prevconn && prevconn->next_stream) {
+ prevconn->next_stream = conn->next_stream;
+ return;
+ }
}
log_err(LD_BUG,"edge conn not in circuit's list?");
}
/** Find each circuit that has been unused for too long, or dirty
- * for too long and has no streams on it: mark it for close.
+ * for too long and has no streax=ms on it: mark it for close.
*/
static void
circuit_expire_old_circuits(time_t now)
time_t cutoff = now - get_options()->CircuitIdleTimeout;
for (circ = global_circuitlist; circ; circ = circ->next) {
- if (circ->marked_for_close)
+ if (circ->marked_for_close || ! CIRCUIT_IS_ORIGIN(circ))
continue;
/* If the circuit has been dirty for too long, and there are no streams
* on it, mark it for close.
*/
if (circ->timestamp_dirty &&
circ->timestamp_dirty + get_options()->MaxCircuitDirtiness < now &&
- CIRCUIT_IS_ORIGIN(circ) &&
- !circ->p_streams /* nothing attached */ ) {
+ !TO_ORIGIN_CIRCUIT(circ)->p_streams /* nothing attached */ ) {
log_debug(LD_CIRC, "Closing n_circ_id %d (dirty %d secs ago, purp %d)",
circ->n_circ_id, (int)(now - circ->timestamp_dirty),
circ->purpose);
/* (only general and purpose_c circs can get dirty) */
- tor_assert(!circ->n_streams);
tor_assert(circ->purpose <= CIRCUIT_PURPOSE_C_REND_JOINED);
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
- } else if (!circ->timestamp_dirty && CIRCUIT_IS_ORIGIN(circ) &&
+ } else if (!circ->timestamp_dirty &&
circ->state == CIRCUIT_STATE_OPEN &&
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) {
if (circ->timestamp_created < cutoff) {
/** A testing circuit has completed. Take whatever stats we want. */
static void
-circuit_testing_opened(circuit_t *circ)
+circuit_testing_opened(origin_circuit_t *circ)
{
/* For now, we only use testing circuits to see if our ORPort is
reachable. But we remember reachability in onionskin_answer(),
so there's no need to record anything here. Just close the circ. */
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
}
/** A testing circuit has failed to build. Take whatever stats we want. */
static void
-circuit_testing_failed(circuit_t *circ, int at_last_hop)
+circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
{
if (server_mode(get_options()) && check_whether_orport_reachable())
return;
* that could use circ.
*/
void
-circuit_has_opened(circuit_t *circ)
+circuit_has_opened(origin_circuit_t *circ)
{
control_event_circuit_status(circ, CIRC_EVENT_BUILT);
- switch (circ->purpose) {
+ switch (TO_CIRCUIT(circ)->purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
rend_client_rendcirc_has_opened(circ);
connection_ap_attach_pending();
circuit_testing_opened(circ);
break;
default:
- log_err(LD_BUG,"unhandled purpose %d",circ->purpose);
+ log_err(LD_BUG,"unhandled purpose %d",circ->_base.purpose);
tor_assert(0);
}
}
/** Called whenever a circuit could not be successfully built.
*/
void
-circuit_build_failed(circuit_t *circ)
+circuit_build_failed(origin_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.
/* We failed at the first hop. If there's an OR connection
to blame, blame it. */
connection_t *n_conn = NULL;
- if (circ->n_conn) {
- n_conn = circ->n_conn;
- } else if (circ->state == CIRCUIT_STATE_OR_WAIT) {
+ if (circ->_base.n_conn) {
+ n_conn = circ->_base.n_conn;
+ } else if (circ->_base.state == CIRCUIT_STATE_OR_WAIT) {
/* we have to hunt for it */
- n_conn = connection_or_get_by_identity_digest(circ->n_conn_id_digest);
+ n_conn = connection_or_get_by_identity_digest(
+ circ->_base.n_conn_id_digest);
}
if (n_conn) {
log_info(LD_OR,
}
}
- switch (circ->purpose) {
+ switch (circ->_base.purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
/* If we never built the circuit, note it as a failure. */
circuit_increment_failure_count();
break;
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
/* at Bob, waiting for introductions */
- if (circ->state != CIRCUIT_STATE_OPEN) {
+ if (circ->_base.state != CIRCUIT_STATE_OPEN) {
circuit_increment_failure_count();
}
/* no need to care here, because bob will rebuild intro
/** Launch a new circuit; see circuit_launch_by_extend_info() for
* details on arguments. */
-circuit_t *
+origin_circuit_t *
circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
int need_uptime, int need_capacity, int internal)
{
- circuit_t *circ;
+ origin_circuit_t *circ;
extend_info_t *info = NULL;
if (exit)
info = extend_info_from_router(exit);
* choose among routers with high bandwidth. If <b>internal</b> is true, the
* last hop need not be an exit node. Return the newly allocated circuit on
* success, or NULL on failure. */
-circuit_t *
+origin_circuit_t *
circuit_launch_by_extend_info(uint8_t purpose, extend_info_t *extend_info,
int need_uptime, int need_capacity, int internal)
{
- circuit_t *circ;
+ origin_circuit_t *circ;
if (!router_have_minimum_dir_info()) {
log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling "
if (circ) {
log_info(LD_CIRC,"Cannibalizing circ '%s' for purpose %d",
build_state_get_exit_nickname(circ->build_state), purpose);
- circ->purpose = purpose;
+ circ->_base.purpose = purpose;
/* reset the birth date of this circ, else expire_building
* will see it and think it's been trying to build since it
* began. */
- circ->timestamp_created = time(NULL);
+ circ->_base.timestamp_created = time(NULL);
switch (purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
/** Launch a new circuit; see circuit_launch_by_extend_info() for
* details on arguments. */
-circuit_t *
+origin_circuit_t *
circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname,
int need_uptime, int need_capacity, int internal)
{
static int
circuit_get_open_circ_or_launch(connection_t *conn,
uint8_t desired_circuit_purpose,
- circuit_t **circp)
+ origin_circuit_t **circp)
{
- circuit_t *circ;
+ origin_circuit_t *circ;
int is_resolve;
int need_uptime, need_internal;
rep_hist_note_used_internal(time(NULL), need_uptime, 1);
if (circ) {
/* write the service_id into circ */
- strlcpy(circ->rend_query, conn->rend_query, sizeof(circ->rend_query));
- if (circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
- circ->state == CIRCUIT_STATE_OPEN)
+ strlcpy(circ->_base.rend_query, conn->rend_query,
+ sizeof(circ->_base.rend_query));
+ if (circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
+ circ->_base.state == CIRCUIT_STATE_OPEN)
rend_client_rendcirc_has_opened(circ);
}
}
* circ's cpath.
*/
static void
-link_apconn_to_circ(connection_t *apconn, circuit_t *circ)
+link_apconn_to_circ(connection_t *apconn, origin_circuit_t *circ)
{
/* add it into the linked list of streams on this circuit */
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.",
- circ->n_circ_id);
+ circ->_base.n_circ_id);
/* reset it, so we can measure circ timeouts */
apconn->timestamp_lastread = time(NULL);
apconn->next_stream = circ->p_streams;
- apconn->on_circuit = circ;
+ apconn->on_circuit = TO_CIRCUIT(circ);
/* assert_connection_ok(conn, time(NULL)); */
circ->p_streams = apconn;
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
tor_assert(circ->cpath);
tor_assert(circ->cpath->prev);
tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
/** If an exit wasn't specifically chosen, save the history for future
* use. */
static void
-consider_recording_trackhost(connection_t *conn, circuit_t *circ)
+consider_recording_trackhost(connection_t *conn, origin_circuit_t *circ)
{
int found_needle = 0;
char *str;
* for connection_ap_handshake_attach_circuit. */
int
connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
- circuit_t *circ)
+ origin_circuit_t *circ)
{
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_AP);
conn->state == AP_CONN_STATE_CONTROLLER_WAIT);
tor_assert(conn->socks_request);
tor_assert(circ);
- tor_assert(circ->state == CIRCUIT_STATE_OPEN);
+ tor_assert(circ->_base.state == CIRCUIT_STATE_OPEN);
conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
- if (!circ->timestamp_dirty)
- circ->timestamp_dirty = time(NULL);
+ if (!circ->_base.timestamp_dirty)
+ circ->_base.timestamp_dirty = time(NULL);
link_apconn_to_circ(conn, circ);
tor_assert(conn->socks_request);
}
if (!connection_edge_is_rendezvous_stream(conn)) { /* we're a general conn */
- circuit_t *circ=NULL;
+ origin_circuit_t *circ=NULL;
if (conn->chosen_exit_name) {
routerinfo_t *router = router_get_by_nickname(conn->chosen_exit_name, 1);
log_debug(LD_APP|LD_CIRC,
"Attaching apconn to circ %d (stream %d sec old).",
- circ->n_circ_id, conn_age);
+ circ->_base.n_circ_id, conn_age);
/* here, print the circ's path. so people can figure out which circs are
* sucking. */
circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ);
return connection_ap_handshake_attach_chosen_circuit(conn, circ);
} else { /* we're a rendezvous conn */
- circuit_t *rendcirc=NULL, *introcirc=NULL;
+ origin_circuit_t *rendcirc=NULL, *introcirc=NULL;
tor_assert(!conn->cpath_layer);
log_info(LD_REND,
"rend joined circ %d already here. attaching. "
"(stream %d sec old)",
- rendcirc->n_circ_id, conn_age);
+ rendcirc->_base.n_circ_id, conn_age);
/* Mark rendezvous circuits as 'newly dirty' every time you use
* them, since the process of rebuilding a rendezvous circ is so
* expensive. There is a tradeoffs between linkability and
* feasibility, at this point.
*/
- rendcirc->timestamp_dirty = time(NULL);
+ rendcirc->_base.timestamp_dirty = time(NULL);
link_apconn_to_circ(conn, rendcirc);
if (connection_ap_handshake_send_begin(conn, rendcirc) < 0)
return 0; /* already marked, let them fade away */
return 1;
}
- if (rendcirc && (rendcirc->purpose ==
+ if (rendcirc && (rendcirc->_base.purpose ==
CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) {
log_info(LD_REND,
"pending-join circ %d already here, with intro ack. "
"Stalling. (stream %d sec old)",
- rendcirc->n_circ_id, conn_age);
+ rendcirc->_base.n_circ_id, conn_age);
return 0;
}
tor_assert(introcirc);
log_info(LD_REND, "Intro circ %d present and awaiting ack (rend %d). "
"Stalling. (stream %d sec old)",
- introcirc->n_circ_id, rendcirc ? rendcirc->n_circ_id : 0,
+ introcirc->_base.n_circ_id,
+ rendcirc ? rendcirc->_base.n_circ_id : 0,
conn_age);
return 0;
}
/* now rendcirc and introcirc are each either undefined or not finished */
if (rendcirc && introcirc &&
- rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
+ rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY) {
log_info(LD_REND,
"ready rend circ %d already here (no intro-ack yet on "
"intro %d). (stream %d sec old)",
- rendcirc->n_circ_id, introcirc->n_circ_id, conn_age);
+ rendcirc->_base.n_circ_id,
+ introcirc->_base.n_circ_id, conn_age);
- tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- if (introcirc->state == CIRCUIT_STATE_OPEN) {
+ tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ if (introcirc->_base.state == CIRCUIT_STATE_OPEN) {
log_info(LD_REND,"found open intro circ %d (rend %d); sending "
"introduction. (stream %d sec old)",
- introcirc->n_circ_id, rendcirc->n_circ_id, conn_age);
+ introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id,
+ conn_age);
if (rend_client_send_introduction(introcirc, rendcirc) < 0) {
return -1;
}
- rendcirc->timestamp_dirty = time(NULL);
- introcirc->timestamp_dirty = time(NULL);
- assert_circuit_ok(rendcirc);
- assert_circuit_ok(introcirc);
+ rendcirc->_base.timestamp_dirty = time(NULL);
+ introcirc->_base.timestamp_dirty = time(NULL);
+ assert_circuit_ok(TO_CIRCUIT(rendcirc));
+ assert_circuit_ok(TO_CIRCUIT(introcirc));
return 0;
}
}
log_info(LD_REND, "Intro (%d) and rend (%d) circs are not both ready. "
"Stalling conn. (%d sec old)",
- introcirc ? introcirc->n_circ_id : 0,
- rendcirc ? rendcirc->n_circ_id : 0, conn_age);
+ introcirc ? introcirc->_base.n_circ_id : 0,
+ rendcirc ? rendcirc->_base.n_circ_id : 0, conn_age);
return 0;
}
}
static void
command_process_create_cell(cell_t *cell, connection_t *conn)
{
- circuit_t *circ;
+ or_circuit_t *circ;
int id_is_high;
if (we_are_hibernating()) {
return;
}
- circ = circuit_get_by_circid_orconn(cell->circ_id, conn);
-
- if (circ) {
+ if (circuit_get_by_circid_orconn(cell->circ_id, conn)) {
routerinfo_t *router = router_get_by_digest(conn->identity_digest);
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Received CREATE cell (circID %d) for known circ. "
return;
}
- circ = circuit_new(cell->circ_id, conn);
- circ->purpose = CIRCUIT_PURPOSE_OR;
- circuit_set_state(circ, CIRCUIT_STATE_ONIONSKIN_PENDING);
+ circ = or_circuit_new(cell->circ_id, conn);
+ circ->_base.purpose = CIRCUIT_PURPOSE_OR;
+ circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
if (cell->command == CELL_CREATE) {
- circ->onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
- memcpy(circ->onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
+ circ->_base.onionskin = tor_malloc(ONIONSKIN_CHALLENGE_LEN);
+ memcpy(circ->_base.onionskin, cell->payload, ONIONSKIN_CHALLENGE_LEN);
/* hand it off to the cpuworkers, and then return. */
if (assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) {
log_warn(LD_GENERAL,"Failed to hand off onionskin. Closing.");
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
log_debug(LD_OR,"success: handed off onionskin.");
tor_assert(cell->command == CELL_CREATE_FAST);
if (fast_server_handshake(cell->payload, reply, keys, sizeof(keys))<0) {
log_warn(LD_OR,"Failed to generate key material. Closing.");
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
if (onionskin_answer(circ, CELL_CREATED_FAST, reply, keys)<0) {
log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return;
}
}
}
if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */
+ origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
log_debug(LD_OR,"at OP. Finishing handshake.");
- if (circuit_finish_handshake(circ, cell->command, cell->payload) < 0) {
+ if (circuit_finish_handshake(origin_circ, cell->command,
+ cell->payload) < 0) {
log_warn(LD_OR,"circuit_finish_handshake failed.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
return;
}
log_debug(LD_OR,"Moving to next skin.");
- if (circuit_send_next_onion_skin(circ) < 0) {
+ if (circuit_send_next_onion_skin(origin_circ) < 0) {
log_info(LD_OR,"circuit_send_next_onion_skin failed.");
/* XXX push this circuit_close lower */
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
return;
}
- if (cell->circ_id == circ->p_circ_id) { /* it's an outgoing cell */
+ if (!CIRCUIT_IS_ORIGIN(circ) &&
+ cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
+ /* it's an outgoing cell */
if ((reason = circuit_receive_relay_cell(cell, circ,
CELL_DIRECTION_OUT)) < 0) {
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell "
}
log_debug(LD_OR,"Received for circID %d.",cell->circ_id);
- if (cell->circ_id == circ->p_circ_id) {
+ if (!CIRCUIT_IS_ORIGIN(circ) &&
+ cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
/* the destroy came from behind */
- circuit_set_circid_orconn(circ, 0, NULL, P_CONN_CHANGED);
+ circuit_set_p_circid_orconn(TO_OR_CIRCUIT(circ), 0, NULL);
circuit_mark_for_close(circ, reason);
} else { /* the destroy came from ahead */
- circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
+ circuit_set_n_circid_orconn(circ, 0, NULL);
if (CIRCUIT_IS_ORIGIN(circ)) {
circuit_mark_for_close(circ, reason);
} else {
int
connection_edge_reached_eof(connection_t *conn)
{
-#ifdef HALF_OPEN
- /* eof reached; we're done reading, but we might want to write more. */
- conn->done_receiving = 1;
- shutdown(conn->s, 0); /* XXX check return, refactor NM */
- if (conn->done_sending) {
- connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
- connection_mark_for_close(conn);
- } else {
- connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
- RELAY_COMMAND_END,
- NULL, 0, conn->cpath_layer);
- }
- return 0;
-#else
if (buf_datalen(conn->inbuf) && connection_state_is_open(conn)) {
/* it still has stuff to process. don't let it die yet. */
return 0;
connection_mark_for_close(conn);
}
return 0;
-#endif
}
/** Handle new bytes on conn->inbuf based on state:
continue;
}
tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
- nickname = build_state_get_exit_nickname(circ->build_state);
+ nickname = build_state_get_exit_nickname(
+ TO_ORIGIN_CIRCUIT(circ)->build_state);
log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
"We tried for %d seconds to connect to '%s' using exit '%s'."
" Retrying on a new circuit.",
conn->timestamp_lastread += cutoff;
conn->num_socks_retries++;
/* move it back into 'pending' state, and try to attach. */
- if (connection_ap_detach_retriable(conn, circ)<0) {
+ if (connection_ap_detach_retriable(conn, TO_ORIGIN_CIRCUIT(circ))<0) {
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
}
} /* end for */
* Returns -1 on err, 1 on success, 0 on not-yet-sure.
*/
int
-connection_ap_detach_retriable(connection_t *conn, circuit_t *circ)
+connection_ap_detach_retriable(connection_t *conn, origin_circuit_t *circ)
{
control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE);
conn->timestamp_lastread = time(NULL);
if (! get_options()->LeaveStreamsUnattached) {
conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
- circuit_detach_stream(circ,conn);
+ circuit_detach_stream(TO_CIRCUIT(circ),conn);
return connection_ap_handshake_attach_circuit(conn);
} else {
conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
- circuit_detach_stream(circ,conn);
+ circuit_detach_stream(TO_CIRCUIT(circ),conn);
return 0;
}
}
*/
int
connection_ap_handshake_rewrite_and_attach(connection_t *conn,
- circuit_t *circ)
+ origin_circuit_t *circ)
{
socks_request_t *socks = conn->socks_request;
hostname_type_t addresstype;
* already in use; return it. Return 0 if can't get a unique stream_id.
*/
static uint16_t
-get_unique_stream_id_by_circ(circuit_t *circ)
+get_unique_stream_id_by_circ(origin_circuit_t *circ)
{
connection_t *tmpconn;
uint16_t test_stream_id;
* If ap_conn is broken, mark it for close and return -1. Else return 0.
*/
int
-connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ)
+connection_ap_handshake_send_begin(connection_t *ap_conn,
+ origin_circuit_t *circ)
{
char payload[CELL_PAYLOAD_SIZE];
int payload_len;
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
- circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return -1;
}
tor_snprintf(payload,RELAY_PAYLOAD_SIZE, "%s:%d",
- (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
+ (circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL) ?
ap_conn->socks_request->address : "",
ap_conn->socks_request->port);
payload_len = strlen(payload)+1;
log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id);
- if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_BEGIN,
+ if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ),
+ RELAY_COMMAND_BEGIN,
payload, payload_len,
ap_conn->cpath_layer) < 0)
return -1; /* circuit is closed, don't continue */
ap_conn->deliver_window = STREAMWINDOW_START;
ap_conn->state = AP_CONN_STATE_CONNECT_WAIT;
log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
- ap_conn->s, circ->n_circ_id);
+ ap_conn->s, circ->_base.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT);
return 0;
}
* If ap_conn is broken, mark it for close and return -1. Else return 0.
*/
int
-connection_ap_handshake_send_resolve(connection_t *ap_conn, circuit_t *circ)
+connection_ap_handshake_send_resolve(connection_t *ap_conn,
+ origin_circuit_t *circ)
{
int payload_len;
const char *string_addr;
tor_assert(ap_conn->state == AP_CONN_STATE_CIRCUIT_WAIT);
tor_assert(ap_conn->socks_request);
tor_assert(ap_conn->socks_request->command == SOCKS_COMMAND_RESOLVE);
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_GENERAL);
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL);
ap_conn->stream_id = get_unique_stream_id_by_circ(circ);
if (ap_conn->stream_id==0) {
connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
- circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return -1;
}
log_debug(LD_APP,
"Sending relay cell to begin stream %d.", ap_conn->stream_id);
- if (connection_edge_send_command(ap_conn, circ, RELAY_COMMAND_RESOLVE,
+ if (connection_edge_send_command(ap_conn, TO_CIRCUIT(circ),
+ RELAY_COMMAND_RESOLVE,
string_addr, payload_len, ap_conn->cpath_layer) < 0)
return -1; /* circuit is closed, don't continue */
ap_conn->state = AP_CONN_STATE_RESOLVE_WAIT;
log_info(LD_APP,"Address sent for resolve, ap socket %d, n_circ_id %d",
- ap_conn->s, circ->n_circ_id);
+ ap_conn->s, circ->_base.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_RESOLVE);
return 0;
}
n_stream->deliver_window = STREAMWINDOW_START;
if (circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED) {
+ origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
log_debug(LD_REND,"begin is for rendezvous. configuring stream.");
n_stream->address = tor_strdup("(rendezvous)");
n_stream->state = EXIT_CONN_STATE_CONNECTING;
sizeof(n_stream->rend_query));
tor_assert(connection_edge_is_rendezvous_stream(n_stream));
assert_circuit_ok(circ);
- if (rend_service_set_connection_addr_port(n_stream, circ) < 0) {
+ if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) {
log_info(LD_REND,"Didn't find rendezvous service (port %d)",
n_stream->port);
connection_edge_end(n_stream, END_STREAM_REASON_EXITPOLICY,
}
assert_circuit_ok(circ);
log_debug(LD_REND,"Finished assigning addr/port");
- n_stream->cpath_layer = circ->cpath->prev; /* link it */
+ n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */
/* add it into the linked list of n_streams on this circuit */
- n_stream->next_stream = circ->n_streams;
+ n_stream->next_stream = origin_circ->p_streams;
n_stream->on_circuit = circ;
- circ->n_streams = n_stream;
+ origin_circ->p_streams = n_stream;
assert_circuit_ok(circ);
connection_exit_connect(n_stream);
case 1: /* resolve worked */
/* add it into the linked list of n_streams on this circuit */
- n_stream->next_stream = circ->n_streams;
+ n_stream->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
n_stream->on_circuit = circ;
- circ->n_streams = n_stream;
+ TO_OR_CIRCUIT(circ)->n_streams = n_stream;
assert_circuit_ok(circ);
log_debug(LD_EXIT,"about to call connection_exit_connect().");
break;
case 0: /* resolve added to pending list */
/* add it into the linked list of resolving_streams on this circuit */
- n_stream->next_stream = circ->resolving_streams;
+ n_stream->next_stream = TO_OR_CIRCUIT(circ)->resolving_streams;
n_stream->on_circuit = circ;
- circ->resolving_streams = n_stream;
+ TO_OR_CIRCUIT(circ)->resolving_streams = n_stream;
assert_circuit_ok(circ);
;
}
* begin resolving the hostname, and (eventually) reply with a RESOLVED cell.
*/
int
-connection_exit_begin_resolve(cell_t *cell, circuit_t *circ)
+connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
{
connection_t *dummy_conn;
relay_header_t rh;
- assert_circuit_ok(circ);
+ assert_circuit_ok(TO_CIRCUIT(circ));
relay_header_unpack(&rh, cell->payload);
/* This 'dummy_conn' only exists to remember the stream ID
return 0;
case 0: /* resolve added to pending list */
dummy_conn->next_stream = circ->resolving_streams;
- dummy_conn->on_circuit = circ;
+ dummy_conn->on_circuit = TO_CIRCUIT(circ);
circ->resolving_streams = dummy_conn;
- assert_circuit_ok(circ);
+ assert_circuit_ok(TO_CIRCUIT(circ));
break;
}
return 0;
const char *state;
if (! CIRCUIT_IS_ORIGIN(circ) || circ->marked_for_close)
continue;
- path = circuit_list_path(circ,0);
+ path = circuit_list_path(TO_ORIGIN_CIRCUIT(circ),0);
if (circ->state == CIRCUIT_STATE_OPEN)
state = "BUILT";
else if (strlen(path))
}
}
+ if (circ && ! CIRCUIT_IS_ORIGIN(circ)) {
+ if (v0)
+ send_control0_error(conn, ERR_NO_CIRC,"Circuit does not originate here");
+ else
+ connection_printf_to_buf(conn,
+ "555 Circuit does not originate here\r\n");
+ goto done;
+ }
+
routers = smartlist_create();
SMARTLIST_FOREACH(router_nicknames, const char *, n,
{
if (zero_circ) {
/* start a new circuit */
- circ = circuit_init(intended_purpose, 0, 0, 0);
+ circ = TO_CIRCUIT( origin_circuit_init(intended_purpose, 0, 0, 0) );
}
/* now circ refers to something that is ready to be extended */
SMARTLIST_FOREACH(routers, routerinfo_t *, r,
{
extend_info_t *info = extend_info_from_router(r);
- circuit_append_new_exit(circ, info);
+ circuit_append_new_exit(TO_ORIGIN_CIRCUIT(circ), info);
extend_info_free(info);
});
/* now that we've populated the cpath, start extending */
if (zero_circ) {
- if (circuit_handle_first_hop(circ) < 0) {
+ if (circuit_handle_first_hop(TO_ORIGIN_CIRCUIT(circ)) < 0) {
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
if (v0)
send_control0_error(conn, ERR_INTERNAL, "couldn't start circuit");
} else {
if (circ->state == CIRCUIT_STATE_OPEN) {
circuit_set_state(circ, CIRCUIT_STATE_BUILDING);
- if (circuit_send_next_onion_skin(circ) < 0) {
+ if (circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)) < 0) {
log_info(LD_CONTROL,
"send_next_onion_skin failed; circuit marked for closing.");
circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
ap_conn->state = AP_CONN_STATE_CONTROLLER_WAIT;
}
- if (circ && circ->state != CIRCUIT_STATE_OPEN) {
+ if (circ &&
+ (circ->state != CIRCUIT_STATE_OPEN || ! CIRCUIT_IS_ORIGIN(circ))) {
if (STATE_IS_V0(conn->state))
send_control0_error(conn, ERR_INTERNAL,
- "Refuse to attach stream to non-open circ.");
+ "Refuse to attach stream to non-open, origin circ.");
else
connection_write_str_to_buf(
- "551 Can't attach stream to non-open circuit\r\n",
- conn);
+ "551 Can't attach stream to non-open, origin circuit\r\n",
+ conn);
return 0;
}
- if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ) < 0) {
+ if (connection_ap_handshake_rewrite_and_attach(ap_conn,
+ circ ? TO_ORIGIN_CIRCUIT(circ) : NULL) < 0) {
if (STATE_IS_V0(conn->state))
send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream.");
else
return 0;
}
- if (!safe || !circ->p_streams) {
+ if (!safe || !CIRCUIT_IS_ORIGIN(circ) ||
+ !TO_ORIGIN_CIRCUIT(circ)->p_streams) {
circuit_mark_for_close(circ, END_CIRC_REASON_NONE);
}
/** Something has happened to circuit <b>circ</b>: tell any interested
* control connections. */
int
-control_event_circuit_status(circuit_t *circ, circuit_status_event_t tp)
+control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp)
{
char *path, *msg;
if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
return 0;
tor_assert(circ);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
path = circuit_list_path(circ,0);
if (EVENT_IS_INTERESTING0(EVENT_CIRCUIT_STATUS)) {
size_t path_len = strlen(path);
msg = tor_malloc(1+4+path_len+1); /* event, circid, path, NUL. */
msg[0] = (uint8_t) tp;
- set_uint32(msg+1, htonl(circ->global_identifier));
+ set_uint32(msg+1, htonl(circ->_base.global_identifier));
strlcpy(msg+5,path,path_len+1);
send_control0_event(EVENT_CIRCUIT_STATUS, (uint32_t)(path_len+6), msg);
}
send_control1_event(EVENT_CIRCUIT_STATUS,
"650 CIRC %lu %s %s\r\n",
- (unsigned long)circ->global_identifier,
+ (unsigned long)circ->_base.global_identifier,
status, path);
}
tor_free(path);
log_debug(LD_OR,"processed onion for a circ that's gone. Dropping.");
goto done_processing;
}
- tor_assert(circ->p_conn);
- if (onionskin_answer(circ, CELL_CREATED, buf+TAG_LEN,
+ tor_assert(! CIRCUIT_IS_ORIGIN(circ));
+ if (onionskin_answer(TO_OR_CIRCUIT(circ), CELL_CREATED, buf+TAG_LEN,
buf+TAG_LEN+ONIONSKIN_REPLY_LEN) < 0) {
log_warn(LD_OR,"onionskin_answer failed. Closing.");
circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
static void
process_pending_task(connection_t *cpuworker)
{
- circuit_t *circ;
+ or_circuit_t *circ;
tor_assert(cpuworker);
assign_to_cpuworker(connection_t *cpuworker, uint8_t question_type,
void *task)
{
- circuit_t *circ;
+ or_circuit_t *circ;
char tag[TAG_LEN];
tor_assert(question_type == CPUWORKER_TASK_ONION);
if (question_type == CPUWORKER_TASK_ONION) {
circ = task;
- tor_assert(circ->onionskin);
+ tor_assert(circ->_base.onionskin);
if (num_cpuworkers_busy == num_cpuworkers) {
log_debug(LD_OR,"No idle cpuworkers. Queuing.");
connection_write_to_buf((char*)&question_type, 1, cpuworker);
connection_write_to_buf(tag, sizeof(tag), cpuworker);
- connection_write_to_buf(circ->onionskin, ONIONSKIN_CHALLENGE_LEN,
+ connection_write_to_buf(circ->_base.onionskin, ONIONSKIN_CHALLENGE_LEN,
cpuworker);
- tor_free(circ->onionskin);
+ tor_free(circ->_base.onionskin);
}
return 0;
}
circ = circuit_get_by_edge_conn(pend->conn);
tor_assert(circ);
+ tor_assert(!CIRCUIT_IS_ORIGIN(circ));
/* unlink pend->conn from resolving_streams, */
circuit_detach_stream(circ, pend->conn);
/* and link it to n_streams */
- pend->conn->next_stream = circ->n_streams;
+ pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
pend->conn->on_circuit = circ;
- circ->n_streams = pend->conn;
+ TO_OR_CIRCUIT(circ)->n_streams = pend->conn;
connection_exit_connect(pend->conn);
} else {
/** Type for a linked list of circuits that are waiting for a free CPU worker
* to process a waiting onion handshake. */
typedef struct onion_queue_t {
- circuit_t *circ;
+ or_circuit_t *circ;
time_t when_added;
struct onion_queue_t *next;
} onion_queue_t;
* if ol_list is too long, in which case do nothing and return -1.
*/
int
-onion_pending_add(circuit_t *circ)
+onion_pending_add(or_circuit_t *circ)
{
onion_queue_t *tmp;
time_t now = time(NULL);
onion_pending_remove(ol_list->circ);
log_info(LD_CIRC,
"Circuit create request is too old; cancelling due to overload.");
- circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
}
return 0;
}
/** Remove the first item from ol_list and return it, or return
* NULL if the list is empty.
*/
-circuit_t *
+or_circuit_t *
onion_next_task(void)
{
- circuit_t *circ;
+ or_circuit_t *circ;
if (!ol_list)
return NULL; /* no onions pending, we're done */
* circ, remove and free that element. Leave circ itself alone.
*/
void
-onion_pending_remove(circuit_t *circ)
+onion_pending_remove(or_circuit_t *circ)
{
onion_queue_t *tmpo, *victim;
time_t expiry_time;
} cpath_build_state_t;
-#define CIRCUIT_MAGIC 0x35315243u
+#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
+#define OR_CIRCUIT_MAGIC 0x98ABC04Fu
+
+typedef uint16_t circid_t;
/**
* A circuit is a path over the onion routing
* "backward" (towards the OP). At the OR, a circuit has only two stream
* ciphers: one for data going forward, and one for data going backward.
*/
-struct circuit_t {
- uint32_t magic; /**< For memory debugging: must equal CIRCUIT_MAGIC. */
+typedef struct circuit_t {
+ uint32_t magic; /**< For memory and type debugging: must equal
+ * ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */
- /** The OR connection that is previous in this circuit. */
- connection_t *p_conn;
/** The OR connection that is next in this circuit. */
connection_t *n_conn;
/** The identity hash of n_conn. */
char n_conn_id_digest[DIGEST_LEN];
- /** Linked list of AP streams associated with this circuit. */
- connection_t *p_streams;
- /** Linked list of Exit streams associated with this circuit. */
- connection_t *n_streams;
- /** Linked list of Exit streams associated with this circuit that are
- * still being resolved. */
- connection_t *resolving_streams;
+ /** The circuit_id used in the next (forward) hop of this circuit. */
+ uint16_t n_circ_id;
/** The IPv4 address of the OR that is next in this circuit. */
uint32_t n_addr;
/** The port for the OR that is next in this circuit. */
uint16_t n_port;
- /** The next stream_id that will be tried when we're attempting to
- * construct a new AP stream originating at this circuit. */
- uint16_t next_stream_id;
/** How many relay data cells can we package (read from edge streams)
* on this circuit before we receive a circuit-level sendme cell asking
* for more? */
* more. */
int deliver_window;
- /** The circuit_id used in the previous (backward) hop of this circuit. */
- uint16_t p_circ_id;
- /** The circuit_id used in the next (forward) hop of this circuit. */
- uint16_t n_circ_id;
-
- /** The cipher used by intermediate hops for cells heading toward the
- * OP. */
- crypto_cipher_env_t *p_crypto;
- /** The cipher used by intermediate hops for cells heading away from
- * the OP. */
- crypto_cipher_env_t *n_crypto;
-
- /** The integrity-checking digest used by intermediate hops, for
- * cells packaged here and heading towards the OP.
- */
- crypto_digest_env_t *p_digest;
- /** The integrity-checking digest used by intermediate hops, for
- * cells packaged at the OP and arriving here.
- */
- crypto_digest_env_t *n_digest;
-
- /** Build state for this circuit. It includes the intended path
- * length, the chosen exit router, rendezvous information, etc.
- */
- cpath_build_state_t *build_state;
- /** The doubly-linked list of crypt_path_t entries, one per hop,
- * for this circuit. This includes ciphers for each hop,
- * integrity-checking digests for each hop, and package/delivery
- * windows for each hop.
- *
- * The cpath field is defined only when we are the circuit's origin.
- */
- crypt_path_t *cpath;
-
/** For storage while passing to cpuworker (state
* CIRCUIT_STATE_ONIONSKIN_PENDING), or while n_conn is pending
* (state CIRCUIT_STATE_OR_WAIT). When defined, it is always
* length ONIONSKIN_CHALLENGE_LEN. */
char *onionskin;
- char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */
-
time_t timestamp_created; /**< When was this circuit created? */
time_t timestamp_dirty; /**< When the circuit was first used, or 0 if the
* circuit is clean. */
*/
char rend_cookie[REND_COOKIE_LEN];
- /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
- * is not marked for close. */
- struct circuit_t *rend_splice;
-
/** Quasi-global identifier for this circuit; used for control.c */
/* XXXX NM This can get re-used after 2**32 circuits. */
uint32_t global_identifier;
struct circuit_t *next; /**< Next circuit in linked list. */
-};
+} circuit_t;
+
+typedef struct origin_circuit_t {
+ circuit_t _base;
+
+ /** Linked list of AP streams associated with this circuit. */
+ connection_t *p_streams;
+ /** The next stream_id that will be tried when we're attempting to
+ * construct a new AP stream originating at this circuit. */
+ uint16_t next_stream_id;
+ /** Build state for this circuit. It includes the intended path
+ * length, the chosen exit router, rendezvous information, etc.
+ */
+ cpath_build_state_t *build_state;
+ /** The doubly-linked list of crypt_path_t entries, one per hop,
+ * for this circuit. This includes ciphers for each hop,
+ * integrity-checking digests for each hop, and package/delivery
+ * windows for each hop.
+ *
+ * The cpath field is defined only when we are the circuit's origin.
+ */
+ crypt_path_t *cpath;
-typedef struct circuit_t circuit_t;
+} origin_circuit_t;
+
+typedef struct or_circuit_t {
+ circuit_t _base;
+
+ /** The circuit_id used in the previous (backward) hop of this circuit. */
+ circid_t p_circ_id;
+ /** The OR connection that is previous in this circuit. */
+ connection_t *p_conn;
+ /** Linked list of Exit streams associated with this circuit. */
+ connection_t *n_streams;
+ /** Linked list of Exit streams associated with this circuit that are
+ * still being resolved. */
+ connection_t *resolving_streams;
+ /** The cipher used by intermediate hops for cells heading toward the
+ * OP. */
+ crypto_cipher_env_t *p_crypto;
+ /** The cipher used by intermediate hops for cells heading away from
+ * the OP. */
+ crypto_cipher_env_t *n_crypto;
+
+ /** The integrity-checking digest used by intermediate hops, for
+ * cells packaged here and heading towards the OP.
+ */
+ crypto_digest_env_t *p_digest;
+ /** The integrity-checking digest used by intermediate hops, for
+ * cells packaged at the OP and arriving here.
+ */
+ crypto_digest_env_t *n_digest;
+
+ /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit
+ * is not marked for close. */
+ struct or_circuit_t *rend_splice;
+
+ char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */
+} or_circuit_t;
+
+#define TO_CIRCUIT(x) (&((x)->_base))
+or_circuit_t *TO_OR_CIRCUIT(circuit_t *x);
+extern INLINE or_circuit_t *TO_OR_CIRCUIT(circuit_t *x)
+{
+ tor_assert(x->magic == OR_CIRCUIT_MAGIC);
+ return (or_circuit_t*) (((char*)x) - STRUCT_OFFSET(or_circuit_t, _base));
+}
+origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x);
+extern INLINE origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x)
+{
+ tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC);
+ return (origin_circuit_t*)
+ (((char*)x) - STRUCT_OFFSET(origin_circuit_t, _base));
+}
#define ALLOW_INVALID_ENTRY 1
#define ALLOW_INVALID_EXIT 2
/********************************* circuitbuild.c **********************/
-char *circuit_list_path(circuit_t *circ, int verbose);
-void circuit_log_path(int severity, unsigned int domain, circuit_t *circ);
-void circuit_rep_hist_note_result(circuit_t *circ);
-void circuit_dump_by_conn(connection_t *conn, int severity);
-circuit_t *circuit_init(uint8_t purpose, int need_uptime,
- int need_capacity, int internal);
-circuit_t *circuit_establish_circuit(uint8_t purpose, extend_info_t *exit,
+char *circuit_list_path(origin_circuit_t *circ, int verbose);
+void circuit_log_path(int severity, unsigned int domain,
+ origin_circuit_t *circ);
+void circuit_rep_hist_note_result(origin_circuit_t *circ);
+origin_circuit_t *origin_circuit_init(uint8_t purpose, int need_uptime,
+ int need_capacity, int internal);
+origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
+ extend_info_t *exit,
int need_uptime, int need_capacity,
int internal);
-int circuit_handle_first_hop(circuit_t *circ);
+int circuit_handle_first_hop(origin_circuit_t *circ);
void circuit_n_conn_done(connection_t *or_conn, int status);
int inform_testing_reachability(void);
-int circuit_send_next_onion_skin(circuit_t *circ);
+int circuit_send_next_onion_skin(origin_circuit_t *circ);
void circuit_note_clock_jumped(int seconds_elapsed);
int circuit_extend(cell_t *cell, circuit_t *circ);
int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data,
int reverse);
-int circuit_finish_handshake(circuit_t *circ, uint8_t cell_type, char *reply);
-int circuit_truncated(circuit_t *circ, crypt_path_t *layer);
-int onionskin_answer(circuit_t *circ, uint8_t cell_type, char *payload,
+int circuit_finish_handshake(origin_circuit_t *circ, uint8_t cell_type,
+ char *reply);
+int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer);
+int onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
char *keys);
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
int *need_capacity);
-int circuit_append_new_exit(circuit_t *circ, extend_info_t *info);
-int circuit_extend_to_new_exit(circuit_t *circ, extend_info_t *info);
+int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
+int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
extend_info_t *extend_info_from_router(routerinfo_t *r);
extend_info_t *extend_info_dup(extend_info_t *info);
circuit_t * _circuit_get_global_list(void);
const char *circuit_state_to_string(int state);
-enum which_conn_changed_t { P_CONN_CHANGED=1, N_CONN_CHANGED=0 };
-void circuit_set_circid_orconn(circuit_t *circ, uint16_t id,
- connection_t *conn,
- enum which_conn_changed_t which);
+void circuit_dump_by_conn(connection_t *conn, int severity);
+void circuit_set_p_circid_orconn(or_circuit_t *circ, uint16_t id,
+ connection_t *conn);
+void circuit_set_n_circid_orconn(circuit_t *circ, uint16_t id,
+ connection_t *conn);
void circuit_set_state(circuit_t *circ, int state);
void circuit_close_all_marked(void);
-circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn);
+origin_circuit_t *origin_circuit_new(void);
+or_circuit_t *or_circuit_new(uint16_t p_circ_id, connection_t *p_conn);
circuit_t *circuit_get_by_circid_orconn(uint16_t circ_id, connection_t *conn);
int circuit_id_used_on_conn(uint16_t circ_id, connection_t *conn);
circuit_t *circuit_get_by_edge_conn(connection_t *conn);
uint8_t purpose);
circuit_t *circuit_get_next_by_pk_and_purpose(circuit_t *start,
const char *digest, uint8_t purpose);
-circuit_t *circuit_get_rendezvous(const char *cookie);
-circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
+or_circuit_t *circuit_get_rendezvous(const char *cookie);
+origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
+ extend_info_t *info,
int need_uptime,
int need_capacity, int internal);
void circuit_mark_all_unused_circs(void);
void circuit_build_needed_circs(time_t now);
void circuit_detach_stream(circuit_t *circ, connection_t *conn);
void circuit_about_to_close_connection(connection_t *conn);
-void circuit_has_opened(circuit_t *circ);
-void circuit_build_failed(circuit_t *circ);
-circuit_t *circuit_launch_by_nickname(uint8_t purpose,
+void circuit_has_opened(origin_circuit_t *circ);
+void circuit_build_failed(origin_circuit_t *circ);
+origin_circuit_t *circuit_launch_by_nickname(uint8_t purpose,
const char *exit_nickname,
int need_uptime, int need_capacity,
int is_internal);
-circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
+origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
extend_info_t *info,
int need_uptime, int need_capacity,
int is_internal);
-circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
+origin_circuit_t *circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
int need_uptime, int need_capacity,
int is_internal);
void circuit_reset_failure_count(int timeout);
int connection_ap_handshake_attach_chosen_circuit(connection_t *conn,
- circuit_t *circ);
+ origin_circuit_t *circ);
int connection_ap_handshake_attach_circuit(connection_t *conn);
/********************************* command.c ***************************/
int connection_edge_finished_flushing(connection_t *conn);
int connection_edge_finished_connecting(connection_t *conn);
-int connection_ap_handshake_send_begin(connection_t *ap_conn, circuit_t *circ);
+int connection_ap_handshake_send_begin(connection_t *ap_conn,
+ origin_circuit_t *circ);
int connection_ap_handshake_send_resolve(connection_t *ap_conn,
- circuit_t *circ);
+ origin_circuit_t *circ);
int connection_ap_make_bridge(char *address, uint16_t port);
void connection_ap_handshake_socks_reply(connection_t *conn, char *reply,
int ttl);
int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
-int connection_exit_begin_resolve(cell_t *cell, circuit_t *circ);
+int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
void connection_exit_connect(connection_t *conn);
int connection_edge_is_rendezvous_stream(connection_t *conn);
int connection_ap_can_use_exit(connection_t *conn, routerinfo_t *exit);
void connection_ap_expire_beginning(void);
void connection_ap_attach_pending(void);
-int connection_ap_detach_retriable(connection_t *conn, circuit_t *circ);
+int connection_ap_detach_retriable(connection_t *conn, origin_circuit_t *circ);
void addressmap_init(void);
void addressmap_clean(time_t now);
void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
time_t max_expires);
int connection_ap_handshake_rewrite_and_attach(connection_t *conn,
- circuit_t *circ);
+ origin_circuit_t *circ);
void set_exit_redirects(smartlist_t *lst);
typedef enum hostname_type_t {
int connection_control_reached_eof(connection_t *conn);
int connection_control_process_inbuf(connection_t *conn);
-int control_event_circuit_status(circuit_t *circ, circuit_status_event_t e);
+int control_event_circuit_status(origin_circuit_t *circ,
+ circuit_status_event_t e);
int control_event_stream_status(connection_t *conn, stream_status_event_t e);
int control_event_or_conn_status(connection_t *conn, or_conn_status_event_t e);
int control_event_bandwidth_used(uint32_t n_read, uint32_t n_written);
/********************************* onion.c ***************************/
-int onion_pending_add(circuit_t *circ);
-circuit_t *onion_next_task(void);
-void onion_pending_remove(circuit_t *circ);
+int onion_pending_add(or_circuit_t *circ);
+or_circuit_t *onion_next_task(void);
+void onion_pending_remove(or_circuit_t *circ);
int onion_skin_create(crypto_pk_env_t *router_key,
crypto_dh_env_t **handshake_state_out,
/********************************* rendclient.c ***************************/
-void rend_client_introcirc_has_opened(circuit_t *circ);
-void rend_client_rendcirc_has_opened(circuit_t *circ);
-int rend_client_introduction_acked(circuit_t *circ, const char *request,
+void rend_client_introcirc_has_opened(origin_circuit_t *circ);
+void rend_client_rendcirc_has_opened(origin_circuit_t *circ);
+int rend_client_introduction_acked(origin_circuit_t *circ, const char *request,
size_t request_len);
void rend_client_refetch_renddesc(const char *query);
int rend_client_remove_intro_point(extend_info_t *failed_intro,
const char *query);
-int rend_client_rendezvous_acked(circuit_t *circ, const char *request,
+int rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request,
size_t request_len);
-int rend_client_receive_rendezvous(circuit_t *circ, const char *request,
+int rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request,
size_t request_len);
void rend_client_desc_here(const char *query);
extend_info_t *rend_client_get_random_intro(const char *query);
-int rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc);
+int rend_client_send_introduction(origin_circuit_t *introcirc,
+ origin_circuit_t *rendcirc);
/********************************* rendcommon.c ***************************/
void rend_services_introduce(void);
void rend_consider_services_upload(time_t now);
-void rend_service_intro_has_opened(circuit_t *circuit);
-int rend_service_intro_established(circuit_t *circuit, const char *request,
+void rend_service_intro_has_opened(origin_circuit_t *circuit);
+int rend_service_intro_established(origin_circuit_t *circuit,
+ const char *request,
size_t request_len);
-void rend_service_rendezvous_has_opened(circuit_t *circuit);
-int rend_service_introduce(circuit_t *circuit, const char *request,
+void rend_service_rendezvous_has_opened(origin_circuit_t *circuit);
+int rend_service_introduce(origin_circuit_t *circuit, const char *request,
size_t 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_relaunch_rendezvous(origin_circuit_t *oldcirc);
+int rend_service_set_connection_addr_port(connection_t *conn,
+ origin_circuit_t *circ);
void rend_service_dump_stats(int severity);
void rend_service_free_all(void);
/********************************* rendmid.c *******************************/
-int rend_mid_establish_intro(circuit_t *circ, const char *request,
+int rend_mid_establish_intro(or_circuit_t *circ, const char *request,
size_t request_len);
-int rend_mid_introduce(circuit_t *circ, const char *request,
+int rend_mid_introduce(or_circuit_t *circ, const char *request,
size_t request_len);
-int rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
+int rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len);
-int rend_mid_rendezvous(circuit_t *circ, const char *request,
+int rend_mid_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len);
/********************************* router.c ***************************/
if (cell_direction == CELL_DIRECTION_OUT) {
cell->circ_id = circ->n_circ_id; /* switch it */
conn = circ->n_conn;
+ } else if (! CIRCUIT_IS_ORIGIN(circ)) {
+ cell->circ_id = TO_OR_CIRCUIT(circ)->p_circ_id; /* switch it */
+ conn = TO_OR_CIRCUIT(circ)->p_conn;
} else {
- cell->circ_id = circ->p_circ_id; /* switch it */
- conn = circ->p_conn;
+ // XXXX NM WARN.
+ return 0;
}
if (!conn) {
- if (circ->rend_splice && cell_direction == CELL_DIRECTION_OUT) {
+ // XXXX Can this splice stuff be done more cleanly?
+ if (! CIRCUIT_IS_ORIGIN(circ) &&
+ TO_OR_CIRCUIT(circ)->rend_splice &&
+ cell_direction == CELL_DIRECTION_OUT) {
+ or_circuit_t *splice = TO_OR_CIRCUIT(circ)->rend_splice;
tor_assert(circ->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
- tor_assert(circ->rend_splice->purpose ==
- CIRCUIT_PURPOSE_REND_ESTABLISHED);
- cell->circ_id = circ->rend_splice->p_circ_id;
- if ((reason = circuit_receive_relay_cell(cell, circ->rend_splice,
+ tor_assert(splice->_base.purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED);
+ cell->circ_id = splice->p_circ_id;
+ if ((reason = circuit_receive_relay_cell(cell, TO_CIRCUIT(splice),
CELL_DIRECTION_IN)) < 0) {
log_warn(LD_REND, "Error relaying cell across rendezvous; closing "
"circuits");
relay_crypt(circuit_t *circ, cell_t *cell, int cell_direction,
crypt_path_t **layer_hint, char *recognized)
{
- crypt_path_t *thishop;
relay_header_t rh;
tor_assert(circ);
if (cell_direction == CELL_DIRECTION_IN) {
if (CIRCUIT_IS_ORIGIN(circ)) { /* We're at the beginning of the circuit.
* We'll want to do layered decrypts. */
- tor_assert(circ->cpath);
- thishop = circ->cpath;
+ crypt_path_t *thishop, *cpath = TO_ORIGIN_CIRCUIT(circ)->cpath;
+ thishop = cpath;
if (thishop->state != CPATH_STATE_OPEN) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Relay cell before first created cell? Closing.");
}
thishop = thishop->next;
- } while (thishop != circ->cpath && thishop->state == CPATH_STATE_OPEN);
+ } while (thishop != cpath && thishop->state == CPATH_STATE_OPEN);
log_warn(LD_OR,"in-cell at OP not recognized. Closing.");
return -1;
} else { /* we're in the middle. Just one crypt. */
- if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0)
+ if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->p_crypto,
+ cell->payload, 1) < 0)
return -1;
// log_fn(LOG_DEBUG,"Skipping recognized check, because we're not "
// "the OP.");
} else /* cell_direction == CELL_DIRECTION_OUT */ {
/* we're in the middle. Just one crypt. */
- if (relay_crypt_one_payload(circ->n_crypto, cell->payload, 0) < 0)
+ if (relay_crypt_one_payload(TO_OR_CIRCUIT(circ)->n_crypto,
+ cell->payload, 0) < 0)
return -1;
relay_header_unpack(&rh, cell->payload);
if (rh.recognized == 0) {
/* it's possibly recognized. have to check digest to be sure. */
- if (relay_digest_matches(circ->n_digest, cell)) {
+ if (relay_digest_matches(TO_OR_CIRCUIT(circ)->n_digest, cell)) {
*recognized = 1;
return 0;
}
return 0;
}
-/** Package a relay cell:
+/** Package a relay cell from an edge:
* - Encrypt it to the right layer
* - connection_or_write_cell_to_buf to the right conn
*/
crypt_path_t *layer_hint)
{
connection_t *conn; /* where to send the cell */
- crypt_path_t *thishop; /* counter for repeated crypts */
if (cell_direction == CELL_DIRECTION_OUT) {
+ crypt_path_t *thishop; /* counter for repeated crypts */
conn = circ->n_conn;
- if (!conn) {
+ if (!CIRCUIT_IS_ORIGIN(circ) || !conn) {
log_warn(LD_BUG,"outgoing relay cell has n_conn==NULL. Dropping.");
return 0; /* just drop it */
}
}
thishop = thishop->prev;
- } while (thishop != circ->cpath->prev);
+ } while (thishop != TO_ORIGIN_CIRCUIT(circ)->cpath->prev);
} else { /* incoming cell */
- conn = circ->p_conn;
- if (!conn) {
+ or_circuit_t *or_circ;
+ if (CIRCUIT_IS_ORIGIN(circ)) {
/* XXXX RD This is a bug, right? */
- log_warn(LD_BUG,"incoming relay cell has p_conn==NULL. Dropping.");
+ log_warn(LD_BUG,"incoming relay cell at origin circuit. Dropping.");
assert_circuit_ok(circ);
return 0; /* just drop it */
}
- relay_set_digest(circ->p_digest, cell);
- if (relay_crypt_one_payload(circ->p_crypto, cell->payload, 1) < 0)
+ or_circ = TO_OR_CIRCUIT(circ);
+ conn = or_circ->p_conn;
+ relay_set_digest(or_circ->p_digest, cell);
+ if (relay_crypt_one_payload(or_circ->p_crypto, cell->payload, 1) < 0)
return -1;
}
++stats_n_relay_cells_relayed;
* that we allow rendezvous *to* an OP.
*/
- for (tmpconn = circ->n_streams; tmpconn; tmpconn=tmpconn->next_stream) {
- if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
- log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
- if (cell_direction == CELL_DIRECTION_OUT ||
- connection_edge_is_rendezvous_stream(tmpconn))
+ if (CIRCUIT_IS_ORIGIN(circ)) {
+ for (tmpconn = TO_ORIGIN_CIRCUIT(circ)->p_streams; tmpconn;
+ tmpconn=tmpconn->next_stream) {
+ if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
+ log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
return tmpconn;
+ }
}
- }
- for (tmpconn = circ->p_streams; tmpconn; tmpconn=tmpconn->next_stream) {
- if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
- log_debug(LD_APP,"found conn for stream %d.", rh.stream_id);
- return tmpconn;
+ } else {
+ for (tmpconn = TO_OR_CIRCUIT(circ)->n_streams; tmpconn;
+ tmpconn=tmpconn->next_stream) {
+ if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
+ log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
+ if (cell_direction == CELL_DIRECTION_OUT ||
+ connection_edge_is_rendezvous_stream(tmpconn))
+ return tmpconn;
+ }
}
- }
- for (tmpconn = circ->resolving_streams; tmpconn;
- tmpconn=tmpconn->next_stream) {
- if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
- log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
- return tmpconn;
+ for (tmpconn = TO_OR_CIRCUIT(circ)->resolving_streams; tmpconn;
+ tmpconn=tmpconn->next_stream) {
+ if (rh.stream_id == tmpconn->stream_id && !tmpconn->marked_for_close) {
+ log_debug(LD_EXIT,"found conn for stream %d.", rh.stream_id);
+ return tmpconn;
+ }
}
}
return NULL; /* probably a begin relay cell */
cell_t cell;
relay_header_t rh;
int cell_direction;
+ /* XXXX NM Split this function into a separate versions per circuit type? */
if (fromconn && fromconn->marked_for_close) {
log_warn(LD_BUG,
if (cpath_layer) {
cell.circ_id = circ->n_circ_id;
cell_direction = CELL_DIRECTION_OUT;
- } else {
- cell.circ_id = circ->p_circ_id;
+ } else if (! CIRCUIT_IS_ORIGIN(circ)) {
+ cell.circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
cell_direction = CELL_DIRECTION_IN;
+ } else {
+ return -1;
}
memset(&rh, 0, sizeof(rh));
*/
static int
connection_edge_process_end_not_open(
- relay_header_t *rh, cell_t *cell, circuit_t *circ,
+ relay_header_t *rh, cell_t *cell, origin_circuit_t *circ,
connection_t *conn, crypt_path_t *layer_hint)
{
struct in_addr in;
< MAX_RESOLVE_FAILURES) {
/* We haven't retried too many times; reattach the connection. */
circuit_log_path(LOG_INFO,LD_APP,circ);
- tor_assert(circ->timestamp_dirty);
- circ->timestamp_dirty -= get_options()->MaxCircuitDirtiness;
+ tor_assert(circ->_base.timestamp_dirty);
+ circ->_base.timestamp_dirty -= get_options()->MaxCircuitDirtiness;
if (conn->chosen_exit_optional) { /* stop wanting a specific exit */
conn->chosen_exit_optional = 0;
relay_header_t *rh, cell_t *cell, circuit_t *circ,
connection_t *conn, crypt_path_t *layer_hint)
{
- if (rh->command == RELAY_COMMAND_END)
- return connection_edge_process_end_not_open(rh, cell, circ, conn,
- layer_hint);
+ if (rh->command == RELAY_COMMAND_END) {
+ if (CIRCUIT_IS_ORIGIN(circ))
+ return connection_edge_process_end_not_open(rh, cell,
+ TO_ORIGIN_CIRCUIT(circ), conn,
+ layer_hint);
+ else
+ return 0;
+ }
if (conn->type == CONN_TYPE_AP && rh->command == RELAY_COMMAND_CONNECTED) {
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (conn->state != AP_CONN_STATE_CONNECT_WAIT) {
log_warn(LD_APP,"Got 'connected' while not in state connect_wait. "
"Dropping.");
client_dns_set_addressmap(conn->socks_request->address, addr,
conn->chosen_exit_name, ttl);
}
- circuit_log_path(LOG_INFO,LD_APP,circ);
+ circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ));
connection_ap_handshake_socks_reply(conn, NULL, 0, SOCKS5_SUCCEEDED);
/* handle anything that might have queued */
if (connection_edge_package_raw_inbuf(conn, 1) < 0) {
if (conn->socks_request && !conn->socks_request->has_finished)
log_warn(LD_BUG,
"Bug: open stream hasn't sent socks answer yet? Closing.");
-#ifdef HALF_OPEN
- conn->done_sending = 1;
- shutdown(conn->s, 1); /* XXX check return; refactor NM */
- if (conn->done_receiving) {
- /* We just *got* an end; no reason to send one. */
- conn->has_sent_end = 1;
- connection_mark_for_close(conn);
- conn->hold_open_until_flushed = 1;
- }
-#else
/* We just *got* an end; no reason to send one. */
conn->has_sent_end = 1;
if (!conn->marked_for_close) {
connection_mark_for_close(conn);
conn->hold_open_until_flushed = 1;
}
-#endif
return 0;
case RELAY_COMMAND_EXTEND:
if (conn) {
return 0;
}
log_debug(domain,"Got an extended cell! Yay.");
- if ((reason = circuit_finish_handshake(circ, CELL_CREATED,
+ if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ),
+ CELL_CREATED,
cell->payload+RELAY_HEADER_SIZE)) < 0) {
log_warn(domain,"circuit_finish_handshake failed.");
return reason;
}
- if ((reason=circuit_send_next_onion_skin(circ))<0) {
+ if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) {
log_info(domain,"circuit_send_next_onion_skin() failed.");
return reason;
}
if (circ->n_conn) {
uint8_t reason = *(uint8_t*)(cell->payload + RELAY_HEADER_SIZE);
connection_or_send_destroy(circ->n_circ_id, circ->n_conn, reason);
- circuit_set_circid_orconn(circ, 0, NULL, N_CONN_CHANGED);
+ circuit_set_n_circid_orconn(circ, 0, NULL);
}
log_debug(LD_EXIT, "Processed 'truncate', replying.");
{
log_warn(LD_EXIT,"'truncated' unsupported at non-origin. Dropping.");
return 0;
}
- circuit_truncated(circ, layer_hint);
+ circuit_truncated(TO_ORIGIN_CIRCUIT(circ), layer_hint);
return 0;
case RELAY_COMMAND_CONNECTED:
if (conn) {
circ->purpose);
return 0;
}
- connection_exit_begin_resolve(cell, circ);
+ connection_exit_begin_resolve(cell, TO_OR_CIRCUIT(circ));
return 0;
case RELAY_COMMAND_RESOLVED:
if (conn) {
log_debug(layer_hint?LD_APP:LD_EXIT,"resuming");
- /* have to check both n_streams and p_streams, to handle rendezvous */
- if (circuit_resume_edge_reading_helper(circ->n_streams, circ, layer_hint)
- >= 0)
- circuit_resume_edge_reading_helper(circ->p_streams, circ, layer_hint);
+ if (CIRCUIT_IS_ORIGIN(circ))
+ circuit_resume_edge_reading_helper(TO_ORIGIN_CIRCUIT(circ)->p_streams,
+ circ, layer_hint);
+ else
+ circuit_resume_edge_reading_helper(TO_OR_CIRCUIT(circ)->n_streams,
+ circ, layer_hint);
}
/** A helper function for circuit_resume_edge_reading() above.
unsigned domain = layer_hint ? LD_APP : LD_EXIT;
if (!layer_hint) {
+ or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
log_debug(domain,"considering circ->package_window %d",
circ->package_window);
if (circ->package_window <= 0) {
log_debug(domain,"yes, not-at-origin. stopped.");
- for (conn = circ->n_streams; conn; conn=conn->next_stream)
+ for (conn = or_circ->n_streams; conn; conn=conn->next_stream)
connection_stop_reading(conn);
return 1;
}
layer_hint->package_window);
if (layer_hint->package_window <= 0) {
log_debug(domain,"yes, at-origin. stopped.");
+#if 0
+ // XXXX NM DEAD CODE.
for (conn = circ->n_streams; conn; conn=conn->next_stream)
if (conn->cpath_layer == layer_hint)
connection_stop_reading(conn);
- for (conn = circ->p_streams; conn; conn=conn->next_stream)
+#endif
+ for (conn = TO_ORIGIN_CIRCUIT(circ)->p_streams; conn;
+ conn=conn->next_stream)
if (conn->cpath_layer == layer_hint)
connection_stop_reading(conn);
return 1;
/** Called when we've established a circuit to an introduction point:
* send the introduction request. */
void
-rend_client_introcirc_has_opened(circuit_t *circ)
+rend_client_introcirc_has_opened(origin_circuit_t *circ)
{
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
tor_assert(circ->cpath);
log_info(LD_REND,"introcirc is open");
* it fails, mark the circ for close and return -1. else return 0.
*/
static int
-rend_client_send_establish_rendezvous(circuit_t *circ)
+rend_client_send_establish_rendezvous(origin_circuit_t *circ)
{
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
log_info(LD_REND, "Sending an ESTABLISH_RENDEZVOUS cell");
- if (crypto_rand(circ->rend_cookie, REND_COOKIE_LEN) < 0) {
+ if (crypto_rand(circ->_base.rend_cookie, REND_COOKIE_LEN) < 0) {
log_warn(LD_BUG, "Internal error: Couldn't produce random cookie.");
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
- if (connection_edge_send_command(NULL,circ,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_ESTABLISH_RENDEZVOUS,
- circ->rend_cookie, REND_COOKIE_LEN,
+ circ->_base.rend_cookie, REND_COOKIE_LEN,
circ->cpath->prev)<0) {
/* circ is already marked for close */
log_warn(LD_GENERAL, "Couldn't send ESTABLISH_RENDEZVOUS cell");
* down introcirc if possible.
*/
int
-rend_client_send_introduction(circuit_t *introcirc, circuit_t *rendcirc)
+rend_client_send_introduction(origin_circuit_t *introcirc,
+ origin_circuit_t *rendcirc)
{
size_t payload_len;
int r;
crypt_path_t *cpath;
off_t dh_offset;
- tor_assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
- tor_assert(rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY);
- tor_assert(!rend_cmp_service_ids(introcirc->rend_query,
- rendcirc->rend_query));
+ tor_assert(introcirc->_base.purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
+ tor_assert(rendcirc->_base.purpose == CIRCUIT_PURPOSE_C_REND_READY);
+ tor_assert(!rend_cmp_service_ids(introcirc->_base.rend_query,
+ rendcirc->_base.rend_query));
- if (rend_cache_lookup_entry(introcirc->rend_query, -1, &entry) < 1) {
+ if (rend_cache_lookup_entry(introcirc->_base.rend_query, -1, &entry) < 1) {
log_warn(LD_REND,
"query %s didn't have valid rend desc in cache. Failing.",
- escaped_safe_str(introcirc->rend_query));
+ escaped_safe_str(introcirc->_base.rend_query));
goto err;
}
klen = crypto_pk_asn1_encode(extend_info->onion_key, tmp+7+DIGEST_LEN+2,
sizeof(tmp)-(7+DIGEST_LEN+2));
set_uint16(tmp+7+DIGEST_LEN, htons(klen));
- memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->rend_cookie, REND_COOKIE_LEN);
+ memcpy(tmp+7+DIGEST_LEN+2+klen, rendcirc->_base.rend_cookie,
+ REND_COOKIE_LEN);
dh_offset = 7+DIGEST_LEN+2+klen+REND_COOKIE_LEN;
} else {
/* Version 0. */
strncpy(tmp, rendcirc->build_state->chosen_exit->nickname,
(MAX_NICKNAME_LEN+1)); /* nul pads */
- memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->rend_cookie, REND_COOKIE_LEN);
+ memcpy(tmp+MAX_NICKNAME_LEN+1, rendcirc->_base.rend_cookie,
+ REND_COOKIE_LEN);
dh_offset = MAX_NICKNAME_LEN+1+REND_COOKIE_LEN;
}
tor_assert(DIGEST_LEN + r <= RELAY_PAYLOAD_SIZE); /* we overran something */
payload_len = DIGEST_LEN + r;
- if (connection_edge_send_command(NULL, introcirc,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(introcirc),
RELAY_COMMAND_INTRODUCE1,
payload, payload_len,
introcirc->cpath->prev)<0) {
}
/* Now, we wait for an ACK or NAK on this circuit. */
- introcirc->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
+ introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
return 0;
err:
- circuit_mark_for_close(introcirc, END_CIRC_AT_ORIGIN);
- circuit_mark_for_close(rendcirc, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_AT_ORIGIN);
return -1;
}
/** Called when a rendezvous circuit is open; sends a establish
* rendezvous circuit as appropriate. */
void
-rend_client_rendcirc_has_opened(circuit_t *circ)
+rend_client_rendcirc_has_opened(origin_circuit_t *circ)
{
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
log_info(LD_REND,"rendcirc is open");
/** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.
*/
int
-rend_client_introduction_acked(circuit_t *circ,
+rend_client_introduction_acked(origin_circuit_t *circ,
const char *request, size_t request_len)
{
circuit_t *rendcirc;
(void) request; // XXXX Use this.
- if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
log_warn(LD_PROTOCOL,
"Received REND_INTRODUCE_ACK on unexpected circuit %d.",
- circ->n_circ_id);
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circ->_base.n_circ_id);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
*/
log_info(LD_REND,"Received ack. Telling rend circ...");
rendcirc = circuit_get_by_rend_query_and_purpose(
- circ->rend_query, CIRCUIT_PURPOSE_C_REND_READY);
+ circ->_base.rend_query, CIRCUIT_PURPOSE_C_REND_READY);
if (rendcirc) { /* remember the ack */
rendcirc->purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED;
} else {
log_info(LD_REND,"...Found no rend circ. Dropping on the floor.");
}
/* close the circuit: we won't need it anymore. */
- circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACKED;
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
} else {
/* It's a NAK; the introduction point didn't relay our request. */
- circ->purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
+ circ->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCING;
/* 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.
*/
if (rend_client_remove_intro_point(circ->build_state->chosen_exit,
- circ->rend_query) > 0) {
+ circ->_base.rend_query) > 0) {
/* There are introduction points left. Re-extend the circuit to
* another intro point and try again. */
extend_info_t *extend_info;
int result;
- extend_info = rend_client_get_random_intro(circ->rend_query);
+ extend_info = rend_client_get_random_intro(circ->_base.rend_query);
if (!extend_info) {
log_warn(LD_REND, "No introduction points left for %s. Closing.",
- escaped_safe_str(circ->rend_query));
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ escaped_safe_str(circ->_base.rend_query));
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
log_info(LD_REND,
"Got nack for %s from %s. Re-extending circ %d, "
"this time to %s.",
- escaped_safe_str(circ->rend_query),
- circ->build_state->chosen_exit->nickname, circ->n_circ_id,
+ escaped_safe_str(circ->_base.rend_query),
+ circ->build_state->chosen_exit->nickname, circ->_base.n_circ_id,
extend_info->nickname);
result = circuit_extend_to_new_exit(circ, extend_info);
extend_info_free(extend_info);
* the circuit to C_REND_READY.
*/
int
-rend_client_rendezvous_acked(circuit_t *circ, const char *request,
+rend_client_rendezvous_acked(origin_circuit_t *circ, const char *request,
size_t request_len)
{
(void) request;
(void) request_len;
/* we just got an ack for our establish-rendezvous. switch purposes. */
- if (circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
log_warn(LD_PROTOCOL,"Got a rendezvous ack when we weren't expecting one. "
"Closing circ.");
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
log_info(LD_REND,"Got rendezvous ack. This circuit is now ready for "
"rendezvous.");
- circ->purpose = CIRCUIT_PURPOSE_C_REND_READY;
+ circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_READY;
return 0;
}
/** Bob sent us a rendezvous cell; join the circuits. */
int
-rend_client_receive_rendezvous(circuit_t *circ, const char *request,
+rend_client_receive_rendezvous(origin_circuit_t *circ, const char *request,
size_t request_len)
{
crypt_path_t *hop;
char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN];
- if ((circ->purpose != CIRCUIT_PURPOSE_C_REND_READY &&
- circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
+ if ((circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY &&
+ circ->_base.purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
|| !circ->build_state->pending_final_cpath) {
log_warn(LD_PROTOCOL,"Got rendezvous2 cell from hidden service, but not "
"expecting it. Closing.");
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
hop->dh_handshake_state = NULL;
/* All is well. Extend the circuit. */
- circ->purpose = CIRCUIT_PURPOSE_C_REND_JOINED;
+ circ->_base.purpose = CIRCUIT_PURPOSE_C_REND_JOINED;
hop->state = CPATH_STATE_OPEN;
/* set the windows to default. these are the windows
* that alice thinks bob has.
circ->build_state->pending_final_cpath = NULL; /* prevent double-free */
return 0;
err:
- circuit_mark_for_close(circ, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_AT_ORIGIN);
return -1;
}
rend_process_relay_cell(circuit_t *circ, int command, size_t length,
const char *payload)
{
+ or_circuit_t *or_circ = NULL;
+ origin_circuit_t *origin_circ = NULL;
int r;
+ if (CIRCUIT_IS_ORIGIN(circ))
+ origin_circ = TO_ORIGIN_CIRCUIT(circ);
+ else
+ or_circ = TO_OR_CIRCUIT(circ);
+
switch (command) {
case RELAY_COMMAND_ESTABLISH_INTRO:
- r = rend_mid_establish_intro(circ,payload,length);
+ r = rend_mid_establish_intro(or_circ,payload,length);
break;
case RELAY_COMMAND_ESTABLISH_RENDEZVOUS:
- r = rend_mid_establish_rendezvous(circ,payload,length);
+ r = rend_mid_establish_rendezvous(or_circ,payload,length);
break;
case RELAY_COMMAND_INTRODUCE1:
- r = rend_mid_introduce(circ,payload,length);
+ r = rend_mid_introduce(or_circ,payload,length);
break;
case RELAY_COMMAND_INTRODUCE2:
- r = rend_service_introduce(circ,payload,length);
+ r = rend_service_introduce(origin_circ,payload,length);
break;
case RELAY_COMMAND_INTRODUCE_ACK:
- r = rend_client_introduction_acked(circ,payload,length);
+ r = rend_client_introduction_acked(origin_circ,payload,length);
break;
case RELAY_COMMAND_RENDEZVOUS1:
- r = rend_mid_rendezvous(circ,payload,length);
+ r = rend_mid_rendezvous(or_circ,payload,length);
break;
case RELAY_COMMAND_RENDEZVOUS2:
- r = rend_client_receive_rendezvous(circ,payload,length);
+ r = rend_client_receive_rendezvous(origin_circ,payload,length);
break;
case RELAY_COMMAND_INTRO_ESTABLISHED:
- r = rend_service_intro_established(circ,payload,length);
+ r = rend_service_intro_established(origin_circ,payload,length);
break;
case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
- r = rend_client_rendezvous_acked(circ,payload,length);
+ r = rend_client_rendezvous_acked(origin_circ,payload,length);
break;
default:
tor_assert(0);
* setting the circuit's purpose and service pk digest.
*/
int
-rend_mid_establish_intro(circuit_t *circ, const char *request,
+rend_mid_establish_intro(or_circuit_t *circ, const char *request,
size_t request_len)
{
crypto_pk_env_t *pk = NULL;
"Received an ESTABLISH_INTRO request on circuit %d",
circ->p_circ_id);
- if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
"Rejecting ESTABLISH_INTRO on non-OR or non-edge circuit.");
reason = END_CIRC_REASON_TORPROTOCOL;
c = NULL;
while ((c = circuit_get_next_by_pk_and_purpose(
c,pk_digest,CIRCUIT_PURPOSE_INTRO_POINT))) {
- log_info(LD_REND, "Replacing old circuit %d for service %s",
- c->p_circ_id, safe_str(serviceid));
+ log_info(LD_REND, "Replacing old circuit for service %s",
+ safe_str(serviceid));
circuit_mark_for_close(c, END_CIRC_REASON_REQUESTED);
}
/* Acknowledge the request. */
- if (connection_edge_send_command(NULL,circ,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_INTRO_ESTABLISHED,
"", 0, NULL)<0) {
log_info(LD_GENERAL, "Couldn't send INTRO_ESTABLISHED cell.");
}
/* Now, set up this circuit. */
- circ->purpose = CIRCUIT_PURPOSE_INTRO_POINT;
- memcpy(circ->rend_pk_digest, pk_digest, DIGEST_LEN);
+ circ->_base.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
+ memcpy(circ->_base.rend_pk_digest, pk_digest, DIGEST_LEN);
log_info(LD_REND,
"Established introduction point on circuit %d for service %s",
reason = END_CIRC_REASON_TORPROTOCOL;
err:
if (pk) crypto_free_pk_env(pk);
- circuit_mark_for_close(circ, reason);
+ circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1;
}
* INTRODUCE2 cell.
*/
int
-rend_mid_introduce(circuit_t *circ, const char *request, size_t request_len)
+rend_mid_introduce(or_circuit_t *circ, const char *request, size_t request_len)
{
circuit_t *intro_circ;
char serviceid[REND_SERVICE_ID_LEN+1];
char nak_body[1];
- if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_warn(LD_PROTOCOL,
"Rejecting INTRODUCE1 on non-OR or non-edge circuit %d.",
circ->p_circ_id);
goto err;
}
- /* change to MAX_HEX_NICKNAME_LEN once 0.0.9.x is obsolete */
+ /* We could change this to MAX_HEX_NICKNAME_LEN now that 0.0.9.x is
+ * obsolete; however, there isn't much reason to do so, and we're going
+ * to revise this protocol anyway.
+ */
if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+
DH_KEY_LEN+CIPHER_KEY_LEN+PKCS1_OAEP_PADDING_OVERHEAD)) {
log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %d; "
/* The first 20 bytes are all we look at: they have a hash of Bob's PK. */
intro_circ = circuit_get_next_by_pk_and_purpose(
NULL, request, CIRCUIT_PURPOSE_INTRO_POINT);
- if (!intro_circ) {
+ if (!intro_circ || CIRCUIT_IS_ORIGIN(intro_circ)) {
log_info(LD_REND,
"No intro circ found for INTRODUCE1 cell (%s) from circuit %d; "
"responding with nack.",
log_info(LD_REND,
"Sending introduction request for service %s "
"from circ %d to circ %d",
- safe_str(serviceid), circ->p_circ_id, intro_circ->p_circ_id);
+ safe_str(serviceid), circ->p_circ_id,
+ TO_OR_CIRCUIT(intro_circ)->p_circ_id);
/* Great. Now we just relay the cell down the circuit. */
if (connection_edge_send_command(NULL, intro_circ,
goto err;
}
/* And sent an ack down Alice's circuit. Empty body means succeeded. */
- if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
+ RELAY_COMMAND_INTRODUCE_ACK,
NULL,0,NULL)) {
log_warn(LD_GENERAL, "Unable to send INTRODUCE_ACK cell to Tor client.");
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
return -1;
}
err:
/* Send the client an NACK */
nak_body[0] = 1;
- if (connection_edge_send_command(NULL,circ,RELAY_COMMAND_INTRODUCE_ACK,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
+ RELAY_COMMAND_INTRODUCE_ACK,
nak_body, 1, NULL)) {
log_warn(LD_GENERAL, "Unable to send NAK to Tor client.");
/* Is this right? */
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
}
return -1;
}
* rendezvous cookie.
*/
int
-rend_mid_establish_rendezvous(circuit_t *circ, const char *request,
+rend_mid_establish_rendezvous(or_circuit_t *circ, const char *request,
size_t request_len)
{
char hexid[9];
int reason = END_CIRC_REASON_TORPROTOCOL;
- if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_warn(LD_PROTOCOL,
"Tried to establish rendezvous on non-OR or non-edge circuit.");
goto err;
}
/* Acknowledge the request. */
- if (connection_edge_send_command(NULL,circ,
+ if (connection_edge_send_command(NULL,TO_CIRCUIT(circ),
RELAY_COMMAND_RENDEZVOUS_ESTABLISHED,
"", 0, NULL)<0) {
log_warn(LD_PROTOCOL, "Couldn't send RENDEZVOUS_ESTABLISHED cell.");
goto err;
}
- circ->purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
- memcpy(circ->rend_cookie, request, REND_COOKIE_LEN);
+ circ->_base.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
+ memcpy(circ->_base.rend_cookie, request, REND_COOKIE_LEN);
base16_encode(hexid,9,request,4);
return 0;
err:
- circuit_mark_for_close(circ, reason);
+ circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1;
}
* connecting the two circuits.
*/
int
-rend_mid_rendezvous(circuit_t *circ, const char *request, size_t request_len)
+rend_mid_rendezvous(or_circuit_t *circ, const char *request,
+ size_t request_len)
{
- circuit_t *rend_circ;
+ or_circuit_t *rend_circ;
char hexid[9];
int reason = END_CIRC_REASON_INTERNAL;
base16_encode(hexid,9,request,request_len<4?request_len:4);
circ->p_circ_id, hexid);
}
- if (circ->purpose != CIRCUIT_PURPOSE_OR || circ->n_conn) {
+ if (circ->_base.purpose != CIRCUIT_PURPOSE_OR || circ->_base.n_conn) {
log_info(LD_REND,
"Tried to complete rendezvous on non-OR or non-edge circuit %d.",
circ->p_circ_id);
}
/* Send the RENDEZVOUS2 cell to Alice. */
- if (connection_edge_send_command(NULL, rend_circ,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(rend_circ),
RELAY_COMMAND_RENDEZVOUS2,
request+REND_COOKIE_LEN,
request_len-REND_COOKIE_LEN, NULL)) {
"Completing rendezvous: circuit %d joins circuit %d (cookie %s)",
circ->p_circ_id, rend_circ->p_circ_id, hexid);
- circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
- rend_circ->purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
- memset(circ->rend_cookie, 0, REND_COOKIE_LEN);
+ circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
+ rend_circ->_base.purpose = CIRCUIT_PURPOSE_REND_ESTABLISHED;
+ memset(circ->_base.rend_cookie, 0, REND_COOKIE_LEN);
rend_circ->rend_splice = circ;
circ->rend_splice = rend_circ;
return 0;
err:
- circuit_mark_for_close(circ, reason);
+ circuit_mark_for_close(TO_CIRCUIT(circ), reason);
return -1;
}
#include "or.h"
-static circuit_t *find_intro_circuit(routerinfo_t *router,
- const char *pk_digest);
+static origin_circuit_t *find_intro_circuit(routerinfo_t *router,
+ const char *pk_digest);
/** Represents the mapping from a virtual port of a rendezvous service to
* a real port on some IP.
rend_service_update_descriptor(rend_service_t *service)
{
rend_service_descriptor_t *d;
- circuit_t *circ;
+ origin_circuit_t *circ;
int i,n;
routerinfo_t *router;
continue;
}
circ = find_intro_circuit(router, service->pk_digest);
- if (circ && circ->purpose == CIRCUIT_PURPOSE_S_INTRO) {
+ if (circ && circ->_base.purpose == CIRCUIT_PURPOSE_S_INTRO) {
/* We have an entirely established intro circuit. */
d->intro_points[d->n_intro_points] = tor_strdup(router->nickname);
d->intro_point_extend_info[d->n_intro_points] =
* rendezvous point.
*/
int
-rend_service_introduce(circuit_t *circuit, const char *request,
+rend_service_introduce(origin_circuit_t *circuit, const char *request,
size_t request_len)
{
char *ptr, *r_cookie;
int r, i;
size_t len, keylen;
crypto_dh_env_t *dh = NULL;
- circuit_t *launched = NULL;
+ origin_circuit_t *launched = NULL;
crypt_path_t *cpath = NULL;
char serviceid[REND_SERVICE_ID_LEN+1];
char hexcookie[9];
int circ_needs_uptime;
base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
- circuit->rend_pk_digest,10);
+ circuit->_base.rend_pk_digest,10);
log_info(LD_REND, "Received INTRODUCE2 cell for service %s on circ %d.",
- escaped(serviceid), circuit->n_circ_id);
+ escaped(serviceid), circuit->_base.n_circ_id);
- if (circuit->purpose != CIRCUIT_PURPOSE_S_INTRO) {
+ if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_INTRO) {
log_warn(LD_PROTOCOL,
"Got an INTRODUCE2 over a non-introduction circuit %d.",
- circuit->n_circ_id);
+ circuit->_base.n_circ_id);
return -1;
}
if (request_len < DIGEST_LEN+REND_COOKIE_LEN+(MAX_NICKNAME_LEN+1)+
DH_KEY_LEN+42) {
log_warn(LD_PROTOCOL, "Got a truncated INTRODUCE2 cell on circ %d.",
- circuit->n_circ_id);
+ circuit->_base.n_circ_id);
return -1;
}
escaped(serviceid));
return -1;
}
- if (memcmp(circuit->rend_pk_digest, request, DIGEST_LEN)) {
+ if (memcmp(circuit->_base.rend_pk_digest, request, DIGEST_LEN)) {
base32_encode(serviceid, REND_SERVICE_ID_LEN+1, request, 10);
log_warn(LD_REND, "Got an INTRODUCE2 cell for the wrong service (%s).",
escaped(serviceid));
extend_info->nickname, hexcookie, serviceid);
tor_assert(launched->build_state);
/* Fill in the circuit's state. */
- memcpy(launched->rend_pk_digest, circuit->rend_pk_digest,
+ memcpy(launched->_base.rend_pk_digest, circuit->_base.rend_pk_digest,
DIGEST_LEN);
- memcpy(launched->rend_cookie, r_cookie, REND_COOKIE_LEN);
- strlcpy(launched->rend_query, service->service_id,
- sizeof(launched->rend_query));
+ memcpy(launched->_base.rend_cookie, r_cookie, REND_COOKIE_LEN);
+ strlcpy(launched->_base.rend_query, service->service_id,
+ sizeof(launched->_base.rend_query));
launched->build_state->pending_final_cpath = cpath =
tor_malloc_zero(sizeof(crypt_path_t));
cpath->magic = CRYPT_PATH_MAGIC;
return 0;
err:
if (dh) crypto_dh_free(dh);
- if (launched) circuit_mark_for_close(launched, END_CIRC_AT_ORIGIN);
+ if (launched)
+ circuit_mark_for_close(TO_CIRCUIT(launched), END_CIRC_AT_ORIGIN);
if (extend_info) extend_info_free(extend_info);
return -1;
}
* than the last hop: launches a new circuit to the same rendezvous point.
*/
void
-rend_service_relaunch_rendezvous(circuit_t *oldcirc)
+rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
{
- circuit_t *newcirc;
+ origin_circuit_t *newcirc;
cpath_build_state_t *newstate, *oldstate;
- tor_assert(oldcirc->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+ tor_assert(oldcirc->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
if (!oldcirc->build_state ||
oldcirc->build_state->failure_count > MAX_REND_FAILURES ||
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_cookie, oldcirc->rend_cookie, REND_COOKIE_LEN);
+ memcpy(newcirc->_base.rend_query, oldcirc->_base.rend_query,
+ REND_SERVICE_ID_LEN+1);
+ memcpy(newcirc->_base.rend_pk_digest, oldcirc->_base.rend_pk_digest,
+ DIGEST_LEN);
+ memcpy(newcirc->_base.rend_cookie, oldcirc->_base.rend_cookie,
+ REND_COOKIE_LEN);
}
/** Launch a circuit to serve as an introduction point for the service
rend_service_launch_establish_intro(rend_service_t *service,
const char *nickname)
{
- circuit_t *launched;
+ origin_circuit_t *launched;
log_info(LD_REND,
"Launching circuit to introduction point %s for service %s",
nickname);
return -1;
}
- strlcpy(launched->rend_query, service->service_id,
- sizeof(launched->rend_query));
- memcpy(launched->rend_pk_digest, service->pk_digest, DIGEST_LEN);
+ strlcpy(launched->_base.rend_query, service->service_id,
+ sizeof(launched->_base.rend_query));
+ memcpy(launched->_base.rend_pk_digest, service->pk_digest, DIGEST_LEN);
- if (launched->state == CIRCUIT_STATE_OPEN)
+ if (launched->_base.state == CIRCUIT_STATE_OPEN)
rend_service_intro_has_opened(launched);
return 0;
}
* sends a RELAY_ESTABLISH_INTRO cell.
*/
void
-rend_service_intro_has_opened(circuit_t *circuit)
+rend_service_intro_has_opened(origin_circuit_t *circuit)
{
rend_service_t *service;
size_t len;
char auth[DIGEST_LEN + 9];
char serviceid[REND_SERVICE_ID_LEN+1];
- tor_assert(circuit->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
- tor_assert(CIRCUIT_IS_ORIGIN(circuit));
+ tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
tor_assert(circuit->cpath);
base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
- circuit->rend_pk_digest,10);
+ circuit->_base.rend_pk_digest,10);
- service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
+ service = rend_service_get_by_pk_digest(circuit->_base.rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %d.",
- serviceid, circuit->n_circ_id);
+ serviceid, circuit->_base.n_circ_id);
goto err;
}
log_info(LD_REND,
"Established circuit %d as introduction point for service %s",
- circuit->n_circ_id, serviceid);
+ circuit->_base.n_circ_id, serviceid);
/* Build the payload for a RELAY_ESTABLISH_INTRO cell. */
len = crypto_pk_asn1_encode(service->private_key, buf+2,
}
len += r;
- if (connection_edge_send_command(NULL, circuit,RELAY_COMMAND_ESTABLISH_INTRO,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit),
+ RELAY_COMMAND_ESTABLISH_INTRO,
buf, len, circuit->cpath->prev)<0) {
log_info(LD_GENERAL,
"Couldn't send introduction request for service %s on circuit %d",
- serviceid, circuit->n_circ_id);
+ serviceid, circuit->_base.n_circ_id);
goto err;
}
return;
err:
- circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
}
/** Called when we get an INTRO_ESTABLISHED cell; mark the circuit as a
* live introduction point, and note that the service descriptor is
* now out-of-date.*/
int
-rend_service_intro_established(circuit_t *circuit, const char *request,
+rend_service_intro_established(origin_circuit_t *circuit, const char *request,
size_t request_len)
{
rend_service_t *service;
(void) request;
(void) request_len;
- if (circuit->purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
+ if (circuit->_base.purpose != CIRCUIT_PURPOSE_S_ESTABLISH_INTRO) {
log_warn(LD_PROTOCOL,
"received INTRO_ESTABLISHED cell on non-intro circuit.");
goto err;
}
- service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
+ service = rend_service_get_by_pk_digest(circuit->_base.rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Unknown service on introduction circuit %d.",
- circuit->n_circ_id);
+ circuit->_base.n_circ_id);
goto err;
}
service->desc_is_dirty = time(NULL);
- circuit->purpose = CIRCUIT_PURPOSE_S_INTRO;
+ circuit->_base.purpose = CIRCUIT_PURPOSE_S_INTRO;
return 0;
err:
- circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
return -1;
}
* RELAY_COMMAND_RENDEZVOUS1 cell.
*/
void
-rend_service_rendezvous_has_opened(circuit_t *circuit)
+rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
{
rend_service_t *service;
char buf[RELAY_PAYLOAD_SIZE];
char serviceid[REND_SERVICE_ID_LEN+1];
char hexcookie[9];
- tor_assert(circuit->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
+ tor_assert(circuit->_base.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
tor_assert(circuit->cpath);
tor_assert(circuit->build_state);
hop = circuit->build_state->pending_final_cpath;
tor_assert(hop);
- base16_encode(hexcookie,9,circuit->rend_cookie,4);
+ base16_encode(hexcookie,9,circuit->_base.rend_cookie,4);
base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
- circuit->rend_pk_digest,10);
+ circuit->_base.rend_pk_digest,10);
log_info(LD_REND,
"Done building circuit %d to rendezvous with "
"cookie %s for service %s",
- circuit->n_circ_id, hexcookie, serviceid);
+ circuit->_base.n_circ_id, hexcookie, serviceid);
- service = rend_service_get_by_pk_digest(circuit->rend_pk_digest);
+ service = rend_service_get_by_pk_digest(circuit->_base.rend_pk_digest);
if (!service) {
log_warn(LD_GENERAL, "Internal error: unrecognized service ID on "
"introduction circuit.");
}
/* All we need to do is send a RELAY_RENDEZVOUS1 cell... */
- memcpy(buf, circuit->rend_cookie, REND_COOKIE_LEN);
+ memcpy(buf, circuit->_base.rend_cookie, REND_COOKIE_LEN);
if (crypto_dh_get_public(hop->dh_handshake_state,
buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) {
log_warn(LD_GENERAL,"Couldn't get DH public key.");
DIGEST_LEN);
/* Send the cell */
- if (connection_edge_send_command(NULL, circuit, RELAY_COMMAND_RENDEZVOUS1,
+ if (connection_edge_send_command(NULL, TO_CIRCUIT(circuit),
+ RELAY_COMMAND_RENDEZVOUS1,
buf, REND_COOKIE_LEN+DH_KEY_LEN+DIGEST_LEN,
circuit->cpath->prev)<0) {
log_warn(LD_GENERAL, "Couldn't send RENDEZVOUS1 cell.");
circuit->build_state->pending_final_cpath = NULL; /* prevent double-free */
/* Change the circuit purpose. */
- circuit->purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
+ circuit->_base.purpose = CIRCUIT_PURPOSE_S_REND_JOINED;
return;
err:
- circuit_mark_for_close(circuit, END_CIRC_AT_ORIGIN);
+ circuit_mark_for_close(TO_CIRCUIT(circuit), END_CIRC_AT_ORIGIN);
}
/*
* <b>router</b> for the service whose public key is <b>pk_digest</b>. Return
* NULL if no such service is found.
*/
-static circuit_t *
+static origin_circuit_t *
find_intro_circuit(routerinfo_t *router, const char *pk_digest)
{
circuit_t *circ = NULL;
+ cpath_build_state_t *build_state = NULL;
tor_assert(router);
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_INTRO))) {
- tor_assert(circ->cpath);
- if (!strcasecmp(circ->build_state->chosen_exit->nickname,
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
+ build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ if (!strcasecmp(build_state->chosen_exit->nickname,
router->nickname)) {
- return circ;
+ return TO_ORIGIN_CIRCUIT(circ);
}
}
circ = NULL;
while ((circ = circuit_get_next_by_pk_and_purpose(circ,pk_digest,
CIRCUIT_PURPOSE_S_ESTABLISH_INTRO))) {
- tor_assert(circ->cpath);
- if (!strcasecmp(circ->build_state->chosen_exit->nickname,
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
+ build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
+ if (!strcasecmp(build_state->chosen_exit->nickname,
router->nickname)) {
- return circ;
+ return TO_ORIGIN_CIRCUIT(circ);
}
}
return NULL;
routerinfo_t *router;
rend_service_t *service;
char *nickname;
- circuit_t *circ;
+ origin_circuit_t *circ;
for (i=0; i < smartlist_len(rend_service_list); ++i) {
service = smartlist_get(rend_service_list, i);
continue;
}
log(severity, LD_GENERAL, " Intro point at %s: circuit is %s",nickname,
- circuit_state_to_string(circ->state));
+ circuit_state_to_string(circ->_base.state));
}
}
}
* or 0 for success.
*/
int
-rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ)
+rend_service_set_connection_addr_port(connection_t *conn,
+ origin_circuit_t *circ)
{
rend_service_t *service;
int i;
rend_service_port_config_t *p;
char serviceid[REND_SERVICE_ID_LEN+1];
- tor_assert(circ->purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
+ tor_assert(circ->_base.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
log_debug(LD_REND,"beginning to hunt for addr/port");
base32_encode(serviceid, REND_SERVICE_ID_LEN+1,
- circ->rend_pk_digest,10);
- service = rend_service_get_by_pk_digest(circ->rend_pk_digest);
+ circ->_base.rend_pk_digest,10);
+ service = rend_service_get_by_pk_digest(circ->_base.rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
"rendezvous circuit %d; closing.",
- serviceid, circ->n_circ_id);
+ serviceid, circ->_base.n_circ_id);
return -1;
}
for (i = 0; i < smartlist_len(service->ports); ++i) {