Browse Source

Merge branch 'tor_api_squashed'

Nick Mathewson 6 years ago
parent
commit
ef25f957e7

+ 1 - 0
.gitignore

@@ -211,6 +211,7 @@ uptime-*.json
 /src/test/fuzz/lf-fuzz-*
 
 # /src/tools/
+/src/tools/libtorrunner.a
 /src/tools/tor-checkkey
 /src/tools/tor-resolve
 /src/tools/tor-cov-resolve

+ 9 - 0
changes/ticket23845

@@ -0,0 +1,9 @@
+  o Major features (embedding):
+    - There is now a documented stable API for programs that need to
+      embed Tor. See tor_api.h for full documentation and known bugs.
+      Closes ticket 23684.
+
+  o Code simplification and refactoring:
+    - The tor_git_revision[] constant no longer needs to be redeclared
+      by everything that links against the rest of Tor.  Done as part
+      of ticket 23845, to simplify our external API.

+ 1 - 0
configure.ac

@@ -375,6 +375,7 @@ AH_BOTTOM([
 
 
 AM_CONDITIONAL(BUILD_NT_SERVICES, test "x$bwin32" = "xtrue")
+AM_CONDITIONAL(BUILD_LIBTORRUNNER, test "x$bwin32" != "xtrue")
 
 dnl Enable C99 when compiling with MIPSpro
 AC_MSG_CHECKING([for MIPSpro compiler])

+ 1 - 2
src/or/config.c

@@ -82,6 +82,7 @@
 #include "dirvote.h"
 #include "dns.h"
 #include "entrynodes.h"
+#include "git_revision.h"
 #include "geoip.h"
 #include "hibernate.h"
 #include "main.h"
@@ -883,8 +884,6 @@ set_options(or_options_t *new_val, char **msg)
   return 0;
 }
 
-extern const char tor_git_revision[]; /* from tor_main.c */
-
 /** The version of this Tor process, as parsed. */
 static char *the_tor_version = NULL;
 /** A shorter version of this Tor process's version, for export in our router

+ 17 - 0
src/or/git_revision.c

@@ -0,0 +1,17 @@
+/* Copyright 2001-2004 Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "git_revision.h"
+
+/** String describing which Tor Git repository version the source was
+ * built from.  This string is generated by a bit of shell kludging in
+ * src/or/include.am, and is usually right.
+ */
+const char tor_git_revision[] =
+#ifndef _MSC_VER
+#include "micro-revision.i"
+#endif
+  "";
+

+ 12 - 0
src/or/git_revision.h

@@ -0,0 +1,12 @@
+/* Copyright 2001-2004 Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_GIT_REVISION_H
+#define TOR_GIT_REVISION_H
+
+extern const char tor_git_revision[];
+
+#endif
+

+ 9 - 2
src/or/include.am

@@ -51,6 +51,7 @@ LIBTOR_A_SOURCES = \
 	src/or/geoip.c					\
 	src/or/entrynodes.c				\
 	src/or/ext_orport.c				\
+	src/or/git_revision.c				\
 	src/or/hibernate.c				\
 	src/or/hs_cache.c				\
 	src/or/hs_cell.c				\
@@ -105,6 +106,7 @@ LIBTOR_A_SOURCES = \
 	src/or/statefile.c				\
 	src/or/status.c					\
 	src/or/torcert.c				\
+	src/or/tor_api.c				\
 	src/or/onion_ntor.c				\
 	$(tor_platform_source)
 
@@ -190,6 +192,7 @@ ORHEADERS = \
 	src/or/fp_pair.h				\
 	src/or/geoip.h					\
 	src/or/entrynodes.h				\
+	src/or/git_revision.h				\
 	src/or/hibernate.h				\
 	src/or/hs_cache.h				\
 	src/or/hs_cell.h				\
@@ -244,9 +247,13 @@ ORHEADERS = \
 	src/or/scheduler.h				\
 	src/or/statefile.h				\
 	src/or/status.h					\
-	src/or/torcert.h
+	src/or/torcert.h				\
+	src/or/tor_api_internal.h
 
-noinst_HEADERS+= $(ORHEADERS) micro-revision.i
+# This may someday want to be an installed file?
+noinst_HEADERS += src/or/tor_api.h
+
+noinst_HEADERS += $(ORHEADERS) micro-revision.i
 
 micro-revision.i: FORCE
 	$(AM_V_at)rm -f micro-revision.tmp; \

+ 8 - 4
src/or/main.c

@@ -105,6 +105,8 @@
 #include "shared_random.h"
 #include "statefile.h"
 #include "status.h"
+#include "tor_api.h"
+#include "tor_api_internal.h"
 #include "util_process.h"
 #include "ext_orport.h"
 #ifdef USE_DMALLOC
@@ -3795,14 +3797,16 @@ sandbox_init_filter(void)
   return cfg;
 }
 
-/** Main entry point for the Tor process.  Called from main(). */
-/* This function is distinct from main() only so we can link main.c into
- * the unittest binary without conflicting with the unittests' main. */
+/* Main entry point for the Tor process.  Called from tor_main(), and by
+ * anybody embedding Tor. */
 int
-tor_main(int argc, char *argv[])
+tor_run_main(const tor_main_configuration_t *tor_cfg)
 {
   int result = 0;
 
+  int argc = tor_cfg->argc;
+  char **argv = tor_cfg->argv;
+
 #ifdef _WIN32
 #ifndef HeapEnableTerminationOnCorruption
 #define HeapEnableTerminationOnCorruption 1

+ 0 - 2
src/or/main.h

@@ -76,8 +76,6 @@ void release_lockfile(void);
 void tor_cleanup(void);
 void tor_free_all(int postfork);
 
-int tor_main(int argc, char *argv[]);
-
 int do_main_loop(void);
 int tor_init(int argc, char **argv);
 

+ 88 - 0
src/or/tor_api.c

@@ -0,0 +1,88 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tor_api.c
+ **/
+
+#include "tor_api.h"
+#include "tor_api_internal.h"
+
+// Include this after the above headers, to insure that they don't
+// depend on anything else.
+#include "orconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// We don't want to use tor_malloc and tor_free here, since this needs
+// to run before anything is initialized at all, and ought to run when
+// we're not linked to anything at all.
+
+#define raw_malloc malloc
+#define raw_free free
+
+tor_main_configuration_t *
+tor_main_configuration_new(void)
+{
+  static const char *fake_argv[] = { "tor" };
+  tor_main_configuration_t *cfg = raw_malloc(sizeof(*cfg));
+  if (cfg == NULL)
+    return NULL;
+
+  memset(cfg, 0, sizeof(*cfg));
+
+  cfg->argc = 1;
+  cfg->argv = (char **) fake_argv;
+
+  return cfg;
+}
+
+int
+tor_main_configuration_set_command_line(tor_main_configuration_t *cfg,
+                                        int argc, char *argv[])
+{
+  if (cfg == NULL)
+    return -1;
+  cfg->argc = argc;
+  cfg->argv = argv;
+  return 0;
+}
+
+void
+tor_main_configuration_free(tor_main_configuration_t *cfg)
+{
+  if (cfg == NULL)
+    return;
+  raw_free(cfg);
+}
+
+/* Main entry point for the Tor process.  Called from main().
+ *
+ * This function is distinct from main() only so we can link main.c into
+ * the unittest binary without conflicting with the unittests' main.
+ *
+ * Some embedders have historically called this function; but that usage is
+ * deprecated: they should use tor_run_main() instead.
+ */
+int
+tor_main(int argc, char *argv[])
+{
+  tor_main_configuration_t *cfg = tor_main_configuration_new();
+  if (!cfg) {
+    puts("INTERNAL ERROR: Allocation failure. Cannot proceed");
+    return 1;
+  }
+  if (tor_main_configuration_set_command_line(cfg, argc, argv) < 0) {
+    puts("INTERNAL ERROR: Can't set command line. Cannot proceed.");
+    return 1;
+  }
+  int rv = tor_run_main(cfg);
+  tor_main_configuration_free(cfg);
+  return rv;
+}
+

+ 102 - 0
src/or/tor_api.h

@@ -0,0 +1,102 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tor_api.h
+ * \brief Public C API for the Tor network service.
+ *
+ * This interface is intended for use by programs that need to link Tor as
+ * a library, and launch it in a separate thread.  If you have the ability
+ * to run Tor as a separate executable, you should probably do that instead
+ * of embedding it as a library.
+ *
+ * To use this API, first construct a tor_main_configuration_t object using
+ * tor_main_configuration_new().  Then, you use one or more other function
+ * calls (such as tor_main_configuration_set_command_line() to configure how
+ * Tor should be run.  Finally, you pass the configuration object to
+ * tor_run_main().
+ *
+ * At this point, tor_run_main() will block its thread to run a Tor daemon;
+ * when the Tor daemon exits, it will return.  See notes on bugs and
+ * limitations below.
+ *
+ * There is no other public C API to Tor: calling any C Tor function not
+ * documented in this file is not guaranteed to be stable.
+ **/
+
+#ifndef TOR_API_H
+#define TOR_API_H
+
+typedef struct tor_main_configuration_t tor_main_configuration_t;
+
+/**
+ * Create and return a new tor_main_configuration().
+ */
+tor_main_configuration_t *tor_main_configuration_new(void);
+
+/**
+ * Set the command-line arguments in <b>cfg</b>.
+ *
+ * The <b>argc</b> and <b>argv</b> values here are as for main().  The
+ * contents of the argv pointer must remain unchanged until tor_run_main() has
+ * finished and you call tor_main_configuration_free().
+ *
+ * Return 0 on success, -1 on failure.
+ */
+int tor_main_configuration_set_command_line(tor_main_configuration_t *cfg,
+                                            int argc, char *argv[]);
+
+/**
+ * Release all storage held in <b>cfg</b>.
+ *
+ * Once you have passed a tor_main_configuration_t to tor_run_main(), you
+ * must not free it until tor_run_main() has finished.
+ */
+void tor_main_configuration_free(tor_main_configuration_t *cfg);
+
+/**
+ * Run the tor process, as if from the command line.
+ *
+ * The command line arguments from tor_main_configuration_set_command_line()
+ * are taken as if they had been passed to main().
+ *
+ * This function will not return until Tor is done running.  It returns zero
+ * on success, and nonzero on failure.
+ *
+ * BUG 23848: In many cases, tor_main will call exit() or abort() instead of
+ * returning.  This is not the intended long-term behavior; we are trying to
+ * fix it.
+ *
+ * BUG 23847: You can only call tor_main() once in a single process; if it
+ * returns and you call it again, you may crash. This is not intended
+ * long-term behavior; we are trying to fix it.
+ *
+ * LIMITATION: You cannot run more than one instance of Tor in the same
+ * process at the same time. Concurrent calls will cause undefined behavior.
+ * We do not currently have plans to change this.
+ *
+ * LIMITATION: While we will try to fix any problems found here, you
+ * should be aware that Tor was originally written to run as its own
+ * process, and that the functionality of this file was added later.  If
+ * you find any bugs or strange behavior, please report them, and we'll
+ * try to straighten them out.
+ */
+int tor_run_main(const tor_main_configuration_t *);
+
+/**
+ * Run the tor process, as if from the command line.
+ *
+ * @deprecated Using this function from outside Tor is deprecated; you should
+ * use use tor_run_main() instead.
+ *
+ * BUGS: This function has all the same bugs as tor_run_main().
+ *
+ * LIMITATIONS: This function has all the limitations of tor_run_main().
+ */
+int tor_main(int argc, char **argv);
+
+#endif /* !defined(TOR_API_H) */
+

+ 20 - 0
src/or/tor_api_internal.h

@@ -0,0 +1,20 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_API_INTERNAL_H
+#define TOR_API_INTERNAL_H
+
+/* The contents of this type are private; don't mess with them from outside
+ * Tor. */
+struct tor_main_configuration_t {
+  /** As in main() */
+  int argc;
+  /** As in main(). This pointer is owned by the caller */
+  char **argv;
+};
+
+#endif
+

+ 0 - 12
src/or/tor_main.c

@@ -3,18 +3,6 @@
  * Copyright (c) 2007-2017, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
-extern const char tor_git_revision[];
-
-/** String describing which Tor Git repository version the source was
- * built from.  This string is generated by a bit of shell kludging in
- * src/or/include.am, and is usually right.
- */
-const char tor_git_revision[] =
-#ifndef _MSC_VER
-#include "micro-revision.i"
-#endif
-  "";
-
 /**
  * \file tor_main.c
  * \brief Stub module containing a main() function.

+ 0 - 5
src/test/bench.c

@@ -3,11 +3,6 @@
  * Copyright (c) 2007-2017, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
-extern const char tor_git_revision[];
-/* Ordinarily defined in tor_main.c; this bit is just here to provide one
- * since we're not linking to tor_main.c */
-const char tor_git_revision[] = "";
-
 /**
  * \file bench.c
  * \brief Benchmarks for lower level Tor modules.

+ 0 - 3
src/test/fuzz/fuzzing_common.c

@@ -9,9 +9,6 @@
 #include "crypto.h"
 #include "crypto_ed25519.h"
 
-extern const char tor_git_revision[];
-const char tor_git_revision[] = "";
-
 static or_options_t *mock_options = NULL;
 static const or_options_t *
 mock_get_options(void)

+ 0 - 6
src/test/testing_common.c

@@ -3,12 +3,6 @@
  * Copyright (c) 2007-2017, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
-extern const char tor_git_revision[];
-
-/* Ordinarily defined in tor_main.c; this bit is just here to provide one
- * since we're not linking to tor_main.c */
-const char tor_git_revision[] = "";
-
 /**
  * \file test_common.c
  * \brief Common pieces to implement unit tests.

+ 5 - 0
src/tools/include.am

@@ -45,3 +45,8 @@ src_tools_tor_cov_gencert_LDADD = src/common/libor-testing.a \
 endif
 
 EXTRA_DIST += src/tools/tor-fw-helper/README
+
+if BUILD_LIBTORRUNNER
+noinst_LIBRARIES += src/tools/libtorrunner.a
+src_tools_libtorrunner_a_SOURCES = src/tools/tor_runner.c src/or/tor_api.c
+endif

+ 101 - 0
src/tools/tor_runner.c

@@ -0,0 +1,101 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file tor_runner.c
+ * @brief Experimental module to emulate tor_run_main() API with fork+exec
+ *
+ * The functions here are meant to allow the application developer to
+ * use the tor_run_main() API without having to care whether Tor is
+ * running in-process or out-of-process.  For in-process usage, the
+ * developer can link Tor as a library and call tor_run_main(); for
+ * out-of-process usage, the developer can link this library instead.
+ *
+ * This interface is EXPERIMENTAL; please let us know if you would like
+ * to depend on it.  We don't know yet whether it will be reliable in
+ * practice.
+ */
+
+/* NOTE: This module is supposed to work without the standard Tor utility
+ * functions.  Don't add more dependencies!
+ */
+
+#include "tor_api.h"
+#include "tor_api_internal.h"
+
+#include "orconfig.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
+
+static void child(const tor_main_configuration_t *cfg)
+  __attribute__((noreturn));
+
+int
+tor_run_main(const tor_main_configuration_t *cfg)
+{
+  pid_t pid = fork();
+  if (pid == 0) {
+    child(cfg);
+    exit(0); /* Unreachable */
+  }
+
+  pid_t stopped_pid;
+  int status = 0;
+  do {
+    stopped_pid = waitpid(pid, &status, 0);
+  } while (stopped_pid == -1);
+
+  /* Note: these return values are not documented.  No return value is
+   * documented! */
+
+  if (stopped_pid != pid) {
+    return -99999;
+  }
+  if (WIFSTOPPED(status)) {
+    return WEXITSTATUS(status);
+  }
+  if (WIFSIGNALED(status)) {
+    return -WTERMSIG(status);
+  }
+
+  return -999988;
+}
+
+/* circumlocution to avoid getting warned about calling calloc instead of
+ * tor_calloc. */
+#define real_calloc calloc
+
+static void
+child(const tor_main_configuration_t *cfg)
+{
+  /* XXXX Close unused file descriptors. */
+
+  char **args = real_calloc(cfg->argc+1, sizeof(char *));
+  memcpy(args, cfg->argv, cfg->argc * sizeof(char *));
+  args[cfg->argc] = NULL;
+
+  int rv = execv(BINDIR "/tor", args);
+
+  if (rv < 0) {
+    exit(254);
+  } else {
+    abort(); /* Unreachable */
+  }
+}
+