aboutsummaryrefslogtreecommitdiffstats
path: root/src/cmd/server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/server.rs')
-rw-r--r--src/cmd/server.rs131
1 files changed, 114 insertions, 17 deletions
diff --git a/src/cmd/server.rs b/src/cmd/server.rs
index db3ae96..0633a77 100644
--- a/src/cmd/server.rs
+++ b/src/cmd/server.rs
@@ -1,6 +1,9 @@
use futures::future::Future as _;
use futures::stream::Stream as _;
+use snafu::futures01::stream::StreamExt as _;
+use snafu::futures01::FutureExt as _;
use snafu::ResultExt as _;
+use std::io::Read as _;
#[derive(Debug, snafu::Snafu)]
pub enum Error {
@@ -19,6 +22,38 @@ pub enum Error {
input: String,
source: std::num::ParseIntError,
},
+
+ #[snafu(display("failed to accept: {}", source))]
+ Acceptor { source: tokio::io::Error },
+
+ #[snafu(display(
+ "failed to send accepted socket to server thread: {}",
+ source
+ ))]
+ SocketChannel {
+ source: tokio::sync::mpsc::error::TrySendError<tokio::net::TcpStream>,
+ },
+
+ #[snafu(display("failed to send accepted socket to server thread"))]
+ TlsSocketChannel {
+ // XXX tokio_tls::Accept doesn't implement Debug or Display
+ // source: tokio::sync::mpsc::error::TrySendError<tokio_tls::Accept<tokio::net::TcpStream>>,
+ },
+
+ #[snafu(display("failed to run server: {}", source))]
+ Server { source: crate::server::Error },
+
+ #[snafu(display("failed to open identity file: {}", source))]
+ OpenIdentityFile { source: std::io::Error },
+
+ #[snafu(display("failed to read identity file: {}", source))]
+ ReadIdentityFile { source: std::io::Error },
+
+ #[snafu(display("failed to parse identity file: {}", source))]
+ ParseIdentity { source: native_tls::Error },
+
+ #[snafu(display("failed to create tls acceptor: {}", source))]
+ CreateAcceptor { source: native_tls::Error },
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -40,6 +75,11 @@ pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
.long("read-timeout")
.takes_value(true),
)
+ .arg(
+ clap::Arg::with_name("tls-identity-file")
+ .long("tls-identity-file")
+ .takes_value(true),
+ )
}
pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> {
@@ -70,34 +110,91 @@ pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> {
.context(super::Server)
},
)?;
- run_impl(address, buffer_size, read_timeout).context(super::Server)
+ let tls_identity_file = matches.value_of("tls-identity-file");
+ run_impl(address, buffer_size, read_timeout, tls_identity_file)
+ .context(super::Server)
}
fn run_impl(
address: std::net::SocketAddr,
buffer_size: usize,
read_timeout: std::time::Duration,
+ tls_identity_file: Option<&str>,
) -> Result<()> {
+ let (acceptor, server) =
+ if let Some(tls_identity_file) = tls_identity_file {
+ create_server_tls(
+ address,
+ buffer_size,
+ read_timeout,
+ tls_identity_file,
+ )?
+ } else {
+ create_server(address, buffer_size, read_timeout)?
+ };
+ tokio::run(futures::future::lazy(move || {
+ tokio::spawn(server.map_err(|e| {
+ eprintln!("{}", e);
+ }));
+
+ acceptor.map_err(|e| {
+ eprintln!("{}", e);
+ })
+ }));
+ Ok(())
+}
+
+fn create_server(
+ address: std::net::SocketAddr,
+ buffer_size: usize,
+ read_timeout: std::time::Duration,
+) -> Result<(
+ Box<dyn futures::future::Future<Item = (), Error = Error> + Send>,
+ Box<dyn futures::future::Future<Item = (), Error = Error> + Send>,
+)> {
let (mut sock_w, sock_r) = tokio::sync::mpsc::channel(100);
let listener = tokio::net::TcpListener::bind(&address).context(Bind)?;
let acceptor = listener
.incoming()
- .map_err(|e| {
- eprintln!("accept failed: {}", e);
- })
- .for_each(move |sock| {
- sock_w.try_send(sock).map_err(|e| {
- eprintln!("sending socket to manager thread failed: {}", e);
- })
- });
+ .context(Acceptor)
+ .for_each(move |sock| sock_w.try_send(sock).context(SocketChannel));
+ let server =
+ crate::server::Server::new(buffer_size, read_timeout, sock_r)
+ .context(Server);
+ Ok((Box::new(acceptor), Box::new(server)))
+}
- tokio::run(futures::future::lazy(move || {
- let server =
- crate::server::Server::new(buffer_size, read_timeout, sock_r)
- .map_err(|e| eprintln!("{}", e));
- tokio::spawn(server);
+fn create_server_tls(
+ address: std::net::SocketAddr,
+ buffer_size: usize,
+ read_timeout: std::time::Duration,
+ tls_identity_file: &str,
+) -> Result<(
+ Box<dyn futures::future::Future<Item = (), Error = Error> + Send>,
+ Box<dyn futures::future::Future<Item = (), Error = Error> + Send>,
+)> {
+ let (mut sock_w, sock_r) = tokio::sync::mpsc::channel(100);
+ let listener = tokio::net::TcpListener::bind(&address).context(Bind)?;
- acceptor
- }));
- Ok(())
+ let mut file =
+ std::fs::File::open(tls_identity_file).context(OpenIdentityFile)?;
+ let mut identity = vec![];
+ file.read_to_end(&mut identity).context(ReadIdentityFile)?;
+ let identity = native_tls::Identity::from_pkcs12(&identity, "")
+ .context(ParseIdentity)?;
+ let acceptor =
+ native_tls::TlsAcceptor::new(identity).context(CreateAcceptor)?;
+ let acceptor = tokio_tls::TlsAcceptor::from(acceptor);
+
+ let acceptor =
+ listener.incoming().context(Acceptor).for_each(move |sock| {
+ let sock = acceptor.accept(sock);
+ sock_w
+ .try_send(sock)
+ .map_err(|_| Error::TlsSocketChannel {})
+ });
+ let server =
+ crate::server::TlsServer::new(buffer_size, read_timeout, sock_r)
+ .context(Server);
+ Ok((Box::new(acceptor), Box::new(server)))
}