[tor-commits] [tor/master] prop224: Scheduled events for service

nickm at torproject.org nickm at torproject.org
Wed Aug 9 00:36:37 UTC 2017


commit 0f104ddce578c52d604931c595b28aa61a184b40
Author: David Goulet <dgoulet at torproject.org>
Date:   Fri Feb 3 15:29:31 2017 -0500

    prop224: Scheduled events for service
    
    Add the main loop entry point to the HS service subsystem. It is run every
    second and make sure that all services are in their quiescent state after that
    which means valid descriptors, all needed circuits opened and latest
    descriptors have been uploaded.
    
    For now, only v2 is supported and placeholders for v3 actions for that main
    loop callback.
    
    Signed-off-by: David Goulet <dgoulet at torproject.org>
---
 src/or/hs_service.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/or/hs_service.h |   2 +
 src/or/main.c       |  30 ++++++++++++---
 3 files changed, 131 insertions(+), 6 deletions(-)

diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index 5fde42ddb..a890389ca 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -11,6 +11,7 @@
 #include "or.h"
 #include "circuitlist.h"
 #include "config.h"
+#include "nodelist.h"
 #include "relay.h"
 #include "rendservice.h"
 #include "router.h"
@@ -24,6 +25,15 @@
 #include "hs/cell_establish_intro.h"
 #include "hs/cell_common.h"
 
+/* Helper macro. Iterate over every service in the global map. The var is the
+ * name of the service pointer. */
+#define FOR_EACH_SERVICE_BEGIN(var)                          \
+    STMT_BEGIN                                               \
+    hs_service_t **var##_iter, *var;                         \
+    HT_FOREACH(var##_iter, hs_service_ht, hs_service_map) {  \
+      var = *var##_iter;
+#define FOR_EACH_SERVICE_END } STMT_END ;
+
 /* Onion service directory file names. */
 static const char *fname_keyfile_prefix = "hs_ed25519";
 static const char *fname_hostname = "hostname";
@@ -510,6 +520,78 @@ load_service_keys(hs_service_t *service)
   return ret;
 }
 
+/* Scheduled event run from the main loop. Make sure all our services are up
+ * to date and ready for the other scheduled events. This includes looking at
+ * the introduction points status and descriptor rotation time. */
+static void
+run_housekeeping_event(time_t now)
+{
+  (void) now;
+}
+
+/* Scheduled event run from the main loop. Make sure all descriptors are up to
+ * date. Once this returns, each service descriptor needs to be considered for
+ * new introduction circuits and then for upload. */
+static void
+run_build_descriptor_event(time_t now)
+{
+  (void) now;
+  /* For v2 services, this step happens in the upload event. */
+
+  /* Run v3+ events. */
+  FOR_EACH_SERVICE_BEGIN(service) {
+    /* XXX: Actually build descriptors. */
+    (void) service;
+  } FOR_EACH_SERVICE_END;
+}
+
+/* Scheduled event run from the main loop. Make sure we have all the circuits
+ * we need for each service. */
+static void
+run_build_circuit_event(time_t now)
+{
+  (void) now;
+
+  /* Make sure we can actually have enough information to build internal
+   * circuits as required by services. */
+  if (router_have_consensus_path() == CONSENSUS_PATH_UNKNOWN) {
+    return;
+  }
+
+  /* Run v2 check. */
+  if (num_rend_services() > 0) {
+    rend_consider_services_intro_points();
+  }
+  /* Run v3+ check. */
+  FOR_EACH_SERVICE_BEGIN(service) {
+    /* XXX: Check every service for validity of circuits. */
+    (void) service;
+  } FOR_EACH_SERVICE_END;
+}
+
+/* Scheduled event run from the main loop. Try to upload the descriptor for
+ * each service. */
+static void
+run_upload_descriptor_event(time_t now)
+{
+  /* v2 services use the same function for descriptor creation and upload so
+   * we do everything here because the intro circuits were checked before. */
+  if (num_rend_services() > 0) {
+    rend_consider_services_upload(now);
+    rend_consider_descriptor_republication();
+  }
+
+  /* Run v3+ check. */
+  FOR_EACH_SERVICE_BEGIN(service) {
+    /* XXX: Upload if needed the descriptor(s). Update next upload time. */
+    (void) service;
+  } FOR_EACH_SERVICE_END;
+}
+
+/* ========== */
+/* Public API */
+/* ========== */
+
 /* Load and/or generate keys for all onion services including the client
  * authorization if any. Return 0 on success, -1 on failure. */
 int
@@ -619,6 +701,29 @@ hs_service_free(hs_service_t *service)
   tor_free(service);
 }
 
+/* Periodic callback. Entry point from the main loop to the HS service
+ * subsystem. This is call every second. This is skipped if tor can't build a
+ * circuit or the network is disabled. */
+void
+hs_service_run_scheduled_events(time_t now)
+{
+  /* First thing we'll do here is to make sure our services are in a
+   * quiescent state for the scheduled events. */
+  run_housekeeping_event(now);
+
+  /* Order matters here. We first make sure the descriptor object for each
+   * service contains the latest data. Once done, we check if we need to open
+   * new introduction circuit. Finally, we try to upload the descriptor for
+   * each service. */
+
+  /* Make sure descriptors are up to date. */
+  run_build_descriptor_event(now);
+  /* Make sure services have enough circuits. */
+  run_build_circuit_event(now);
+  /* Upload the descriptors if needed/possible. */
+  run_upload_descriptor_event(now);
+}
+
 /* Initialize the service HS subsystem. */
 void
 hs_service_init(void)
diff --git a/src/or/hs_service.h b/src/or/hs_service.h
index ad95a20ed..493329e22 100644
--- a/src/or/hs_service.h
+++ b/src/or/hs_service.h
@@ -223,6 +223,8 @@ void hs_service_free(hs_service_t *service);
 void hs_service_stage_services(const smartlist_t *service_list);
 int hs_service_load_all_keys(void);
 
+void hs_service_run_scheduled_events(time_t now);
+
 /* These functions are only used by unit tests and we need to expose them else
  * hs_service.o ends up with no symbols in libor.a which makes clang throw a
  * warning at compile time. See #21825. */
diff --git a/src/or/main.c b/src/or/main.c
index dc2318496..a45e64929 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1194,6 +1194,7 @@ CALLBACK(heartbeat);
 CALLBACK(clean_consdiffmgr);
 CALLBACK(reset_padding_counts);
 CALLBACK(check_canonical_channels);
+CALLBACK(hs_service);
 
 #undef CALLBACK
 
@@ -1229,6 +1230,7 @@ static periodic_event_item_t periodic_events[] = {
   CALLBACK(clean_consdiffmgr),
   CALLBACK(reset_padding_counts),
   CALLBACK(check_canonical_channels),
+  CALLBACK(hs_service),
   END_OF_PERIODIC_EVENTS
 };
 #undef CALLBACK
@@ -1461,12 +1463,6 @@ run_scheduled_events(time_t now)
   /* 6. And remove any marked circuits... */
   circuit_close_all_marked();
 
-  /* 7. And upload service descriptors if necessary. */
-  if (have_completed_a_circuit() && !net_is_disabled()) {
-    rend_consider_services_upload(now);
-    rend_consider_descriptor_republication();
-  }
-
   /* 8. and blow away any connections that need to die. have to do this now,
    * because if we marked a conn for close and left its socket -1, then
    * we'll pass it to poll/select and bad things will happen.
@@ -2101,6 +2097,28 @@ clean_consdiffmgr_callback(time_t now, const or_options_t *options)
   return CDM_CLEAN_CALLBACK_INTERVAL;
 }
 
+/*
+ * Periodic callback: Run scheduled events for HS service. This is called
+ * every second.
+ */
+static int
+hs_service_callback(time_t now, const or_options_t *options)
+{
+  (void) options;
+
+  /* We need to at least be able to build circuits and that we actually have
+   * a working network. */
+  if (!have_completed_a_circuit() || net_is_disabled()) {
+    goto end;
+  }
+
+  hs_service_run_scheduled_events(now);
+
+ end:
+  /* Every 1 second. */
+  return 1;
+}
+
 /** Timer: used to invoke second_elapsed_callback() once per second. */
 static periodic_timer_t *second_timer = NULL;
 /** Number of libevent errors in the last second: we die if we get too many. */





More information about the tor-commits mailing list