Merge branch 'pr275_squashed'

This commit is contained in:
Nick Mathewson 2018-08-16 08:43:05 -04:00
commit c8aecd14fe
22 changed files with 394 additions and 247 deletions

View File

@ -350,6 +350,37 @@ check-typos:
echo "You can install the latest version of misspell here: https://github.com/client9/misspell#install"; \ echo "You can install the latest version of misspell here: https://github.com/client9/misspell#install"; \
fi fi
.PHONY: rustfmt
rustfmt:
if USE_RUST
@if test -x "`which cargo-fmt 2>&1;true`"; then \
echo "Formatting Rust code ..."; \
(cd "$(top_srcdir)/src/rust" && cargo fmt --all --); \
else \
echo "Tor uses rustfmt (via cargo-fmt) to format Rust code."; \
echo "However, it seems that you don't have rustfmt installed."; \
printf "You can install rustfmt by following the directions here:"; \
echo " https://github.com/rust-lang-nursery/rustfmt"; \
fi
endif
.PHONY: check-rustfmt
check-rustfmt:
if USE_RUST
@if test -x "`which cargo-fmt 2>&1;true`"; then \
printf "Running rustfmt..."; \
(cd "$(top_srcdir)/src/rust" && cargo fmt --all -- --check && echo "done.") || \
(echo "**************** check-rustfmt failed. ****************"; \
echo " Run \`make rustfmt\` to apply the above changes."; \
exit 1); \
else \
echo "Tor uses rustfmt (via cargo-fmt) to format Rust code."; \
echo "However, it seems that you don't have rustfmt installed."; \
printf "You can install rustfmt by following the directions here:"; \
echo " https://github.com/rust-lang-nursery/rustfmt"; \
fi
endif
.PHONY: clippy .PHONY: clippy
clippy: clippy:
if USE_RUST if USE_RUST

View File

@ -104,7 +104,7 @@ repo.
Documentation Documentation
--------------- ---------------
You MUST include `#[deny(missing_docs)]` in your crate. You MUST include `#![deny(missing_docs)]` in your crate.
For function/method comments, you SHOULD include a one-sentence, "first person" For function/method comments, you SHOULD include a one-sentence, "first person"
description of function behaviour (see requirements for documentation as description of function behaviour (see requirements for documentation as

View File

@ -1,2 +1,12 @@
max_width = 80 max_width = 100
comment_width = 80 hard_tabs = false
tab_spaces = 4
newline_style = "Unix"
#use_small_heuristics = "Default"
reorder_imports = true
reorder_modules = true
remove_nested_parens = true
merge_derives = true
use_try_shorthand = false
use_field_init_shorthand = false
force_explicit_abi = true

View File

@ -10,14 +10,12 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::env; use std::env;
use std::fs::File; use std::fs::File;
use std::io::prelude::*;
use std::io; use std::io;
use std::io::prelude::*;
use std::path::PathBuf; use std::path::PathBuf;
/// Wrapper around a key-value map. /// Wrapper around a key-value map.
struct Config( struct Config(HashMap<String, String>);
HashMap<String,String>
);
/// Locate a config.rust file generated by autoconf, starting in the OUT_DIR /// Locate a config.rust file generated by autoconf, starting in the OUT_DIR
/// location provided by cargo and recursing up the directory tree. Note that /// location provided by cargo and recursing up the directory tree. Note that
@ -31,9 +29,9 @@ fn find_cfg() -> io::Result<String> {
return Ok(path.to_str().unwrap().to_owned()); return Ok(path.to_str().unwrap().to_owned());
} }
path.pop(); // remove config.rust path.pop(); // remove config.rust
if ! path.pop() { // can't remove last part of directory if !path.pop() {
return Err(io::Error::new(io::ErrorKind::NotFound, // can't remove last part of directory
"No config.rust")); return Err(io::Error::new(io::ErrorKind::NotFound, "No config.rust"));
} }
} }
} }
@ -55,12 +53,11 @@ impl Config {
} }
let idx = match s.find("=") { let idx = match s.find("=") {
None => { None => {
return Err(io::Error::new(io::ErrorKind::InvalidData, return Err(io::Error::new(io::ErrorKind::InvalidData, "missing ="));
"missing =")); }
}, Some(x) => x,
Some(x) => x
}; };
let (var,eq_val) = s.split_at(idx); let (var, eq_val) = s.split_at(idx);
let val = &eq_val[1..]; let val = &eq_val[1..];
map.insert(var.to_owned(), val.to_owned()); map.insert(var.to_owned(), val.to_owned());
} }
@ -70,34 +67,34 @@ impl Config {
/// Return a reference to the value whose key is 'key'. /// Return a reference to the value whose key is 'key'.
/// ///
/// Panics if 'key' is not found in the configuration. /// Panics if 'key' is not found in the configuration.
fn get(&self, key : &str) -> &str { fn get(&self, key: &str) -> &str {
self.0.get(key).unwrap() self.0.get(key).unwrap()
} }
/// Add a dependency on a static C library that is part of Tor, by name. /// Add a dependency on a static C library that is part of Tor, by name.
fn component(&self, s : &str) { fn component(&self, s: &str) {
println!("cargo:rustc-link-lib=static={}", s); println!("cargo:rustc-link-lib=static={}", s);
} }
/// Add a dependency on a native library that is not part of Tor, by name. /// Add a dependency on a native library that is not part of Tor, by name.
fn dependency(&self, s : &str) { fn dependency(&self, s: &str) {
println!("cargo:rustc-link-lib={}", s); println!("cargo:rustc-link-lib={}", s);
} }
/// Add a link path, relative to Tor's build directory. /// Add a link path, relative to Tor's build directory.
fn link_relpath(&self, s : &str) { fn link_relpath(&self, s: &str) {
let builddir = self.get("BUILDDIR"); let builddir = self.get("BUILDDIR");
println!("cargo:rustc-link-search=native={}/{}", builddir, s); println!("cargo:rustc-link-search=native={}/{}", builddir, s);
} }
/// Add an absolute link path. /// Add an absolute link path.
fn link_path(&self, s : &str) { fn link_path(&self, s: &str) {
println!("cargo:rustc-link-search=native={}", s); println!("cargo:rustc-link-search=native={}", s);
} }
/// Parse the CFLAGS in s, looking for -l and -L items, and adding /// Parse the CFLAGS in s, looking for -l and -L items, and adding
/// rust configuration as appropriate. /// rust configuration as appropriate.
fn from_cflags(&self, s : &str) { fn from_cflags(&self, s: &str) {
let mut next_is_lib = false; let mut next_is_lib = false;
let mut next_is_path = false; let mut next_is_path = false;
for ent in self.get(s).split_whitespace() { for ent in self.get(s).split_whitespace() {
@ -184,7 +181,7 @@ pub fn main() {
cfg.from_cflags("TOR_LZMA_LIBS"); cfg.from_cflags("TOR_LZMA_LIBS");
cfg.from_cflags("TOR_ZSTD_LIBS"); cfg.from_cflags("TOR_ZSTD_LIBS");
cfg.from_cflags("LIBS"); cfg.from_cflags("LIBS");
}, }
_ => { _ => {
panic!("No configuration in build.rs for package {}", package); panic!("No configuration in build.rs for package {}", package);
} }

View File

@ -6,17 +6,17 @@
pub use digest::Digest; pub use digest::Digest;
use digest::generic_array::typenum::U32;
use digest::generic_array::typenum::U64;
use digest::generic_array::GenericArray;
use digest::BlockInput; use digest::BlockInput;
use digest::FixedOutput; use digest::FixedOutput;
use digest::Input; use digest::Input;
use digest::generic_array::GenericArray;
use digest::generic_array::typenum::U32;
use digest::generic_array::typenum::U64;
use external::crypto_digest::CryptoDigest;
use external::crypto_digest::DigestAlgorithm;
use external::crypto_digest::get_256_bit_digest; use external::crypto_digest::get_256_bit_digest;
use external::crypto_digest::get_512_bit_digest; use external::crypto_digest::get_512_bit_digest;
use external::crypto_digest::CryptoDigest;
use external::crypto_digest::DigestAlgorithm;
pub use external::crypto_digest::DIGEST256_LEN; pub use external::crypto_digest::DIGEST256_LEN;
pub use external::crypto_digest::DIGEST512_LEN; pub use external::crypto_digest::DIGEST512_LEN;
@ -54,7 +54,9 @@ pub struct Sha256 {
/// A new `Sha256` digest. /// A new `Sha256` digest.
impl Default for Sha256 { impl Default for Sha256 {
fn default() -> Sha256 { fn default() -> Sha256 {
Sha256{ engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_256)) } Sha256 {
engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_256)),
}
} }
} }
@ -121,7 +123,9 @@ pub struct Sha512 {
/// A new `Sha512` digest. /// A new `Sha512` digest.
impl Default for Sha512 { impl Default for Sha512 {
fn default() -> Sha512 { fn default() -> Sha512 {
Sha512{ engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_512)) } Sha512 {
engine: CryptoDigest::new(Some(DigestAlgorithm::SHA2_512)),
}
} }
} }
@ -182,9 +186,10 @@ mod test {
fn sha256_digest() { fn sha256_digest() {
let mut h: Sha256 = Sha256::new(); let mut h: Sha256 = Sha256::new();
let mut result: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN]; let mut result: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
let expected = [151, 223, 53, 136, 181, 163, 242, 75, 171, 195, let expected = [
133, 27, 55, 47, 11, 167, 26, 157, 205, 222, 212, 151, 223, 53, 136, 181, 163, 242, 75, 171, 195, 133, 27, 55, 47, 11, 167, 26, 157, 205,
59, 20, 185, 208, 105, 97, 191, 193, 112, 125, 157]; 222, 212, 59, 20, 185, 208, 105, 97, 191, 193, 112, 125, 157,
];
h.input(b"foo"); h.input(b"foo");
h.input(b"bar"); h.input(b"bar");
@ -209,11 +214,12 @@ mod test {
let mut h: Sha512 = Sha512::new(); let mut h: Sha512 = Sha512::new();
let mut result: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN]; let mut result: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
let expected = [203, 55, 124, 16, 176, 245, 166, 44, 128, 54, 37, 167, let expected = [
153, 217, 233, 8, 190, 69, 231, 103, 245, 209, 71, 212, 116, 203, 55, 124, 16, 176, 245, 166, 44, 128, 54, 37, 167, 153, 217, 233, 8, 190, 69, 231,
73, 7, 203, 5, 89, 122, 164, 237, 211, 41, 160, 175, 20, 122, 103, 245, 209, 71, 212, 116, 73, 7, 203, 5, 89, 122, 164, 237, 211, 41, 160, 175, 20,
221, 12, 244, 24, 30, 211, 40, 250, 30, 121, 148, 38, 88, 38, 122, 221, 12, 244, 24, 30, 211, 40, 250, 30, 121, 148, 38, 88, 38, 179, 237, 61, 126,
179, 237, 61, 126, 246, 240, 103, 202, 153, 24, 90]; 246, 240, 103, 202, 153, 24, 90,
];
h.input(b"foo"); h.input(b"foo");
h.input(b"bar"); h.input(b"bar");

View File

@ -24,7 +24,8 @@
//! assert!(result == [b'X'; DIGEST256_LEN]); //! assert!(result == [b'X'; DIGEST256_LEN]);
//! ``` //! ```
#[deny(missing_docs)] // XXX: add missing docs
//#![deny(missing_docs)]
// External crates from cargo or TOR_RUST_DEPENDENCIES. // External crates from cargo or TOR_RUST_DEPENDENCIES.
extern crate digest; extern crate digest;
@ -41,5 +42,5 @@ extern crate external;
#[macro_use] #[macro_use]
extern crate tor_log; extern crate tor_log;
pub mod digests; // Unfortunately named "digests" plural to avoid name conflict with the digest crate pub mod digests; // Unfortunately named "digests" plural to avoid name conflict with the digest crate
pub mod rand; pub mod rand;

View File

@ -12,15 +12,15 @@
mod internal { mod internal {
use std::u64; use std::u64;
use rand_core::impls::next_u32_via_fill;
use rand_core::impls::next_u64_via_fill;
use rand_core::CryptoRng; use rand_core::CryptoRng;
use rand_core::Error; use rand_core::Error;
use rand_core::RngCore; use rand_core::RngCore;
use rand_core::impls::next_u32_via_fill;
use rand_core::impls::next_u64_via_fill;
use external::c_tor_crypto_rand; use external::c_tor_crypto_rand;
use external::c_tor_crypto_strongest_rand;
use external::c_tor_crypto_seed_rng; use external::c_tor_crypto_seed_rng;
use external::c_tor_crypto_strongest_rand;
use tor_log::LogDomain; use tor_log::LogDomain;
use tor_log::LogSeverity; use tor_log::LogSeverity;
@ -45,12 +45,15 @@ mod internal {
#[allow(dead_code)] #[allow(dead_code)]
pub fn new() -> Self { pub fn new() -> Self {
if !c_tor_crypto_seed_rng() { if !c_tor_crypto_seed_rng() {
tor_log_msg!(LogSeverity::Warn, LogDomain::General, tor_log_msg!(
"TorRng::from_seed()", LogSeverity::Warn,
"The RNG could not be seeded!"); LogDomain::General,
"TorRng::from_seed()",
"The RNG could not be seeded!"
);
} }
// XXX also log success at info level —isis // XXX also log success at info level —isis
TorRng{ _unused: [0u8; 0] } TorRng { _unused: [0u8; 0] }
} }
} }
@ -92,12 +95,15 @@ mod internal {
#[allow(dead_code)] #[allow(dead_code)]
pub fn new() -> Self { pub fn new() -> Self {
if !c_tor_crypto_seed_rng() { if !c_tor_crypto_seed_rng() {
tor_log_msg!(LogSeverity::Warn, LogDomain::General, tor_log_msg!(
"TorStrongestRng::from_seed()", LogSeverity::Warn,
"The RNG could not be seeded!"); LogDomain::General,
"TorStrongestRng::from_seed()",
"The RNG could not be seeded!"
);
} }
// XXX also log success at info level —isis // XXX also log success at info level —isis
TorStrongestRng{ _unused: [0u8; 0] } TorStrongestRng { _unused: [0u8; 0] }
} }
} }
@ -137,4 +143,3 @@ mod internal {
// Finally, expose the public functionality of whichever appropriate internal // Finally, expose the public functionality of whichever appropriate internal
// module. // module.
pub use self::internal::*; pub use self::internal::*;

View File

@ -125,15 +125,35 @@ type smartlist_t = Stringlist;
#[allow(dead_code)] #[allow(dead_code)]
extern "C" { extern "C" {
fn crypto_digest(digest: *mut c_char, m: *const c_char, len: size_t) -> c_int; fn crypto_digest(digest: *mut c_char, m: *const c_char, len: size_t) -> c_int;
fn crypto_digest256(digest: *mut c_char, m: *const c_char, len: size_t, fn crypto_digest256(
algorithm: digest_algorithm_t) -> c_int; digest: *mut c_char,
fn crypto_digest512(digest: *mut c_char, m: *const c_char, len: size_t, m: *const c_char,
algorithm: digest_algorithm_t) -> c_int; len: size_t,
fn crypto_common_digests(ds_out: *mut common_digests_t, m: *const c_char, len: size_t) -> c_int; algorithm: digest_algorithm_t,
fn crypto_digest_smartlist_prefix(digest_out: *mut c_char, len_out: size_t, prepend: *const c_char, ) -> c_int;
lst: *const smartlist_t, append: *const c_char, alg: digest_algorithm_t); fn crypto_digest512(
fn crypto_digest_smartlist(digest_out: *mut c_char, len_out: size_t, digest: *mut c_char,
lst: *const smartlist_t, append: *const c_char, alg: digest_algorithm_t); m: *const c_char,
len: size_t,
algorithm: digest_algorithm_t,
) -> c_int;
fn crypto_common_digests(ds_out: *mut common_digests_t, m: *const c_char, len: size_t)
-> c_int;
fn crypto_digest_smartlist_prefix(
digest_out: *mut c_char,
len_out: size_t,
prepend: *const c_char,
lst: *const smartlist_t,
append: *const c_char,
alg: digest_algorithm_t,
);
fn crypto_digest_smartlist(
digest_out: *mut c_char,
len_out: size_t,
lst: *const smartlist_t,
append: *const c_char,
alg: digest_algorithm_t,
);
fn crypto_digest_algorithm_get_name(alg: digest_algorithm_t) -> *const c_char; fn crypto_digest_algorithm_get_name(alg: digest_algorithm_t) -> *const c_char;
fn crypto_digest_algorithm_get_length(alg: digest_algorithm_t) -> size_t; fn crypto_digest_algorithm_get_length(alg: digest_algorithm_t) -> size_t;
fn crypto_digest_algorithm_parse_name(name: *const c_char) -> c_int; fn crypto_digest_algorithm_parse_name(name: *const c_char) -> c_int;
@ -145,11 +165,21 @@ extern "C" {
fn crypto_digest_get_digest(digest: *mut crypto_digest_t, out: *mut c_char, out_len: size_t); fn crypto_digest_get_digest(digest: *mut crypto_digest_t, out: *mut c_char, out_len: size_t);
fn crypto_digest_dup(digest: *const crypto_digest_t) -> *mut crypto_digest_t; fn crypto_digest_dup(digest: *const crypto_digest_t) -> *mut crypto_digest_t;
fn crypto_digest_assign(into: *mut crypto_digest_t, from: *const crypto_digest_t); fn crypto_digest_assign(into: *mut crypto_digest_t, from: *const crypto_digest_t);
fn crypto_hmac_sha256(hmac_out: *mut c_char, key: *const c_char, key_len: size_t, fn crypto_hmac_sha256(
msg: *const c_char, msg_len: size_t); hmac_out: *mut c_char,
fn crypto_mac_sha3_256(mac_out: *mut uint8_t, len_out: size_t, key: *const c_char,
key: *const uint8_t, key_len: size_t, key_len: size_t,
msg: *const uint8_t, msg_len: size_t); msg: *const c_char,
msg_len: size_t,
);
fn crypto_mac_sha3_256(
mac_out: *mut uint8_t,
len_out: size_t,
key: *const uint8_t,
key_len: size_t,
msg: *const uint8_t,
msg_len: size_t,
);
fn crypto_xof_new() -> *mut crypto_xof_t; fn crypto_xof_new() -> *mut crypto_xof_t;
fn crypto_xof_add_bytes(xof: *mut crypto_xof_t, data: *const uint8_t, len: size_t); fn crypto_xof_add_bytes(xof: *mut crypto_xof_t, data: *const uint8_t, len: size_t);
fn crypto_xof_squeeze_bytes(xof: *mut crypto_xof_t, out: *mut uint8_t, len: size_t); fn crypto_xof_squeeze_bytes(xof: *mut crypto_xof_t, out: *mut uint8_t, len: size_t);
@ -238,12 +268,12 @@ impl CryptoDigest {
unsafe { unsafe {
// XXX This is a pretty awkward API to use from Rust... // XXX This is a pretty awkward API to use from Rust...
digest = match algo { digest = match algo {
DIGEST_SHA1 => crypto_digest_new(), DIGEST_SHA1 => crypto_digest_new(),
DIGEST_SHA256 => crypto_digest256_new(DIGEST_SHA256), DIGEST_SHA256 => crypto_digest256_new(DIGEST_SHA256),
DIGEST_SHA3_256 => crypto_digest256_new(DIGEST_SHA3_256), DIGEST_SHA3_256 => crypto_digest256_new(DIGEST_SHA3_256),
DIGEST_SHA512 => crypto_digest512_new(DIGEST_SHA512), DIGEST_SHA512 => crypto_digest512_new(DIGEST_SHA512),
DIGEST_SHA3_512 => crypto_digest512_new(DIGEST_SHA3_512), DIGEST_SHA3_512 => crypto_digest512_new(DIGEST_SHA3_512),
_ => abort(), _ => abort(),
} }
} }
} }
@ -285,9 +315,11 @@ impl CryptoDigest {
/// * `crypto_digest_add_bytes` /// * `crypto_digest_add_bytes`
pub fn add_bytes(&self, bytes: &[u8]) { pub fn add_bytes(&self, bytes: &[u8]) {
unsafe { unsafe {
crypto_digest_add_bytes(self.0 as *mut crypto_digest_t, crypto_digest_add_bytes(
bytes.as_ptr() as *const c_char, self.0 as *mut crypto_digest_t,
bytes.len() as size_t) bytes.as_ptr() as *const c_char,
bytes.len() as size_t,
)
} }
} }
} }
@ -331,9 +363,11 @@ pub fn get_256_bit_digest(digest: CryptoDigest) -> [u8; DIGEST256_LEN] {
let mut buffer: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN]; let mut buffer: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN];
unsafe { unsafe {
crypto_digest_get_digest(digest.0, crypto_digest_get_digest(
buffer.as_mut_ptr() as *mut c_char, digest.0,
DIGEST256_LEN as size_t); buffer.as_mut_ptr() as *mut c_char,
DIGEST256_LEN as size_t,
);
if buffer.as_ptr().is_null() { if buffer.as_ptr().is_null() {
abort(); abort();
@ -373,9 +407,11 @@ pub fn get_512_bit_digest(digest: CryptoDigest) -> [u8; DIGEST512_LEN] {
let mut buffer: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN]; let mut buffer: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN];
unsafe { unsafe {
crypto_digest_get_digest(digest.0, crypto_digest_get_digest(
buffer.as_mut_ptr() as *mut c_char, digest.0,
DIGEST512_LEN as size_t); buffer.as_mut_ptr() as *mut c_char,
DIGEST512_LEN as size_t,
);
if buffer.as_ptr().is_null() { if buffer.as_ptr().is_null() {
abort(); abort();
@ -390,17 +426,29 @@ mod test {
#[test] #[test]
fn test_layout_common_digests_t() { fn test_layout_common_digests_t() {
assert_eq!(::std::mem::size_of::<common_digests_t>(), 64usize, assert_eq!(
concat!("Size of: ", stringify!(common_digests_t))); ::std::mem::size_of::<common_digests_t>(),
assert_eq!(::std::mem::align_of::<common_digests_t>(), 1usize, 64usize,
concat!("Alignment of ", stringify!(common_digests_t))); concat!("Size of: ", stringify!(common_digests_t))
);
assert_eq!(
::std::mem::align_of::<common_digests_t>(),
1usize,
concat!("Alignment of ", stringify!(common_digests_t))
);
} }
#[test] #[test]
fn test_layout_crypto_digest_t() { fn test_layout_crypto_digest_t() {
assert_eq!(::std::mem::size_of::<crypto_digest_t>(), 0usize, assert_eq!(
concat!("Size of: ", stringify!(crypto_digest_t))); ::std::mem::size_of::<crypto_digest_t>(),
assert_eq!(::std::mem::align_of::<crypto_digest_t>(), 1usize, 0usize,
concat!("Alignment of ", stringify!(crypto_digest_t))); concat!("Size of: ", stringify!(crypto_digest_t))
);
assert_eq!(
::std::mem::align_of::<crypto_digest_t>(),
1usize,
concat!("Alignment of ", stringify!(crypto_digest_t))
);
} }
} }

View File

@ -2,7 +2,7 @@
// Copyright (c) 2018, isis agora lovecruft // Copyright (c) 2018, isis agora lovecruft
// See LICENSE for licensing information // See LICENSE for licensing information
//! Bindings to external (P)RNG interfaces and utilities in //! Bindings to external (P)RNG interfaces and utilities in
//! src/common/crypto_rand.[ch]. //! src/common/crypto_rand.[ch].
//! //!
//! We wrap our C implementations in src/common/crypto_rand.[ch] here in order //! We wrap our C implementations in src/common/crypto_rand.[ch] here in order
@ -80,8 +80,5 @@ pub fn c_tor_crypto_rand_time_range(min: &Duration, max: &Duration) -> Duration
/// Return a pseudorandom 64-bit float, chosen uniformly from the range [0.0, 1.0). /// Return a pseudorandom 64-bit float, chosen uniformly from the range [0.0, 1.0).
pub fn c_tor_crypto_rand_double() -> f64 { pub fn c_tor_crypto_rand_double() -> f64 {
unsafe { unsafe { crypto_rand_double() }
crypto_rand_double()
}
} }

View File

@ -5,10 +5,7 @@ use libc::{c_char, c_int};
use std::ffi::CString; use std::ffi::CString;
extern "C" { extern "C" {
fn tor_version_as_new_as( fn tor_version_as_new_as(platform: *const c_char, cutoff: *const c_char) -> c_int;
platform: *const c_char,
cutoff: *const c_char,
) -> c_int;
} }
/// Wrap calls to tor_version_as_new_as, defined in routerparse.c /// Wrap calls to tor_version_as_new_as, defined in routerparse.c
@ -25,9 +22,7 @@ pub fn c_tor_version_as_new_as(platform: &str, cutoff: &str) -> bool {
Err(_) => return false, Err(_) => return false,
}; };
let result: c_int = unsafe { let result: c_int = unsafe { tor_version_as_new_as(c_platform.as_ptr(), c_cutoff.as_ptr()) };
tor_version_as_new_as(c_platform.as_ptr(), c_cutoff.as_ptr())
};
result == 1 result == 1
} }

View File

@ -24,20 +24,30 @@ pub enum ProtoverError {
impl Display for ProtoverError { impl Display for ProtoverError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
ProtoverError::Overlap ProtoverError::Overlap => write!(
=> write!(f, "Two or more (low, high) protover ranges would overlap once expanded."), f,
ProtoverError::LowGreaterThanHigh "Two or more (low, high) protover ranges would overlap once expanded."
=> write!(f, "The low in a (low, high) protover range was greater than high."), ),
ProtoverError::Unparseable ProtoverError::LowGreaterThanHigh => write!(
=> write!(f, "The protover string was unparseable."), f,
ProtoverError::ExceedsMax "The low in a (low, high) protover range was greater than high."
=> write!(f, "The high in a (low, high) protover range exceeds u32::MAX."), ),
ProtoverError::ExceedsExpansionLimit ProtoverError::Unparseable => write!(f, "The protover string was unparseable."),
=> write!(f, "The protover string would exceed the maximum expansion limit."), ProtoverError::ExceedsMax => write!(
ProtoverError::UnknownProtocol f,
=> write!(f, "A protocol in the protover string we attempted to parse is unknown."), "The high in a (low, high) protover range exceeds u32::MAX."
ProtoverError::ExceedsNameLimit ),
=> write!(f, "An unrecognised protocol name was too long."), ProtoverError::ExceedsExpansionLimit => write!(
f,
"The protover string would exceed the maximum expansion limit."
),
ProtoverError::UnknownProtocol => write!(
f,
"A protocol in the protover string we attempted to parse is unknown."
),
ProtoverError::ExceedsNameLimit => {
write!(f, "An unrecognised protocol name was too long.")
}
} }
} }
} }

View File

@ -62,8 +62,7 @@ pub extern "C" fn protover_all_supported(
}; };
if let Some(unsupported) = relay_proto_entry.all_supported() { if let Some(unsupported) = relay_proto_entry.all_supported() {
let c_unsupported: CString = match CString::new(unsupported.to_string()) let c_unsupported: CString = match CString::new(unsupported.to_string()) {
{
Ok(n) => n, Ok(n) => n,
Err(_) => return 1, Err(_) => return 1,
}; };
@ -113,9 +112,7 @@ pub extern "C" fn protocol_list_supports_protocol(
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn protover_contains_long_protocol_names_( pub extern "C" fn protover_contains_long_protocol_names_(c_protocol_list: *const c_char) -> c_int {
c_protocol_list: *const c_char,
) -> c_int {
if c_protocol_list.is_null() { if c_protocol_list.is_null() {
return 1; return 1;
} }
@ -216,8 +213,7 @@ pub extern "C" fn protover_compute_vote(
}; };
proto_entries.push(entry); proto_entries.push(entry);
} }
let vote: UnvalidatedProtoEntry = let vote: UnvalidatedProtoEntry = ProtoverVote::compute(&proto_entries, &hold);
ProtoverVote::compute(&proto_entries, &hold);
allocate_and_copy_string(&vote.to_string()) allocate_and_copy_string(&vote.to_string())
} }
@ -225,10 +221,7 @@ pub extern "C" fn protover_compute_vote(
/// Provide an interface for C to translate arguments and return types for /// Provide an interface for C to translate arguments and return types for
/// protover::is_supported_here /// protover::is_supported_here
#[no_mangle] #[no_mangle]
pub extern "C" fn protover_is_supported_here( pub extern "C" fn protover_is_supported_here(c_protocol: uint32_t, version: uint32_t) -> c_int {
c_protocol: uint32_t,
version: uint32_t,
) -> c_int {
let protocol = match translate_to_rust(c_protocol) { let protocol = match translate_to_rust(c_protocol) {
Ok(n) => n, Ok(n) => n,
Err(_) => return 0, Err(_) => return 0,
@ -242,9 +235,7 @@ pub extern "C" fn protover_is_supported_here(
/// Provide an interface for C to translate arguments and return types for /// Provide an interface for C to translate arguments and return types for
/// protover::compute_for_old_tor /// protover::compute_for_old_tor
#[no_mangle] #[no_mangle]
pub extern "C" fn protover_compute_for_old_tor( pub extern "C" fn protover_compute_for_old_tor(version: *const c_char) -> *const c_char {
version: *const c_char,
) -> *const c_char {
let supported: &'static CStr; let supported: &'static CStr;
let empty: &'static CStr; let empty: &'static CStr;

View File

@ -22,18 +22,19 @@
//! protocols to develop independently, without having to claim compatibility //! protocols to develop independently, without having to claim compatibility
//! with specific versions of Tor. //! with specific versions of Tor.
#[deny(missing_docs)] // XXX: add missing docs
//#![deny(missing_docs)]
extern crate external;
extern crate libc; extern crate libc;
extern crate smartlist; extern crate smartlist;
extern crate external;
extern crate tor_allocate; extern crate tor_allocate;
#[macro_use] #[macro_use]
extern crate tor_util; extern crate tor_util;
pub mod errors; pub mod errors;
pub mod ffi;
pub mod protoset; pub mod protoset;
mod protover; mod protover;
pub mod ffi;
pub use protover::*; pub use protover::*;

View File

@ -53,7 +53,7 @@ impl Default for ProtoSet {
fn default() -> Self { fn default() -> Self {
let pairs: Vec<(Version, Version)> = Vec::new(); let pairs: Vec<(Version, Version)> = Vec::new();
ProtoSet{ pairs } ProtoSet { pairs }
} }
} }
@ -73,7 +73,7 @@ impl<'a> ProtoSet {
pairs.sort_unstable(); pairs.sort_unstable();
pairs.dedup(); pairs.dedup();
ProtoSet{ pairs }.is_ok() ProtoSet { pairs }.is_ok()
} }
} }
@ -263,7 +263,8 @@ impl ProtoSet {
/// ``` /// ```
// XXX we could probably do something more efficient here. —isis // XXX we could probably do something more efficient here. —isis
pub fn retain<F>(&mut self, f: F) pub fn retain<F>(&mut self, f: F)
where F: FnMut(&Version) -> bool where
F: FnMut(&Version) -> bool,
{ {
let mut expanded: Vec<Version> = self.clone().expand(); let mut expanded: Vec<Version> = self.clone().expand();
expanded.retain(f); expanded.retain(f);
@ -299,7 +300,7 @@ impl FromStr for ProtoSet {
/// * there are greater than 2^16 version numbers to expand. /// * there are greater than 2^16 version numbers to expand.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::str::FromStr; /// use std::str::FromStr;
/// ///
@ -350,10 +351,10 @@ impl FromStr for ProtoSet {
} else if p.contains('-') { } else if p.contains('-') {
let mut pair = p.split('-'); let mut pair = p.split('-');
let low = pair.next().ok_or(ProtoverError::Unparseable)?; let low = pair.next().ok_or(ProtoverError::Unparseable)?;
let high = pair.next().ok_or(ProtoverError::Unparseable)?; let high = pair.next().ok_or(ProtoverError::Unparseable)?;
let lo: Version = low.parse().or(Err(ProtoverError::Unparseable))?; let lo: Version = low.parse().or(Err(ProtoverError::Unparseable))?;
let hi: Version = high.parse().or(Err(ProtoverError::Unparseable))?; let hi: Version = high.parse().or(Err(ProtoverError::Unparseable))?;
if lo == u32::MAX || hi == u32::MAX { if lo == u32::MAX || hi == u32::MAX {
@ -457,11 +458,11 @@ impl From<Vec<Version>> for ProtoSet {
if has_range { if has_range {
let first: Version = match v.first() { let first: Version = match v.first() {
Some(x) => *x, Some(x) => *x,
None => continue, None => continue,
}; };
let last: Version = match v.get(index) { let last: Version = match v.get(index) {
Some(x) => *x, Some(x) => *x,
None => continue, None => continue,
}; };
debug_assert!(last == end, format!("last = {}, end = {}", last, end)); debug_assert!(last == end, format!("last = {}, end = {}", last, end));
@ -474,7 +475,7 @@ impl From<Vec<Version>> for ProtoSet {
} else { } else {
let last: Version = match v.get(index) { let last: Version = match v.get(index) {
Some(x) => *x, Some(x) => *x,
None => continue, None => continue,
}; };
version_pairs.push((last, last)); version_pairs.push((last, last));
v.remove(index); v.remove(index);
@ -498,22 +499,22 @@ mod test {
} }
macro_rules! assert_contains_each { macro_rules! assert_contains_each {
($protoset:expr, $versions:expr) => ( ($protoset:expr, $versions:expr) => {
for version in $versions { for version in $versions {
assert!($protoset.contains(version)); assert!($protoset.contains(version));
} }
) };
} }
macro_rules! test_protoset_contains_versions { macro_rules! test_protoset_contains_versions {
($list:expr, $str:expr) => ( ($list:expr, $str:expr) => {
let versions: &[Version] = $list; let versions: &[Version] = $list;
let protoset: Result<ProtoSet, ProtoverError> = ProtoSet::from_str($str); let protoset: Result<ProtoSet, ProtoverError> = ProtoSet::from_str($str);
assert!(protoset.is_ok()); assert!(protoset.is_ok());
let p = protoset.unwrap(); let p = protoset.unwrap();
assert_contains_each!(p, versions); assert_contains_each!(p, versions);
) };
} }
#[test] #[test]
@ -555,26 +556,41 @@ mod test {
#[test] #[test]
fn test_versions_from_slice_overlap() { fn test_versions_from_slice_overlap() {
assert_eq!(Err(ProtoverError::Overlap), ProtoSet::from_slice(&[(1, 3), (2, 4)])); assert_eq!(
Err(ProtoverError::Overlap),
ProtoSet::from_slice(&[(1, 3), (2, 4)])
);
} }
#[test] #[test]
fn test_versions_from_str_max() { fn test_versions_from_str_max() {
assert_eq!(Err(ProtoverError::ExceedsMax), ProtoSet::from_str("4294967295")); assert_eq!(
Err(ProtoverError::ExceedsMax),
ProtoSet::from_str("4294967295")
);
} }
#[test] #[test]
fn test_versions_from_slice_max() { fn test_versions_from_slice_max() {
assert_eq!(Err(ProtoverError::ExceedsMax), ProtoSet::from_slice(&[(4294967295, 4294967295)])); assert_eq!(
Err(ProtoverError::ExceedsMax),
ProtoSet::from_slice(&[(4294967295, 4294967295)])
);
} }
#[test] #[test]
fn test_protoset_contains() { fn test_protoset_contains() {
let protoset: ProtoSet = ProtoSet::from_slice(&[(0, 5), (7, 9), (13, 14)]).unwrap(); let protoset: ProtoSet = ProtoSet::from_slice(&[(0, 5), (7, 9), (13, 14)]).unwrap();
for x in 0..6 { assert!(protoset.contains(&x), format!("should contain {}", x)); } for x in 0..6 {
for x in 7..10 { assert!(protoset.contains(&x), format!("should contain {}", x)); } assert!(protoset.contains(&x), format!("should contain {}", x));
for x in 13..15 { assert!(protoset.contains(&x), format!("should contain {}", x)); } }
for x in 7..10 {
assert!(protoset.contains(&x), format!("should contain {}", x));
}
for x in 13..15 {
assert!(protoset.contains(&x), format!("should contain {}", x));
}
for x in [6, 10, 11, 12, 15, 42, 43, 44, 45, 1234584].iter() { for x in [6, 10, 11, 12, 15, 42, 43, 44, 45, 1234584].iter() {
assert!(!protoset.contains(&x), format!("should not contain {}", x)); assert!(!protoset.contains(&x), format!("should not contain {}", x));
@ -585,7 +601,9 @@ mod test {
fn test_protoset_contains_0_3() { fn test_protoset_contains_0_3() {
let protoset: ProtoSet = ProtoSet::from_slice(&[(0, 3)]).unwrap(); let protoset: ProtoSet = ProtoSet::from_slice(&[(0, 3)]).unwrap();
for x in 0..4 { assert!(protoset.contains(&x), format!("should contain {}", x)); } for x in 0..4 {
assert!(protoset.contains(&x), format!("should contain {}", x));
}
} }
macro_rules! assert_protoset_from_vec_contains_all { macro_rules! assert_protoset_from_vec_contains_all {
@ -611,7 +629,7 @@ mod test {
#[test] #[test]
fn test_protoset_from_vec_unordered() { fn test_protoset_from_vec_unordered() {
let v: Vec<Version> = vec!(2, 3, 8, 4, 3, 9, 7, 2); let v: Vec<Version> = vec![2, 3, 8, 4, 3, 9, 7, 2];
let ps: ProtoSet = v.into(); let ps: ProtoSet = v.into();
assert_eq!(ps.to_string(), "2-4,7-9"); assert_eq!(ps.to_string(), "2-4,7-9");

View File

@ -1,8 +1,8 @@
// Copyright (c) 2016-2018, The Tor Project, Inc. */ // Copyright (c) 2016-2018, The Tor Project, Inc. */
// See LICENSE for licensing information */ // See LICENSE for licensing information */
use std::collections::HashMap;
use std::collections::hash_map; use std::collections::hash_map;
use std::collections::HashMap;
use std::ffi::CStr; use std::ffi::CStr;
use std::fmt; use std::fmt;
use std::str; use std::str;
@ -12,8 +12,8 @@ use std::string::String;
use external::c_tor_version_as_new_as; use external::c_tor_version_as_new_as;
use errors::ProtoverError; use errors::ProtoverError;
use protoset::Version;
use protoset::ProtoSet; use protoset::ProtoSet;
use protoset::Version;
/// The first version of Tor that included "proto" entries in its descriptors. /// The first version of Tor that included "proto" entries in its descriptors.
/// Authorities should use this to decide whether to guess proto lines. /// Authorities should use this to decide whether to guess proto lines.
@ -26,7 +26,7 @@ const FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS: &'static str = "0.2.9.3-alpha";
/// before concluding that someone is trying to DoS us /// before concluding that someone is trying to DoS us
/// ///
/// C_RUST_COUPLED: protover.c `MAX_PROTOCOLS_TO_EXPAND` /// C_RUST_COUPLED: protover.c `MAX_PROTOCOLS_TO_EXPAND`
const MAX_PROTOCOLS_TO_EXPAND: usize = (1<<16); const MAX_PROTOCOLS_TO_EXPAND: usize = (1 << 16);
/// The maximum size an `UnknownProtocol`'s name may be. /// The maximum size an `UnknownProtocol`'s name may be.
pub(crate) const MAX_PROTOCOL_NAME_LENGTH: usize = 100; pub(crate) const MAX_PROTOCOL_NAME_LENGTH: usize = 100;
@ -132,16 +132,18 @@ impl From<Protocol> for UnknownProtocol {
/// ///
// C_RUST_COUPLED: protover.c `protover_get_supported_protocols` // C_RUST_COUPLED: protover.c `protover_get_supported_protocols`
pub(crate) fn get_supported_protocols_cstr() -> &'static CStr { pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
cstr!("Cons=1-2 \ cstr!(
Desc=1-2 \ "Cons=1-2 \
DirCache=1-2 \ Desc=1-2 \
HSDir=1-2 \ DirCache=1-2 \
HSIntro=3-4 \ HSDir=1-2 \
HSRend=1-2 \ HSIntro=3-4 \
Link=1-5 \ HSRend=1-2 \
LinkAuth=1,3 \ Link=1-5 \
Microdesc=1-2 \ LinkAuth=1,3 \
Relay=1-2") Microdesc=1-2 \
Relay=1-2"
)
} }
/// A map of protocol names to the versions of them which are supported. /// A map of protocol names to the versions of them which are supported.
@ -150,7 +152,7 @@ pub struct ProtoEntry(HashMap<Protocol, ProtoSet>);
impl Default for ProtoEntry { impl Default for ProtoEntry {
fn default() -> ProtoEntry { fn default() -> ProtoEntry {
ProtoEntry( HashMap::new() ) ProtoEntry(HashMap::new())
} }
} }
@ -240,7 +242,7 @@ impl FromStr for ProtoEntry {
/// Generate an implementation of `ToString` for either a `ProtoEntry` or an /// Generate an implementation of `ToString` for either a `ProtoEntry` or an
/// `UnvalidatedProtoEntry`. /// `UnvalidatedProtoEntry`.
macro_rules! impl_to_string_for_proto_entry { macro_rules! impl_to_string_for_proto_entry {
($t:ty) => ( ($t:ty) => {
impl ToString for $t { impl ToString for $t {
fn to_string(&self) -> String { fn to_string(&self) -> String {
let mut parts: Vec<String> = Vec::new(); let mut parts: Vec<String> = Vec::new();
@ -252,7 +254,7 @@ macro_rules! impl_to_string_for_proto_entry {
parts.join(" ") parts.join(" ")
} }
} }
) };
} }
impl_to_string_for_proto_entry!(ProtoEntry); impl_to_string_for_proto_entry!(ProtoEntry);
@ -266,7 +268,7 @@ pub struct UnvalidatedProtoEntry(HashMap<UnknownProtocol, ProtoSet>);
impl Default for UnvalidatedProtoEntry { impl Default for UnvalidatedProtoEntry {
fn default() -> UnvalidatedProtoEntry { fn default() -> UnvalidatedProtoEntry {
UnvalidatedProtoEntry( HashMap::new() ) UnvalidatedProtoEntry(HashMap::new())
} }
} }
@ -324,7 +326,7 @@ impl UnvalidatedProtoEntry {
pub fn all_supported(&self) -> Option<UnvalidatedProtoEntry> { pub fn all_supported(&self) -> Option<UnvalidatedProtoEntry> {
let mut unsupported: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default(); let mut unsupported: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default();
let supported: ProtoEntry = match ProtoEntry::supported() { let supported: ProtoEntry = match ProtoEntry::supported() {
Ok(x) => x, Ok(x) => x,
Err(_) => return None, Err(_) => return None,
}; };
@ -454,9 +456,9 @@ impl UnvalidatedProtoEntry {
/// * If a protocol name is an empty string, e.g. `"Cons=1,3 =3-5"`. /// * If a protocol name is an empty string, e.g. `"Cons=1,3 =3-5"`.
/// * If a protocol name cannot be parsed as utf-8. /// * If a protocol name cannot be parsed as utf-8.
/// * If the version numbers are an empty string, e.g. `"Cons="`. /// * If the version numbers are an empty string, e.g. `"Cons="`.
fn parse_protocol_and_version_str<'a>(protocol_string: &'a str) fn parse_protocol_and_version_str<'a>(
-> Result<Vec<(&'a str, &'a str)>, ProtoverError> protocol_string: &'a str,
{ ) -> Result<Vec<(&'a str, &'a str)>, ProtoverError> {
let mut protovers: Vec<(&str, &str)> = Vec::new(); let mut protovers: Vec<(&str, &str)> = Vec::new();
for subproto in protocol_string.split(' ') { for subproto in protocol_string.split(' ') {
@ -523,9 +525,9 @@ impl FromStr for UnvalidatedProtoEntry {
impl UnvalidatedProtoEntry { impl UnvalidatedProtoEntry {
/// Create an `UnknownProtocol`, ignoring whether or not it /// Create an `UnknownProtocol`, ignoring whether or not it
/// exceeds MAX_PROTOCOL_NAME_LENGTH. /// exceeds MAX_PROTOCOL_NAME_LENGTH.
pub(crate) fn from_str_any_len(protocol_string: &str) pub(crate) fn from_str_any_len(
-> Result<UnvalidatedProtoEntry, ProtoverError> protocol_string: &str,
{ ) -> Result<UnvalidatedProtoEntry, ProtoverError> {
let mut parsed: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default(); let mut parsed: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default();
let parts: Vec<(&str, &str)> = let parts: Vec<(&str, &str)> =
UnvalidatedProtoEntry::parse_protocol_and_version_str(protocol_string)?; UnvalidatedProtoEntry::parse_protocol_and_version_str(protocol_string)?;
@ -560,11 +562,11 @@ impl From<ProtoEntry> for UnvalidatedProtoEntry {
/// The "protocols" are *not* guaranteed to be known/supported `Protocol`s, in /// The "protocols" are *not* guaranteed to be known/supported `Protocol`s, in
/// order to allow new subprotocols to be introduced even if Directory /// order to allow new subprotocols to be introduced even if Directory
/// Authorities don't yet know of them. /// Authorities don't yet know of them.
pub struct ProtoverVote( HashMap<UnknownProtocol, HashMap<Version, usize>> ); pub struct ProtoverVote(HashMap<UnknownProtocol, HashMap<Version, usize>>);
impl Default for ProtoverVote { impl Default for ProtoverVote {
fn default() -> ProtoverVote { fn default() -> ProtoverVote {
ProtoverVote( HashMap::new() ) ProtoverVote(HashMap::new())
} }
} }
@ -578,9 +580,10 @@ impl IntoIterator for ProtoverVote {
} }
impl ProtoverVote { impl ProtoverVote {
pub fn entry(&mut self, key: UnknownProtocol) pub fn entry(
-> hash_map::Entry<UnknownProtocol, HashMap<Version, usize>> &mut self,
{ key: UnknownProtocol,
) -> hash_map::Entry<UnknownProtocol, HashMap<Version, usize>> {
self.0.entry(key) self.0.entry(key)
} }
@ -602,7 +605,10 @@ impl ProtoverVote {
/// assert_eq!("Link=3", vote.to_string()); /// assert_eq!("Link=3", vote.to_string());
/// ``` /// ```
// C_RUST_COUPLED: protover.c protover_compute_vote // C_RUST_COUPLED: protover.c protover_compute_vote
pub fn compute(proto_entries: &[UnvalidatedProtoEntry], threshold: &usize) -> UnvalidatedProtoEntry { pub fn compute(
proto_entries: &[UnvalidatedProtoEntry],
threshold: &usize,
) -> UnvalidatedProtoEntry {
let mut all_count: ProtoverVote = ProtoverVote::default(); let mut all_count: ProtoverVote = ProtoverVote::default();
let mut final_output: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default(); let mut final_output: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default();
@ -628,8 +634,7 @@ impl ProtoverVote {
all_count.entry(protocol.clone()).or_insert(HashMap::new()); all_count.entry(protocol.clone()).or_insert(HashMap::new());
for version in versions.clone().expand() { for version in versions.clone().expand() {
let counter: &mut usize = let counter: &mut usize = supported_vers.entry(version).or_insert(0);
supported_vers.entry(version).or_insert(0);
*counter += 1; *counter += 1;
} }
} }
@ -708,16 +713,22 @@ pub(crate) fn compute_for_old_tor_cstr(version: &str) -> &'static CStr {
return empty; return empty;
} }
if c_tor_version_as_new_as(version, "0.2.9.1-alpha") { if c_tor_version_as_new_as(version, "0.2.9.1-alpha") {
return cstr!("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 \ return cstr!(
Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2"); "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 \
Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2"
);
} }
if c_tor_version_as_new_as(version, "0.2.7.5") { if c_tor_version_as_new_as(version, "0.2.7.5") {
return cstr!("Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \ return cstr!(
Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2"); "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2"
);
} }
if c_tor_version_as_new_as(version, "0.2.4.19") { if c_tor_version_as_new_as(version, "0.2.4.19") {
return cstr!("Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \ return cstr!(
Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2"); "Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2"
);
} }
empty empty
} }
@ -752,7 +763,9 @@ pub(crate) fn compute_for_old_tor_cstr(version: &str) -> &'static CStr {
pub fn compute_for_old_tor(version: &str) -> Result<&'static str, ProtoverError> { pub fn compute_for_old_tor(version: &str) -> Result<&'static str, ProtoverError> {
// .to_str() fails with a Utf8Error if it couldn't validate the // .to_str() fails with a Utf8Error if it couldn't validate the
// utf-8, so convert that here into an Unparseable ProtoverError. // utf-8, so convert that here into an Unparseable ProtoverError.
compute_for_old_tor_cstr(version).to_str().or(Err(ProtoverError::Unparseable)) compute_for_old_tor_cstr(version)
.to_str()
.or(Err(ProtoverError::Unparseable))
} }
#[cfg(test)] #[cfg(test)]
@ -763,19 +776,19 @@ mod test {
use super::*; use super::*;
macro_rules! assert_protoentry_is_parseable { macro_rules! assert_protoentry_is_parseable {
($e:expr) => ( ($e:expr) => {
let protoentry: Result<ProtoEntry, ProtoverError> = $e.parse(); let protoentry: Result<ProtoEntry, ProtoverError> = $e.parse();
assert!(protoentry.is_ok(), format!("{:?}", protoentry.err())); assert!(protoentry.is_ok(), format!("{:?}", protoentry.err()));
) };
} }
macro_rules! assert_protoentry_is_unparseable { macro_rules! assert_protoentry_is_unparseable {
($e:expr) => ( ($e:expr) => {
let protoentry: Result<ProtoEntry, ProtoverError> = $e.parse(); let protoentry: Result<ProtoEntry, ProtoverError> = $e.parse();
assert!(protoentry.is_err()); assert!(protoentry.is_err());
) };
} }
#[test] #[test]
@ -861,24 +874,45 @@ mod test {
#[test] #[test]
fn test_contract_protocol_list() { fn test_contract_protocol_list() {
let mut versions = ""; let mut versions = "";
assert_eq!(String::from(versions), ProtoSet::from_str(&versions).unwrap().to_string()); assert_eq!(
String::from(versions),
ProtoSet::from_str(&versions).unwrap().to_string()
);
versions = "1"; versions = "1";
assert_eq!(String::from(versions), ProtoSet::from_str(&versions).unwrap().to_string()); assert_eq!(
String::from(versions),
ProtoSet::from_str(&versions).unwrap().to_string()
);
versions = "1-2"; versions = "1-2";
assert_eq!(String::from(versions), ProtoSet::from_str(&versions).unwrap().to_string()); assert_eq!(
String::from(versions),
ProtoSet::from_str(&versions).unwrap().to_string()
);
versions = "1,3"; versions = "1,3";
assert_eq!(String::from(versions), ProtoSet::from_str(&versions).unwrap().to_string()); assert_eq!(
String::from(versions),
ProtoSet::from_str(&versions).unwrap().to_string()
);
versions = "1-4"; versions = "1-4";
assert_eq!(String::from(versions), ProtoSet::from_str(&versions).unwrap().to_string()); assert_eq!(
String::from(versions),
ProtoSet::from_str(&versions).unwrap().to_string()
);
versions = "1,3,5-7"; versions = "1,3,5-7";
assert_eq!(String::from(versions), ProtoSet::from_str(&versions).unwrap().to_string()); assert_eq!(
String::from(versions),
ProtoSet::from_str(&versions).unwrap().to_string()
);
versions = "1-3,500"; versions = "1-3,500";
assert_eq!(String::from(versions), ProtoSet::from_str(&versions).unwrap().to_string()); assert_eq!(
String::from(versions),
ProtoSet::from_str(&versions).unwrap().to_string()
);
} }
} }

View File

@ -3,10 +3,10 @@
extern crate protover; extern crate protover;
use protover::errors::ProtoverError;
use protover::ProtoEntry; use protover::ProtoEntry;
use protover::ProtoverVote; use protover::ProtoverVote;
use protover::UnvalidatedProtoEntry; use protover::UnvalidatedProtoEntry;
use protover::errors::ProtoverError;
#[test] #[test]
fn parse_protocol_with_single_proto_and_single_version() { fn parse_protocol_with_single_proto_and_single_version() {
@ -179,14 +179,16 @@ fn protover_compute_vote_returns_two_protocols_for_two_matching() {
#[test] #[test]
fn protover_compute_vote_returns_one_protocol_when_one_out_of_two_matches() { fn protover_compute_vote_returns_one_protocol_when_one_out_of_two_matches() {
let protocols: &[UnvalidatedProtoEntry] = &["Cons=1 Link=2".parse().unwrap(), "Cons=1".parse().unwrap()]; let protocols: &[UnvalidatedProtoEntry] =
&["Cons=1 Link=2".parse().unwrap(), "Cons=1".parse().unwrap()];
let listed = ProtoverVote::compute(protocols, &2); let listed = ProtoverVote::compute(protocols, &2);
assert_eq!("Cons=1", listed.to_string()); assert_eq!("Cons=1", listed.to_string());
} }
#[test] #[test]
fn protover_compute_vote_returns_protocols_that_it_doesnt_currently_support() { fn protover_compute_vote_returns_protocols_that_it_doesnt_currently_support() {
let protocols: &[UnvalidatedProtoEntry] = &["Foo=1 Cons=2".parse().unwrap(), "Bar=1".parse().unwrap()]; let protocols: &[UnvalidatedProtoEntry] =
&["Foo=1 Cons=2".parse().unwrap(), "Bar=1".parse().unwrap()];
let listed = ProtoverVote::compute(protocols, &1); let listed = ProtoverVote::compute(protocols, &1);
assert_eq!("Bar=1 Cons=2 Foo=1", listed.to_string()); assert_eq!("Bar=1 Cons=2 Foo=1", listed.to_string());
} }
@ -222,10 +224,12 @@ fn protover_compute_vote_returns_matching_for_longer_mix_with_threshold_two() {
#[test] #[test]
fn protover_compute_vote_handles_duplicated_versions() { fn protover_compute_vote_handles_duplicated_versions() {
let protocols: &[UnvalidatedProtoEntry] = &["Cons=1".parse().unwrap(), "Cons=1".parse().unwrap()]; let protocols: &[UnvalidatedProtoEntry] =
&["Cons=1".parse().unwrap(), "Cons=1".parse().unwrap()];
assert_eq!("Cons=1", ProtoverVote::compute(protocols, &2).to_string()); assert_eq!("Cons=1", ProtoverVote::compute(protocols, &2).to_string());
let protocols: &[UnvalidatedProtoEntry] = &["Cons=1-2".parse().unwrap(), "Cons=1-2".parse().unwrap()]; let protocols: &[UnvalidatedProtoEntry] =
&["Cons=1-2".parse().unwrap(), "Cons=1-2".parse().unwrap()];
assert_eq!("Cons=1-2", ProtoverVote::compute(protocols, &2).to_string()); assert_eq!("Cons=1-2", ProtoverVote::compute(protocols, &2).to_string());
} }
@ -246,12 +250,18 @@ fn parse_protocol_with_single_protocol_and_two_nonsequential_versions() {
#[test] #[test]
fn protover_is_supported_here_returns_true_for_supported_protocol() { fn protover_is_supported_here_returns_true_for_supported_protocol() {
assert_eq!(true, protover::is_supported_here(&protover::Protocol::Cons, &1)); assert_eq!(
true,
protover::is_supported_here(&protover::Protocol::Cons, &1)
);
} }
#[test] #[test]
fn protover_is_supported_here_returns_false_for_unsupported_protocol() { fn protover_is_supported_here_returns_false_for_unsupported_protocol() {
assert_eq!(false, protover::is_supported_here(&protover::Protocol::Cons, &5)); assert_eq!(
false,
protover::is_supported_here(&protover::Protocol::Cons, &5)
);
} }
#[test] #[test]

View File

@ -1,9 +1,9 @@
// Copyright (c) 2016-2018, The Tor Project, Inc. */ // Copyright (c) 2016-2018, The Tor Project, Inc. */
// See LICENSE for licensing information */ // See LICENSE for licensing information */
use std::slice;
use libc::{c_char, c_int}; use libc::{c_char, c_int};
use std::ffi::CStr; use std::ffi::CStr;
use std::slice;
/// Smartlists are a type used in C code in tor to define a collection of a /// Smartlists are a type used in C code in tor to define a collection of a
/// generic type, which has a capacity and a number used. Each Smartlist /// generic type, which has a capacity and a number used. Each Smartlist
@ -65,8 +65,8 @@ mod test {
fn test_get_list_of_strings() { fn test_get_list_of_strings() {
extern crate libc; extern crate libc;
use std::ffi::CString;
use libc::c_char; use libc::c_char;
use std::ffi::CString;
use super::Smartlist; use super::Smartlist;
use super::Stringlist; use super::Stringlist;
@ -89,13 +89,13 @@ mod test {
let args = vec![String::from("a"), String::from("b")]; let args = vec![String::from("a"), String::from("b")];
// for each string, transform it into a CString // for each string, transform it into a CString
let c_strings: Vec<_> = args.iter() let c_strings: Vec<_> = args
.iter()
.map(|arg| CString::new(arg.as_str()).unwrap()) .map(|arg| CString::new(arg.as_str()).unwrap())
.collect(); .collect();
// then, collect a pointer for each CString // then, collect a pointer for each CString
let p_args: Vec<_> = let p_args: Vec<_> = c_strings.iter().map(|arg| arg.as_ptr()).collect();
c_strings.iter().map(|arg| arg.as_ptr()).collect();
let p: *const *const c_char = p_args.as_ptr(); let p: *const *const c_char = p_args.as_ptr();

View File

@ -3,9 +3,9 @@
// No-op defined purely for testing at the module level // No-op defined purely for testing at the module level
use libc::c_char; use libc::c_char;
#[cfg(not(feature = "testing"))]
use std::{ptr, slice, mem};
use libc::c_void; use libc::c_void;
#[cfg(not(feature = "testing"))]
use std::{mem, ptr, slice};
// Define a no-op implementation for testing Rust modules without linking to C // Define a no-op implementation for testing Rust modules without linking to C
#[cfg(feature = "testing")] #[cfg(feature = "testing")]
@ -72,15 +72,14 @@ mod test {
#[test] #[test]
fn test_allocate_and_copy_string_with_empty() { fn test_allocate_and_copy_string_with_empty() {
use libc::{c_void, free};
use std::ffi::CStr; use std::ffi::CStr;
use libc::{free, c_void};
use tor_allocate::allocate_and_copy_string; use tor_allocate::allocate_and_copy_string;
let allocated_empty = allocate_and_copy_string(""); let allocated_empty = allocate_and_copy_string("");
let allocated_empty_rust = let allocated_empty_rust = unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() };
unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() };
assert_eq!("", allocated_empty_rust); assert_eq!("", allocated_empty_rust);
@ -89,15 +88,14 @@ mod test {
#[test] #[test]
fn test_allocate_and_copy_string_with_not_empty_string() { fn test_allocate_and_copy_string_with_not_empty_string() {
use libc::{c_void, free};
use std::ffi::CStr; use std::ffi::CStr;
use libc::{free, c_void};
use tor_allocate::allocate_and_copy_string; use tor_allocate::allocate_and_copy_string;
let allocated_empty = allocate_and_copy_string("foo bar biz"); let allocated_empty = allocate_and_copy_string("foo bar biz");
let allocated_empty_rust = let allocated_empty_rust = unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() };
unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() };
assert_eq!("foo bar biz", allocated_empty_rust); assert_eq!("foo bar biz", allocated_empty_rust);

View File

@ -48,12 +48,7 @@ macro_rules! tor_log_msg {
} }
#[inline] #[inline]
pub fn tor_log_msg_impl( pub fn tor_log_msg_impl(severity: LogSeverity, domain: LogDomain, function: &str, message: String) {
severity: LogSeverity,
domain: LogDomain,
function: &str,
message: String,
) {
use std::ffi::CString; use std::ffi::CString;
/// Default function name to log in case of errors when converting /// Default function name to log in case of errors when converting
@ -63,7 +58,7 @@ pub fn tor_log_msg_impl(
/// Default message to log in case of errors when converting a log /// Default message to log in case of errors when converting a log
/// message to a CString /// message to a CString
const ERR_LOG_MSG: &str = "Unable to log message from Rust \ const ERR_LOG_MSG: &str = "Unable to log message from Rust \
module due to error when converting to CString"; module due to error when converting to CString";
let func = match CString::new(function) { let func = match CString::new(function) {
Ok(n) => n, Ok(n) => n,
@ -90,9 +85,9 @@ pub fn tor_log_msg_impl(
/// testing. /// testing.
#[cfg(not(test))] #[cfg(not(test))]
pub mod log { pub mod log {
use libc::{c_char, c_int};
use super::LogDomain; use super::LogDomain;
use super::LogSeverity; use super::LogSeverity;
use libc::{c_char, c_int};
/// Severity log types. These mirror definitions in /src/common/torlog.h /// Severity log types. These mirror definitions in /src/common/torlog.h
/// C_RUST_COUPLED: src/common/log.c, log domain types /// C_RUST_COUPLED: src/common/log.c, log domain types
@ -144,9 +139,9 @@ pub mod log {
/// without linking to C. /// without linking to C.
#[cfg(test)] #[cfg(test)]
pub mod log { pub mod log {
use libc::{c_char, c_int};
use super::LogDomain; use super::LogDomain;
use super::LogSeverity; use super::LogSeverity;
use libc::{c_char, c_int};
pub static mut LAST_LOGGED_FUNCTION: *mut String = 0 as *mut String; pub static mut LAST_LOGGED_FUNCTION: *mut String = 0 as *mut String;
pub static mut LAST_LOGGED_MESSAGE: *mut String = 0 as *mut String; pub static mut LAST_LOGGED_MESSAGE: *mut String = 0 as *mut String;
@ -185,8 +180,8 @@ pub mod log {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use tor_log::*;
use tor_log::log::{LAST_LOGGED_FUNCTION, LAST_LOGGED_MESSAGE}; use tor_log::log::{LAST_LOGGED_FUNCTION, LAST_LOGGED_MESSAGE};
use tor_log::*;
#[test] #[test]
fn test_get_log_message() { fn test_get_log_message() {
@ -198,7 +193,7 @@ mod test {
"test_macro", "test_macro",
"test log message {}", "test log message {}",
"a", "a",
); );
} }
test_macro(); test_macro();
@ -244,21 +239,21 @@ mod test {
"test_macro", "test_macro",
"{}", "{}",
"All the world's a stage, and all the men and women \ "All the world's a stage, and all the men and women \
merely players: they have their exits and their \ merely players: they have their exits and their \
entrances; and one man in his time plays many parts, his \ entrances; and one man in his time plays many parts, his \
acts being seven ages." acts being seven ages."
); );
} }
test_macro(); test_macro();
let expected_string = "All the world's a \ let expected_string = "All the world's a \
stage, and all the men \ stage, and all the men \
and women merely players: \ and women merely players: \
they have their exits and \ they have their exits and \
their entrances; and one man \ their entrances; and one man \
in his time plays many parts, \ in his time plays many parts, \
his acts being seven ages."; his acts being seven ages.";
let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) }; let function = unsafe { Box::from_raw(LAST_LOGGED_FUNCTION) };
assert_eq!("test_macro", *function); assert_eq!("test_macro", *function);

View File

@ -1,5 +1,5 @@
extern crate tor_util;
extern crate protover; extern crate protover;
extern crate tor_util;
pub use tor_util::*;
pub use protover::*; pub use protover::*;
pub use tor_util::*;

View File

@ -5,7 +5,7 @@
//! called from C. //! called from C.
//! //!
use tor_log::{LogSeverity, LogDomain}; use tor_log::{LogDomain, LogSeverity};
/// Returns a short string to announce Rust support during startup. /// Returns a short string to announce Rust support during startup.
/// ///
@ -22,6 +22,6 @@ pub extern "C" fn rust_log_welcome_string() {
LogDomain::General, LogDomain::General,
"rust_log_welcome_string", "rust_log_welcome_string",
"Tor is running with Rust integration. Please report \ "Tor is running with Rust integration. Please report \
any bugs you encounter." any bugs you encounter."
); );
} }

View File

@ -131,10 +131,10 @@ mod test {
#[test] #[test]
fn cstr_macro_bad_input() { fn cstr_macro_bad_input() {
let waving: &'static CStr = cstr!("waving not drowning o/"); let waving: &'static CStr = cstr!("waving not drowning o/");
let drowning: &'static CStr = cstr!("\0 drowning not waving"); let drowning: &'static CStr = cstr!("\0 drowning not waving");
assert!(waving.to_str().unwrap() == "waving not drowning o/"); assert!(waving.to_str().unwrap() == "waving not drowning o/");
assert!(drowning.to_str().unwrap() == "") assert!(drowning.to_str().unwrap() == "")
} }
} }