trying to flesh out Transport and the SslTransport implementation of it

lumi created

Change summary

src/error.rs     |  8 ++++++
src/transport.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 62 insertions(+), 5 deletions(-)

Detailed changes

src/error.rs 🔗

@@ -6,10 +6,12 @@ use openssl::ssl::HandshakeError;
 use openssl::error::ErrorStack;
 
 use xml::reader::Error as XmlError;
+use xml::writer::Error as EmitterError;
 
 #[derive(Debug)]
 pub enum Error {
     XmlError(XmlError),
+    EmitterError(EmitterError),
     IoError(io::Error),
     HandshakeError(HandshakeError<TcpStream>),
     OpenSslErrorStack(ErrorStack),
@@ -22,6 +24,12 @@ impl From<XmlError> for Error {
     }
 }
 
+impl From<EmitterError> for Error {
+    fn from(err: EmitterError) -> Error {
+        Error::EmitterError(err)
+    }
+}
+
 impl From<io::Error> for Error {
     fn from(err: io::Error) -> Error {
         Error::IoError(err)

src/transport.rs 🔗

@@ -3,7 +3,10 @@ use std::io;
 
 use std::net::{SocketAddr, TcpStream};
 
-use xml::reader::{EventReader, XmlEvent};
+use xml::reader::{EventReader, XmlEvent as XmlReaderEvent};
+use xml::writer::{EventWriter, XmlEvent as XmlWriterEvent};
+
+use std::sync::{Arc, Mutex};
 
 use ns;
 
@@ -11,8 +14,50 @@ use error::Error;
 
 use openssl::ssl::{SslMethod, SslConnectorBuilder, SslStream};
 
+pub trait Transport {
+    fn write_event<'a, E: Into<XmlWriterEvent<'a>>>(&mut self, event: E) -> Result<(), Error>;
+    fn read_event(&mut self) -> Result<XmlReaderEvent, Error>;
+}
+
+struct LockedWrite<W: Write>(Arc<Mutex<W>>);
+
+impl<W: Write> io::Write for LockedWrite<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let mut inner = self.0.lock().unwrap(); // TODO: make safer
+        inner.write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        let mut inner = self.0.lock().unwrap(); // TODO: make safer
+        inner.flush()
+    }
+}
+
+struct LockedRead<R: Read>(Arc<Mutex<R>>);
+
+impl<R: Read> io::Read for LockedRead<R> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut inner = self.0.lock().unwrap(); // TODO: make safer
+        inner.read(buf)
+    }
+}
+
 pub struct SslTransport {
-    inner: SslStream<TcpStream>,
+    inner: Arc<Mutex<SslStream<TcpStream>>>, // TODO: this feels rather ugly
+    reader: EventReader<LockedRead<SslStream<TcpStream>>>, // TODO: especially feels ugly because
+                                                           //       this read would keep the lock
+                                                           //       held very long (potentially)
+    writer: EventWriter<LockedWrite<SslStream<TcpStream>>>,
+}
+
+impl Transport for SslTransport {
+    fn write_event<'a, E: Into<XmlWriterEvent<'a>>>(&mut self, event: E) -> Result<(), Error> {
+        Ok(self.writer.write(event)?)
+    }
+
+    fn read_event(&mut self) -> Result<XmlReaderEvent, Error> {
+        Ok(self.reader.next()?)
+    }
 }
 
 impl SslTransport {
@@ -26,7 +71,7 @@ impl SslTransport {
         let mut parser = EventReader::new(stream);
         loop { // TODO: possibly a timeout?
             match parser.next()? {
-                XmlEvent::StartElement { name, namespace, .. } => {
+                XmlReaderEvent::StartElement { name, namespace, .. } => {
                     if let Some(ns) = name.namespace {
                         if ns == ns::TLS && name.local_name == "proceed" {
                             break;
@@ -41,9 +86,13 @@ impl SslTransport {
         }
         let stream = parser.into_inner();
         let ssl_connector = SslConnectorBuilder::new(SslMethod::tls())?.build();
-        let ssl_stream = ssl_connector.connect(host, stream)?;
+        let ssl_stream = Arc::new(Mutex::new(ssl_connector.connect(host, stream)?));
+        let reader = EventReader::new(LockedRead(ssl_stream.clone()));
+        let writer = EventWriter::new(LockedWrite(ssl_stream.clone()));
         Ok(SslTransport {
-            inner: ssl_stream
+            inner: ssl_stream,
+            reader: reader,
+            writer: writer,
         })
     }
 }