Sketched out implementation

doesn't work
This commit is contained in:
Steven Fackler 2013-09-19 12:54:01 -07:00
parent d04c4ef435
commit a7dab3624e
3 changed files with 87 additions and 20 deletions

View File

@ -1,6 +1,6 @@
#[doc(hidden)]; #[doc(hidden)];
use std::libc::{c_int, c_long, c_void}; use std::libc::{c_int, c_void};
// openssl/ssl.h // openssl/ssl.h
pub type SSL_CTX = c_void; pub type SSL_CTX = c_void;
@ -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_set_connect_state(ssl: *SSL))
externfn!(fn SSL_connect(ssl: *SSL) -> c_int) externfn!(fn SSL_connect(ssl: *SSL) -> c_int)
externfn!(fn SSL_get_error(ssl: *SSL, ret: c_int) -> 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_s_mem() -> *BIO_METHOD)
externfn!(fn BIO_new(type_: *BIO_METHOD) -> *BIO) externfn!(fn BIO_new(type_: *BIO_METHOD) -> *BIO)

View File

@ -1,4 +1,4 @@
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::unstable::atomics::{AtomicBool, INIT_ATOMIC_BOOL, Acquire, Release};
use std::task; use std::task;
use std::ptr; use std::ptr;
@ -70,6 +70,7 @@ impl Drop for Ssl {
} }
} }
#[deriving(Eq, TotalEq, ToStr)]
enum SslError { enum SslError {
ErrorNone, ErrorNone,
ErrorSsl, ErrorSsl,
@ -114,6 +115,20 @@ impl Ssl {
_ => unreachable!() _ => 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 { struct MemBio {
@ -150,12 +165,13 @@ impl MemBio {
let ret = ffi::BIO_read(self.bio, vec::raw::to_ptr(buf) as *c_void, let ret = ffi::BIO_read(self.bio, vec::raw::to_ptr(buf) as *c_void,
buf.len() as c_int); buf.len() as c_int);
if ret < 0 { if ret < 0 {
fail2!("read returned {}", ret); 0
} } else {
ret as uint ret as uint
} }
} }
} }
}
pub struct SslStream<S> { pub struct SslStream<S> {
priv ctx: SslCtx, priv ctx: SslCtx,
@ -179,47 +195,86 @@ impl<S: Stream> SslStream<S> {
let mut stream = SslStream { let mut stream = SslStream {
ctx: ctx, ctx: ctx,
ssl: ssl, ssl: ssl,
// Max record size for SSLv3/TLSv1 is 16k
buf: vec::from_elem(16 * 1024, 0u8), buf: vec::from_elem(16 * 1024, 0u8),
rbio: rbio, rbio: rbio,
wbio: wbio, wbio: wbio,
stream: stream stream: stream
}; };
stream.connect(); do stream.in_retry_wrapper |ssl| {
ssl.ssl.connect()
};
stream stream
} }
fn connect(&mut self) { fn in_retry_wrapper(&mut self, blk: &fn(&mut SslStream<S>) -> int)
info!("in connect"); -> Result<int, SslError> {
loop { loop {
let ret = self.ssl.connect(); let ret = blk(self);
info2!("connect returned {}", ret); if ret > 0 {
if ret == 1 { return Ok(ret);
return;
} }
match self.ssl.get_error(ret) { match self.ssl.get_error(ret) {
ErrorWantRead => { ErrorWantRead => {
info2!("want read");
self.flush(); self.flush();
match self.stream.read(self.buf) { match self.stream.read(self.buf) {
Some(len) => self.rbio.write(self.buf.slice_to(len)), Some(len) => self.rbio.write(self.buf.slice_to(len)),
None => unreachable!() None => unreachable!() // FIXME
} }
} }
ErrorWantWrite => { ErrorWantWrite => self.flush(),
info2!("want write"); err => return Err(err)
self.flush();
}
_ => unreachable!()
} }
} }
} }
fn flush(&mut self) { fn write_through(&mut self) {
loop {
let len = self.wbio.read(self.buf); let len = self.wbio.read(self.buf);
if len == 0 {
return;
}
self.stream.write(self.buf.slice_to(len)); 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(); self.stream.flush();
} }
} }

View File

@ -1,6 +1,8 @@
extern mod ssl; extern mod ssl;
use std::rt::io::{Writer};
use std::rt::io::net::tcp::TcpStream; use std::rt::io::net::tcp::TcpStream;
use std::vec;
use ssl::{Sslv23, SslCtx, SslStream}; use ssl::{Sslv23, SslCtx, SslStream};
@ -14,3 +16,11 @@ fn test_new_sslstream() {
let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()); let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap());
SslStream::new(SslCtx::new(Sslv23), stream); 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();
}