tokio-rustls: release 0.14.1 (#27)
* Support half-closed states #23 * Update examples
This commit is contained in:
parent
93d7c7590c
commit
e8a8a59971
@ -1,5 +1,7 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
"tokio-rustls"
|
"tokio-rustls",
|
||||||
|
"tokio-rustls/examples/client",
|
||||||
|
"tokio-rustls/examples/server"
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tokio-rustls"
|
name = "tokio-rustls"
|
||||||
version = "0.14.0"
|
version = "0.14.1"
|
||||||
authors = ["quininer kel <quininer@live.com>"]
|
authors = ["quininer kel <quininer@live.com>"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
repository = "https://github.com/tokio-rs/tls"
|
repository = "https://github.com/tokio-rs/tls"
|
||||||
|
@ -5,8 +5,7 @@ authors = ["quininer <quininer@live.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures-util = "0.3"
|
tokio = { version = "0.2", features = [ "full" ] }
|
||||||
tokio = { version = "0.2", features = [ "net", "io-std", "io-util", "rt-threaded" ] }
|
argh = "0.1"
|
||||||
structopt = "0.2"
|
|
||||||
tokio-rustls = { path = "../.." }
|
tokio-rustls = { path = "../.." }
|
||||||
webpki-roots = "0.18"
|
webpki-roots = "0.20"
|
||||||
|
@ -1,88 +1,80 @@
|
|||||||
use std::io;
|
use argh::FromArgs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::net::ToSocketAddrs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::net::ToSocketAddrs;
|
use tokio::io::{copy, split, stdin as tokio_stdin, stdout as tokio_stdout, AsyncWriteExt};
|
||||||
use std::io::BufReader;
|
|
||||||
use futures_util::future;
|
|
||||||
use structopt::StructOpt;
|
|
||||||
use tokio::runtime;
|
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio::io::{
|
use tokio_rustls::{rustls::ClientConfig, webpki::DNSNameRef, TlsConnector};
|
||||||
AsyncWriteExt,
|
|
||||||
copy, split,
|
|
||||||
stdin as tokio_stdin, stdout as tokio_stdout
|
|
||||||
};
|
|
||||||
use tokio_rustls::{ TlsConnector, rustls::ClientConfig, webpki::DNSNameRef };
|
|
||||||
|
|
||||||
|
/// Tokio Rustls client example
|
||||||
#[derive(StructOpt)]
|
#[derive(FromArgs)]
|
||||||
struct Options {
|
struct Options {
|
||||||
|
/// host
|
||||||
|
#[argh(positional)]
|
||||||
host: String,
|
host: String,
|
||||||
|
|
||||||
/// port
|
/// port
|
||||||
#[structopt(short="p", long="port", default_value="443")]
|
#[argh(option, short = 'p', default = "443")]
|
||||||
port: u16,
|
port: u16,
|
||||||
|
|
||||||
/// domain
|
/// domain
|
||||||
#[structopt(short="d", long="domain")]
|
#[argh(option, short = 'd')]
|
||||||
domain: Option<String>,
|
domain: Option<String>,
|
||||||
|
|
||||||
/// cafile
|
/// cafile
|
||||||
#[structopt(short="c", long="cafile", parse(from_os_str))]
|
#[argh(option, short = 'c')]
|
||||||
cafile: Option<PathBuf>
|
cafile: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
fn main() -> io::Result<()> {
|
async fn main() -> io::Result<()> {
|
||||||
let options = Options::from_args();
|
let options: Options = argh::from_env();
|
||||||
|
|
||||||
let addr = (options.host.as_str(), options.port)
|
let addr = (options.host.as_str(), options.port)
|
||||||
.to_socket_addrs()?
|
.to_socket_addrs()?
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| io::Error::from(io::ErrorKind::NotFound))?;
|
.ok_or_else(|| io::Error::from(io::ErrorKind::NotFound))?;
|
||||||
let domain = options.domain.unwrap_or(options.host);
|
let domain = options.domain.unwrap_or(options.host);
|
||||||
let content = format!(
|
let content = format!("GET / HTTP/1.0\r\nHost: {}\r\n\r\n", domain);
|
||||||
"GET / HTTP/1.0\r\nHost: {}\r\n\r\n",
|
|
||||||
domain
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut runtime = runtime::Builder::new()
|
|
||||||
.basic_scheduler()
|
|
||||||
.enable_io()
|
|
||||||
.build()?;
|
|
||||||
let mut config = ClientConfig::new();
|
let mut config = ClientConfig::new();
|
||||||
if let Some(cafile) = &options.cafile {
|
if let Some(cafile) = &options.cafile {
|
||||||
let mut pem = BufReader::new(File::open(cafile)?);
|
let mut pem = BufReader::new(File::open(cafile)?);
|
||||||
config.root_store.add_pem_file(&mut pem)
|
config
|
||||||
|
.root_store
|
||||||
|
.add_pem_file(&mut pem)
|
||||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))?;
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid cert"))?;
|
||||||
} else {
|
} else {
|
||||||
config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
config
|
||||||
|
.root_store
|
||||||
|
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
||||||
}
|
}
|
||||||
let connector = TlsConnector::from(Arc::new(config));
|
let connector = TlsConnector::from(Arc::new(config));
|
||||||
|
|
||||||
let fut = async {
|
let stream = TcpStream::connect(&addr).await?;
|
||||||
let stream = TcpStream::connect(&addr).await?;
|
|
||||||
|
|
||||||
let (mut stdin, mut stdout) = (tokio_stdin(), tokio_stdout());
|
let (mut stdin, mut stdout) = (tokio_stdin(), tokio_stdout());
|
||||||
|
|
||||||
let domain = DNSNameRef::try_from_ascii_str(&domain)
|
let domain = DNSNameRef::try_from_ascii_str(&domain)
|
||||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid dnsname"))?;
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid dnsname"))?;
|
||||||
|
|
||||||
let mut stream = connector.connect(domain, stream).await?;
|
let mut stream = connector.connect(domain, stream).await?;
|
||||||
stream.write_all(content.as_bytes()).await?;
|
stream.write_all(content.as_bytes()).await?;
|
||||||
|
|
||||||
let (mut reader, mut writer) = split(stream);
|
let (mut reader, mut writer) = split(stream);
|
||||||
future::select(
|
|
||||||
copy(&mut reader, &mut stdout),
|
|
||||||
copy(&mut stdin, &mut writer)
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.factor_first()
|
|
||||||
.0?;
|
|
||||||
|
|
||||||
Ok(())
|
tokio::select! {
|
||||||
};
|
ret = copy(&mut reader, &mut stdout) => {
|
||||||
|
ret?;
|
||||||
|
},
|
||||||
|
ret = copy(&mut stdin, &mut writer) => {
|
||||||
|
ret?;
|
||||||
|
writer.shutdown().await?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
runtime.block_on(fut)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ authors = ["quininer <quininer@live.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures-util = "0.3"
|
tokio = { version = "0.2", features = [ "full" ] }
|
||||||
tokio = { version = "0.2", features = [ "net", "io-util", "rt-threaded" ] }
|
argh = "0.1"
|
||||||
structopt = "0.2"
|
|
||||||
tokio-rustls = { path = "../.." }
|
tokio-rustls = { path = "../.." }
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
|
use argh::FromArgs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::sync::Arc;
|
use std::io::{self, BufReader};
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
use std::path::{ PathBuf, Path };
|
use std::path::{Path, PathBuf};
|
||||||
use std::io::{ self, BufReader };
|
use std::sync::Arc;
|
||||||
use futures_util::future::TryFutureExt;
|
use tokio::io::{copy, sink, split, AsyncWriteExt};
|
||||||
use structopt::StructOpt;
|
|
||||||
use tokio::runtime;
|
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tokio::io::{ AsyncWriteExt, copy, split };
|
use tokio_rustls::rustls::internal::pemfile::{certs, rsa_private_keys};
|
||||||
use tokio_rustls::rustls::{ Certificate, NoClientAuth, PrivateKey, ServerConfig };
|
use tokio_rustls::rustls::{Certificate, NoClientAuth, PrivateKey, ServerConfig};
|
||||||
use tokio_rustls::rustls::internal::pemfile::{ certs, rsa_private_keys };
|
|
||||||
use tokio_rustls::TlsAcceptor;
|
use tokio_rustls::TlsAcceptor;
|
||||||
|
|
||||||
|
/// Tokio Rustls server example
|
||||||
#[derive(StructOpt)]
|
#[derive(FromArgs)]
|
||||||
struct Options {
|
struct Options {
|
||||||
|
/// bind addr
|
||||||
|
#[argh(positional)]
|
||||||
addr: String,
|
addr: String,
|
||||||
|
|
||||||
/// cert file
|
/// cert file
|
||||||
#[structopt(short="c", long="cert", parse(from_os_str))]
|
#[argh(option, short = 'c')]
|
||||||
cert: PathBuf,
|
cert: PathBuf,
|
||||||
|
|
||||||
/// key file
|
/// key file
|
||||||
#[structopt(short="k", long="key", parse(from_os_str))]
|
#[argh(option, short = 'k')]
|
||||||
key: PathBuf,
|
key: PathBuf,
|
||||||
|
|
||||||
/// echo mode
|
/// echo mode
|
||||||
#[structopt(short="e", long="echo-mode")]
|
#[argh(switch, short = 'e')]
|
||||||
echo: bool
|
echo_mode: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_certs(path: &Path) -> io::Result<Vec<Certificate>> {
|
fn load_certs(path: &Path) -> io::Result<Vec<Certificate>> {
|
||||||
@ -40,60 +40,62 @@ fn load_keys(path: &Path) -> io::Result<Vec<PrivateKey>> {
|
|||||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))
|
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid key"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> io::Result<()> {
|
||||||
|
let options: Options = argh::from_env();
|
||||||
|
|
||||||
fn main() -> io::Result<()> {
|
let addr = options
|
||||||
let options = Options::from_args();
|
.addr
|
||||||
|
.to_socket_addrs()?
|
||||||
let addr = options.addr.to_socket_addrs()?
|
|
||||||
.next()
|
.next()
|
||||||
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?;
|
.ok_or_else(|| io::Error::from(io::ErrorKind::AddrNotAvailable))?;
|
||||||
let certs = load_certs(&options.cert)?;
|
let certs = load_certs(&options.cert)?;
|
||||||
let mut keys = load_keys(&options.key)?;
|
let mut keys = load_keys(&options.key)?;
|
||||||
let flag_echo = options.echo;
|
let flag_echo = options.echo_mode;
|
||||||
|
|
||||||
let mut runtime = runtime::Builder::new()
|
|
||||||
.threaded_scheduler()
|
|
||||||
.enable_io()
|
|
||||||
.build()?;
|
|
||||||
let handle = runtime.handle().clone();
|
|
||||||
let mut config = ServerConfig::new(NoClientAuth::new());
|
let mut config = ServerConfig::new(NoClientAuth::new());
|
||||||
config.set_single_cert(certs, keys.remove(0))
|
config
|
||||||
|
.set_single_cert(certs, keys.remove(0))
|
||||||
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
|
||||||
let acceptor = TlsAcceptor::from(Arc::new(config));
|
let acceptor = TlsAcceptor::from(Arc::new(config));
|
||||||
|
|
||||||
let fut = async {
|
let mut listener = TcpListener::bind(&addr).await?;
|
||||||
let mut listener = TcpListener::bind(&addr).await?;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (stream, peer_addr) = listener.accept().await?;
|
let (stream, peer_addr) = listener.accept().await?;
|
||||||
let acceptor = acceptor.clone();
|
let acceptor = acceptor.clone();
|
||||||
|
|
||||||
let fut = async move {
|
let fut = async move {
|
||||||
let mut stream = acceptor.accept(stream).await?;
|
let mut stream = acceptor.accept(stream).await?;
|
||||||
|
|
||||||
if flag_echo {
|
if flag_echo {
|
||||||
let (mut reader, mut writer) = split(stream);
|
let (mut reader, mut writer) = split(stream);
|
||||||
let n = copy(&mut reader, &mut writer).await?;
|
let n = copy(&mut reader, &mut writer).await?;
|
||||||
writer.flush().await?;
|
writer.flush().await?;
|
||||||
println!("Echo: {} - {}", peer_addr, n);
|
println!("Echo: {} - {}", peer_addr, n);
|
||||||
} else {
|
} else {
|
||||||
stream.write_all(
|
let mut output = sink();
|
||||||
|
stream
|
||||||
|
.write_all(
|
||||||
&b"HTTP/1.0 200 ok\r\n\
|
&b"HTTP/1.0 200 ok\r\n\
|
||||||
Connection: close\r\n\
|
Connection: close\r\n\
|
||||||
Content-length: 12\r\n\
|
Content-length: 12\r\n\
|
||||||
\r\n\
|
\r\n\
|
||||||
Hello world!"[..]
|
Hello world!"[..],
|
||||||
).await?;
|
)
|
||||||
stream.flush().await?;
|
.await?;
|
||||||
println!("Hello: {}", peer_addr);
|
stream.shutdown().await?;
|
||||||
}
|
copy(&mut stream, &mut output).await?;
|
||||||
|
println!("Hello: {}", peer_addr);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(()) as io::Result<()>
|
Ok(()) as io::Result<()>
|
||||||
};
|
};
|
||||||
|
|
||||||
handle.spawn(fut.unwrap_or_else(|err| eprintln!("{:?}", err)));
|
tokio::spawn(async move {
|
||||||
}
|
if let Err(err) = fut.await {
|
||||||
};
|
eprintln!("{:?}", err);
|
||||||
|
}
|
||||||
runtime.block_on(fut)
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user