ソースを参照

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@torproject.org>
David Goulet 7 年 前
コミット
0f104ddce5
3 ファイル変更131 行追加6 行削除
  1. 105 0
      src/or/hs_service.c
  2. 2 0
      src/or/hs_service.h
  3. 24 6
      src/or/main.c

+ 105 - 0
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)

+ 2 - 0
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. */

+ 24 - 6
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. */