Here is a tentative socket constructor:
use std::net::TcpStream;
use rustls::{ClientConnection, RootCertStore, Stream};
pub struct TlsSocket<'a> {
tls_instance: Stream<'a, ClientConnection, TcpStream>,
}
impl<'a> TlsSocket<'a> {
pub fn new() -> Self {
let root_store = RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
let mut config = rustls::ClientConfig::builder()
.with_root_certificates(root_store)
.with_no_client_auth();
// Allow using SSLKEYLOGFILE.
config.key_log = Arc::new(rustls::KeyLogFile::new());
let server_name = "my_site.net".try_into().unwrap();
let mut conn = rustls::ClientConnection::new(Arc::new(config), server_name).unwrap();
let mut sock = TcpStream::connect("my_site.net:8000").unwrap();
let tls = rustls::Stream::new(&mut conn, &mut sock);
TlsSocket { tls_instance: tls }
}
}
However, I get the error:
cannot return value referencing local variable `sock`
returns a value referencing data owned by the current function
I think I understand the error: at the end of the function new
, conn
and sock
cannot be dangling. new
should move them out, somehow.
I thought the lifetime annotation on Stream would let the compiler know that conn
and sock
must exist as long as the tls
rustls::Stream
exists...
pub struct Stream<'a, C, T>
where
C: 'a + ?Sized,
T: 'a + Read + Write + ?Sized, {
pub conn: &mut C,
pub sock: &mut T,
}
But that's not the case.
What I am doing wrong?
I thought the lifetime annotation on Stream would let the compiler know that
conn
andsock
must exist as long as the tlsrustls::Stream
exists...
You are correct -- it does convey exactly that information to the compiler. However, the compiler will not automatically make it so! You are responsible for putting them somewhere that will outlive the Stream
, and also where they won't be moved until the Stream
ceases to exist. Because you haven't, the compiler gives you this error.
In other words, lifetimes give the compiler enough information to verify that what you're doing is correct, but it won't magically do extra things to satisfy the lifetime constraints.
Stream
refers to an existing connection and socket, without taking ownership of them. Consider using StreamOwned
instead, which takes ownership of these values and therefore does not need to borrow anything.