Index: /home/karsten/tor/tor-trunk-155-patch4/ChangeLog =================================================================== --- /home/karsten/tor/tor-trunk-155-patch4/ChangeLog (revision 17050) +++ /home/karsten/tor/tor-trunk-155-patch4/ChangeLog (working copy) @@ -3,6 +3,9 @@ - Now NodeFamily and MyFamily config options allow spaces in identity fingerprints, so it's easier to paste them in. Suggested by Lucky Green. + - Start building more server-side introduction circuits than needed + (five), pick the first three that succeed, and use the others as + general-purpose circuits. Changes in version 0.2.1.6-alpha - 2008-09-30 Index: /home/karsten/tor/tor-trunk-155-patch4/src/or/circuitlist.c =================================================================== --- /home/karsten/tor/tor-trunk-155-patch4/src/or/circuitlist.c (revision 17050) +++ /home/karsten/tor/tor-trunk-155-patch4/src/or/circuitlist.c (working copy) @@ -860,6 +860,28 @@ DIGEST_LEN); } +/** Return the number of introduction points that are or have been + * established for the given service address and rendezvous version. */ +int +circuit_get_num_intro_points(const char *query, int rend_version) +{ + int num_ipos = 0; + circuit_t *circ; + for (circ = global_circuitlist; circ; circ = circ->next) { + if (!circ->marked_for_close && + circ->state == CIRCUIT_STATE_OPEN && + (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || + circ->purpose == CIRCUIT_PURPOSE_S_INTRO)) { + origin_circuit_t *oc = TO_ORIGIN_CIRCUIT(circ); + if (oc->rend_data && + oc->rend_data->rend_desc_version == rend_version && + !rend_cmp_service_ids(query, oc->rend_data->onion_address)) + num_ipos++; + } + } + return num_ipos; +} + /** Return a circuit that is open, is CIRCUIT_PURPOSE_C_GENERAL, * has a timestamp_dirty value of 0, has flags matching the CIRCLAUNCH_* * flags in flags, and if info is defined, does not already use info Index: /home/karsten/tor/tor-trunk-155-patch4/src/or/or.h =================================================================== --- /home/karsten/tor/tor-trunk-155-patch4/src/or/or.h (revision 17050) +++ /home/karsten/tor/tor-trunk-155-patch4/src/or/or.h (working copy) @@ -2725,6 +2725,7 @@ const char *digest, uint8_t purpose); or_circuit_t *circuit_get_rendezvous(const char *cookie); or_circuit_t *circuit_get_intro_point(const char *digest); +int circuit_get_num_intro_points(const char *query, int rend_version); origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, int flags); void circuit_mark_all_unused_circs(void); Index: /home/karsten/tor/tor-trunk-155-patch4/src/or/rendservice.c =================================================================== --- /home/karsten/tor/tor-trunk-155-patch4/src/or/rendservice.c (revision 17050) +++ /home/karsten/tor/tor-trunk-155-patch4/src/or/rendservice.c (working copy) @@ -1307,6 +1307,18 @@ goto err; } + /* If we already have enough introduction circuits, redefine this + * one as a general circuit. */ + if (circuit_get_num_intro_points(serviceid, + circuit->rend_data->rend_desc_version) > NUM_INTRO_POINTS) { + log_info(LD_CIRC|LD_REND, "We have just finished an introduction " + "circuit, but we already have enough. Redefining purpose to " + "general."); + TO_CIRCUIT(circuit)->purpose = CIRCUIT_PURPOSE_C_GENERAL; + circuit_has_opened(circuit); + return; + } + log_info(LD_REND, "Established circuit %d as introduction point for service %s", circuit->_base.n_circ_id, serviceid); @@ -1823,9 +1835,12 @@ /* Remember how many introduction circuits we started with. */ prev_intro_nodes = smartlist_len(service->intro_nodes); - - /* The directory is now here. Pick three ORs as intro points. */ - for (j=prev_intro_nodes; j < NUM_INTRO_POINTS; ++j) { + /* The directory is now here. Pick three ORs as intro points (plus, if + * we currently have none at all, two more so that we can pick the first + * three afterwards). */ +#define NUM_INTRO_POINTS_INIT (NUM_INTRO_POINTS + 2) + for (j=prev_intro_nodes; j < (prev_intro_nodes == 0 ? + NUM_INTRO_POINTS_INIT : NUM_INTRO_POINTS); ++j) { router_crn_flags_t flags = CRN_NEED_UPTIME; if (get_options()->_AllowInvalid & ALLOW_INVALID_INTRODUCTION) flags |= CRN_ALLOW_INVALID;