summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2015-04-30 13:32:52 -0400
committerNick Mathewson <nickm@torproject.org>2015-04-30 13:32:52 -0400
commit41efe22c030e7c896ae5e1c380a3d783c03f0861 (patch)
treec5bc268d84a4a7e2c144bfa17ad53c8fc70ea5b7
parent26e0f8635af62eef115452e31d55e3f40fe1e90d (diff)
parenta9b9f6d90f473e1a4fad3816ee73190da15b2291 (diff)
downloadtor-41efe22c030e7c896ae5e1c380a3d783c03f0861.tar.gz
tor-41efe22c030e7c896ae5e1c380a3d783c03f0861.zip
Merge branch 'bug15814_027_04'
-rw-r--r--src/or/circuituse.c2
-rw-r--r--src/or/connection_edge.c37
-rw-r--r--src/or/control.c28
-rw-r--r--src/or/or.h10
-rw-r--r--src/or/rendclient.c100
-rw-r--r--src/or/rendclient.h9
-rw-r--r--src/or/rendcommon.c97
-rw-r--r--src/or/rendcommon.h8
-rw-r--r--src/or/rendservice.c19
9 files changed, 218 insertions, 92 deletions
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index d0d31ad9cf..b54a4d2a7f 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -2149,7 +2149,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
* that an attempt to connect to a hidden service just
* succeeded. Tell rendclient.c. */
rend_client_note_connection_attempt_ended(
- ENTRY_TO_EDGE_CONN(apconn)->rend_data->onion_address);
+ ENTRY_TO_EDGE_CONN(apconn)->rend_data);
}
if (cpath) { /* we were given one; use it */
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 670905f136..cc6e3d7c58 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -102,8 +102,7 @@ connection_mark_unattached_ap_,(entry_connection_t *conn, int endreason,
* but we should fix it someday anyway. */
if ((edge_conn->on_circuit != NULL || edge_conn->edge_has_sent_end) &&
connection_edge_is_rendezvous_stream(edge_conn)) {
- rend_client_note_connection_attempt_ended(
- edge_conn->rend_data->onion_address);
+ rend_client_note_connection_attempt_ended(edge_conn->rend_data);
}
if (base_conn->marked_for_close) {
@@ -1499,12 +1498,27 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
return -1;
}
+ /* Look up if we have client authorization configured for this hidden
+ * service. If we do, associate it with the rend_data. */
+ rend_service_authorization_t *client_auth =
+ rend_client_lookup_service_authorization(socks->address);
+
+ const char *cookie = NULL;
+ rend_auth_type_t auth_type = REND_NO_AUTH;
+ if (client_auth) {
+ log_info(LD_REND, "Using previously configured client authorization "
+ "for hidden service request.");
+ auth_type = client_auth->auth_type;
+ cookie = client_auth->descriptor_cookie;
+ }
+
/* Fill in the rend_data field so we can start doing a connection to
* a hidden service. */
rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data =
- tor_malloc_zero(sizeof(rend_data_t));
- strlcpy(rend_data->onion_address, socks->address,
- sizeof(rend_data->onion_address));
+ rend_data_client_create(socks->address, NULL, cookie, auth_type);
+ if (rend_data == NULL) {
+ return -1;
+ }
log_info(LD_REND,"Got a hidden service request for ID '%s'",
safe_str_client(rend_data->onion_address));
@@ -1547,19 +1561,6 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
return 0;
}
- /* Look up if we have client authorization configured for this hidden
- * service. If we do, associate it with the rend_data. */
- rend_service_authorization_t *client_auth =
- rend_client_lookup_service_authorization(
- rend_data->onion_address);
- if (client_auth) {
- log_info(LD_REND, "Using previously configured client authorization "
- "for hidden service request.");
- memcpy(rend_data->descriptor_cookie,
- client_auth->descriptor_cookie, REND_DESC_COOKIE_LEN);
- rend_data->auth_type = client_auth->auth_type;
- }
-
/* We have the descriptor so launch a connection to the HS. */
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
log_info(LD_REND, "Descriptor is here. Great.");
diff --git a/src/or/control.c b/src/or/control.c
index 7c8a6c4aa7..4578f2d95e 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -3389,25 +3389,21 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len,
}
}
- rend_query = tor_malloc_zero(sizeof(*rend_query));
-
- if (hsaddress) {
- strncpy(rend_query->onion_address, hsaddress,
- sizeof(rend_query->onion_address));
- } else if (desc_id) {
- /* Using a descriptor ID, we force the user to provide at least one
- * hsdir server using the SERVER= option. */
- if (!hsdirs || !smartlist_len(hsdirs)) {
+ rend_query = rend_data_client_create(hsaddress, desc_id, NULL,
+ REND_NO_AUTH);
+ if (rend_query == NULL) {
+ connection_printf_to_buf(conn, "551 Error creating the HS query\r\n");
+ goto done;
+ }
+
+ /* Using a descriptor ID, we force the user to provide at least one
+ * hsdir server using the SERVER= option. */
+ if (desc_id && (!hsdirs || !smartlist_len(hsdirs))) {
connection_printf_to_buf(conn, "512 %s option is required\r\n",
opt_server);
goto done;
- }
- memcpy(rend_query->descriptor_id, desc_id,
- sizeof(rend_query->descriptor_id));
- } else {
- /* We can't get in here because of the first argument check. */
- tor_assert(0);
}
+
/* We are about to trigger HSDir fetch so send the OK now because after
* that 650 event(s) are possible so better to have the 250 OK before them
* to avoid out of order replies. */
@@ -3423,7 +3419,7 @@ done:
smartlist_free(args);
/* Contains data pointer that we don't own thus no cleanup. */
smartlist_free(hsdirs);
- tor_free(rend_query);
+ rend_data_free(rend_query);
exit:
return 0;
}
diff --git a/src/or/or.h b/src/or/or.h
index dee1881034..d9be1be37d 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -793,6 +793,11 @@ typedef struct rend_data_t {
/** Onion address (without the .onion part) that a client requests. */
char onion_address[REND_SERVICE_ID_LEN_BASE32+1];
+ /** Descriptor ID for each replicas computed from the onion address. If
+ * the onion address is empty, this array MUST be empty. We keep them so
+ * we know when to purge our entry in the last hsdir request table. */
+ char descriptor_id[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS][DIGEST_LEN];
+
/** (Optional) descriptor cookie that is used by a client. */
char descriptor_cookie[REND_DESC_COOKIE_LEN];
@@ -800,8 +805,9 @@ typedef struct rend_data_t {
rend_auth_type_t auth_type;
/** Descriptor ID for a client request. The control port command HSFETCH
- * can use this. */
- char descriptor_id[DIGEST_LEN];
+ * uses this. It's set if the descriptor query should only use this
+ * descriptor ID. */
+ char desc_id_fetch[DIGEST_LEN];
/** Hash of the hidden service's PK used by a service. */
char rend_pk_digest[DIGEST_LEN];
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 13781c212e..834759cdc7 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -474,9 +474,8 @@ rend_client_introduction_acked(origin_circuit_t *circ,
/** Contains the last request times to hidden service directories for
* certain queries; each key is a string consisting of the
- * concatenation of a base32-encoded HS directory identity digest, a
- * base32-encoded HS descriptor ID, and a hidden service address
- * (without the ".onion" part); each value is a pointer to a time_t
+ * concatenation of a base32-encoded HS directory identity digest and
+ * base32-encoded HS descriptor ID; each value is a pointer to a time_t
* holding the time of the last request for that descriptor ID to that
* HS directory. */
static strmap_t *last_hid_serv_requests_ = NULL;
@@ -492,8 +491,7 @@ get_last_hid_serv_requests(void)
}
#define LAST_HID_SERV_REQUEST_KEY_LEN (REND_DESC_ID_V2_LEN_BASE32 + \
- REND_DESC_ID_V2_LEN_BASE32 + \
- REND_SERVICE_ID_LEN_BASE32)
+ REND_DESC_ID_V2_LEN_BASE32)
/** Look up the last request time to hidden service directory <b>hs_dir</b>
* for descriptor ID <b>desc_id_base32</b>. If <b>set</b> is non-zero,
@@ -554,20 +552,23 @@ directory_clean_last_hid_serv_requests(time_t now)
}
}
-/** Remove all requests related to the hidden service named
- * <b>onion_address</b> from the history of times of requests to
- * hidden service directories.
+/** Remove all requests related to the descriptor ID <b>desc_id</b> from the
+ * history of times of requests to hidden service directories.
+ * <b>desc_id</b> is an unencoded descriptor ID of size DIGEST_LEN.
*
* This is called from rend_client_note_connection_attempt_ended(), which
- * must be idempotent, so any future changes to this function must leave
- * it idempotent too.
- */
+ * must be idempotent, so any future changes to this function must leave it
+ * idempotent too. */
static void
-purge_hid_serv_from_last_hid_serv_requests(const char *onion_address)
+purge_hid_serv_from_last_hid_serv_requests(const char *desc_id)
{
strmap_iter_t *iter;
strmap_t *last_hid_serv_requests = get_last_hid_serv_requests();
- /* XXX023 tor_assert(strlen(onion_address) == REND_SERVICE_ID_LEN_BASE32); */
+ char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+
+ /* Key is stored with the base32 encoded desc_id. */
+ base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
+ DIGEST_LEN);
for (iter = strmap_iter_init(last_hid_serv_requests);
!strmap_iter_done(iter); ) {
const char *key;
@@ -575,9 +576,9 @@ purge_hid_serv_from_last_hid_serv_requests(const char *onion_address)
strmap_iter_get(iter, &key, &val);
/* XXX023 tor_assert(strlen(key) == LAST_HID_SERV_REQUEST_KEY_LEN); */
if (tor_memeq(key + LAST_HID_SERV_REQUEST_KEY_LEN -
- REND_SERVICE_ID_LEN_BASE32,
- onion_address,
- REND_SERVICE_ID_LEN_BASE32)) {
+ REND_DESC_ID_V2_LEN_BASE32,
+ desc_id_base32,
+ REND_DESC_ID_V2_LEN_BASE32)) {
iter = strmap_iter_next_rmv(last_hid_serv_requests, iter);
tor_free(val);
} else {
@@ -791,8 +792,7 @@ end:
* On success, 1 is returned. If no hidden service is left to ask, return 0.
* On error, -1 is returned. */
static int
-fetch_v2_desc_by_addr(const rend_data_t *query,
- smartlist_t *hsdirs)
+fetch_v2_desc_by_addr(rend_data_t *query, smartlist_t *hsdirs)
{
char descriptor_id[DIGEST_LEN];
int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
@@ -822,6 +822,16 @@ fetch_v2_desc_by_addr(const rend_data_t *query,
goto end;
}
+ if (tor_memcmp(descriptor_id, query->descriptor_id[chosen_replica],
+ sizeof(descriptor_id)) != 0) {
+ /* Not equal from what we currently have so purge the last hid serv
+ * request cache and update the descriptor ID with the new value. */
+ purge_hid_serv_from_last_hid_serv_requests(
+ query->descriptor_id[chosen_replica]);
+ memcpy(query->descriptor_id[chosen_replica], descriptor_id,
+ sizeof(query->descriptor_id[chosen_replica]));
+ }
+
/* Trigger the fetch with the computed descriptor ID. */
ret = fetch_v2_desc_by_descid(descriptor_id, query, hsdirs);
if (ret != 0) {
@@ -848,8 +858,7 @@ end:
* On success, 1 is returned. If no hidden service is left to ask, return 0.
* On error, -1 is returned. */
int
-rend_client_fetch_v2_desc(const rend_data_t *query,
- smartlist_t *hsdirs)
+rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs)
{
int ret;
@@ -860,8 +869,8 @@ rend_client_fetch_v2_desc(const rend_data_t *query,
if (query->onion_address[0] != '\0') {
ret = fetch_v2_desc_by_addr(query, hsdirs);
- } else if (query->descriptor_id[0] != '\0') {
- ret = fetch_v2_desc_by_descid(query->descriptor_id, query, hsdirs);
+ } else if (!tor_digest_is_zero(query->desc_id_fetch)) {
+ ret = fetch_v2_desc_by_descid(query->desc_id_fetch, query, hsdirs);
} else {
/* Query data is invalid. */
ret = -1;
@@ -876,7 +885,7 @@ error:
* one (possibly) working introduction point in it, start a connection to a
* hidden service directory to fetch a v2 rendezvous service descriptor. */
void
-rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
+rend_client_refetch_v2_renddesc(rend_data_t *rend_query)
{
int ret;
rend_cache_entry_t *e = NULL;
@@ -963,7 +972,7 @@ rend_client_cancel_descriptor_fetches(void)
*/
int
rend_client_report_intro_point_failure(extend_info_t *failed_intro,
- const rend_data_t *rend_query,
+ rend_data_t *rend_query,
unsigned int failure_type)
{
int i, r;
@@ -1213,28 +1222,28 @@ rend_client_desc_trynow(const char *query)
"unavailable (try again later).",
safe_str_client(query));
connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED);
- rend_client_note_connection_attempt_ended(query);
+ rend_client_note_connection_attempt_ended(rend_data);
}
} SMARTLIST_FOREACH_END(base_conn);
}
-/** Clear temporary state used only during an attempt to connect to
- * the hidden service named <b>onion_address</b>. Called when a
- * connection attempt has ended; it is possible for this to be called
- * multiple times while handling an ended connection attempt, and
- * any future changes to this function must ensure it remains
- * idempotent.
- */
+/** Clear temporary state used only during an attempt to connect to the
+ * hidden service with <b>rend_data</b>. Called when a connection attempt
+ * has ended; it is possible for this to be called multiple times while
+ * handling an ended connection attempt, and any future changes to this
+ * function must ensure it remains idempotent. */
void
-rend_client_note_connection_attempt_ended(const char *onion_address)
+rend_client_note_connection_attempt_ended(const rend_data_t *rend_data)
{
+ unsigned int have_onion = 0;
rend_cache_entry_t *cache_entry = NULL;
- /* Ignore return value; we find an entry, or we don't. */
- (void) rend_cache_lookup_entry(onion_address, -1, &cache_entry);
- log_info(LD_REND, "Connection attempt for %s has ended; "
- "cleaning up temporary state.",
- safe_str_client(onion_address));
+ if (*rend_data->onion_address != '\0') {
+ /* Ignore return value; we find an entry, or we don't. */
+ (void) rend_cache_lookup_entry(rend_data->onion_address, -1,
+ &cache_entry);
+ have_onion = 1;
+ }
/* Clear the timed_out flag on all remaining intro points for this HS. */
if (cache_entry != NULL) {
@@ -1244,7 +1253,20 @@ rend_client_note_connection_attempt_ended(const char *onion_address)
}
/* Remove the HS's entries in last_hid_serv_requests. */
- purge_hid_serv_from_last_hid_serv_requests(onion_address);
+ if (have_onion) {
+ unsigned int replica;
+ for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id);
+ replica++) {
+ const char *desc_id = rend_data->descriptor_id[replica];
+ purge_hid_serv_from_last_hid_serv_requests(desc_id);
+ }
+ log_info(LD_REND, "Connection attempt for %s has ended; "
+ "cleaning up temporary state.",
+ safe_str_client(rend_data->onion_address));
+ } else {
+ /* We only have an ID for a fetch. Probably used by HSFETCH. */
+ purge_hid_serv_from_last_hid_serv_requests(rend_data->desc_id_fetch);
+ }
}
/** Return a newly allocated extend_info_t* for a randomly chosen introduction
diff --git a/src/or/rendclient.h b/src/or/rendclient.h
index d6fea678d0..639ec1eff4 100644
--- a/src/or/rendclient.h
+++ b/src/or/rendclient.h
@@ -19,9 +19,8 @@ void rend_client_rendcirc_has_opened(origin_circuit_t *circ);
int rend_client_introduction_acked(origin_circuit_t *circ,
const uint8_t *request,
size_t request_len);
-void rend_client_refetch_v2_renddesc(const rend_data_t *rend_query);
-int rend_client_fetch_v2_desc(const rend_data_t *query,
- smartlist_t *hsdirs);
+void rend_client_refetch_v2_renddesc(rend_data_t *rend_query);
+int rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs);
void rend_client_cancel_descriptor_fetches(void);
void rend_client_purge_last_hid_serv_requests(void);
@@ -30,7 +29,7 @@ void rend_client_purge_last_hid_serv_requests(void);
#define INTRO_POINT_FAILURE_UNREACHABLE 2
int rend_client_report_intro_point_failure(extend_info_t *failed_intro,
- const rend_data_t *rend_query,
+ rend_data_t *rend_query,
unsigned int failure_type);
int rend_client_rendezvous_acked(origin_circuit_t *circ,
@@ -41,7 +40,7 @@ int rend_client_receive_rendezvous(origin_circuit_t *circ,
size_t request_len);
void rend_client_desc_trynow(const char *query);
-void rend_client_note_connection_attempt_ended(const char *onion_address);
+void rend_client_note_connection_attempt_ended(const rend_data_t *rend_data);
extend_info_t *rend_client_get_random_intro(const rend_data_t *rend_query);
int rend_client_any_intro_points_usable(const rend_cache_entry_t *entry);
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 03dd757921..1b042f9fe9 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -1404,3 +1404,100 @@ rend_data_dup(const rend_data_t *data)
return tor_memdup(data, sizeof(rend_data_t));
}
+/** Compute descriptor ID for each replicas and save them. A valid onion
+ * address must be present in the <b>rend_data</b>.
+ *
+ * Return 0 on success else -1. */
+static int
+compute_desc_id(rend_data_t *rend_data)
+{
+ int ret, replica;
+ time_t now = time(NULL);
+
+ tor_assert(rend_data);
+
+ /* Compute descriptor ID for each replicas. */
+ for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id);
+ replica++) {
+ ret = rend_compute_v2_desc_id(rend_data->descriptor_id[replica],
+ rend_data->onion_address,
+ rend_data->descriptor_cookie,
+ now, replica);
+ if (ret < 0) {
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
+/** Allocate and initialize a rend_data_t object for a service using the
+ * given arguments. Only the <b>onion_address</b> is not optional.
+ *
+ * Return a valid rend_data_t pointer. */
+rend_data_t *
+rend_data_service_create(const char *onion_address, const char *pk_digest,
+ const uint8_t *cookie, rend_auth_type_t auth_type)
+{
+ rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));
+
+ /* We need at least one else the call is wrong. */
+ tor_assert(onion_address != NULL);
+
+ if (pk_digest) {
+ memcpy(rend_data->rend_pk_digest, pk_digest,
+ sizeof(rend_data->rend_pk_digest));
+ }
+ if (cookie) {
+ memcpy(rend_data->rend_cookie, cookie,
+ sizeof(rend_data->rend_cookie));
+ }
+
+ strlcpy(rend_data->onion_address, onion_address,
+ sizeof(rend_data->onion_address));
+ rend_data->auth_type = auth_type;
+
+ return rend_data;
+}
+
+/** Allocate and initialize a rend_data_t object for a client request using
+ * the given arguments. Either an onion address or a descriptor ID is
+ * needed. Both can be given but only the onion address will be used to make
+ * the descriptor fetch.
+ *
+ * Return a valid rend_data_t pointer or NULL on error meaning the
+ * descriptor IDs couldn't be computed from the given data. */
+rend_data_t *
+rend_data_client_create(const char *onion_address, const char *desc_id,
+ const char *cookie, rend_auth_type_t auth_type)
+{
+ rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));
+
+ /* We need at least one else the call is wrong. */
+ tor_assert(onion_address != NULL || desc_id != NULL);
+
+ if (cookie) {
+ memcpy(rend_data->descriptor_cookie, cookie,
+ sizeof(rend_data->descriptor_cookie));
+ }
+ if (desc_id) {
+ memcpy(rend_data->desc_id_fetch, desc_id,
+ sizeof(rend_data->desc_id_fetch));
+ }
+ if (onion_address) {
+ strlcpy(rend_data->onion_address, onion_address,
+ sizeof(rend_data->onion_address));
+ if (compute_desc_id(rend_data) < 0) {
+ goto error;
+ }
+ }
+
+ rend_data->auth_type = auth_type;
+
+ return rend_data;
+
+error:
+ rend_data_free(rend_data);
+ return NULL;
+}
diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h
index b86cdb7fa6..a4d55d21d0 100644
--- a/src/or/rendcommon.h
+++ b/src/or/rendcommon.h
@@ -67,5 +67,13 @@ void rend_get_descriptor_id_bytes(char *descriptor_id_out,
const char *secret_id_part);
size_t rend_cache_get_total_allocation(void);
+rend_data_t *rend_data_client_create(const char *onion_address,
+ const char *desc_id,
+ const char *cookie,
+ rend_auth_type_t auth_type);
+rend_data_t *rend_data_service_create(const char *onion_address,
+ const char *pk_digest,
+ const uint8_t *cookie,
+ rend_auth_type_t auth_type);
#endif
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index f257f6e89f..eb94202ed8 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -1735,13 +1735,11 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
hexcookie, serviceid);
tor_assert(launched->build_state);
/* Fill in the circuit's state. */
- launched->rend_data = tor_malloc_zero(sizeof(rend_data_t));
- memcpy(launched->rend_data->rend_pk_digest,
- circuit->rend_data->rend_pk_digest,
- DIGEST_LEN);
- memcpy(launched->rend_data->rend_cookie, parsed_req->rc, REND_COOKIE_LEN);
- strlcpy(launched->rend_data->onion_address, service->service_id,
- sizeof(launched->rend_data->onion_address));
+
+ launched->rend_data =
+ rend_data_service_create(service->service_id,
+ circuit->rend_data->rend_pk_digest,
+ parsed_req->rc, service->auth_type);
launched->build_state->service_pending_final_cpath_ref =
tor_malloc_zero(sizeof(crypt_path_reference_t));
@@ -2713,10 +2711,9 @@ rend_service_launch_establish_intro(rend_service_t *service,
intro->extend_info = extend_info_dup(launched->build_state->chosen_exit);
}
- launched->rend_data = tor_malloc_zero(sizeof(rend_data_t));
- strlcpy(launched->rend_data->onion_address, service->service_id,
- sizeof(launched->rend_data->onion_address));
- memcpy(launched->rend_data->rend_pk_digest, service->pk_digest, DIGEST_LEN);
+ launched->rend_data = rend_data_service_create(service->service_id,
+ service->pk_digest, NULL,
+ service->auth_type);
launched->intro_key = crypto_pk_dup_key(intro->intro_key);
if (launched->base_.state == CIRCUIT_STATE_OPEN)
rend_service_intro_has_opened(launched);