diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4636ce6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +target +docker +.git +tmp +documents diff --git a/TODO.md b/TODO.md index 1cc19ae..5396993 100644 --- a/TODO.md +++ b/TODO.md @@ -2,9 +2,6 @@ ## High priority -* ws - * add integration test for non-TLS configuration, maybe behind reverse proxy - ## Medium priority * quit whole program if any thread panics diff --git a/aquatic_common/src/access_list.rs b/aquatic_common/src/access_list.rs index d002d2f..04e7532 100644 --- a/aquatic_common/src/access_list.rs +++ b/aquatic_common/src/access_list.rs @@ -28,6 +28,7 @@ impl AccessListMode { } #[derive(Clone, Debug, PartialEq, TomlConfig, Deserialize)] +#[serde(default, deny_unknown_fields)] pub struct AccessListConfig { pub mode: AccessListMode, /// Path to access list file consisting of newline-separated hex-encoded info hashes. @@ -39,7 +40,7 @@ pub struct AccessListConfig { impl Default for AccessListConfig { fn default() -> Self { Self { - path: "".into(), + path: "./access-list.txt".into(), mode: AccessListMode::Off, } } @@ -63,6 +64,11 @@ impl AccessList { for line in reader.lines() { let line = line?; + let line = line.trim(); + + if line.is_empty() { + continue; + } new_list .insert_from_line(&line) diff --git a/aquatic_common/src/cli.rs b/aquatic_common/src/cli.rs index 6c9a2e0..db18f09 100644 --- a/aquatic_common/src/cli.rs +++ b/aquatic_common/src/cli.rs @@ -69,6 +69,7 @@ impl Options { "-h" | "--help" => { return Err(None); } + "" => (), _ => { return Err(Some("Unrecognized argument".to_string())); } diff --git a/aquatic_ws/src/lib.rs b/aquatic_ws/src/lib.rs index 7d48a08..d7e961d 100644 --- a/aquatic_ws/src/lib.rs +++ b/aquatic_ws/src/lib.rs @@ -96,6 +96,8 @@ pub fn run(config: Config) -> ::anyhow::Result<()> { executors.push(executor); } + ::log::info!("spawned socket workers"); + for i in 0..(config.swarm_workers) { let sentinel = sentinel.clone(); let config = config.clone(); @@ -129,6 +131,8 @@ pub fn run(config: Config) -> ::anyhow::Result<()> { executors.push(executor); } + ::log::info!("spawned swarm workers"); + if config.cpu_pinning.active { set_affinity_for_util_worker( &config.cpu_pinning, diff --git a/aquatic_ws/src/workers/socket.rs b/aquatic_ws/src/workers/socket.rs index fdfd5a9..61870c7 100644 --- a/aquatic_ws/src/workers/socket.rs +++ b/aquatic_ws/src/workers/socket.rs @@ -65,6 +65,8 @@ pub async fn run_socket_worker( let listener = create_tcp_listener(&config, priv_dropper).expect("create tcp listener"); + ::log::info!("created tcp listener"); + let (control_message_senders, _) = control_message_mesh_builder .join(Role::Producer) .await @@ -86,6 +88,8 @@ pub async fn run_socket_worker( out_message_mesh_builder.join(Role::Consumer).await.unwrap(); let out_message_consumer_id = ConsumerId(out_message_receivers.consumer_id().unwrap()); + ::log::info!("joined channels"); + let connection_slab = Rc::new(RefCell::new(Slab::new())); // Periodically clean connections @@ -718,28 +722,42 @@ fn create_tcp_listener( socket2::Domain::IPV6 }; + ::log::info!("creating socket.."); + let socket = socket2::Socket::new(domain, socket2::Type::STREAM, Some(socket2::Protocol::TCP)) .with_context(|| "create socket")?; if config.network.only_ipv6 { + ::log::info!("setting socket to ipv6 only.."); + socket .set_only_v6(true) .with_context(|| "socket: set only ipv6")?; } + ::log::info!("setting SO_REUSEPORT on socket.."); + socket .set_reuse_port(true) .with_context(|| "socket: set reuse port")?; + ::log::info!("binding socket.."); + socket .bind(&config.network.address.into()) .with_context(|| format!("socket: bind to {}", config.network.address))?; + ::log::info!("listening on socket.."); + socket .listen(config.network.tcp_backlog) .with_context(|| format!("socket: listen {}", config.network.address))?; + ::log::info!("running PrivilegeDropper::after_socket_creation.."); + priv_dropper.after_socket_creation()?; + ::log::info!("casting socket to glommio TcpListener.."); + Ok(unsafe { TcpListener::from_raw_fd(socket.into_raw_fd()) }) } diff --git a/docker/aquatic_udp.Dockerfile b/docker/aquatic_udp.Dockerfile new file mode 100644 index 0000000..1d9f4b6 --- /dev/null +++ b/docker/aquatic_udp.Dockerfile @@ -0,0 +1,44 @@ +# syntax=docker/dockerfile:1 + +# aquatic_udp +# +# Customize by setting CONFIG_FILE_CONTENTS and +# ACCESS_LIST_CONTENTS environment variables. +# +# By default runs tracker on port 3000 without info hash access control. +# +# Run from repository root directory with: +# $ DOCKER_BUILDKIT=1 docker build -t aquatic-udp -f docker/aquatic_udp.Dockerfile . +# $ docker run -it -p 0.0.0.0:3000:3000/udp --name aquatic-udp aquatic-udp +# +# Pass --network="host" to run command for much better performance. + +FROM rust:latest AS builder + +WORKDIR /usr/src/aquatic + +COPY . . + +RUN . ./scripts/env-native-cpu-without-avx-512 && cargo build --release -p aquatic_udp + +FROM debian:stable-slim + +ENV CONFIG_FILE_CONTENTS "log_level = 'warn'" +ENV ACCESS_LIST_CONTENTS "" + +WORKDIR /root/ + +COPY --from=builder /usr/src/aquatic/target/release/aquatic_udp ./ + +# Create entry point script for setting config and access +# list file contents at runtime +COPY <<-"EOT" ./entrypoint.sh +#!/bin/bash +echo -e "$CONFIG_FILE_CONTENTS" > ./config.toml +echo -e "$ACCESS_LIST_CONTENTS" > ./access-list.txt +exec ./aquatic_udp -c ./config.toml "$@" +EOT + +RUN chmod +x ./entrypoint.sh + +ENTRYPOINT ["./entrypoint.sh"] diff --git a/docker/aquatic_ws.Dockerfile b/docker/aquatic_ws.Dockerfile new file mode 100644 index 0000000..104e80c --- /dev/null +++ b/docker/aquatic_ws.Dockerfile @@ -0,0 +1,58 @@ +# syntax=docker/dockerfile:1 + +# aquatic_ws +# +# WORK IN PROGRESS: currently doesn't work due to issues with spawning worker +# threads, possibly related to https://github.com/DataDog/glommio/issues/547 +# +# Customize by setting CONFIG_FILE_CONTENTS and +# ACCESS_LIST_CONTENTS environment variables. +# +# If no changes are made to configuration, aquatic_ws is run: +# - on port 3000 +# - without TLS +# - with http health checks enabled +# - only allowing announces for hashes in access list, e.g., contained +# in ACCESS_LIST_CONTENTS env var +# +# Run from root directory of aquatic repository with: +# $ DOCKER_BUILDKIT=1 docker build -t aquatic-ws -f docker/aquatic_ws.Dockerfile . +# $ docker run -it --ulimit memlock=65536:65536 -p 0.0.0.0:3000:3000 --name aquatic-ws aquatic-ws +# +# Pass --network="host" to run command for much better performance. + +FROM rust:latest AS builder + +WORKDIR /usr/src/aquatic + +COPY . . + +RUN . ./scripts/env-native-cpu-without-avx-512 && cargo build --release -p aquatic_ws + +FROM debian:stable-slim + +ENV CONFIG_FILE_CONTENTS "\ + log_level = 'info'\n\ + [network]\n\ + enable_http_health_checks = true\n\ + [access_list]\n\ + mode = 'allow'\n\ + " +ENV ACCESS_LIST_CONTENTS "0f0f0f0f0f1f1f1f1f1f2f2f2f2f2f3f3f3f3f3f" + +WORKDIR /root/ + +COPY --from=builder /usr/src/aquatic/target/release/aquatic_ws ./ + +# Create entry point script for setting config and access +# list file contents at runtime +COPY <<-"EOT" ./entrypoint.sh +#!/bin/bash +echo -e "$CONFIG_FILE_CONTENTS" > ./config.toml +echo -e "$ACCESS_LIST_CONTENTS" > ./access-list.txt +exec ./aquatic_ws -c ./config.toml "$@" +EOT + +RUN chmod +x ./entrypoint.sh + +ENTRYPOINT ["./entrypoint.sh"]