aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2017-05-19 08:47:18 -0400
committerNick Mathewson <nickm@torproject.org>2017-05-19 08:47:18 -0400
commit69ef94820b29500d93a8f2775764b8b96284bacb (patch)
tree1337215f718c30da8cc8d1529c5a3a890e488316 /src
parent92d335b3dcd7b302d8a07c105f9fe8a98848cad3 (diff)
parent70c067102b7d2576fa456d2872bb41abf559dff6 (diff)
downloadtor-69ef94820b29500d93a8f2775764b8b96284bacb.tar.gz
tor-69ef94820b29500d93a8f2775764b8b96284bacb.zip
Merge branch 'add_rust_squashed'
Diffstat (limited to 'src')
-rw-r--r--src/common/compat_rust.c39
-rw-r--r--src/common/compat_rust.h28
-rw-r--r--src/common/include.am6
m---------src/ext/rust0
-rw-r--r--src/include.am1
-rw-r--r--src/or/include.am3
-rw-r--r--src/or/main.c10
-rw-r--r--src/rust/.cargo/config.in8
-rw-r--r--src/rust/.rustfmt.toml2
-rw-r--r--src/rust/Cargo.lock14
-rw-r--r--src/rust/Cargo.toml7
-rw-r--r--src/rust/include.am6
-rw-r--r--src/rust/tor_util/Cargo.toml13
-rw-r--r--src/rust/tor_util/ffi.rs56
-rw-r--r--src/rust/tor_util/include.am13
-rw-r--r--src/rust/tor_util/lib.rs13
-rw-r--r--src/rust/tor_util/rust_string.rs101
-rw-r--r--src/rust/tor_util/tests/rust_string.rs37
-rw-r--r--src/test/fuzz/include.am3
-rw-r--r--src/test/include.am33
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_rust.c31
-rwxr-xr-xsrc/test/test_rust.sh13
-rw-r--r--src/tools/include.am14
25 files changed, 437 insertions, 16 deletions
diff --git a/src/common/compat_rust.c b/src/common/compat_rust.c
new file mode 100644
index 0000000000..366fd4037b
--- /dev/null
+++ b/src/common/compat_rust.c
@@ -0,0 +1,39 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file rust_compat.c
+ * \brief Rust FFI compatibility functions and helpers. This file is only built
+ * if Rust is not used.
+ **/
+
+#include "compat_rust.h"
+#include "util.h"
+
+/**
+ * Free storage pointed to by <b>str</b>, and itself.
+ */
+void
+rust_str_free(rust_str_t str)
+{
+ char *s = (char *)str;
+ tor_free(s);
+}
+
+/**
+ * Return zero-terminated contained string.
+ */
+const char *
+rust_str_get(const rust_str_t str)
+{
+ return (const char *)str;
+}
+
+/* If we were using Rust, we'd say so on startup. */
+rust_str_t
+rust_welcome_string(void)
+{
+ char *s = tor_malloc_zero(1);
+ return (rust_str_t)s;
+}
+
diff --git a/src/common/compat_rust.h b/src/common/compat_rust.h
new file mode 100644
index 0000000000..752a29b56c
--- /dev/null
+++ b/src/common/compat_rust.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file rust_compat.h
+ * \brief Headers for rust_compat.c
+ **/
+
+#ifndef TOR_RUST_COMPAT_H
+#define TOR_RUST_COMPAT_H
+
+#include "torint.h"
+
+/**
+ * Strings allocated in Rust must be freed from Rust code again. Let's make
+ * it less likely to accidentally mess up and call tor_free() on it, because
+ * currently it'll just work but might break at any time.
+ */
+typedef uintptr_t rust_str_t;
+
+void rust_str_free(rust_str_t);
+
+const char *rust_str_get(const rust_str_t);
+
+rust_str_t rust_welcome_string(void);
+
+#endif
+
diff --git a/src/common/include.am b/src/common/include.am
index 51b7da65f5..1253888815 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -100,6 +100,11 @@ LIBOR_A_SRC = \
$(threads_impl_source) \
$(readpassphrase_source)
+if USE_RUST
+else
+LIBOR_A_SRC += src/common/compat_rust.c
+endif
+
src/common/src_common_libor_testing_a-log.$(OBJEXT) \
src/common/log.$(OBJEXT): micro-revision.i
@@ -147,6 +152,7 @@ COMMONHEADERS = \
src/common/compat.h \
src/common/compat_libevent.h \
src/common/compat_openssl.h \
+ src/common/compat_rust.h \
src/common/compat_threads.h \
src/common/compat_time.h \
src/common/compress.h \
diff --git a/src/ext/rust b/src/ext/rust
new file mode 160000
+Subproject 240296800824e40b10cb8c16da0e71156335394
diff --git a/src/include.am b/src/include.am
index f78853f50f..90ecf90d45 100644
--- a/src/include.am
+++ b/src/include.am
@@ -2,6 +2,7 @@ include src/ext/include.am
include src/trunnel/include.am
include src/common/include.am
include src/or/include.am
+include src/rust/include.am
include src/test/include.am
include src/tools/include.am
include src/win32/include.am
diff --git a/src/or/include.am b/src/or/include.am
index 7b031f737b..1ef5afa013 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -124,7 +124,8 @@ src_or_tor_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-ctime.a \
src/trace/libor-trace.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+ $(rust_ldadd)
if COVERAGE_ENABLED
src_or_tor_cov_SOURCES = src/or/tor_main.c
diff --git a/src/or/main.c b/src/or/main.c
index 398c4f63d2..2520a7e21d 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -59,6 +59,7 @@
#include "circuitlist.h"
#include "circuituse.h"
#include "command.h"
+#include "compat_rust.h"
#include "compress.h"
#include "config.h"
#include "confparse.h"
@@ -3073,6 +3074,15 @@ tor_init(int argc, char *argv[])
"Expect more bugs than usual.");
}
+ {
+ rust_str_t rust_str = rust_welcome_string();
+ const char *s = rust_str_get(rust_str);
+ if (strlen(s) > 0) {
+ log_notice(LD_GENERAL, "%s", s);
+ }
+ rust_str_free(rust_str);
+ }
+
if (network_init()<0) {
log_err(LD_BUG,"Error initializing network; exiting.");
return -1;
diff --git a/src/rust/.cargo/config.in b/src/rust/.cargo/config.in
new file mode 100644
index 0000000000..414b253a57
--- /dev/null
+++ b/src/rust/.cargo/config.in
@@ -0,0 +1,8 @@
+[source]
+
+@RUST_DL@ [source.crates-io]
+@RUST_DL@ registry = 'https://github.com/rust-lang/crates.io-index'
+@RUST_DL@ replace-with = 'vendored-sources'
+
+@RUST_DL@ [source.vendored-sources]
+@RUST_DL@ directory = '@RUST_DEPENDENCIES@'
diff --git a/src/rust/.rustfmt.toml b/src/rust/.rustfmt.toml
new file mode 100644
index 0000000000..f25bd51883
--- /dev/null
+++ b/src/rust/.rustfmt.toml
@@ -0,0 +1,2 @@
+max_width = 80
+comment_width = 80
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
new file mode 100644
index 0000000000..4ac9606ce8
--- /dev/null
+++ b/src/rust/Cargo.lock
@@ -0,0 +1,14 @@
+[root]
+name = "tor_util"
+version = "0.0.1"
+dependencies = [
+ "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "babb8281da88cba992fa1f4ddec7d63ed96280a1a53ec9b919fd37b53d71e502"
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
new file mode 100644
index 0000000000..fc4377e8b4
--- /dev/null
+++ b/src/rust/Cargo.toml
@@ -0,0 +1,7 @@
+[workspace]
+members = ["tor_util"]
+
+[profile.release]
+debug = true
+panic = "abort"
+
diff --git a/src/rust/include.am b/src/rust/include.am
new file mode 100644
index 0000000000..20afc6c4db
--- /dev/null
+++ b/src/rust/include.am
@@ -0,0 +1,6 @@
+include src/rust/tor_util/include.am
+
+EXTRA_DIST +=\
+ src/rust/Cargo.toml \
+ src/rust/Cargo.lock \
+ src/rust/.cargo/config.in
diff --git a/src/rust/tor_util/Cargo.toml b/src/rust/tor_util/Cargo.toml
new file mode 100644
index 0000000000..f175fbdfb0
--- /dev/null
+++ b/src/rust/tor_util/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+authors = ["The Tor Project"]
+name = "tor_util"
+version = "0.0.1"
+
+[lib]
+name = "tor_util"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
+
+[dependencies]
+libc = "*"
+
diff --git a/src/rust/tor_util/ffi.rs b/src/rust/tor_util/ffi.rs
new file mode 100644
index 0000000000..af4bfc41af
--- /dev/null
+++ b/src/rust/tor_util/ffi.rs
@@ -0,0 +1,56 @@
+//! FFI functions, only to be called from C.
+//!
+//! Equivalent C versions of these live in `src/common/compat_rust.c`
+
+use std::mem::forget;
+use std::ffi::CString;
+
+use libc;
+use rust_string::RustString;
+
+/// Free the passed `RustString` (`rust_str_t` in C), to be used in place of
+/// `tor_free`().
+///
+/// # Examples
+/// ```c
+/// rust_str_t r_s = rust_welcome_string();
+/// rust_str_free(r_s);
+/// ```
+#[no_mangle]
+#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
+pub unsafe extern "C" fn rust_str_free(_str: RustString) {
+ // Empty body: Just drop _str and we're done (Drop takes care of it).
+}
+
+/// Lends an immutable, NUL-terminated C String.
+///
+/// # Examples
+/// ```c
+/// rust_str_t r_s = rust_welcome_string();
+/// const char *s = rust_str_get(r_s);
+/// printf("%s", s);
+/// rust_str_free(r_s);
+/// ```
+#[no_mangle]
+pub unsafe extern "C" fn rust_str_get(str: RustString) -> *const libc::c_char {
+ let res = str.as_ptr();
+ forget(str);
+ res
+}
+
+/// Returns a short string to announce Rust support during startup.
+///
+/// # Examples
+/// ```c
+/// rust_str_t r_s = rust_welcome_string();
+/// const char *s = rust_str_get(r_s);
+/// printf("%s", s);
+/// rust_str_free(r_s);
+/// ```
+#[no_mangle]
+pub extern "C" fn rust_welcome_string() -> RustString {
+ let s = CString::new("Tor is running with Rust integration. Please report \
+ any bugs you encouter.")
+ .unwrap();
+ RustString::from(s)
+}
diff --git a/src/rust/tor_util/include.am b/src/rust/tor_util/include.am
new file mode 100644
index 0000000000..17a755fe09
--- /dev/null
+++ b/src/rust/tor_util/include.am
@@ -0,0 +1,13 @@
+EXTRA_DIST +=\
+ src/rust/tor_util/Cargo.toml \
+ src/rust/tor_util/lib.rs \
+ src/rust/tor_util/ffi.rs \
+ src/rust/tor_util/rust_string.rs
+
+src/rust/target/release/libtor_util.a: FORCE
+ ( cd "$(abs_top_srcdir)/src/rust/tor_util" ; \
+ CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \
+ HOME="$(abs_top_builddir)/src/rust" \
+ $(CARGO) build --release --quiet $(CARGO_ONLINE) )
+
+FORCE:
diff --git a/src/rust/tor_util/lib.rs b/src/rust/tor_util/lib.rs
new file mode 100644
index 0000000000..79d583d1ae
--- /dev/null
+++ b/src/rust/tor_util/lib.rs
@@ -0,0 +1,13 @@
+//! C <-> Rust compatibility helpers and types.
+//!
+//! Generically useful, small scale helpers should go here. This goes for both
+//! the C side (in the form of the ffi module) as well as the Rust side
+//! (individual modules per functionality). The corresponding C stuff lives in
+//! `src/common/compat_rust.{c,h}`.
+
+extern crate libc;
+
+mod rust_string;
+pub mod ffi;
+
+pub use rust_string::*;
diff --git a/src/rust/tor_util/rust_string.rs b/src/rust/tor_util/rust_string.rs
new file mode 100644
index 0000000000..46ec3fd7a8
--- /dev/null
+++ b/src/rust/tor_util/rust_string.rs
@@ -0,0 +1,101 @@
+use std::ffi::CString;
+use std::mem::forget;
+use libc;
+
+/// Compatibility wrapper for strings allocated in Rust and passed to C.
+///
+/// Rust doesn't ensure the safety of freeing memory across an FFI boundary, so
+/// we need to take special care to ensure we're not accidentally calling
+/// `tor_free`() on any string allocated in Rust. To more easily differentiate
+/// between strings that possibly (if Rust support is enabled) were allocated
+/// in Rust, C has the `rust_str_t` helper type. The equivalent on the Rust
+/// side is `RustString`.
+///
+/// Note: This type must not be used for strings allocated in C.
+#[repr(C)]
+#[derive(Debug)]
+pub struct RustString(*mut libc::c_char);
+
+impl RustString {
+ /// Returns a pointer to the underlying NUL-terminated byte array.
+ ///
+ /// Note that this function is not typically useful for Rust callers,
+ /// except in a direct FFI context.
+ ///
+ /// # Examples
+ /// ```
+ /// # use tor_util::RustString;
+ /// use std::ffi::CString;
+ ///
+ /// let r = RustString::from(CString::new("asdf").unwrap());
+ /// let c_str = r.as_ptr();
+ /// assert_eq!(b'a', unsafe { *c_str as u8});
+ /// ```
+ pub fn as_ptr(&self) -> *const libc::c_char {
+ self.0 as *const libc::c_char
+ }
+}
+
+impl From<CString> for RustString {
+ /// Constructs a new `RustString`
+ ///
+ /// # Examples
+ /// ```
+ /// # use tor_util::RustString;
+ /// use std::ffi::CString;
+ ///
+ /// let r = RustString::from(CString::new("asdf").unwrap());
+ /// ```
+ fn from(str: CString) -> RustString {
+ RustString(str.into_raw())
+ }
+}
+
+impl Into<CString> for RustString {
+ /// Reconstructs a `CString` from this `RustString`.
+ ///
+ /// Useful to take ownership back from a `RustString` that was given to C
+ /// code.
+ ///
+ /// # Examples
+ /// ```
+ /// # use tor_util::RustString;
+ /// use std::ffi::CString;
+ ///
+ /// let cs = CString::new("asdf").unwrap();
+ /// let r = RustString::from(cs.clone());
+ /// let cs2 = r.into();
+ /// assert_eq!(cs, cs2);
+ /// ```
+ fn into(self) -> CString {
+ // Calling from_raw is always OK here: We only construct self using
+ // valid CStrings and don't expose anything that could mutate it
+ let ret = unsafe { CString::from_raw(self.0) };
+ forget(self);
+ ret
+ }
+}
+
+impl Drop for RustString {
+ fn drop(&mut self) {
+ // Don't use into() here, because we would need to move out of
+ // self. Same safety consideration. Immediately drop the created
+ // CString, which takes care of freeing the wrapped string.
+ unsafe { CString::from_raw(self.0) };
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::mem;
+ use super::*;
+
+ use libc;
+
+ /// Ensures we're not adding overhead by using RustString.
+ #[test]
+ fn size_of() {
+ assert_eq!(mem::size_of::<*mut libc::c_char>(),
+ mem::size_of::<RustString>())
+ }
+}
diff --git a/src/rust/tor_util/tests/rust_string.rs b/src/rust/tor_util/tests/rust_string.rs
new file mode 100644
index 0000000000..1ff605a43c
--- /dev/null
+++ b/src/rust/tor_util/tests/rust_string.rs
@@ -0,0 +1,37 @@
+extern crate tor_util;
+extern crate libc;
+
+use std::ffi::CString;
+use tor_util::RustString;
+
+#[test]
+fn rust_string_conversions_preserve_c_string() {
+ let s = CString::new("asdf foo").unwrap();
+ let r = RustString::from(s.clone());
+ let r2 = RustString::from(s.clone());
+ let c = r2.as_ptr();
+ assert_eq!(unsafe { libc::strlen(c) }, 8);
+ let c_str = r.into();
+ assert_eq!(s, c_str);
+}
+
+#[test]
+fn empty_string() {
+ let s = CString::new("").unwrap();
+ let r = RustString::from(s.clone());
+ let c = r.as_ptr();
+ assert_eq!(unsafe { libc::strlen(c) }, 0);
+ let c_str = r.into();
+ assert_eq!(s, c_str);
+}
+
+#[test]
+fn c_string_with_unicode() {
+ // The euro sign is three bytes
+ let s = CString::new("asd€asd").unwrap();
+ let r = RustString::from(s.clone());
+ let c = r.as_ptr();
+ assert_eq!(unsafe { libc::strlen(c) }, 9);
+ let c_str = r.into();
+ assert_eq!(s, c_str);
+}
diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am
index 500377f6d7..6008238bba 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -20,7 +20,8 @@ FUZZING_LIBS = \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ \
- @TOR_ZSTD_LIBS@
+ @TOR_ZSTD_LIBS@ \
+ $(rust_ldadd)
oss-fuzz-prereqs: \
src/or/libtor-testing.a \
diff --git a/src/test/include.am b/src/test/include.am
index 4d6215e593..29ba1ce7c9 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -5,8 +5,11 @@ TESTS_ENVIRONMENT = \
export PYTHON="$(PYTHON)"; \
export SHELL="$(SHELL)"; \
export abs_top_srcdir="$(abs_top_srcdir)"; \
+ export abs_top_builddir="$(abs_top_builddir)"; \
export builddir="$(builddir)"; \
- export TESTING_TOR_BINARY="$(TESTING_TOR_BINARY)";
+ export TESTING_TOR_BINARY="$(TESTING_TOR_BINARY)"; \
+ export CARGO="$(CARGO)"; \
+ export CARGO_ONLINE="$(CARGO_ONLINE)";
TESTSCRIPTS = \
src/test/fuzz_static_testcases.sh \
@@ -19,6 +22,11 @@ TESTSCRIPTS = \
src/test/test_workqueue_socketpair.sh \
src/test/test_switch_id.sh
+if USE_RUST
+TESTSCRIPTS += \
+ src/test/test_rust.sh
+endif
+
if USEPYTHON
TESTSCRIPTS += src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh
endif
@@ -132,6 +140,7 @@ src_test_test_SOURCES = \
src/test/test_routerkeys.c \
src/test/test_routerlist.c \
src/test/test_routerset.c \
+ src/test/test_rust.c \
src/test/test_scheduler.c \
src/test/test_shared_random.c \
src/test/test_socks.c \
@@ -183,7 +192,8 @@ src_test_test_switch_id_LDADD = \
src/common/libor-testing.a \
src/common/libor-ctime-testing.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+ $(rust_ldadd)
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
@@ -198,7 +208,8 @@ src_test_test_LDADD = src/or/libtor-testing.a \
src/trace/libor-trace.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+ $(rust_ldadd)
src_test_test_slow_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_slow_CFLAGS = $(src_test_test_CFLAGS)
@@ -222,7 +233,8 @@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
src/trace/libor-trace.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+ $(rust_ldadd)
src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
@@ -234,7 +246,8 @@ src_test_test_workqueue_LDADD = src/or/libtor-testing.a \
src/trace/libor-trace.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+ $(rust_ldadd)
src_test_test_timers_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_timers_CFLAGS = $(src_test_test_CFLAGS)
@@ -245,7 +258,8 @@ src_test_test_timers_LDADD = \
src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_LZMA_LIBS@
+ @TOR_LZMA_LIBS@ \
+ $(rust_ldadd)
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
noinst_HEADERS+= \
@@ -273,7 +287,8 @@ src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \
src/trace/libor-trace.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
- @TOR_LZMA_LIBS@
+ @TOR_LZMA_LIBS@ \
+ $(rust_ldadd)
src_test_test_ntor_cl_AM_CPPFLAGS = \
-I"$(top_srcdir)/src/or"
@@ -294,7 +309,8 @@ src_test_test_bt_cl_LDADD = src/common/libor-testing.a \
src/common/libor-ctime-testing.a \
src/trace/libor-trace.a \
@TOR_LIB_MATH@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ \
+ $(rust_ldadd)
src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
@@ -309,6 +325,7 @@ EXTRA_DIST += \
src/test/test_zero_length_keys.sh \
src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.sh \
src/test/test-network.sh \
+ src/test/test_rust.sh \
src/test/test_switch_id.sh \
src/test/test_workqueue_cancel.sh \
src/test/test_workqueue_efd.sh \
diff --git a/src/test/test.c b/src/test/test.c
index 30944d805d..68f5f90fd7 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1234,6 +1234,7 @@ struct testgroup_t testgroups[] = {
{ "routerkeys/", routerkeys_tests },
{ "routerlist/", routerlist_tests },
{ "routerset/" , routerset_tests },
+ { "rust/", rust_tests },
{ "scheduler/", scheduler_tests },
{ "socks/", socks_tests },
{ "shared-random/", sr_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 0ba91fb3f6..6abaf39e6f 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -232,6 +232,7 @@ extern struct testcase_t router_tests[];
extern struct testcase_t routerkeys_tests[];
extern struct testcase_t routerlist_tests[];
extern struct testcase_t routerset_tests[];
+extern struct testcase_t rust_tests[];
extern struct testcase_t scheduler_tests[];
extern struct testcase_t storagedir_tests[];
extern struct testcase_t socks_tests[];
diff --git a/src/test/test_rust.c b/src/test/test_rust.c
new file mode 100644
index 0000000000..6ad57d6fcb
--- /dev/null
+++ b/src/test/test_rust.c
@@ -0,0 +1,31 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "compat_rust.h"
+#include "test.h"
+#include "util.h"
+
+static void
+test_welcome_string(void *arg)
+{
+ (void)arg;
+ rust_str_t s = rust_welcome_string();
+ const char *c_str = rust_str_get(s);
+ tt_assert(c_str);
+ size_t len = strlen(c_str);
+#ifdef HAVE_RUST
+ tt_assert(len > 0);
+#else
+ tt_assert(len == 0);
+#endif
+
+ done:
+ rust_str_free(s);
+}
+
+struct testcase_t rust_tests[] = {
+ { "welcome_string", test_welcome_string, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh
new file mode 100755
index 0000000000..4427c70f13
--- /dev/null
+++ b/src/test/test_rust.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Test all the Rust crates we're using
+
+crates=tor_util
+
+exitcode=0
+
+for crate in $crates; do
+ cd "${abs_top_srcdir:-.}/src/rust/${crate}"
+ CARGO_TARGET_DIR="${abs_top_builddir}/src/rust/target" HOME="${abs_top_builddir}/src/rust" "${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} || exitcode=1
+done
+
+exit $exitcode
diff --git a/src/tools/include.am b/src/tools/include.am
index 5eadb03a05..717af9e2ae 100644
--- a/src/tools/include.am
+++ b/src/tools/include.am
@@ -8,7 +8,8 @@ src_tools_tor_resolve_SOURCES = src/tools/tor-resolve.c
src_tools_tor_resolve_LDFLAGS =
src_tools_tor_resolve_LDADD = src/common/libor.a \
src/common/libor-ctime.a \
- @TOR_LIB_MATH@ @TOR_LIB_WS32@
+ @TOR_LIB_MATH@ @TOR_LIB_WS32@ \
+ $(rust_ldadd)
if COVERAGE_ENABLED
src_tools_tor_cov_resolve_SOURCES = src/tools/tor-resolve.c
@@ -22,11 +23,12 @@ endif
src_tools_tor_gencert_SOURCES = src/tools/tor-gencert.c
src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
src_tools_tor_gencert_LDADD = src/common/libor.a src/common/libor-crypto.a \
- src/common/libor-ctime.a \
- $(LIBKECCAK_TINY) \
- $(LIBDONNA) \
- @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ src/common/libor-ctime.a \
+ $(LIBKECCAK_TINY) \
+ $(LIBDONNA) \
+ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
+ $(rust_ldadd)
if COVERAGE_ENABLED
src_tools_tor_cov_gencert_SOURCES = src/tools/tor-gencert.c