Loading src/ssl/ffi.rs +3 −1 Original line number Diff line number Diff line #[doc(hidden)]; use std::libc::{c_int, c_long, c_void}; use std::libc::{c_int, c_void}; // openssl/ssl.h pub type SSL_CTX = c_void; Loading Loading @@ -35,6 +35,8 @@ externfn!(fn SSL_set_bio(ssl: *SSL, rbio: *BIO, wbio: *BIO)) externfn!(fn SSL_set_connect_state(ssl: *SSL)) externfn!(fn SSL_connect(ssl: *SSL) -> c_int) externfn!(fn SSL_get_error(ssl: *SSL, ret: c_int) -> c_int) externfn!(fn SSL_read(ssl: *SSL, buf: *c_void, num: c_int) -> c_int) externfn!(fn SSL_write(ssl: *SSL, buf: *c_void, num: c_int) -> c_int) externfn!(fn BIO_s_mem() -> *BIO_METHOD) externfn!(fn BIO_new(type_: *BIO_METHOD) -> *BIO) Loading src/ssl/lib.rs +74 −19 Original line number Diff line number Diff line use std::rt::io::{Stream, Decorator}; use std::rt::io::{Reader, Writer, Stream, Decorator}; use std::unstable::atomics::{AtomicBool, INIT_ATOMIC_BOOL, Acquire, Release}; use std::task; use std::ptr; Loading Loading @@ -70,6 +70,7 @@ impl Drop for Ssl { } } #[deriving(Eq, TotalEq, ToStr)] enum SslError { ErrorNone, ErrorSsl, Loading Loading @@ -114,6 +115,20 @@ impl Ssl { _ => unreachable!() } } fn read(&self, buf: &[u8]) -> int { unsafe { ffi::SSL_read(self.ssl, vec::raw::to_ptr(buf) as *c_void, buf.len() as c_int) as int } } fn write(&self, buf: &[u8]) -> int { unsafe { ffi::SSL_write(self.ssl, vec::raw::to_ptr(buf) as *c_void, buf.len() as c_int) as int } } } struct MemBio { Loading Loading @@ -150,12 +165,13 @@ impl MemBio { let ret = ffi::BIO_read(self.bio, vec::raw::to_ptr(buf) as *c_void, buf.len() as c_int); if ret < 0 { fail2!("read returned {}", ret); } 0 } else { ret as uint } } } } pub struct SslStream<S> { priv ctx: SslCtx, Loading @@ -179,47 +195,86 @@ impl<S: Stream> SslStream<S> { let mut stream = SslStream { ctx: ctx, ssl: ssl, // Max record size for SSLv3/TLSv1 is 16k buf: vec::from_elem(16 * 1024, 0u8), rbio: rbio, wbio: wbio, stream: stream }; stream.connect(); do stream.in_retry_wrapper |ssl| { ssl.ssl.connect() }; stream } fn connect(&mut self) { info!("in connect"); fn in_retry_wrapper(&mut self, blk: &fn(&mut SslStream<S>) -> int) -> Result<int, SslError> { loop { let ret = self.ssl.connect(); info2!("connect returned {}", ret); if ret == 1 { return; let ret = blk(self); if ret > 0 { return Ok(ret); } match self.ssl.get_error(ret) { ErrorWantRead => { info2!("want read"); self.flush(); match self.stream.read(self.buf) { Some(len) => self.rbio.write(self.buf.slice_to(len)), None => unreachable!() None => unreachable!() // FIXME } } ErrorWantWrite => { info2!("want write"); self.flush(); } _ => unreachable!() ErrorWantWrite => self.flush(), err => return Err(err) } } } fn flush(&mut self) { fn write_through(&mut self) { loop { let len = self.wbio.read(self.buf); if len == 0 { return; } self.stream.write(self.buf.slice_to(len)); } } } impl<S: Stream> Reader for SslStream<S> { fn read(&mut self, buf: &mut [u8]) -> Option<uint> { let ret = do self.in_retry_wrapper |ssl| { ssl.ssl.read(buf) }; match ret { Ok(num) => Some(num as uint), Err(_) => None } } fn eof(&mut self) -> bool { self.stream.eof() } } impl<S: Stream> Writer for SslStream<S> { fn write(&mut self, buf: &[u8]) { let ret = do self.in_retry_wrapper |ssl| { ssl.ssl.write(buf) }; match ret { Ok(_) => (), Err(err) => fail2!("Write error: {}", err.to_str()) } self.write_through(); } fn flush(&mut self) { self.write_through(); self.stream.flush(); } } Loading src/ssl/test.rs +10 −0 Original line number Diff line number Diff line extern mod ssl; use std::rt::io::{Writer}; use std::rt::io::net::tcp::TcpStream; use std::vec; use ssl::{Sslv23, SslCtx, SslStream}; Loading @@ -14,3 +16,11 @@ fn test_new_sslstream() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()); SslStream::new(SslCtx::new(Sslv23), stream); } #[test] fn test_write() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()); let mut stream = SslStream::new(SslCtx::new(Sslv23), stream); stream.write("hello".as_bytes()); stream.flush(); } Loading
src/ssl/ffi.rs +3 −1 Original line number Diff line number Diff line #[doc(hidden)]; use std::libc::{c_int, c_long, c_void}; use std::libc::{c_int, c_void}; // openssl/ssl.h pub type SSL_CTX = c_void; Loading Loading @@ -35,6 +35,8 @@ externfn!(fn SSL_set_bio(ssl: *SSL, rbio: *BIO, wbio: *BIO)) externfn!(fn SSL_set_connect_state(ssl: *SSL)) externfn!(fn SSL_connect(ssl: *SSL) -> c_int) externfn!(fn SSL_get_error(ssl: *SSL, ret: c_int) -> c_int) externfn!(fn SSL_read(ssl: *SSL, buf: *c_void, num: c_int) -> c_int) externfn!(fn SSL_write(ssl: *SSL, buf: *c_void, num: c_int) -> c_int) externfn!(fn BIO_s_mem() -> *BIO_METHOD) externfn!(fn BIO_new(type_: *BIO_METHOD) -> *BIO) Loading
src/ssl/lib.rs +74 −19 Original line number Diff line number Diff line use std::rt::io::{Stream, Decorator}; use std::rt::io::{Reader, Writer, Stream, Decorator}; use std::unstable::atomics::{AtomicBool, INIT_ATOMIC_BOOL, Acquire, Release}; use std::task; use std::ptr; Loading Loading @@ -70,6 +70,7 @@ impl Drop for Ssl { } } #[deriving(Eq, TotalEq, ToStr)] enum SslError { ErrorNone, ErrorSsl, Loading Loading @@ -114,6 +115,20 @@ impl Ssl { _ => unreachable!() } } fn read(&self, buf: &[u8]) -> int { unsafe { ffi::SSL_read(self.ssl, vec::raw::to_ptr(buf) as *c_void, buf.len() as c_int) as int } } fn write(&self, buf: &[u8]) -> int { unsafe { ffi::SSL_write(self.ssl, vec::raw::to_ptr(buf) as *c_void, buf.len() as c_int) as int } } } struct MemBio { Loading Loading @@ -150,12 +165,13 @@ impl MemBio { let ret = ffi::BIO_read(self.bio, vec::raw::to_ptr(buf) as *c_void, buf.len() as c_int); if ret < 0 { fail2!("read returned {}", ret); } 0 } else { ret as uint } } } } pub struct SslStream<S> { priv ctx: SslCtx, Loading @@ -179,47 +195,86 @@ impl<S: Stream> SslStream<S> { let mut stream = SslStream { ctx: ctx, ssl: ssl, // Max record size for SSLv3/TLSv1 is 16k buf: vec::from_elem(16 * 1024, 0u8), rbio: rbio, wbio: wbio, stream: stream }; stream.connect(); do stream.in_retry_wrapper |ssl| { ssl.ssl.connect() }; stream } fn connect(&mut self) { info!("in connect"); fn in_retry_wrapper(&mut self, blk: &fn(&mut SslStream<S>) -> int) -> Result<int, SslError> { loop { let ret = self.ssl.connect(); info2!("connect returned {}", ret); if ret == 1 { return; let ret = blk(self); if ret > 0 { return Ok(ret); } match self.ssl.get_error(ret) { ErrorWantRead => { info2!("want read"); self.flush(); match self.stream.read(self.buf) { Some(len) => self.rbio.write(self.buf.slice_to(len)), None => unreachable!() None => unreachable!() // FIXME } } ErrorWantWrite => { info2!("want write"); self.flush(); } _ => unreachable!() ErrorWantWrite => self.flush(), err => return Err(err) } } } fn flush(&mut self) { fn write_through(&mut self) { loop { let len = self.wbio.read(self.buf); if len == 0 { return; } self.stream.write(self.buf.slice_to(len)); } } } impl<S: Stream> Reader for SslStream<S> { fn read(&mut self, buf: &mut [u8]) -> Option<uint> { let ret = do self.in_retry_wrapper |ssl| { ssl.ssl.read(buf) }; match ret { Ok(num) => Some(num as uint), Err(_) => None } } fn eof(&mut self) -> bool { self.stream.eof() } } impl<S: Stream> Writer for SslStream<S> { fn write(&mut self, buf: &[u8]) { let ret = do self.in_retry_wrapper |ssl| { ssl.ssl.write(buf) }; match ret { Ok(_) => (), Err(err) => fail2!("Write error: {}", err.to_str()) } self.write_through(); } fn flush(&mut self) { self.write_through(); self.stream.flush(); } } Loading
src/ssl/test.rs +10 −0 Original line number Diff line number Diff line extern mod ssl; use std::rt::io::{Writer}; use std::rt::io::net::tcp::TcpStream; use std::vec; use ssl::{Sslv23, SslCtx, SslStream}; Loading @@ -14,3 +16,11 @@ fn test_new_sslstream() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()); SslStream::new(SslCtx::new(Sslv23), stream); } #[test] fn test_write() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()); let mut stream = SslStream::new(SslCtx::new(Sslv23), stream); stream.write("hello".as_bytes()); stream.flush(); }