Commit 864fd039 authored by eta's avatar eta
Browse files

Improve documentation around Cargo features; make Runtime require Debug

- arti#445 highlighted the lack of good documentation around Arti's
  multiple runtime support, as well as it being difficult to determine
  what runtime was actually in use.
- Improve the documentation to solve the first problem.
- To solve the second problem, make Runtime require Debug (which is
  arguably a good idea anyway, since it makes them easier to embed in
  things), and print out the current runtime's Debug information when
  arti is invoked with `--version`.
- (It also prints out other Cargo features, too!)

fixes arti#445
parent 0597c31a
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -67,17 +67,39 @@ follow Rust's semantic versioning best practices.)

Arti can act as a SOCKS proxy that uses the Tor network.

To try it out, run the demo program in `arti` as follows.  It will open a
To try it out, compile and run the `arti` binary using the below. It will open a
SOCKS proxy on port 9150.

    % cargo run --release -- proxy
    $ cargo run -p arti --release -- proxy

Again, do not use this program yet if you seriously need anonymity, privacy,
security, or stability.

You can build a binary (but not run it) with:

    $ cargo build -p arti --release

The result can be found as `target/release/arti`.

If you run into any trouble building the program, please have a
look at [the troubleshooting guide](doc/TROUBLESHOOTING.md).

### Custom compile-time options

Arti has a number of configurable [Cargo features](https://doc.rust-lang.org/cargo/reference/features.html) that,
among other things, can affect which asynchronous runtime to use. Use

    $ cargo doc -p arti --open

to view the Arti crate-level docs in your browser, which contain a full list.

You can pass these features to Cargo while building with `--features` (note that you might need `--no-default-features`
in order to not use the default runtime choices, too). For example, to use `async-std` instead of Tokio:

    $ cargo run -p arti --no-default-features --features async-std,native-tls -- proxy

Use `target/release/arti --version` to see what features the currently built Arti binary is using.

## Minimum supported Rust Version

Our current Minimum Supported Rust Version (MSRV) is 1.56.
+49 −14
Original line number Diff line number Diff line
@@ -140,6 +140,39 @@ use tracing::{info, warn};
/// Shorthand for a boxed and pinned Future.
type PinnedFuture<T> = std::pin::Pin<Box<dyn futures::Future<Output = T>>>;

/// Create a runtime for Arti to use.
fn create_runtime() -> std::io::Result<impl Runtime> {
    cfg_if::cfg_if! {
        if #[cfg(all(feature="tokio", feature="native-tls"))] {
        use tor_rtcompat::tokio::TokioNativeTlsRuntime as ChosenRuntime;
        } else if #[cfg(all(feature="tokio", feature="rustls"))] {
            use tor_rtcompat::tokio::TokioRustlsRuntime as ChosenRuntime;
        } else if #[cfg(all(feature="async-std", feature="native-tls"))] {
            use tor_rtcompat::async_std::AsyncStdNativeTlsRuntime as ChosenRuntime;
        } else if #[cfg(all(feature="async-std", feature="rustls"))] {
            use tor_rtcompat::async_std::AsyncStdRustlsRuntime as ChosenRuntime;
        } else {
            compile_error!("You must configure both an async runtime and a TLS stack. See doc/TROUBLESHOOTING.md for more.");
        }
    }
    ChosenRuntime::create()
}

/// Return a (non-exhaustive) array of enabled Cargo features, for version printing purposes.
fn list_enabled_features() -> &'static [&'static str] {
    // HACK(eta): We can't get this directly, so we just do this awful hack instead.
    // Note that we only list features that aren't about the runtime used, since that already
    // gets printed separately.
    &[
        #[cfg(feature = "journald")]
        "journald",
        #[cfg(feature = "static-sqlite")]
        "static-sqlite",
        #[cfg(feature = "static-native-tls")]
        "static-native-tls",
    ]
}

/// Run the main loop of the proxy.
///
/// # Panics
@@ -234,9 +267,25 @@ pub fn main_main() -> Result<()> {
        config_file_help.push_str(&format!(" Defaults to {:?}", default));
    }

    // We create the runtime now so that we can use its `Debug` impl to describe it for
    // the version string.
    let runtime = create_runtime()?;
    let features = list_enabled_features();
    let long_version = format!(
        "{}\nusing runtime: {:?}\noptional features: {}",
        env!("CARGO_PKG_VERSION"),
        runtime,
        if features.is_empty() {
            "<none>".into()
        } else {
            features.join(", ")
        }
    );

    let matches =
        App::new("Arti")
            .version(env!("CARGO_PKG_VERSION"))
            .long_version(&long_version as &str)
            .author("The Tor Project Developers")
            .about("A Rust Tor implementation.")
            // HACK(eta): clap generates "arti [OPTIONS] <SUBCOMMAND>" for this usage string by
@@ -379,20 +428,6 @@ pub fn main_main() -> Result<()> {

        process::use_max_file_limit(&config);

        cfg_if::cfg_if! {
            if #[cfg(all(feature="tokio", feature="native-tls"))] {
            use tor_rtcompat::tokio::TokioNativeTlsRuntime as ChosenRuntime;
            } else if #[cfg(all(feature="tokio", feature="rustls"))] {
                use tor_rtcompat::tokio::TokioRustlsRuntime as ChosenRuntime;
            } else if #[cfg(all(feature="async-std", feature="native-tls"))] {
                use tor_rtcompat::async_std::AsyncStdNativeTlsRuntime as ChosenRuntime;
            } else if #[cfg(all(feature="async-std", feature="rustls"))] {
                use tor_rtcompat::async_std::AsyncStdRustlsRuntime as ChosenRuntime;
            }
        }

        let runtime = ChosenRuntime::create()?;

        let rt_copy = runtime.clone();
        rt_copy.block_on(run(
            runtime,
+3 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ use async_trait::async_trait;
use futures::stream;
use futures::task::Spawn;
use futures::{AsyncRead, AsyncWrite, Future};
use std::fmt::Debug;
use std::io::Result as IoResult;
use std::net::SocketAddr;
use std::time::{Duration, Instant, SystemTime};
@@ -53,6 +54,7 @@ pub trait Runtime:
    + TcpProvider
    + TlsProvider<Self::TcpStream>
    + UdpProvider
    + Debug
    + 'static
{
}
@@ -67,6 +69,7 @@ impl<T> Runtime for T where
        + TcpProvider
        + TlsProvider<Self::TcpStream>
        + UdpProvider
        + Debug
        + 'static
{
}
+2 −0
Original line number Diff line number Diff line
@@ -137,6 +137,8 @@
#![warn(clippy::unseparated_literal_suffix)]
#![deny(clippy::unwrap_used)]

extern crate core;

pub mod io;
pub mod net;
pub mod time;
+8 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@

use super::io::{stream_pair, LocalStream};
use super::MockNetRuntime;
use core::fmt;
use tor_rtcompat::tls::TlsConnector;
use tor_rtcompat::{CertifiedConn, Runtime, TcpListener, TcpProvider, TlsProvider};

@@ -18,6 +19,7 @@ use futures::sink::SinkExt;
use futures::stream::{Stream, StreamExt};
use futures::FutureExt;
use std::collections::HashMap;
use std::fmt::Formatter;
use std::io::{Error as IoError, ErrorKind, Result as IoResult};
use std::net::{IpAddr, SocketAddr};
use std::pin::Pin;
@@ -103,6 +105,12 @@ pub struct MockNetProvider {
    inner: Arc<MockNetProviderInner>,
}

impl fmt::Debug for MockNetProvider {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("MockNetProvider").finish_non_exhaustive()
    }
}

/// Shared part of a MockNetworkProvider.
///
/// This is separate because providers need to implement Clone, but
Loading