some of the infrastructure to let ORs connect on demand

svn:r1998
This commit is contained in:
Roger Dingledine 2004-07-02 09:29:01 +00:00
parent cbab134bd9
commit 62dcf9e20f
6 changed files with 85 additions and 40 deletions

View File

@ -225,7 +225,8 @@ circuit_t *circuit_establish_circuit(uint8_t purpose,
circ->n_port = firsthop->or_port;
if(!n_conn) { /* launch the connection */
n_conn = connection_or_connect(firsthop);
n_conn = connection_or_connect(firsthop->addr, firsthop->or_port,
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);
@ -255,21 +256,33 @@ circuit_t *circuit_establish_circuit(uint8_t purpose,
/** Find circuits that are waiting on <b>or_conn</b> to become open,
* if any, and get them to send their create cells forward.
*/
void circuit_n_conn_open(connection_t *or_conn) {
void circuit_n_conn_done(connection_t *or_conn, int success) {
circuit_t *circ;
for(circ=global_circuitlist;circ;circ = circ->next) {
if (circ->marked_for_close)
continue;
if(CIRCUIT_IS_ORIGIN(circ) && circ->n_addr == or_conn->addr && circ->n_port == or_conn->port) {
if(!circ->n_conn &&
circ->n_addr == or_conn->addr &&
circ->n_port == or_conn->port &&
!memcmp(or_conn->identity_digest, circ->n_conn_id_digest, DIGEST_LEN)) {
tor_assert(circ->state == CIRCUIT_STATE_OR_WAIT);
log_fn(LOG_DEBUG,"Found circ %d, sending onion skin.", circ->n_circ_id);
circ->n_conn = or_conn;
if(circuit_send_next_onion_skin(circ) < 0) {
log_fn(LOG_INFO,"send_next_onion_skin failed; circuit marked for closing.");
if(!success) { /* or_conn failed; close circ */
log_fn(LOG_INFO,"or_conn failed. Closing circ.");
circuit_mark_for_close(circ);
continue;
/* XXX could this be bad, eg if next_onion_skin failed because conn died? */
}
log_fn(LOG_DEBUG,"Found circ %d, sending create cell.", circ->n_circ_id);
circ->n_conn = or_conn;
if(CIRCUIT_IS_ORIGIN(circ)) {
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);
continue;
/* XXX could this be bad, eg if next_onion_skin failed because conn died? */
}
} else {
/* XXX008 pull the create cell out of circ->onionskin, and send it */
}
}
}
@ -418,24 +431,38 @@ int circuit_extend(cell_t *cell, circuit_t *circ) {
n_conn = connection_twin_get_by_addr_port(circ->n_addr,circ->n_port);
onionskin = cell->payload+RELAY_HEADER_SIZE+4+2;
} else {
/* XXXX Roger: in this case, we should create the connnection if
* n_conn is null. */
n_conn = connection_get_by_identity_digest(
cell->payload+RELAY_HEADER_SIZE+4+2,
CONN_TYPE_OR);
onionskin = cell->payload+RELAY_HEADER_SIZE+4+2+DIGEST_LEN;
}
if(!n_conn || n_conn->type != CONN_TYPE_OR) {
/* I've disabled making connections through OPs, but it's definitely
* possible here. I'm not sure if it would be a bug or a feature.
*
* Note also that this will close circuits where the onion has the same
if(!n_conn) { /* we should try to open a connection */
/* Note that this will close circuits where the onion has the same
* router twice in a row in the path. I think that's ok.
*/
routerinfo_t *router;
struct in_addr in;
in.s_addr = htonl(circ->n_addr);
log_fn(LOG_INFO,"Next router (%s:%d) not connected. Closing.", inet_ntoa(in), circ->n_port);
log_fn(LOG_INFO,"Next router (%s:%d) not connected. Connecting.",
inet_ntoa(in), circ->n_port);
if (old_format) {
router = router_get_by_addr_port(circ->n_addr, circ->n_port);
if(!router) {
log_fn(LOG_INFO,"Next hop is an unknown router. Closing.");
circuit_mark_for_close(circ);
return 0;
}
} else { /* new format */
router = router_get_by_digest(cell->payload+RELAY_HEADER_SIZE+4+2);
}
/* XXX copy onionskin into circ->onionskin, get into the right
* state, launch an or conn to the right place.
*...
*/
#if 0 /* if we do truncateds, no need to kill circ */
connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED,
NULL, 0, NULL);

View File

@ -454,6 +454,8 @@ void assert_circuit_ok(const circuit_t *c)
if (c->n_conn)
tor_assert(c->n_conn->type == CONN_TYPE_OR);
/* XXX008 have to memcpy id_digest when we attach n_conn */
tor_assert(!memcmp(c->n_conn->identity_digest, c->n_conn_id_digest, DIGEST_LEN));
if (c->p_conn)
tor_assert(c->p_conn->type == CONN_TYPE_OR);
for (conn = c->p_streams; conn; conn = conn->next_stream)

View File

@ -393,7 +393,11 @@ void circuit_about_to_close_connection(connection_t *conn) {
switch(conn->type) {
case CONN_TYPE_OR:
/* We must close all the circuits on it. */
if(conn->state != OR_CONN_STATE_OPEN) {
/* Inform any pending (not attached) circs that they should give up. */
circuit_n_conn_done(conn, 0);
}
/* Now close all the attached circuits on it. */
while((circ = circuit_get_by_conn(conn))) {
if(circ->n_conn == conn) /* it's closing in front of us */
circ->n_conn = NULL;

View File

@ -119,6 +119,7 @@ connection_or_init_conn_from_address(connection_t *conn,
const char *id_digest)
{
routerinfo_t *r;
struct in_addr in;
r = router_get_by_digest(id_digest);
if (r) {
connection_or_init_conn_from_router(conn,r);
@ -132,14 +133,17 @@ connection_or_init_conn_from_address(connection_t *conn,
conn->nickname = tor_malloc(HEX_DIGEST_LEN+1);
base16_encode(conn->nickname, HEX_DIGEST_LEN+1,
conn->identity_digest, DIGEST_LEN);
/* Do something about address? Or is it already set? XXXX NMNM */
tor_free(conn->address);
in.s_addr = htonl(addr);
conn->address = tor_strdup(inet_ntoa(in));
}
/** Launch a new OR connection to <b>router</b>.
/** Launch a new OR connection to <b>addr</b>:<b>port</b> and expect to
* handshake with an OR with identity digest <b>id_digest</b>.
*
* If <b>router</b> is me, do nothing. If we're already connected to <b>router</b>,
* return that connection. If the connect is in progress, set conn's
* state to 'connecting' and return. If connect to <b>router</b> succeeds, call
* If <b>id_digest</b> is me, do nothing. If we're already connected to it,
* return that connection. If the connect() is in progress, set conn's
* state to 'connecting' and return. If connect() succeeds, call
* connection_tls_start_handshake() on it.
*
* This function is called from router_retry_connections(), for
@ -148,30 +152,30 @@ connection_or_init_conn_from_address(connection_t *conn,
*
* Return the launched conn, or NULL if it failed.
*/
connection_t *connection_or_connect(routerinfo_t *router) {
connection_t *connection_or_connect(uint32_t addr, uint16_t port,
const char *id_digest) {
connection_t *conn;
tor_assert(router);
tor_assert(id_digest);
if(router_is_me(router)) {
log_fn(LOG_WARN,"You asked me to connect to myself! Failing.");
if(0) { /* XXX008 if I'm an OR and id_digest is my digest */
log_fn(LOG_WARN,"Request to connect to myself! Failing.");
return NULL;
}
/* this function should never be called if we're already connected to router, but */
/* check first to be sure */
conn = connection_get_by_identity_digest(router->identity_digest,
CONN_TYPE_OR);
/* this function should never be called if we're already connected to
* id_digest, but check first to be sure */
conn = connection_get_by_identity_digest(id_digest, CONN_TYPE_OR);
if(conn)
return conn;
conn = connection_new(CONN_TYPE_OR);
/* set up conn so it's got all the data we need to remember */
connection_or_init_conn_from_router(conn, router);
connection_or_init_conn_from_address(conn, addr, port, id_digest);
conn->state = OR_CONN_STATE_CONNECTING;
switch(connection_connect(conn, router->address, router->addr, router->or_port)) {
switch(connection_connect(conn, conn->address, addr, port)) {
case -1:
connection_free(conn);
return NULL;
@ -252,7 +256,7 @@ int connection_tls_continue_handshake(connection_t *conn) {
*
* If either of us is an OP, set bandwidth to the default OP bandwidth.
*
* If all is successful and he's an OR, then call circuit_n_conn_open()
* If all is successful and he's an OR, then call circuit_n_conn_done()
* to handle events that have been pending on the tls handshake
* completion, and set the directory to be dirty (only matters if I'm
* a dirserver).
@ -284,6 +288,10 @@ connection_tls_finish_handshake(connection_t *conn) {
log_fn(LOG_DEBUG, "Other side (%s:%d) claims to be '%s'", conn->address,
conn->port, nickname);
router = router_get_by_nickname(nickname);
/* XXX008 here we need to tolerate unknown routers, so ORs can
* connect to us even when we don't know they're verified. This
* should probably be a call to router_get_by_digest() now, since
* we can't trust the nickname some guy shows up with. */
if (!router) {
log_fn(LOG_INFO, "Unrecognized router with nickname '%s' at %s:%d",
nickname, conn->address, conn->port);
@ -316,7 +324,7 @@ connection_tls_finish_handshake(connection_t *conn) {
conn->receiver_bucket = conn->bandwidth = DEFAULT_BANDWIDTH_OP;
}
directory_set_dirty();
circuit_n_conn_open(conn); /* send the pending creates, if any. */
circuit_n_conn_done(conn, 1); /* send the pending creates, if any. */
/* Note the success */
rep_hist_note_connect_succeeded(nickname, time(NULL));
return 0;

View File

@ -270,7 +270,7 @@
#define CIRCUIT_STATE_BUILDING 0
/** Circuit state: Waiting to process the onionskin. */
#define CIRCUIT_STATE_ONIONSKIN_PENDING 1
/** Circuit state: I'm the OP, my firsthop is still connecting. */
/** Circuit state: I'd like to deliver a create, but my n_conn is still connecting. */
#define CIRCUIT_STATE_OR_WAIT 2
/** Circuit state: onionskin(s) processed, ready to send/receive cells. */
#define CIRCUIT_STATE_OPEN 3
@ -700,6 +700,8 @@ struct circuit_t {
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. */
@ -754,8 +756,9 @@ struct circuit_t {
*/
crypt_path_t *cpath;
char onionskin[ONIONSKIN_CHALLENGE_LEN]; /**< For storage while onionskin
* pending. */
/** For storage while passing to cpuworker, or while n_conn is pending. */
char onionskin[ONIONSKIN_CHALLENGE_LEN];
char handshake_digest[DIGEST_LEN]; /**< Stores KH for intermediate hops. */
time_t timestamp_created; /**< When was this circuit created? */
@ -917,7 +920,7 @@ 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_nickname);
void circuit_n_conn_open(connection_t *or_conn);
void circuit_n_conn_done(connection_t *or_conn, int success);
int circuit_send_next_onion_skin(circuit_t *circ);
int circuit_extend(cell_t *cell, circuit_t *circ);
int circuit_init_cpath_crypto(crypt_path_t *cpath, char *key_data, int reverse);
@ -1108,7 +1111,8 @@ int connection_or_process_inbuf(connection_t *conn);
int connection_or_finished_flushing(connection_t *conn);
int connection_or_finished_connecting(connection_t *conn);
connection_t *connection_or_connect(routerinfo_t *router);
connection_t *connection_or_connect(uint32_t addr, uint16_t port,
const char *id_digest);
int connection_tls_start_handshake(connection_t *conn, int receiving);
int connection_tls_continue_handshake(connection_t *conn);

View File

@ -321,7 +321,7 @@ void router_retry_connections(void) {
CONN_TYPE_OR)) {
/* not in the list */
log_fn(LOG_DEBUG,"connecting to OR %s:%u.",router->address,router->or_port);
connection_or_connect(router);
connection_or_connect(router->addr, router->or_port, router->identity_digest);
}
}
}