diff --git a/Cargo.lock b/Cargo.lock index aa4e467..d7c64c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,6 +63,7 @@ dependencies = [ "mio", "native-tls", "serde", + "socket2", ] [[package]] @@ -91,7 +92,6 @@ dependencies = [ "serde", "serde_urlencoded", "simplelog", - "socket2", ] [[package]] diff --git a/aquatic_common_tcp/Cargo.toml b/aquatic_common_tcp/Cargo.toml index f24dae0..ddbd123 100644 --- a/aquatic_common_tcp/Cargo.toml +++ b/aquatic_common_tcp/Cargo.toml @@ -13,4 +13,5 @@ anyhow = "1" aquatic_common = { path = "../aquatic_common" } mio = { version = "0.7", features = ["tcp", "os-poll", "os-util"] } native-tls = "0.2" -serde = { version = "1", features = ["derive"] } \ No newline at end of file +serde = { version = "1", features = ["derive"] } +socket2 = { version = "0.3", features = ["reuseport"] } \ No newline at end of file diff --git a/aquatic_common_tcp/src/config.rs b/aquatic_common_tcp/src/config.rs index 8cd23e3..f463f4f 100644 --- a/aquatic_common_tcp/src/config.rs +++ b/aquatic_common_tcp/src/config.rs @@ -1,3 +1,5 @@ +use std::net::SocketAddr; + use serde::{Serialize, Deserialize}; @@ -29,6 +31,14 @@ pub struct HandlerConfig { pub channel_recv_timeout_microseconds: u64, } +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(default)] +pub struct SocketConfig { + /// Bind to this address + pub address: SocketAddr, + pub ipv6_only: bool, +} + #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(default)] @@ -73,6 +83,16 @@ impl Default for HandlerConfig { } +impl Default for SocketConfig { + fn default() -> Self { + Self { + address: SocketAddr::from(([0, 0, 0, 0], 3000)), + ipv6_only: false, + } + } +} + + impl Default for TlsConfig { fn default() -> Self { Self { diff --git a/aquatic_common_tcp/src/network/mod.rs b/aquatic_common_tcp/src/network/mod.rs index 0915833..7f80efd 100644 --- a/aquatic_common_tcp/src/network/mod.rs +++ b/aquatic_common_tcp/src/network/mod.rs @@ -5,8 +5,9 @@ use std::io::Read; use anyhow::Context; use native_tls::{Identity, TlsAcceptor}; +use socket2::{Socket, Domain, Type, Protocol}; -use crate::config::TlsConfig; +use crate::config::{TlsConfig, SocketConfig}; pub fn create_tls_acceptor( @@ -32,4 +33,33 @@ pub fn create_tls_acceptor( } else { Ok(None) } +} + + +// will be almost identical to ws version +pub fn create_listener( + config: &SocketConfig +) -> ::anyhow::Result<::std::net::TcpListener> { + let builder = if config.address.is_ipv4(){ + Socket::new(Domain::ipv4(), Type::stream(), Some(Protocol::tcp())) + } else { + Socket::new(Domain::ipv6(), Type::stream(), Some(Protocol::tcp())) + }.context("Couldn't create socket2::Socket")?; + + if config.ipv6_only { + builder.set_only_v6(true) + .context("Couldn't put socket in ipv6 only mode")? + } + + builder.set_nonblocking(true) + .context("Couldn't put socket in non-blocking mode")?; + builder.set_reuse_port(true) + .context("Couldn't put socket in reuse_port mode")?; + builder.bind(&config.address.into()).with_context(|| + format!("Couldn't bind socket to address {}", config.address) + )?; + builder.listen(128) + .context("Couldn't listen for connections on socket")?; + + Ok(builder.into_tcp_listener()) } \ No newline at end of file diff --git a/aquatic_http/Cargo.toml b/aquatic_http/Cargo.toml index aa44523..7d0d5b0 100644 --- a/aquatic_http/Cargo.toml +++ b/aquatic_http/Cargo.toml @@ -33,7 +33,6 @@ privdrop = "0.3" rand = { version = "0.7", features = ["small_rng"] } serde = { version = "1", features = ["derive"] } serde_urlencoded = "0.6" -socket2 = { version = "0.3", features = ["reuseport"] } simplelog = "0.8" [dev-dependencies] diff --git a/aquatic_http/src/lib/config.rs b/aquatic_http/src/lib/config.rs index 78ca6a5..89c84ac 100644 --- a/aquatic_http/src/lib/config.rs +++ b/aquatic_http/src/lib/config.rs @@ -1,5 +1,3 @@ -use std::net::SocketAddr; - use serde::{Serialize, Deserialize}; pub use aquatic_common_tcp::config::*; @@ -21,12 +19,12 @@ pub struct Config { } + #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(default)] pub struct NetworkConfig { - /// Bind to this address - pub address: SocketAddr, - pub ipv6_only: bool, + #[serde(flatten)] + pub socket: SocketConfig, #[serde(flatten)] pub tls: TlsConfig, pub poll_event_capacity: usize, @@ -34,7 +32,6 @@ pub struct NetworkConfig { } - #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(default)] pub struct ProtocolConfig { @@ -66,8 +63,7 @@ impl Default for Config { impl Default for NetworkConfig { fn default() -> Self { Self { - address: SocketAddr::from(([0, 0, 0, 0], 3000)), - ipv6_only: false, + socket: SocketConfig::default(), tls: TlsConfig::default(), poll_event_capacity: 4096, poll_timeout_milliseconds: 50, diff --git a/aquatic_http/src/lib/network/mod.rs b/aquatic_http/src/lib/network/mod.rs index 3506ea7..a63aa23 100644 --- a/aquatic_http/src/lib/network/mod.rs +++ b/aquatic_http/src/lib/network/mod.rs @@ -10,6 +10,8 @@ use native_tls::TlsAcceptor; use mio::{Events, Poll, Interest, Token}; use mio::net::TcpListener; +use aquatic_common_tcp::network::create_listener; + use crate::common::*; use crate::config::Config; use crate::protocol::*; @@ -67,7 +69,7 @@ pub fn run_socket_worker( response_channel_receiver: ResponseChannelReceiver, opt_tls_acceptor: Option, ){ - match create_listener(&config){ + match create_listener(&config.network.socket){ Ok(listener) => { socket_worker_statuses.lock()[socket_worker_index] = Some(Ok(())); diff --git a/aquatic_http/src/lib/network/utils.rs b/aquatic_http/src/lib/network/utils.rs index 08e57a2..2e07c22 100644 --- a/aquatic_http/src/lib/network/utils.rs +++ b/aquatic_http/src/lib/network/utils.rs @@ -2,42 +2,10 @@ use std::time::Instant; use anyhow::Context; use mio::Token; -use socket2::{Socket, Domain, Type, Protocol}; - -use crate::config::Config; use super::*; -// will be almost identical to ws version -pub fn create_listener( - config: &Config -) -> ::anyhow::Result<::std::net::TcpListener> { - let builder = if config.network.address.is_ipv4(){ - Socket::new(Domain::ipv4(), Type::stream(), Some(Protocol::tcp())) - } else { - Socket::new(Domain::ipv6(), Type::stream(), Some(Protocol::tcp())) - }.context("Couldn't create socket2::Socket")?; - - if config.network.ipv6_only { - builder.set_only_v6(true) - .context("Couldn't put socket in ipv6 only mode")? - } - - builder.set_nonblocking(true) - .context("Couldn't put socket in non-blocking mode")?; - builder.set_reuse_port(true) - .context("Couldn't put socket in reuse_port mode")?; - builder.bind(&config.network.address.into()).with_context(|| - format!("Couldn't bind socket to address {}", config.network.address) - )?; - builder.listen(128) - .context("Couldn't listen for connections on socket")?; - - Ok(builder.into_tcp_listener()) -} - - /// Don't bother with deregistering from Poll. In my understanding, this is /// done automatically when the stream is dropped, as long as there are no /// other references to the file descriptor, such as when it is accessed