rust_thrift_tls/
tls_socket.rs1use std::io::{self, ErrorKind, Read, Write};
19use std::net::{Shutdown, TcpStream};
20use std::sync::{Arc, Mutex};
21
22use thrift::transport::{ReadHalf, TIoChannel, WriteHalf};
23use thrift::{new_transport_error, TransportErrorKind};
24
25use rustls::StreamOwned as RusTLSStream;
26use rustls::{ClientSession, RootCertStore, ServerSession, Session};
27use webpki;
28
29use super::X509Credentials;
30
31pub type TLSStream<S> = Arc<Mutex<RusTLSStream<S, TcpStream>>>;
32
33pub struct TLSTTcpChannel<S>
36where
37 S: Session,
38{
39 stream: Option<TLSStream<S>>,
40 shutdown: Shutdown,
41}
42
43impl<S> TLSTTcpChannel<S>
44where
45 S: Session,
46{
47 pub fn new() -> TLSTTcpChannel<S> {
52 TLSTTcpChannel {
53 stream: None,
54 shutdown: Shutdown::Both,
55 }
56 }
57
58 pub fn close(&mut self) -> thrift::Result<()> {
63 let shutdown_direction = self.shutdown;
64 self.if_set(|s| s.get_mut().shutdown(shutdown_direction))
65 .map_err(From::from)
66 }
67
68 fn if_set<F, T>(&mut self, mut stream_operation: F) -> io::Result<T>
69 where
70 F: FnMut(&mut RusTLSStream<S, TcpStream>) -> io::Result<T>,
71 {
72 if let Some(ref mut s) = self.stream {
73 stream_operation(&mut s.lock().unwrap())
74 } else {
75 Err(io::Error::new(
76 ErrorKind::NotConnected,
77 "tcp endpoint not connected",
78 ))
79 }
80 }
81}
82
83impl TLSTTcpChannel<ServerSession> {
84 pub fn with_stream(stream: TLSStream<ServerSession>) -> TLSTTcpChannel<ServerSession> {
89 TLSTTcpChannel {
90 stream: Some(stream),
91 shutdown: Shutdown::Both,
92 }
93 }
94}
95
96impl TLSTTcpChannel<ClientSession> {
97 pub fn open(
102 &mut self,
103 remote_address: &str,
104 key_pair: Option<X509Credentials>,
105 root_cert_store: Option<RootCertStore>,
106 ) -> thrift::Result<()> {
107 if self.stream.is_some() {
108 Err(new_transport_error(
109 TransportErrorKind::AlreadyOpen,
110 "TLS session connection previously opened",
111 ))
112 } else {
113 let tsap: Vec<&str> = remote_address.rsplit(':').collect();
114 if tsap.len() != 2 {
115 return Err(new_transport_error(
116 TransportErrorKind::Unknown,
117 format!("Invalid remote address: '{}'", remote_address),
118 ));
119 }
120
121 let dns_name = match webpki::DNSNameRef::try_from_ascii_str(tsap[1]) {
122 Ok(dns_nameref) => dns_nameref,
123 Err(e) => {
124 return Err(new_transport_error(
125 TransportErrorKind::Unknown,
126 format!("Invalid DNS name: '{}'", e),
127 ))
128 }
129 };
130 let config = super::make_tls_client_config(key_pair, root_cert_store);
131
132 let sess = ClientSession::new(&config, dns_name);
133 let sock = TcpStream::connect(remote_address).unwrap();
134 self.stream = Some(Arc::new(Mutex::new(RusTLSStream::new(sess, sock))));
135
136 Ok(())
137 }
138 }
139}
140
141impl<S> TIoChannel for TLSTTcpChannel<S>
142where
143 S: Session,
144{
145 fn split(self) -> thrift::Result<(ReadHalf<Self>, WriteHalf<Self>)>
146 where
147 Self: Sized,
148 {
149 if let Some(stream) = self.stream {
150 let read_half = ReadHalf::new(TLSTTcpChannel {
151 stream: Some(stream.clone()),
152 shutdown: Shutdown::Read,
153 });
154 let write_half = WriteHalf::new(TLSTTcpChannel {
155 stream: Some(stream),
156 shutdown: Shutdown::Write,
157 });
158 Ok((read_half, write_half))
159 } else {
160 Err(new_transport_error(
161 TransportErrorKind::Unknown,
162 "cannot clone underlying tcp stream",
163 ))
164 }
165 }
166}
167
168impl<S> Read for TLSTTcpChannel<S>
169where
170 S: Session,
171{
172 fn read(&mut self, b: &mut [u8]) -> io::Result<usize> {
173 self.if_set(|s| s.read(b))
174 }
175}
176
177impl<S> Write for TLSTTcpChannel<S>
178where
179 S: Session,
180{
181 fn write(&mut self, b: &[u8]) -> io::Result<usize> {
182 self.if_set(|s| s.write(b))
183 }
184
185 fn flush(&mut self) -> io::Result<()> {
186 self.if_set(|s| s.flush())
187 }
188}