mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-11 05:33:47 +01:00
add minimal rust module for logging to tor's logger
Allows an optional no-op for testing purposes
This commit is contained in:
parent
719db28f54
commit
3dfe8e6522
@ -52,6 +52,13 @@
|
||||
|
||||
#define raw_assert(x) assert(x) // assert OK
|
||||
|
||||
/** Defining compile-time constants for Tor log levels (used by the Rust
|
||||
* log wrapper at src/rust/tor_log) */
|
||||
const int _LOG_WARN = LOG_WARN;
|
||||
const int _LOG_NOTICE = LOG_NOTICE;
|
||||
const log_domain_mask_t _LD_GENERAL = LD_GENERAL;
|
||||
const log_domain_mask_t _LD_NET = LD_NET;
|
||||
|
||||
/** Information for a single logfile; only used in log.c */
|
||||
typedef struct logfile_t {
|
||||
struct logfile_t *next; /**< Next logfile_t in the linked list. */
|
||||
|
@ -31,6 +31,16 @@
|
||||
* "maximum severity" read "most severe" and "numerically *lowest* severity".
|
||||
*/
|
||||
|
||||
/** This defines log levels that are linked in the Rust log module, rather
|
||||
* than re-defining these in both Rust and C.
|
||||
*
|
||||
* C_RUST_COUPLED src/rust/tor_log LogSeverity, LogDomain
|
||||
*/
|
||||
extern const int _LOG_WARN;
|
||||
extern const int _LOG_NOTICE;
|
||||
extern const log_domain_mask_t _LD_NET;
|
||||
extern const log_domain_mask_t _LD_GENERAL;
|
||||
|
||||
/** Debug-level severity: for hyper-verbose messages of no interest to
|
||||
* anybody but developers. */
|
||||
#define LOG_DEBUG 7
|
||||
|
@ -132,7 +132,7 @@ void evdns_shutdown(int);
|
||||
#ifdef HAVE_RUST
|
||||
// helper function defined in Rust to output a log message indicating if tor is
|
||||
// running with Rust enabled. See src/rust/tor_util
|
||||
char *rust_welcome_string(void);
|
||||
void rust_welcome_string(void);
|
||||
#endif
|
||||
|
||||
/********* PROTOTYPES **********/
|
||||
@ -3283,11 +3283,7 @@ tor_init(int argc, char *argv[])
|
||||
}
|
||||
|
||||
#ifdef HAVE_RUST
|
||||
char *rust_str = rust_welcome_string();
|
||||
if (rust_str != NULL && strlen(rust_str) > 0) {
|
||||
log_notice(LD_GENERAL, "%s", rust_str);
|
||||
}
|
||||
tor_free(rust_str);
|
||||
rust_welcome_string();
|
||||
#endif /* defined(HAVE_RUST) */
|
||||
|
||||
if (network_init()<0) {
|
||||
|
10
src/rust/Cargo.lock
generated
10
src/rust/Cargo.lock
generated
@ -4,6 +4,7 @@ version = "0.0.1"
|
||||
dependencies = [
|
||||
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tor_allocate 0.0.1",
|
||||
"tor_log 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -26,6 +27,7 @@ dependencies = [
|
||||
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smartlist 0.0.1",
|
||||
"tor_allocate 0.0.1",
|
||||
"tor_log 0.1.0",
|
||||
"tor_util 0.0.1",
|
||||
]
|
||||
|
||||
@ -43,6 +45,14 @@ dependencies = [
|
||||
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tor_log"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tor_allocate 0.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tor_rust"
|
||||
version = "0.1.0"
|
||||
|
@ -1,5 +1,6 @@
|
||||
[workspace]
|
||||
members = ["tor_util", "protover", "smartlist", "external", "tor_allocate", "tor_rust"]
|
||||
members = ["tor_util", "protover", "smartlist", "external", "tor_allocate",
|
||||
"tor_rust", "tor_log"]
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
@ -18,6 +18,9 @@ path = "../tor_util"
|
||||
[dependencies.tor_allocate]
|
||||
path = "../tor_allocate"
|
||||
|
||||
[dependencies.tor_log]
|
||||
path = "../tor_log"
|
||||
|
||||
[lib]
|
||||
name = "protover"
|
||||
path = "lib.rs"
|
||||
|
@ -26,6 +26,7 @@ extern crate libc;
|
||||
extern crate smartlist;
|
||||
extern crate external;
|
||||
extern crate tor_allocate;
|
||||
extern crate tor_log;
|
||||
|
||||
mod protover;
|
||||
pub mod ffi;
|
||||
|
@ -1,13 +1,14 @@
|
||||
// Copyright (c) 2016-2017, The Tor Project, Inc. */
|
||||
// See LICENSE for licensing information */
|
||||
|
||||
use external::c_tor_version_as_new_as;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::fmt;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::string::String;
|
||||
|
||||
use tor_log::*;
|
||||
use external::c_tor_version_as_new_as;
|
||||
|
||||
/// The first version of Tor that included "proto" entries in its descriptors.
|
||||
/// Authorities should use this to decide whether to guess proto lines.
|
||||
///
|
||||
@ -186,7 +187,6 @@ fn get_versions(version_string: &str) -> Result<HashSet<u32>, &'static str> {
|
||||
Ok(versions)
|
||||
}
|
||||
|
||||
|
||||
/// Parse the subprotocol type and its version numbers.
|
||||
///
|
||||
/// # Inputs
|
||||
@ -240,6 +240,20 @@ fn get_proto_and_vers<'a>(
|
||||
fn contains_only_supported_protocols(proto_entry: &str) -> bool {
|
||||
let (name, mut vers) = match get_proto_and_vers(proto_entry) {
|
||||
Ok(n) => n,
|
||||
Err("Too many versions to expand") => {
|
||||
tor_log_msg!(
|
||||
LogSeverity::Warn,
|
||||
LogDomain::LdNet,
|
||||
"get_versions",
|
||||
"When expanding a protocol list from an authority, I
|
||||
got too many protocols. This is possibly an attack or a bug,
|
||||
unless the Tor network truly has expanded to support over {}
|
||||
different subprotocol versions. The offending string was: {}",
|
||||
MAX_PROTOCOLS_TO_EXPAND,
|
||||
proto_entry
|
||||
);
|
||||
return false;
|
||||
}
|
||||
Err(_) => return false,
|
||||
};
|
||||
|
||||
|
@ -1,12 +1,17 @@
|
||||
// Copyright (c) 2016-2017, The Tor Project, Inc. */
|
||||
// See LICENSE for licensing information */
|
||||
// No-op defined purely for testing at the module level
|
||||
use libc::c_char;
|
||||
|
||||
use libc::{c_char, c_void};
|
||||
#[cfg(not(feature = "testing"))]
|
||||
use std::{ptr, slice, mem};
|
||||
use libc::c_void;
|
||||
|
||||
#[cfg(not(test))]
|
||||
extern "C" {
|
||||
fn tor_malloc_(size: usize) -> *mut c_void;
|
||||
// Define a no-op implementation for testing Rust modules without linking to C
|
||||
#[cfg(feature = "testing")]
|
||||
pub fn allocate_and_copy_string(s: &String) -> *mut c_char {
|
||||
use std::ffi::CString;
|
||||
CString::new(s.as_str()).unwrap().into_raw()
|
||||
}
|
||||
|
||||
// Defined only for tests, used for testing purposes, so that we don't need
|
||||
@ -17,6 +22,11 @@ unsafe extern "C" fn tor_malloc_(size: usize) -> *mut c_void {
|
||||
malloc(size)
|
||||
}
|
||||
|
||||
#[cfg(all(not(test), not(feature = "testing")))]
|
||||
extern "C" {
|
||||
fn tor_malloc_(size: usize) -> *mut c_void;
|
||||
}
|
||||
|
||||
/// Allocate memory using tor_malloc_ and copy an existing string into the
|
||||
/// allocated buffer, returning a pointer that can later be called in C.
|
||||
///
|
||||
@ -28,6 +38,7 @@ unsafe extern "C" fn tor_malloc_(size: usize) -> *mut c_void {
|
||||
///
|
||||
/// A `*mut c_char` that should be freed by tor_free in C
|
||||
///
|
||||
#[cfg(not(feature = "testing"))]
|
||||
pub fn allocate_and_copy_string(src: &String) -> *mut c_char {
|
||||
let bytes: &[u8] = src.as_bytes();
|
||||
|
||||
|
18
src/rust/tor_log/Cargo.toml
Normal file
18
src/rust/tor_log/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "tor_log"
|
||||
version = "0.1.0"
|
||||
authors = ["The Tor Project"]
|
||||
|
||||
[lib]
|
||||
name = "tor_log"
|
||||
path = "lib.rs"
|
||||
crate_type = ["rlib", "staticlib"]
|
||||
|
||||
[features]
|
||||
testing = []
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.22"
|
||||
|
||||
[dependencies.tor_allocate]
|
||||
path = "../tor_allocate"
|
17
src/rust/tor_log/lib.rs
Normal file
17
src/rust/tor_log/lib.rs
Normal file
@ -0,0 +1,17 @@
|
||||
//! Copyright (c) 2016-2017, The Tor Project, Inc. */
|
||||
//! See LICENSE for licensing information */
|
||||
|
||||
//! Logging wrapper for Rust to utilize Tor's logger, found at
|
||||
//! src/common/log.c and src/common/torlog.h
|
||||
//!
|
||||
//! Exposes different interfaces depending on whether we are running in test
|
||||
//! or non-test mode. When testing, we use a no-op implementation,
|
||||
//! otherwise we link directly to C.
|
||||
|
||||
extern crate libc;
|
||||
extern crate tor_allocate;
|
||||
|
||||
mod tor_log;
|
||||
|
||||
pub use tor_log::*;
|
||||
pub use tor_log::log::*;
|
236
src/rust/tor_log/tor_log.rs
Normal file
236
src/rust/tor_log/tor_log.rs
Normal file
@ -0,0 +1,236 @@
|
||||
// Copyright (c) 2016-2017, The Tor Project, Inc. */
|
||||
// See LICENSE for licensing information */
|
||||
|
||||
|
||||
/// The related domain which the logging message is relevant. For example,
|
||||
/// log messages relevant to networking would use LogDomain::LdNet, whereas
|
||||
/// general messages can use LdGeneral.
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum LogDomain {
|
||||
LdNet,
|
||||
LdGeneral,
|
||||
}
|
||||
|
||||
/// The severity level at which to log messages.
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum LogSeverity {
|
||||
Notice,
|
||||
Warn,
|
||||
}
|
||||
|
||||
/// Main entry point for Rust modules to log messages.
|
||||
///
|
||||
/// # Inputs
|
||||
///
|
||||
/// * A `severity` of type LogSeverity, which defines the level of severity the
|
||||
/// message will be logged.
|
||||
/// * A `domain` of type LogDomain, which defines the domain the log message
|
||||
/// will be associated with.
|
||||
/// * A `function` of type &str, which defines the name of the function where
|
||||
/// the message is being logged. There is a current RFC for a macro that
|
||||
/// defines function names. When it is, we should use it. See
|
||||
/// https://github.com/rust-lang/rfcs/pull/1719
|
||||
/// * A `message` of type &str, which is the log message itself.
|
||||
#[macro_export]
|
||||
macro_rules! tor_log_msg {
|
||||
($severity: path,
|
||||
$domain: path,
|
||||
$function: expr,
|
||||
$($message:tt)*) =>
|
||||
{
|
||||
{
|
||||
use std::ffi::CString;
|
||||
|
||||
/// Default function name to log in case of errors when converting
|
||||
/// a function name to a CString
|
||||
const ERR_LOG_FUNCTION: &'static str = "tor_log_msg";
|
||||
|
||||
/// Default message to log in case of errors when converting a log
|
||||
/// message to a CString
|
||||
const ERR_LOG_MSG: &'static str = "Unable to log message from Rust
|
||||
module due to error when converting to CString";
|
||||
|
||||
let func = match CString::new($function) {
|
||||
Ok(n) => n,
|
||||
Err(_) => CString::new(ERR_LOG_FUNCTION).unwrap(),
|
||||
};
|
||||
|
||||
let msg = match CString::new(format!($($message)*)) {
|
||||
Ok(n) => n,
|
||||
Err(_) => CString::new(ERR_LOG_MSG).unwrap(),
|
||||
};
|
||||
|
||||
let func_ptr = func.as_ptr();
|
||||
let msg_ptr = msg.as_ptr();
|
||||
|
||||
unsafe {
|
||||
tor_log_string(translate_severity($severity),
|
||||
translate_domain($domain),
|
||||
func_ptr, msg_ptr
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// This module exposes no-op functionality purely for the purpose of testing
|
||||
/// Rust at the module level.
|
||||
#[cfg(any(test, feature = "testing"))]
|
||||
pub mod log {
|
||||
use libc::{c_char, c_int};
|
||||
use super::LogDomain;
|
||||
use super::LogSeverity;
|
||||
|
||||
/// Expose a no-op logging interface purely for testing Rust modules at the
|
||||
/// module level.
|
||||
pub fn tor_log_string<'a>(
|
||||
severity: c_int,
|
||||
domain: u32,
|
||||
function: *const c_char,
|
||||
message: *const c_char,
|
||||
) -> (c_int, u32, String, String) {
|
||||
use std::ffi::CStr;
|
||||
|
||||
let func = unsafe { CStr::from_ptr(function) }.to_str().unwrap();
|
||||
let func_allocated = String::from(func);
|
||||
|
||||
let msg = unsafe { CStr::from_ptr(message) }.to_str().unwrap();
|
||||
let msg_allocated = String::from(msg);
|
||||
(severity, domain, func_allocated, msg_allocated)
|
||||
}
|
||||
|
||||
pub unsafe fn translate_domain(_domain: LogDomain) -> u32 {
|
||||
1
|
||||
}
|
||||
|
||||
pub unsafe fn translate_severity(_severity: LogSeverity) -> c_int {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
/// This implementation is used when compiling for actual use, as opposed to
|
||||
/// testing.
|
||||
#[cfg(all(not(test), not(feature = "testing")))]
|
||||
pub mod log {
|
||||
use libc::{c_char, c_int};
|
||||
use super::LogDomain;
|
||||
use super::LogSeverity;
|
||||
|
||||
/// Severity log types. These mirror definitions in /src/common/torlog.h
|
||||
/// C_RUST_COUPLED: src/common/log.c, log domain types
|
||||
extern "C" {
|
||||
#[no_mangle]
|
||||
static _LOG_WARN: c_int;
|
||||
static _LOG_NOTICE: c_int;
|
||||
}
|
||||
|
||||
/// Domain log types. These mirror definitions in /src/common/torlog.h
|
||||
/// C_RUST_COUPLED: src/common/log.c, log severity types
|
||||
extern "C" {
|
||||
#[no_mangle]
|
||||
static _LD_NET: u32;
|
||||
static _LD_GENERAL: u32;
|
||||
}
|
||||
|
||||
/// Translate Rust defintions of log domain levels to C. This exposes a 1:1
|
||||
/// mapping between types.
|
||||
///
|
||||
/// Allow for default cases in case Rust and C log types get out of sync
|
||||
#[allow(unreachable_patterns)]
|
||||
pub unsafe fn translate_domain(domain: LogDomain) -> u32 {
|
||||
match domain {
|
||||
LogDomain::LdNet => _LD_NET,
|
||||
LogDomain::LdGeneral => _LD_GENERAL,
|
||||
_ => _LD_GENERAL,
|
||||
}
|
||||
}
|
||||
|
||||
/// Translate Rust defintions of log severity levels to C. This exposes a
|
||||
/// 1:1 mapping between types.
|
||||
///
|
||||
/// Allow for default cases in case Rust and C log types get out of sync
|
||||
#[allow(unreachable_patterns)]
|
||||
pub unsafe fn translate_severity(severity: LogSeverity) -> c_int {
|
||||
match severity {
|
||||
LogSeverity::Warn => _LOG_WARN,
|
||||
LogSeverity::Notice => _LOG_NOTICE,
|
||||
_ => _LOG_NOTICE,
|
||||
}
|
||||
}
|
||||
|
||||
/// The main entry point into Tor's logger. When in non-test mode, this
|
||||
/// will link directly with `tor_log_string` in /src/or/log.c
|
||||
extern "C" {
|
||||
pub fn tor_log_string(
|
||||
severity: c_int,
|
||||
domain: u32,
|
||||
function: *const c_char,
|
||||
string: *const c_char,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use tor_log::*;
|
||||
use tor_log::log::*;
|
||||
|
||||
use libc::c_int;
|
||||
|
||||
#[test]
|
||||
fn test_get_log_message() {
|
||||
|
||||
fn test_macro<'a>() -> (c_int, u32, String, String) {
|
||||
let (x, y, z, a) =
|
||||
tor_log_msg!(
|
||||
LogSeverity::Warn,
|
||||
LogDomain::LdNet,
|
||||
"test_macro",
|
||||
"test log message {}",
|
||||
"a",
|
||||
);
|
||||
(x, y, z, a)
|
||||
}
|
||||
|
||||
let (severity, domain, function_name, log_msg) = test_macro();
|
||||
|
||||
let expected_severity =
|
||||
unsafe { translate_severity(LogSeverity::Warn) };
|
||||
assert_eq!(severity, expected_severity);
|
||||
|
||||
let expected_domain = unsafe { translate_domain(LogDomain::LdNet) };
|
||||
assert_eq!(domain, expected_domain);
|
||||
|
||||
assert_eq!("test_macro", function_name);
|
||||
assert_eq!("test log message a", log_msg);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_log_message_multiple_values() {
|
||||
fn test_macro<'a>() -> (c_int, u32, String, String) {
|
||||
let (x, y, z, a) = tor_log_msg!(
|
||||
LogSeverity::Warn,
|
||||
LogDomain::LdNet,
|
||||
"test_macro 2",
|
||||
"test log message {} {} {} {}",
|
||||
10,
|
||||
9,
|
||||
8,
|
||||
7
|
||||
);
|
||||
(x, y, z, a)
|
||||
}
|
||||
|
||||
let (severity, domain, function_name, log_msg) = test_macro();
|
||||
|
||||
let expected_severity =
|
||||
unsafe { translate_severity(LogSeverity::Warn) };
|
||||
assert_eq!(severity, expected_severity);
|
||||
|
||||
let expected_domain = unsafe { translate_domain(LogDomain::LdNet) };
|
||||
assert_eq!(domain, expected_domain);
|
||||
|
||||
assert_eq!("test_macro 2", function_name);
|
||||
assert_eq!("test log message 10 9 8 7", log_msg);
|
||||
}
|
||||
}
|
@ -11,6 +11,9 @@ crate_type = ["rlib", "staticlib"]
|
||||
[dependencies.tor_allocate]
|
||||
path = "../tor_allocate"
|
||||
|
||||
[dependencies.tor_log]
|
||||
path = "../tor_log"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.22"
|
||||
|
||||
|
@ -5,8 +5,7 @@
|
||||
//! called from C.
|
||||
//!
|
||||
|
||||
use libc::c_char;
|
||||
use tor_allocate::allocate_and_copy_string;
|
||||
use tor_log::*;
|
||||
|
||||
/// Returns a short string to announce Rust support during startup.
|
||||
///
|
||||
@ -17,10 +16,12 @@ use tor_allocate::allocate_and_copy_string;
|
||||
/// tor_free(rust_str);
|
||||
/// ```
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_welcome_string() -> *mut c_char {
|
||||
let rust_welcome = String::from(
|
||||
pub extern "C" fn rust_welcome_string() {
|
||||
tor_log_msg!(
|
||||
LogSeverity::Notice,
|
||||
LogDomain::LdGeneral,
|
||||
"rust_welcome_string",
|
||||
"Tor is running with Rust integration. Please report \
|
||||
any bugs you encounter.",
|
||||
any bugs you encounter."
|
||||
);
|
||||
allocate_and_copy_string(&rust_welcome)
|
||||
}
|
||||
|
@ -7,5 +7,6 @@
|
||||
|
||||
extern crate libc;
|
||||
extern crate tor_allocate;
|
||||
extern crate tor_log;
|
||||
|
||||
pub mod ffi;
|
||||
|
@ -11,7 +11,7 @@ for crate in $crates; do
|
||||
cd "${abs_top_builddir:-../../..}/src/rust"
|
||||
CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \
|
||||
CARGO_HOME="${abs_top_builddir:-../../..}/src/rust" \
|
||||
"${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} \
|
||||
"${CARGO:-cargo}" test --all-features ${CARGO_ONLINE-"--frozen"} \
|
||||
--manifest-path "${abs_top_srcdir:-.}/src/rust/${crate}/Cargo.toml" \
|
||||
|| exitcode=1
|
||||
cd -
|
||||
|
Loading…
Reference in New Issue
Block a user