diff options
author | Roger Dingledine <arma@torproject.org> | 2004-04-13 22:56:24 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2004-04-13 22:56:24 +0000 |
commit | 1d7979b4608623434bf84678b5622acdd8dcfefa (patch) | |
tree | 6bf68085df6c1b8169f4ef86915726e301e5bb43 /src/or | |
parent | 5514ad715bd4a730fe5cff36ae99d9f8c39969f0 (diff) | |
download | tor-1d7979b4608623434bf84678b5622acdd8dcfefa.tar tor-1d7979b4608623434bf84678b5622acdd8dcfefa.tar.gz |
let introcircs receive acks. rend streams now deal correctly again.
(i think)
svn:r1614
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/circuit.c | 38 | ||||
-rw-r--r-- | src/or/connection_edge.c | 52 | ||||
-rw-r--r-- | src/or/or.h | 22 | ||||
-rw-r--r-- | src/or/rendclient.c | 25 |
4 files changed, 80 insertions, 57 deletions
diff --git a/src/or/circuit.c b/src/or/circuit.c index a599e891d..f6a73c643 100644 --- a/src/or/circuit.c +++ b/src/or/circuit.c @@ -275,9 +275,10 @@ static int circuit_is_acceptable(circuit_t *circ, if(purpose == CIRCUIT_PURPOSE_C_REND_JOINED && !must_be_open) { if(circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND && circ->purpose != CIRCUIT_PURPOSE_C_REND_READY && + circ->purpose != CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED && circ->purpose != CIRCUIT_PURPOSE_C_REND_JOINED) return 0; - } else if (purpose == CIRCUIT_PURPOSE_C_INTRODUCING) { + } else if (purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT && !must_be_open) { if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCING && circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) return 0; @@ -311,8 +312,10 @@ static int circuit_is_acceptable(circuit_t *circ, return 0; } } else { /* not general */ - if(rend_cmp_service_ids(conn->rend_query, circ->rend_query)) { - /* this circ is not for this conn */ + if(rend_cmp_service_ids(conn->rend_query, circ->rend_query) && + (circ->rend_query[0] || purpose != CIRCUIT_PURPOSE_C_REND_JOINED)) { + /* this circ is not for this conn, and it's not suitable + * for cannibalizing either */ return 0; } } @@ -340,9 +343,9 @@ static int circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose) return 1; } break; - case CIRCUIT_PURPOSE_C_INTRODUCING: - /* more recently created is best */ - if(a->timestamp_created > b->timestamp_created) + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + /* the closer it is to ack_wait the better it is */ + if(a->purpose > b->purpose) return 1; break; case CIRCUIT_PURPOSE_C_REND_JOINED: @@ -356,25 +359,28 @@ static int circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose) /* Find the best circ that conn can use, preferably one which is * dirty. Circ must not be too old. - * If !conn, return newest. + * conn must be defined. * * If must_be_open, ignore circs not in CIRCUIT_STATE_OPEN. * * circ_purpose specifies what sort of circuit we must have. - * It can be C_GENERAL, C_INTRODUCING, or C_REND_JOINED. + * It can be C_GENERAL, C_INTRODUCE_ACK_WAIT, or C_REND_JOINED. * * If it's REND_JOINED and must_be_open==0, then return the closest * rendezvous-purposed circuit that you can find. * - * If circ_purpose is not GENERAL, then conn must be defined. + * If it's INTRODUCE_ACK_WAIT and must_be_open==0, then return the + * closest introduce-purposed circuit that you can find. */ circuit_t *circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose) { circuit_t *circ, *best=NULL; time_t now = time(NULL); + assert(conn); + assert(purpose == CIRCUIT_PURPOSE_C_GENERAL || - purpose == CIRCUIT_PURPOSE_C_INTRODUCING || + purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT || purpose == CIRCUIT_PURPOSE_C_REND_JOINED); for (circ=global_circuitlist;circ;circ = circ->next) { @@ -391,6 +397,18 @@ circuit_t *circuit_get_best(connection_t *conn, return best; } +circuit_t *circuit_get_by_rend_query_and_purpose(const char *rend_query, uint8_t purpose) { + circuit_t *circ; + + for (circ = global_circuitlist; circ; circ = circ->next) { + if (!circ->marked_for_close && + circ->purpose == purpose && + !rend_cmp_service_ids(rend_query, circ->rend_query)) + return circ; + } + return NULL; +} + /* Return the first circuit in global_circuitlist after 'start' whose * rend_pk_digest field is 'digest' and whose purpose is purpose. Returns * NULL if no circuit is found. If 'start' is null, begin at the start of diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 26d3226cf..77422df4b 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -806,7 +806,7 @@ circuit_get_open_circ_or_launch(connection_t *conn, char *exitname=NULL; uint8_t new_circ_purpose; - if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCING) { + if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { /* need to pick an intro point */ exitname = rend_client_get_random_intro(conn->rend_query); if(!exitname) { @@ -823,6 +823,8 @@ circuit_get_open_circ_or_launch(connection_t *conn, if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED) new_circ_purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND; + else if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) + new_circ_purpose = CIRCUIT_PURPOSE_C_INTRODUCING; else new_circ_purpose = desired_circuit_purpose; @@ -893,16 +895,13 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) { } else { /* we're a rendezvous conn */ circuit_t *rendcirc=NULL, *introcirc=NULL; - /* before anything else, see if we've already been attached - * to a rendezvous circuit */ - if(conn->cpath_layer) { - return 1; - } + assert(!conn->cpath_layer); - /* else, start by finding a rendezvous circuit for us */ + /* start by finding a rendezvous circuit for us */ retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_REND_JOINED, &rendcirc); if(retval < 0) return -1; /* failed */ + assert(rendcirc); if(retval > 0) { /* one is already established, attach */ @@ -913,36 +912,41 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) { return 1; } - if(rendcirc && - rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY && - rendcirc->build_state->pending_final_cpath) { - log_fn(LOG_INFO,"pending-join circ already here. reusing."); - link_apconn_to_circ(conn, rendcirc); - /* don't send the begin, because we're still waiting for contact from bob */ - return 1; + if(rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) { + log_fn(LOG_INFO,"pending-join circ already here, with intro ack. Stalling."); + return 0; } /* it's on its way. find an intro circ. */ - retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_INTRODUCING, &introcirc); + retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT, &introcirc); if(retval < 0) return -1; /* failed */ + assert(introcirc); if(retval > 0) { - log_fn(LOG_INFO,"Intro circ is ready for us"); - if(rendcirc && - rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY) { - /* then we know !pending_final_cpath, from above */ - log_fn(LOG_INFO,"intro and rend circs are both ready. introducing."); - /* this call marks introcirc for close */ + /* one has already sent the intro. keep waiting. */ + log_fn(LOG_INFO,"Intro circ present and awaiting ack. Stalling."); + return 0; + } + + /* now both rendcirc and introcirc are defined, and neither is finished */ + + if(rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY) { + log_fn(LOG_INFO,"ready rend circ already here (no intro-ack yet)."); + /* look around for any new intro circs that should introduce */ + + assert(introcirc->purpose == CIRCUIT_PURPOSE_C_INTRODUCING); + if(introcirc->state == CIRCUIT_STATE_OPEN) { + log_fn(LOG_INFO,"found open intro circ; sending introduction."); + /* XXX here we should cannibalize the rend circ if it's a zero service id */ if(rend_client_send_introduction(introcirc, rendcirc) < 0) { return -1; } - /* now attach conn to rendcirc */ - link_apconn_to_circ(conn, rendcirc); if(!rendcirc->timestamp_dirty) rendcirc->timestamp_dirty = time(NULL); - return 1; + return 0; } } + log_fn(LOG_INFO,"Intro and rend circs are not both ready. Stalling conn."); return 0; } diff --git a/src/or/or.h b/src/or/or.h index c6949281e..d91cd1207 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -209,10 +209,12 @@ * circuits that are c_establish_rend are either on their way * to becoming open, or they are open and have sent the * establish_rendezvous cell but haven't received an ack. - * circuits that are c_rend_ready are open and have received an - * ack, but haven't heard from bob yet. if they have a + * circuits that are c_rend_ready are open and have received a + * rend ack, but haven't heard from bob yet. if they have a * buildstate->pending_final_cpath then they're expecting a * cell from bob, else they're not. + * circuits that are c_rend_ready_intro_acked are open, and + * some intro circ has sent its intro and received an ack. * circuits that are c_rend_joined are open, have heard from * bob, and are talking to him. */ @@ -222,14 +224,15 @@ #define CIRCUIT_PURPOSE_C_ESTABLISH_REND 8 /* at Alice, waiting for ack */ #define CIRCUIT_PURPOSE_C_REND_READY 9 /* at Alice, waiting for Bob */ -#define CIRCUIT_PURPOSE_C_REND_JOINED 10 /* at Alice, rendezvous established */ +#define CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED 10 /* at Alice, waiting for Bob */ +#define CIRCUIT_PURPOSE_C_REND_JOINED 11 /* at Alice, rendezvous established */ -#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 11 /* at Bob, waiting for introductions */ -#define CIRCUIT_PURPOSE_S_INTRO 12 /* at Bob, successfully established intro */ -#define CIRCUIT_PURPOSE_S_CONNECT_REND 13 /* at Bob, connecting to rend point */ +#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 12 /* at Bob, waiting for introductions */ +#define CIRCUIT_PURPOSE_S_INTRO 13 /* at Bob, successfully established intro */ +#define CIRCUIT_PURPOSE_S_CONNECT_REND 14 /* at Bob, connecting to rend point */ -#define CIRCUIT_PURPOSE_S_REND_JOINED 14 /* at Bob, rendezvous established.*/ -#define _CIRCUIT_PURPOSE_MAX 14 +#define CIRCUIT_PURPOSE_S_REND_JOINED 15 /* at Bob, rendezvous established.*/ +#define _CIRCUIT_PURPOSE_MAX 15 #define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>_CIRCUIT_PURPOSE_OR_MAX) #define CIRCUIT_IS_ORIGIN(c) (CIRCUIT_PURPOSE_IS_ORIGIN((c)->purpose)) @@ -685,6 +688,7 @@ circuit_t *circuit_get_by_circ_id_conn(uint16_t circ_id, connection_t *conn); circuit_t *circuit_get_by_conn(connection_t *conn); circuit_t *circuit_get_best(connection_t *conn, int must_be_open, uint8_t purpose); +circuit_t *circuit_get_by_rend_query_and_purpose(const char *rend_query, uint8_t purpose); circuit_t *circuit_get_next_by_pk_and_purpose(circuit_t *circuit, const char *servid, uint8_t purpose); circuit_t *circuit_get_rendezvous(const char *cookie); @@ -1038,7 +1042,7 @@ int rend_client_rendezvous_acked(circuit_t *circ, const char *request, int reque int rend_client_receive_rendezvous(circuit_t *circ, const char *request, int request_len); void rend_client_desc_fetched(char *query, int success); -int rend_cmp_service_ids(char *one, char *two); +int rend_cmp_service_ids(const char *one, const char *two); char *rend_client_get_random_intro(char *query); int rend_parse_rendezvous_address(char *address); diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 27d6fd5f1..112dd8afd 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -8,16 +8,11 @@ void rend_client_introcirc_is_open(circuit_t *circ) { - circuit_t *rendcirc = NULL; assert(circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING); assert(CIRCUIT_IS_ORIGIN(circ) && circ->cpath); log_fn(LOG_INFO,"introcirc is open"); connection_ap_attach_pending(); - while ((rendcirc = circuit_get_next_by_pk_and_purpose( - rendcirc, circ->rend_pk_digest, CIRCUIT_PURPOSE_C_REND_READY))) { - rend_client_send_introduction(circ, rendcirc); - } } /* send the establish-rendezvous cell. if it fails, mark @@ -154,6 +149,7 @@ rend_client_introduction_acked(circuit_t *circ, int i, r; rend_cache_entry_t *ent; char *nickname; + circuit_t *rendcirc; if (circ->purpose != CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { log_fn(LOG_WARN, "Received REND_INTRODUCE_ACK on unexpected circuit %d", @@ -166,7 +162,15 @@ rend_client_introduction_acked(circuit_t *circ, if (request_len == 0) { /* It's an ACK; the introduction point relayed our introduction request. */ - /* So close the circuit; we won't need it any more. */ + /* Locate the rend circ which is waiting to hear about this ack, + * and tell it. + */ + rendcirc = circuit_get_by_rend_query_and_purpose( + circ->rend_query, CIRCUIT_PURPOSE_C_REND_READY); + if(rendcirc) { /* remember the ack */ + rendcirc->purpose = CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED; + } + /* close the circuit: we won't need it anymore. */ circuit_mark_for_close(circ); } else { /* It's a NAK; the introduction point didn't relay our request. */ @@ -305,13 +309,6 @@ rend_client_receive_rendezvous(circuit_t *circ, const char *request, int request onion_append_to_cpath(&circ->cpath, hop); circ->build_state->pending_final_cpath = NULL; /* prevent double-free */ - - for(apconn = circ->p_streams; apconn; apconn = apconn->next_stream) { - apconn->cpath_layer = circ->cpath->prev; - /* now the last hop is different. be sure to send all the way. */ - if(connection_ap_handshake_send_begin(apconn, circ) < 0) - return -1; - } return 0; err: circuit_mark_for_close(circ); @@ -356,7 +353,7 @@ void rend_client_desc_fetched(char *query, int success) { } } -int rend_cmp_service_ids(char *one, char *two) { +int rend_cmp_service_ids(const char *one, const char *two) { return strcasecmp(one,two); } |