Commit 431856d7 authored by opara's avatar opara 🙃
Browse files

arti: add 'proxy.socket_{send,recv}_buf_size' config options

parent db8a3fc5
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -61,6 +61,16 @@
# https://spec.torproject.org/http-connect.html
#enable_http_connect = true

# The socket buffer sizes (`SO_SNDBUF` and `SO_RCVBUF`) to use for
# SOCKS and HTTP CONNECT sockets.
#
# The defaults are intended to work well for all use cases.
# If you find that you need to change these options,
# you may want to open an issue at
# https://gitlab.torproject.org/tpo/core/arti/-/work_items.
#socket_send_buf_size = "128 KB"
#socket_recv_buf_size = "128 KB"

# Configure logging
[logging]

+28 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
// (This module is called `cfg` to avoid name clash with the `config` crate, which we use.)

use derive_deftly::Deftly;
use tor_basic_utils::ByteQty;
use tor_config_path::CfgPath;

#[cfg(feature = "onion-service-service")]
@@ -50,6 +51,23 @@ pub(crate) const ARTI_EXAMPLE_CONFIG: &str = concat!(include_str!("./arti-exampl
#[cfg(test)]
const OLDEST_SUPPORTED_CONFIG: &str = concat!(include_str!("./oldest-supported-config.toml"),);

// Our proxy sockets will use a small-ish fixed kernel socket buffer size.
// Tor streams are slow relative to a pair of loopback sockets,
// so don't need socket buffers as large as what Linux provides by default
// (sometimes several MBs).
//
// This has a few advantages over the defaults:
// - Less buffer bloat.
// - Better ability to make congestion/flow control decisions.
// - Disables TCP autotuning, which means behaviour will better match Shadow sims.
// - Easier to reason about stream performance when the buffer size isn't dynamic.
//
// See https://gitlab.torproject.org/tpo/core/arti/-/work_items/2500.
/// See [`ProxyConfig::socket_send_buf_size`].
const DEFAULT_SEND_BUF_SIZE: usize = 128_000;
/// See [`ProxyConfig::socket_recv_buf_size`].
const DEFAULT_RECV_BUF_SIZE: usize = 128_000;

/// Replacement for rpc config when the rpc feature is disabled.
#[cfg(not(feature = "rpc"))]
type RpcConfig = ();
@@ -120,6 +138,14 @@ pub(crate) struct ProxyConfig {
    ))]
    #[deftly(tor_config(default = "true"))]
    pub(crate) enable_http_connect: bool,

    /// The send buffer size (`SO_SNDBUF`) of proxy sockets.
    #[deftly(tor_config(default = "ByteQty(DEFAULT_SEND_BUF_SIZE)"))]
    pub(crate) socket_send_buf_size: ByteQty,

    /// The receive buffer size (`SO_RCVBUF`) of proxy sockets.
    #[deftly(tor_config(default = "ByteQty(DEFAULT_RECV_BUF_SIZE)"))]
    pub(crate) socket_recv_buf_size: ByteQty,
}

impl ProxyConfig {
@@ -561,6 +587,8 @@ mod test {
                "use_obsolete_software",
                "circuit_timing.disused_circuit_timeout",
                "storage.port_info_file",
                "proxy.socket_send_buf_size",
                "proxy.socket_recv_buf_size",
            ],
        );

+2 −20
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ use futures::stream::StreamExt;
use std::net::IpAddr;
use std::sync::Arc;
use tor_basic_utils::error_sources::ErrorSources;
use tor_rtcompat::{NetStreamProvider, SpawnExt};
use tor_rtcompat::{NetStreamProvider, SpawnExt, TcpListenOptions};
use tracing::{debug, error, info, instrument, warn};

#[allow(unused)]
@@ -386,6 +386,7 @@ pub(crate) async fn bind_proxy<R: Runtime>(
    runtime: R,
    tor_client: TorClient<R>,
    listen: Listen,
    listen_options: TcpListenOptions,
    protocols: ListenProtocols,
    rpc_mgr: Option<Arc<RpcMgr>>,
) -> Result<StreamProxy<R>> {
@@ -396,25 +397,6 @@ pub(crate) async fn bind_proxy<R: Runtime>(
        );
    }

    // Our proxy sockets will use a small-ish fixed kernel socket buffer size.
    // Tor streams are slow relative to a pair of loopback sockets,
    // so don't need socket buffers as large as what Linux provides by default
    // (sometimes several MBs).
    //
    // This has a few advantages over the defaults:
    // - Less buffer bloat.
    // - Better ability to make congestion/flow control decisions.
    // - Disables TCP autotuning, which means behaviour will better match Shadow sims.
    // - Easier to reason about stream performance when the buffer size isn't dynamic.
    //
    // See https://gitlab.torproject.org/tpo/core/arti/-/work_items/2500.
    let mut listen_options = tor_rtcompat::TcpListenOptions::builder();
    listen_options
        .common()
        .send_buffer_size(Some(128_000))
        .recv_buffer_size(Some(128_000));
    let listen_options = listen_options.build()?;

    let mut listeners = Vec::new();

    // Try to bind to the listener ports.
+18 −3
Original line number Diff line number Diff line
@@ -185,6 +185,14 @@ async fn run_proxy<R: ToplevelRuntime>(
        }
    }

    // The options that we'll use for our listening proxy sockets.
    let mut listen_options = tor_rtcompat::TcpListenOptions::builder();
    listen_options
        .common()
        .send_buffer_size(Some(arti_config.proxy().socket_send_buf_size.as_usize()))
        .recv_buffer_size(Some(arti_config.proxy().socket_recv_buf_size.as_usize()));
    let listen_options = listen_options.build()?;

    let mut proxy: Vec<PinnedFuture<Result<()>>> = Vec::new();
    let mut ports = Vec::new();
    if !socks_listen.is_empty() {
@@ -193,7 +201,14 @@ async fn run_proxy<R: ToplevelRuntime>(
        let socks_listen = socks_listen.clone();
        let listener_type = protocols.to_string();

        let stream_proxy = proxy::bind_proxy(runtime, client, socks_listen, protocols, rpc_mgr)
        let stream_proxy = proxy::bind_proxy(
            runtime,
            client,
            socks_listen,
            listen_options,
            protocols,
            rpc_mgr,
        )
        .await
        .with_context(|| format!("Unable to launch {listener_type} proxy"))?;
        let port_info = stream_proxy.port_info()?;