[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [tor/master] Don't remove rend cpath element from relaunched service-side rend circs



commit b46a7ebb2bf2cae94a9ce4447c55014dd90ad868
Author: Robert Ransom <rransom.8774@xxxxxxxxx>
Date:   Fri Jan 6 22:44:20 2012 -0800

    Don't remove rend cpath element from relaunched service-side rend circs
    
    Fixes bug 4842, not in any release.
---
 src/or/circuitlist.c |   14 ++++++++++++++
 src/or/or.h          |   15 +++++++++++++++
 src/or/rendservice.c |   33 +++++++++++++++++++++++++++------
 3 files changed, 56 insertions(+), 6 deletions(-)

diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 97b6162..319acdb 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -39,6 +39,7 @@ static smartlist_t *circuits_pending_or_conns=NULL;
 static void circuit_free(circuit_t *circ);
 static void circuit_free_cpath(crypt_path_t *cpath);
 static void circuit_free_cpath_node(crypt_path_t *victim);
+static void cpath_ref_decref(crypt_path_reference_t *cpath_ref);
 
 /********* END VARIABLES ************/
 
@@ -600,6 +601,7 @@ circuit_free(circuit_t *circ)
     if (ocirc->build_state) {
         extend_info_free(ocirc->build_state->chosen_exit);
         circuit_free_cpath_node(ocirc->build_state->pending_final_cpath);
+        cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref);
     }
     tor_free(ocirc->build_state);
 
@@ -723,6 +725,18 @@ circuit_free_cpath_node(crypt_path_t *victim)
   tor_free(victim);
 }
 
+/** Release a crypt_path_reference_t*, which may be NULL. */
+static void
+cpath_ref_decref(crypt_path_reference_t *cpath_ref)
+{
+  if (cpath_ref != NULL) {
+    if (--(cpath_ref->refcount) == 0) {
+      circuit_free_cpath_node(cpath_ref->cpath);
+      tor_free(cpath_ref);
+    }
+  }
+}
+
 /** A helper function for circuit_dump_by_conn() below. Log a bunch
  * of information about circuit <b>circ</b>.
  */
diff --git a/src/or/or.h b/src/or/or.h
index 2acb621..8fe3e0f 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2406,6 +2406,18 @@ typedef struct crypt_path_t {
                        * at this step? */
 } crypt_path_t;
 
+/** A reference-counted pointer to a crypt_path_t, used only to share
+ * the final rendezvous cpath to be used on a service-side rendezvous
+ * circuit among multiple circuits built in parallel to the same
+ * destination rendezvous point. */
+typedef struct {
+  /** The reference count. */
+  unsigned int refcount;
+  /** The pointer.  Set to NULL when the crypt_path_t is put into use
+   * on an opened rendezvous circuit. */
+  crypt_path_t *cpath;
+} crypt_path_reference_t;
+
 #define CPATH_KEY_MATERIAL_LEN (20*2+16*2)
 
 #define DH_KEY_LEN DH_BYTES
@@ -2432,6 +2444,9 @@ typedef struct {
   unsigned int onehop_tunnel : 1;
   /** The crypt_path_t to append after rendezvous: used for rendezvous. */
   crypt_path_t *pending_final_cpath;
+  /** A ref-counted reference to the crypt_path_t to append after
+   * rendezvous; used on the service side. */
+  crypt_path_reference_t *service_pending_final_cpath_ref;
   /** How many times has building a circuit for this task failed? */
   int failure_count;
   /** At what time should we give up on this task? */
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index bbc9c91..fc4d878 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -1385,7 +1385,12 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
   memcpy(launched->rend_data->rend_cookie, r_cookie, REND_COOKIE_LEN);
   strlcpy(launched->rend_data->onion_address, service->service_id,
           sizeof(launched->rend_data->onion_address));
-  launched->build_state->pending_final_cpath = cpath =
+
+  launched->build_state->service_pending_final_cpath_ref =
+    tor_malloc_zero(sizeof(crypt_path_reference_t));
+  launched->build_state->service_pending_final_cpath_ref->refcount = 1;
+
+  launched->build_state->service_pending_final_cpath_ref->cpath = cpath =
     tor_malloc_zero(sizeof(crypt_path_t));
   cpath->magic = CRYPT_PATH_MAGIC;
   launched->build_state->expiry_time = now + MAX_REND_TIMEOUT;
@@ -1445,7 +1450,7 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
   oldstate = oldcirc->build_state;
   tor_assert(oldstate);
 
-  if (oldstate->pending_final_cpath == NULL) {
+  if (oldstate->service_pending_final_cpath_ref == NULL) {
     log_info(LD_REND,"Skipping relaunch of circ that failed on its first hop. "
              "Initiator will retry.");
     return;
@@ -1467,8 +1472,9 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc)
   tor_assert(newstate);
   newstate->failure_count = oldstate->failure_count+1;
   newstate->expiry_time = oldstate->expiry_time;
-  newstate->pending_final_cpath = oldstate->pending_final_cpath;
-  oldstate->pending_final_cpath = NULL;
+  newstate->service_pending_final_cpath_ref =
+    oldstate->service_pending_final_cpath_ref;
+  ++(newstate->service_pending_final_cpath_ref->refcount);
 
   newcirc->rend_data = rend_data_dup(oldcirc->rend_data);
 }
@@ -1726,8 +1732,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
   tor_assert(!(circuit->build_state->onehop_tunnel));
 #endif
   tor_assert(circuit->rend_data);
-  hop = circuit->build_state->pending_final_cpath;
-  tor_assert(hop);
+  hop = circuit->build_state->service_pending_final_cpath_ref->cpath;
 
   base16_encode(hexcookie,9,circuit->rend_data->rend_cookie,4);
   base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
@@ -1743,6 +1748,22 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit)
    * no effect on Tor's behaviour. */
   circuit->hs_circ_has_timed_out = 0;
 
+  /* If hop is NULL, another rend circ has already connected to this
+   * rend point.  Close this circ. */
+  if (hop == NULL) {
+    log_info(LD_REND, "Another rend circ has already reached this rend point; "
+             "closing this rend circ.");
+    reason = END_CIRC_REASON_NONE;
+    goto err;
+  }
+
+  /* Remove our final cpath element from the reference, so that no
+   * other circuit will try to use it.  Store it in
+   * pending_final_cpath for now to ensure that it will be freed if
+   * our rendezvous attempt fails. */
+  circuit->build_state->pending_final_cpath = hop;
+  circuit->build_state->service_pending_final_cpath_ref->cpath = NULL;
+
   service = rend_service_get_by_pk_digest(
                 circuit->rend_data->rend_pk_digest);
   if (!service) {



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits