Support inheriting TCP listener from parent process via file descriptor zero.
Closes #36
Diff
Cargo.lock | 21 +++++++++++++++++++++
Cargo.toml | 1 +
src/config.rs | 13 +++++++++++++
src/server.rs | 43 ++++++++++++++++++++++++++++++++++---------
4 files changed, 69 insertions(+), 9 deletions(-)
@@ -485,6 +485,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
[[package]]
name = "listenfd"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "492158e732f2e2de81c592f0a2427e57e12cd3d59877378fe7af624b6bbe0ca1"
dependencies = [
"libc",
"uuid",
"winapi",
]
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -858,6 +869,7 @@ dependencies = [
"humansize",
"hyper",
"jemallocator",
"listenfd",
"mime_guess",
"nix",
"num_cpus",
@@ -1117,6 +1129,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "uuid"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
dependencies = [
"cfg-if 0.1.10",
]
[[package]]
name = "version_check"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -45,6 +45,7 @@ pin-project = "1.0"
tokio-rustls = { version = "0.22" }
humansize = "1.1"
time = "0.1"
listenfd = "0.3.3"
[target.'cfg(not(windows))'.dependencies.nix]
version = "0.14"
@@ -13,6 +13,19 @@ pub struct Config {
#[structopt(
long,
short = "f",
env = "SERVER_LISTEN_FD",
conflicts_with_all(&["host", "port"])
)]
pub fd: Option<usize>,
#[structopt(
long,
short = "n",
default_value = "1",
env = "SERVER_THREADS_MULTIPLIER"
@@ -1,7 +1,8 @@
use hyper::server::conn::AddrIncoming;
use hyper::server::Server as HyperServer;
use hyper::service::{make_service_fn, service_fn};
use std::net::{IpAddr, SocketAddr};
use listenfd::ListenFd;
use std::net::{IpAddr, SocketAddr, TcpListener};
use std::sync::Arc;
use structopt::StructOpt;
@@ -58,8 +59,26 @@ impl Server {
tracing::info!("runtime worker threads: {}", self.threads);
let ip = opts.host.parse::<IpAddr>()?;
let addr = SocketAddr::from((ip, opts.port));
let (tcplistener, addr_string);
match opts.fd {
Some(fd) => {
addr_string = format!("@FD({})", fd);
tcplistener = ListenFd::from_env()
.take_tcp_listener(fd)?
.expect("Failed to convert inherited FD into a a TCP listener");
tracing::info!(
"Converted inherited file descriptor {} to a TCP listener",
fd
);
}
None => {
let ip = opts.host.parse::<IpAddr>()?;
let addr = SocketAddr::from((ip, opts.port));
tcplistener = TcpListener::bind(addr)?;
addr_string = format!("{:?}", addr);
tracing::info!("Bound to TCP socket {}", addr_string);
}
}
let root_dir = helpers::get_valid_dirpath(&opts.root)?;
@@ -111,7 +130,12 @@ impl Server {
}
});
let mut incoming = AddrIncoming::bind(&addr)?;
tcplistener
.set_nonblocking(true)
.expect("Cannot set non-blocking");
let listener = tokio::net::TcpListener::from_std(tcplistener)
.expect("Failed to create tokio::net::TcpListener");
let mut incoming = AddrIncoming::from_listener(listener)?;
incoming.set_nodelay(true);
let tls = TlsConfigBuilder::new()
@@ -124,9 +148,9 @@ impl Server {
HyperServer::builder(TlsAcceptor::new(tls, incoming)).serve(make_service);
tracing::info!(
parent: tracing::info_span!("Server::start_server", ?addr, ?threads),
parent: tracing::info_span!("Server::start_server", ?addr_string, ?threads),
"listening on https://{}",
addr
addr_string
);
server.await
@@ -153,14 +177,15 @@ impl Server {
}
});
let server = HyperServer::bind(&addr)
let server = HyperServer::from_tcp(tcplistener)
.unwrap()
.tcp_nodelay(true)
.serve(make_service);
tracing::info!(
parent: tracing::info_span!("Server::start_server", ?addr, ?threads),
parent: tracing::info_span!("Server::start_server", ?addr_string, ?threads),
"listening on http://{}",
addr
addr_string
);
server.await