diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 4862442678..9d2b77286b 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -19,14 +19,13 @@ extern circuit_t *global_circuitlist;
/********* END VARIABLES ************/
-static int
-circuit_deliver_create_cell(circuit_t *circ, char *payload);
-static cpath_build_state_t *
-onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest,
- int need_uptime, int need_capacity, int internal);
-static int onion_extend_cpath(crypt_path_t **head_ptr,
- cpath_build_state_t *state, routerinfo_t **router_out);
+static int circuit_deliver_create_cell(circuit_t *circ, char *payload);
+static int onion_pick_cpath_exit(circuit_t *circ, routerinfo_t *exit);
+static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
+static int onion_next_router_in_cpath(circuit_t *circ, routerinfo_t **router);
+static int onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state);
static int count_acceptable_routers(smartlist_t *routers);
+static int onion_append_hop(crypt_path_t **head_ptr, routerinfo_t *choice);
/** Iterate over values of circ_id, starting from conn-\>next_circ_id,
* and with the high bit specified by circ_id_type (see
@@ -229,7 +228,39 @@ void circuit_dump_by_conn(connection_t *conn, int severity) {
}
}
-/** Build a new circuit for purpose. If exit_digest
+/** 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) {
+ int r;
+again:
+ r = onion_extend_cpath(&circ->cpath, circ->build_state);
+// || !CIRCUIT_IS_ORIGIN(circ)) { // wtf? -rd
+ if (r < 0) {
+ log_fn(LOG_INFO,"Generating cpath hop failed.");
+ circuit_mark_for_close(circ);
+ return -1;
+ }
+ if (r == 0)
+ goto again;
+ return 0; /* if r == 1 */
+}
+
+/** Create and return new 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) {
+ circuit_t *circ = circuit_new(0, NULL); /* sets circ->p_circ_id and circ->p_conn */
+ circ->state = 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;
+ return circ;
+}
+
+/** Build a new circuit for purpose. If exit
* is defined, then use that as your exit router, else choose a suitable
* exit node.
*
@@ -237,36 +268,39 @@ void circuit_dump_by_conn(connection_t *conn, int severity) {
* it's not open already.
*/
circuit_t *
-circuit_establish_circuit(uint8_t purpose, const char *exit_digest,
+circuit_establish_circuit(uint8_t purpose, routerinfo_t *exit,
int need_uptime, int need_capacity, int internal) {
- routerinfo_t *firsthop;
- connection_t *n_conn;
circuit_t *circ;
- circ = circuit_new(0, NULL); /* sets circ->p_circ_id and circ->p_conn */
- circ->state = CIRCUIT_STATE_OR_WAIT;
- circ->build_state = onion_new_cpath_build_state(purpose, exit_digest,
- need_uptime, need_capacity, internal);
- circ->purpose = purpose;
+ circ = circuit_init(purpose, need_uptime, need_capacity, internal);
- if (! circ->build_state) {
- log_fn(LOG_INFO,"Generating cpath failed.");
- circuit_mark_for_close(circ);
- return NULL;
- }
-
- if (onion_extend_cpath(&circ->cpath, circ->build_state, &firsthop)<0 ||
- !CIRCUIT_IS_ORIGIN(circ)) {
- log_fn(LOG_INFO,"Generating first cpath hop failed.");
+ if (onion_pick_cpath_exit(circ, exit) < 0 ||
+ onion_populate_cpath(circ) < 0) {
circuit_mark_for_close(circ);
return NULL;
}
control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED);
- /* now see if we're already connected to the first OR in 'route' */
+ if (circuit_handle_first_hop(circ) < 0) {
+ circuit_mark_for_close(circ);
+ return NULL;
+ }
+ return circ;
+}
+/** Start establishing the first hop of our circuit. Figure out what
+ * OR we should connect to, and if necessary start the connection to
+ * 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) {
+ routerinfo_t *firsthop;
+ connection_t *n_conn;
+
+ onion_next_router_in_cpath(circ, &firsthop);
tor_assert(firsthop);
+
+ /* now see if we're already connected to the first OR in 'route' */
log_fn(LOG_DEBUG,"Looking for firsthop '%s:%u'",
firsthop->address,firsthop->or_port);
/* imprint the circuit with its future n_conn->id */
@@ -282,8 +316,7 @@ circuit_establish_circuit(uint8_t purpose, const char *exit_digest,
firsthop->identity_digest);
if (!n_conn) { /* connect failed, forget the whole thing */
log_fn(LOG_INFO,"connect to firsthop failed. Closing.");
- circuit_mark_for_close(circ);
- return NULL;
+ return -1;
}
}
@@ -291,7 +324,7 @@ circuit_establish_circuit(uint8_t purpose, const char *exit_digest,
/* return success. The onion/circuit/etc will be taken care of automatically
* (may already have been) whenever n_conn reaches OR_CONN_STATE_OPEN.
*/
- return circ;
+ return 0;
} else { /* it's already open. use it. */
circ->n_addr = n_conn->addr;
circ->n_port = n_conn->port;
@@ -299,11 +332,10 @@ circuit_establish_circuit(uint8_t purpose, const char *exit_digest,
log_fn(LOG_DEBUG,"Conn open. Delivering first onion skin.");
if (circuit_send_next_onion_skin(circ) < 0) {
log_fn(LOG_INFO,"circuit_send_next_onion_skin failed.");
- circuit_mark_for_close(circ);
- return NULL;
+ return -1;
}
}
- return circ;
+ return 0;
}
/** Find circuits that are waiting on or_conn to become open,
@@ -425,8 +457,8 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
tor_assert(circ->cpath->state == CPATH_STATE_OPEN);
tor_assert(circ->state == CIRCUIT_STATE_BUILDING);
log_fn(LOG_DEBUG,"starting to send subsequent skin.");
- r = onion_extend_cpath(&circ->cpath, circ->build_state, &router);
- if (r==1) {
+ r = onion_next_router_in_cpath(circ, &router);
+ if (r > 0) {
/* done building the circuit. whew. */
circ->state = CIRCUIT_STATE_OPEN;
log_fn(LOG_INFO,"circuit built!");
@@ -439,11 +471,10 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
circuit_rep_hist_note_result(circ);
circuit_has_opened(circ); /* do other actions as necessary */
return 0;
- } else if (r<0) {
- log_fn(LOG_INFO,"Unable to extend circuit path.");
+ } else if (r < 0) {
return -1;
}
- hop = circ->cpath->prev;
+ hop = onion_next_hop_in_cpath(circ->cpath);
*(uint32_t*)payload = htonl(hop->addr);
*(uint16_t*)(payload+4) = htons(hop->port);
@@ -469,6 +500,9 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
return 0;
}
+/** Our clock just jumped forward by seconds_elapsed. Assume
+ * something has also gone wrong with our network: notify the user,
+ * and abandon all not-yet-used circuits. */
void circuit_note_clock_jumped(int seconds_elapsed) {
log_fn(LOG_NOTICE,"Your clock just jumped %d seconds forward; assuming established circuits no longer work.", seconds_elapsed);
has_completed_circuit=0; /* so it'll log when it works again */
@@ -620,10 +654,8 @@ int circuit_finish_handshake(circuit_t *circ, char *reply) {
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS)
hop = circ->cpath;
else {
- for (hop=circ->cpath->next;
- hop != circ->cpath && hop->state == CPATH_STATE_OPEN;
- hop=hop->next) ;
- if (hop == circ->cpath) { /* got an extended when we're all done? */
+ hop = onion_next_hop_in_cpath(circ->cpath);
+ if (!hop) { /* got an extended when we're all done? */
log_fn(LOG_WARN,"got extended when circ already built? Closing.");
return -1;
}
@@ -646,7 +678,7 @@ int circuit_finish_handshake(circuit_t *circ, char *reply) {
}
hop->state = CPATH_STATE_OPEN;
- log_fn(LOG_INFO,"Finished building circuit:");
+ log_fn(LOG_INFO,"Finished building circuit hop:");
circuit_log_path(LOG_INFO,circ);
control_event_circuit_status(circ, CIRC_EVENT_EXTENDED);
@@ -1101,81 +1133,53 @@ choose_good_exit_server(uint8_t purpose, routerlist_t *dir,
return NULL;
}
-/** Allocate a cpath_build_state_t, populate it based on
- * purpose and exit_digest (if specified), and
- * return it.
- */
-static cpath_build_state_t *
-onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest,
- int need_uptime, int need_capacity, int internal)
-{
+/** Decide a suitable length for circ's cpath, and pick an exit
+ * router (or use exit 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, routerinfo_t *exit) {
+ cpath_build_state_t *state = circ->build_state;
+
routerlist_t *rl;
int r;
- cpath_build_state_t *info;
- routerinfo_t *exit;
router_get_routerlist(&rl);
- if (!rl)
- return NULL;
- r = new_route_len(get_options()->PathlenCoinWeight, purpose, rl->routers);
+ if (!rl) {
+ log_fn(LOG_WARN,"router_get_routerlist returned empty list; closing circ.");
+ return -1;
+ }
+ r = new_route_len(get_options()->PathlenCoinWeight, circ->purpose, rl->routers);
if (r < 1) /* must be at least 1 */
- return NULL;
- info = tor_malloc_zero(sizeof(cpath_build_state_t));
- info->desired_path_len = r;
- info->need_uptime = need_uptime;
- info->need_capacity = need_capacity;
- info->is_internal = internal;
- if (exit_digest) { /* the circuit-builder pre-requested one */
- memcpy(info->chosen_exit_digest, exit_digest, DIGEST_LEN);
- exit = router_get_by_digest(exit_digest);
- if (exit) {
- info->chosen_exit_name = tor_strdup(exit->nickname);
- } else {
- info->chosen_exit_name = tor_malloc(HEX_DIGEST_LEN+1);
- base16_encode(info->chosen_exit_name, HEX_DIGEST_LEN+1,
- exit_digest, DIGEST_LEN);
- }
- log_fn(LOG_INFO,"Using requested exit node '%s'", info->chosen_exit_name);
+ return -1;
+ state->desired_path_len = r;
+
+ if (exit) { /* the circuit-builder pre-requested one */
+ log_fn(LOG_INFO,"Using requested exit node '%s'", exit->nickname);
} else { /* we have to decide one */
- exit = choose_good_exit_server(purpose, rl, need_uptime, need_capacity);
+ exit = choose_good_exit_server(circ->purpose, rl,
+ state->need_uptime, state->need_capacity);
if (!exit) {
log_fn(LOG_WARN,"failed to choose an exit server");
- tor_free(info);
- return NULL;
+ return -1;
}
- memcpy(info->chosen_exit_digest, exit->identity_digest, DIGEST_LEN);
- info->chosen_exit_name = tor_strdup(exit->nickname);
}
- return info;
+ memcpy(state->chosen_exit_digest, exit->identity_digest, DIGEST_LEN);
+ state->chosen_exit_name = tor_strdup(exit->nickname);
+ return 0;
}
/** Take the open circ originating here, give it a new exit destination
- * to exit_digest (use nickname directly if it's provided, else strdup
- * out of router->nickname), and get it to send the next extend cell.
+ * to exit, and get it to send the next extend cell.
*/
int
-circuit_append_new_hop(circuit_t *circ, char *nickname, const char *exit_digest) {
- routerinfo_t *exit = router_get_by_digest(exit_digest);
- tor_assert(CIRCUIT_IS_ORIGIN(circ));
- circ->state = CIRCUIT_STATE_BUILDING;
+circuit_append_new_exit(circuit_t *circ, routerinfo_t *exit) {
+ tor_assert(exit);
+ tor_assert(circ && CIRCUIT_IS_ORIGIN(circ));
tor_free(circ->build_state->chosen_exit_name);
- if (nickname) {
- circ->build_state->chosen_exit_name = nickname;
- } else if (exit) {
- circ->build_state->chosen_exit_name = tor_strdup(exit->nickname);
- } else {
- circ->build_state->chosen_exit_name = tor_malloc(HEX_DIGEST_LEN+1);
- base16_encode(circ->build_state->chosen_exit_name, HEX_DIGEST_LEN+1,
- exit_digest, DIGEST_LEN);
- }
- memcpy(circ->build_state->chosen_exit_digest, exit_digest, DIGEST_LEN);
+ circ->build_state->chosen_exit_name = tor_strdup(exit->nickname);
+ memcpy(circ->build_state->chosen_exit_digest, exit->identity_digest, DIGEST_LEN);
++circ->build_state->desired_path_len;
- if (circuit_send_next_onion_skin(circ)<0) {
- log_fn(LOG_WARN, "Couldn't extend circuit to new point '%s'.",
- circ->build_state->chosen_exit_name);
- circuit_mark_for_close(circ);
- return -1;
- }
+ onion_append_hop(&circ->cpath, exit);
return 0;
}
@@ -1296,21 +1300,52 @@ static routerinfo_t *choose_good_entry_server(cpath_build_state_t *state)
return choice;
}
-/** Choose a suitable next hop in the cpath head_ptr,
- * based on state. Add the hop info to head_ptr, and return a
- * pointer to the chosen router in router_out.
+/** Return the first non-open hop in cpath, or return NULL if all
+ * hops are open. */
+static crypt_path_t *
+onion_next_hop_in_cpath(crypt_path_t *cpath) {
+ crypt_path_t *hop = cpath;
+ do {
+ if (hop->state != CPATH_STATE_OPEN)
+ return hop;
+ hop = hop->next;
+ } while (hop != cpath);
+ return NULL;
+}
+
+/** Find the router corresponding to the first non-open hop in
+ * circ->cpath. Make sure it's state closed. Return 1 if all
+ * hops are open (the circuit is complete), 0 if we find a router
+ * (and set it to *router), and -1 if we fail to lookup the router.
*/
static int
-onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t
- *state, routerinfo_t **router_out)
+onion_next_router_in_cpath(circuit_t *circ, routerinfo_t **router) {
+ routerinfo_t *r;
+ crypt_path_t *hop = onion_next_hop_in_cpath(circ->cpath);
+ if (!hop) /* all hops are open */
+ return 1;
+ tor_assert(hop->state == CPATH_STATE_CLOSED);
+ r = router_get_by_digest(hop->identity_digest);
+ if (!r) {
+ log_fn(LOG_WARN,"Circuit intended to extend to a hop whose routerinfo we've lost. Cancelling circuit.");
+ return -1;
+ }
+ *router = r;
+ return 0;
+}
+
+/** Choose a suitable next hop in the cpath head_ptr,
+ * based on state. Append the hop info to head_ptr.
+ */
+static int
+onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t *state)
{
int cur_len;
- crypt_path_t *cpath, *hop;
+ crypt_path_t *cpath;
routerinfo_t *choice;
smartlist_t *excludednodes;
tor_assert(head_ptr);
- tor_assert(router_out);
if (!*head_ptr) {
cur_len = 0;
@@ -1320,11 +1355,13 @@ onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t
++cur_len;
}
}
+
if (cur_len >= state->desired_path_len) {
log_fn(LOG_DEBUG, "Path is complete: %d steps long",
state->desired_path_len);
return 1;
}
+
log_fn(LOG_DEBUG, "Path is %d long; we want %d", cur_len,
state->desired_path_len);
@@ -1348,7 +1385,16 @@ onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t
log_fn(LOG_DEBUG,"Chose router %s for hop %d (exit is %s)",
choice->nickname, cur_len+1, state->chosen_exit_name);
- hop = tor_malloc_zero(sizeof(crypt_path_t));
+ onion_append_hop(head_ptr, choice);
+ return 0;
+}
+
+/** Create a new hop, annotate it with information about its
+ * corresponding router choice, and append it to the
+ * end of the cpath head_ptr. */
+static int
+onion_append_hop(crypt_path_t **head_ptr, routerinfo_t *choice) {
+ crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t));
/* link hop into the cpath, at the end. */
onion_append_to_cpath(head_ptr, hop);
@@ -1362,9 +1408,6 @@ onion_extend_cpath(crypt_path_t **head_ptr, cpath_build_state_t
hop->package_window = CIRCWINDOW_START;
hop->deliver_window = CIRCWINDOW_START;
- log_fn(LOG_DEBUG, "Extended circuit path with %s for hop %d",
- choice->nickname, cur_len+1);
-
- *router_out = choice;
return 0;
}
+
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 2c5c300e3e..a25c874fd9 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -76,7 +76,8 @@ void circuit_close_all_marked(void)
*/
circuit_t *circuit_new(uint16_t p_circ_id, connection_t *p_conn) {
circuit_t *circ;
- static uint32_t n_circuits_allocated = 0;
+ static uint32_t n_circuits_allocated = 1;
+ /* never zero, since a global ID of 0 treated specially by the controller */
circ = tor_malloc_zero(sizeof(circuit_t));
circ->magic = CIRCUIT_MAGIC;
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 836bb66b70..ea51a4c2d1 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -356,14 +356,14 @@ circuit_predict_and_launch_new(void)
if (need_ports) {
log_fn(LOG_INFO,"Have %d clean circs (%d internal), need another exit circ.",
num, num_internal);
- circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL,
+ circuit_launch_by_router(CIRCUIT_PURPOSE_C_GENERAL, NULL,
port_needs_uptime, port_needs_capacity, 0);
} else if (need_hidserv &&
((num_uptime_internal<2 && hidserv_needs_uptime) ||
num_internal<2)) {
log_fn(LOG_INFO,"Have %d clean circs (%d uptime-internal, %d internal),"
" need another hidserv circ.", num, num_uptime_internal, num_internal);
- circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL,
+ circuit_launch_by_router(CIRCUIT_PURPOSE_C_GENERAL, NULL,
hidserv_needs_uptime, hidserv_needs_capacity, 1);
}
}
@@ -400,7 +400,7 @@ void circuit_build_needed_circs(time_t now) {
circ &&
circ->timestamp_created + TESTING_CIRCUIT_INTERVAL < now) {
log_fn(LOG_INFO,"Creating a new testing circuit.");
- circuit_launch_by_identity(CIRCUIT_PURPOSE_C_GENERAL, NULL, 0, 0, 0);
+ circuit_launch_by_router(CIRCUIT_PURPOSE_C_GENERAL, NULL, 0, 0, 0);
}
#endif
}
@@ -562,7 +562,7 @@ circuit_testing_failed(circuit_t *circ, int at_last_hop) {
routerinfo_t *me = router_get_my_routerinfo();
if (!at_last_hop)
- circuit_launch_by_identity(CIRCUIT_PURPOSE_TESTING, me->identity_digest, 0, 0, 1);
+ circuit_launch_by_router(CIRCUIT_PURPOSE_TESTING, me, 0, 0, 1);
else
log_fn(LOG_INFO,"Our testing circuit (to see if your ORPort is reachable) has failed. I'll try again later.");
}
@@ -684,9 +684,10 @@ static int did_circs_fail_last_period = 0;
* success. */
#define MAX_CIRCUIT_FAILURES 5
+/** Launch a new circuit based on our arguments. */
circuit_t *
-circuit_launch_by_identity(uint8_t purpose, const char *exit_digest,
- int need_uptime, int need_capacity, int internal)
+circuit_launch_by_router(uint8_t purpose, routerinfo_t *exit,
+ int need_uptime, int need_capacity, int internal)
{
circuit_t *circ;
@@ -720,9 +721,15 @@ circuit_launch_by_identity(uint8_t purpose, const char *exit_digest,
case CIRCUIT_PURPOSE_C_INTRODUCING:
case CIRCUIT_PURPOSE_S_CONNECT_REND:
/* need to add a new hop */
- tor_assert(exit_digest);
- if (circuit_append_new_hop(circ, NULL, exit_digest) < 0)
+ tor_assert(exit);
+ circuit_append_new_exit(circ, exit);
+ circ->state = CIRCUIT_STATE_BUILDING;
+ if (circuit_send_next_onion_skin(circ)<0) {
+ log_fn(LOG_WARN, "Couldn't extend circuit to new point '%s'.",
+ circ->build_state->chosen_exit_name);
+ circuit_mark_for_close(circ);
return NULL;
+ }
break;
default:
log_fn(LOG_WARN,"Bug: unexpected purpose %d when cannibalizing a general circ.",
@@ -744,7 +751,7 @@ circuit_launch_by_identity(uint8_t purpose, const char *exit_digest,
}
/* try a circ. if it fails, circuit_mark_for_close will increment n_circuit_failures */
- return circuit_establish_circuit(purpose, exit_digest,
+ return circuit_establish_circuit(purpose, exit,
need_uptime, need_capacity, internal);
}
@@ -753,18 +760,17 @@ circuit_t *
circuit_launch_by_nickname(uint8_t purpose, const char *exit_nickname,
int need_uptime, int need_capacity, int internal)
{
- const char *digest = NULL;
+ routerinfo_t *router = NULL;
if (exit_nickname) {
- routerinfo_t *r = router_get_by_nickname(exit_nickname);
- if (!r) {
+ router = router_get_by_nickname(exit_nickname);
+ if (!router) {
log_fn(LOG_WARN, "No such OR as '%s'", exit_nickname);
return NULL;
}
- digest = r->identity_digest;
}
- return circuit_launch_by_identity(purpose, digest,
- need_uptime, need_capacity, internal);
+ return circuit_launch_by_router(purpose, router,
+ need_uptime, need_capacity, internal);
}
/** Record another failure at opening a general circuit. When we have
diff --git a/src/or/control.c b/src/or/control.c
index e8f6d0e35e..39e82c1664 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -642,12 +642,6 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
send_control_error(conn, ERR_SYNTAX, "extendcircuit message too short");
return 0;
}
- circ_id = ntohl(get_uint32(body));
- if (!(circ = circuit_get_by_global_id(circ_id))) {
- send_control_error(conn, ERR_NO_STREAM,
- "No connection found with given ID");
- return 0;
- }
router_nicknames = smartlist_create();
routers = smartlist_create();
@@ -661,20 +655,45 @@ handle_control_extendcircuit(connection_t *conn, uint32_t len,
}
smartlist_add(routers, r);
});
+ if (!smartlist_len(routers)) {
+ send_control_error(conn, ERR_SYNTAX, "No router names provided");
+ goto done;
+ }
+
+ circ_id = ntohl(get_uint32(body));
+ if (!circ_id) {
+ /* start a new circuit */
+ circ = circuit_init(CIRCUIT_PURPOSE_C_GENERAL, 0, 0, 0);
+ } else {
+ circ = circuit_get_by_global_id(circ_id);
+ if (!circ) {
+ send_control_error(conn, ERR_NO_CIRC,
+ "No circuit found with given ID");
+ goto done;
+ }
+ }
+
+ /* now circ refers to something that is ready to be extended */
-#if 1
- /*XXXX RD*/
- send_control_error(conn, ERR_INTERNAL, "EXTENDCIRCUIT not implemented.");
-#else
SMARTLIST_FOREACH(routers, routerinfo_t *, r,
{
- /*XXXX RD*/
- if (circuit_extend_path(circ, r)<0) {
- send_control_error(conn, ERR_INTERNAL, "Unable to extend path.");
- goto done;
- }
+ circuit_append_new_exit(circ, r);
});
-#endif
+
+ /* now that we've populated the cpath, start extending */
+ if (!circ_id) {
+ if (circuit_handle_first_hop(circ) < 0) {
+ circuit_mark_for_close(circ);
+ }
+ } else {
+ if (circ->state == CIRCUIT_STATE_OPEN) {
+ circ->state = CIRCUIT_STATE_BUILDING;
+ if (circuit_send_next_onion_skin(circ) < 0) {
+ log_fn(LOG_INFO,"send_next_onion_skin failed; circuit marked for closing.");
+ circuit_mark_for_close(circ);
+ }
+ }
+ }
send_control_done(conn);
done:
diff --git a/src/or/or.h b/src/or/or.h
index 1991d7fcf5..d35e95e3f1 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1120,8 +1120,11 @@ char *circuit_list_path(circuit_t *circ, int verbose);
void circuit_log_path(int severity, 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_establish_circuit(uint8_t purpose, const char *exit_digest,
+circuit_t *circuit_init(uint8_t purpose, int need_uptime,
+ int need_capacity, int internal);
+circuit_t *circuit_establish_circuit(uint8_t purpose, routerinfo_t *exit,
int need_uptime, int need_capacity, int internal);
+int circuit_handle_first_hop(circuit_t *circ);
void circuit_n_conn_done(connection_t *or_conn, int status);
int circuit_send_next_onion_skin(circuit_t *circ);
void circuit_note_clock_jumped(int seconds_elapsed);
@@ -1133,7 +1136,7 @@ int onionskin_answer(circuit_t *circ, unsigned char *payload, unsigned char *key
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
int *need_capacity);
-int circuit_append_new_hop(circuit_t *circ, char *nickname, const char *exit_digest);
+int circuit_append_new_exit(circuit_t *circ, routerinfo_t *exit);
void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
/********************************* circuitlist.c ***********************/
@@ -1181,8 +1184,8 @@ void circuit_has_opened(circuit_t *circ);
void circuit_build_failed(circuit_t *circ);
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_identity(uint8_t purpose, const char *exit_digest,
- int need_uptime, int need_capacity, int is_internal);
+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);
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 7111dadda6..7f44bc24f6 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -225,8 +225,15 @@ rend_client_introduction_acked(circuit_t *circ,
}
log_fn(LOG_INFO, "Chose new intro point %s for %s (circ %d)",
nickname, circ->rend_query, circ->n_circ_id);
- if (circuit_append_new_hop(circ, nickname, r->identity_digest) < 0)
+ tor_free(nickname);
+ circuit_append_new_exit(circ, r);
+ circ->state = CIRCUIT_STATE_BUILDING;
+ if (circuit_send_next_onion_skin(circ)<0) {
+ log_fn(LOG_WARN, "Couldn't extend circuit to new point '%s'.",
+ circ->build_state->chosen_exit_name);
+ circuit_mark_for_close(circ);
return -1;
+ }
}
}
return 0;
diff --git a/src/or/router.c b/src/or/router.c
index 0d158c7eaa..d70211bd0c 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -385,7 +385,7 @@ void consider_testing_reachability(void) {
routerinfo_t *me = router_get_my_routerinfo();
if (!can_reach_or_port) {
- circuit_launch_by_identity(CIRCUIT_PURPOSE_TESTING, me->identity_digest, 0, 0, 1);
+ circuit_launch_by_router(CIRCUIT_PURPOSE_TESTING, me, 0, 0, 1);
}
if (!can_reach_dir_port && me->dir_port) {
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 0ae62ad308..6763902f88 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -628,7 +628,7 @@ routerinfo_t *router_get_by_hexdigest(const char *hexdigest) {
}
/** Return the router in our routerlist whose 20-byte key digest
- * is hexdigest. Return NULL if no such router is known. */
+ * is digest. Return NULL if no such router is known. */
routerinfo_t *router_get_by_digest(const char *digest) {
int i;
routerinfo_t *router;