From d04c4ef435949622d6784d42c5b9ce1d4d5bc6d2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 5 Oct 2013 15:49:46 -0700 Subject: [PATCH] Connect working --- src/ssl/ffi.rs | 18 ++++++++-- src/ssl/lib.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++++-- src/ssl/test.rs | 2 +- 3 files changed, 109 insertions(+), 5 deletions(-) diff --git a/src/ssl/ffi.rs b/src/ssl/ffi.rs index c3144545..07591b78 100644 --- a/src/ssl/ffi.rs +++ b/src/ssl/ffi.rs @@ -1,13 +1,24 @@ #[doc(hidden)]; -use std::libc::{c_int, c_void}; +use std::libc::{c_int, c_long, c_void}; +// openssl/ssl.h pub type SSL_CTX = c_void; pub type SSL_METHOD = c_void; pub type SSL = c_void; pub type BIO = c_void; pub type BIO_METHOD = c_void; +pub static SSL_ERROR_NONE: c_int = 0; +pub static SSL_ERROR_SSL: c_int = 1; +pub static SSL_ERROR_WANT_READ: c_int = 2; +pub static SSL_ERROR_WANT_WRITE: c_int = 3; +pub static SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; +pub static SSL_ERROR_SYSCALL: c_int = 5; +pub static SSL_ERROR_ZERO_RETURN: c_int = 6; +pub static SSL_ERROR_WANT_CONNECT: c_int = 7; +pub static SSL_ERROR_WANT_ACCEPT: c_int = 8; + #[link_args = "-lssl"] extern "C" { } @@ -22,8 +33,11 @@ externfn!(fn SSL_new(ctx: *SSL_CTX) -> *SSL) externfn!(fn SSL_free(ssl: *SSL)) externfn!(fn SSL_set_bio(ssl: *SSL, rbio: *BIO, wbio: *BIO)) externfn!(fn SSL_set_connect_state(ssl: *SSL)) -externfn!(fn SSL_do_handshake(ssl: *SSL)) +externfn!(fn SSL_connect(ssl: *SSL) -> c_int) +externfn!(fn SSL_get_error(ssl: *SSL, ret: c_int) -> c_int) externfn!(fn BIO_s_mem() -> *BIO_METHOD) externfn!(fn BIO_new(type_: *BIO_METHOD) -> *BIO) externfn!(fn BIO_free(a: *BIO) -> c_int) +externfn!(fn BIO_read(b: *BIO, buf: *c_void, len: c_int) -> c_int) +externfn!(fn BIO_write(b: *BIO, buf: *c_void, len: c_int) -> c_int) diff --git a/src/ssl/lib.rs b/src/ssl/lib.rs index a65d8eac..401a7b3d 100644 --- a/src/ssl/lib.rs +++ b/src/ssl/lib.rs @@ -2,6 +2,8 @@ use std::rt::io::{Stream, Decorator}; use std::unstable::atomics::{AtomicBool, INIT_ATOMIC_BOOL, Acquire, Release}; use std::task; use std::ptr; +use std::vec; +use std::libc::{c_int, c_void}; mod ffi; @@ -68,6 +70,17 @@ impl Drop for Ssl { } } +enum SslError { + ErrorNone, + ErrorSsl, + ErrorWantRead, + ErrorWantWrite, + ErrorWantX509Lookup, + ErrorZeroReturn, + ErrorWantConnect, + ErrorWantAccept, +} + impl Ssl { fn new(ctx: &SslCtx) -> Ssl { let ssl = unsafe { ffi::SSL_new(ctx.ctx) }; @@ -83,6 +96,24 @@ impl Ssl { fn set_connect_state(&self) { unsafe { ffi::SSL_set_connect_state(self.ssl); } } + + fn connect(&self) -> int { + unsafe { ffi::SSL_connect(self.ssl) as int } + } + + fn get_error(&self, ret: int) -> SslError { + match unsafe { ffi::SSL_get_error(self.ssl, ret as c_int) } { + ffi::SSL_ERROR_NONE => ErrorNone, + ffi::SSL_ERROR_SSL => ErrorSsl, + ffi::SSL_ERROR_WANT_READ => ErrorWantRead, + ffi::SSL_ERROR_WANT_WRITE => ErrorWantWrite, + ffi::SSL_ERROR_WANT_X509_LOOKUP => ErrorWantX509Lookup, + ffi::SSL_ERROR_ZERO_RETURN => ErrorZeroReturn, + ffi::SSL_ERROR_WANT_CONNECT => ErrorWantConnect, + ffi::SSL_ERROR_WANT_ACCEPT => ErrorWantAccept, + _ => unreachable!() + } + } } struct MemBio { @@ -102,11 +133,34 @@ impl MemBio { MemBio { bio: bio } } + + fn write(&self, buf: &[u8]) { + unsafe { + let ret = ffi::BIO_write(self.bio, + vec::raw::to_ptr(buf) as *c_void, + buf.len() as c_int); + if ret < 0 { + fail2!("write returned {}", ret); + } + } + } + + fn read(&self, buf: &[u8]) -> uint { + unsafe { + 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); + } + ret as uint + } + } } pub struct SslStream { priv ctx: SslCtx, priv ssl: Ssl, + priv buf: ~[u8], priv rbio: MemBio, priv wbio: MemBio, priv stream: S @@ -122,16 +176,52 @@ impl SslStream { ssl.set_bio(&rbio, &wbio); ssl.set_connect_state(); - let stream = SslStream { + let mut stream = SslStream { ctx: ctx, ssl: ssl, + buf: vec::from_elem(16 * 1024, 0u8), rbio: rbio, wbio: wbio, stream: stream - } + }; + + stream.connect(); stream } + + fn connect(&mut self) { + info!("in connect"); + loop { + let ret = self.ssl.connect(); + info2!("connect returned {}", ret); + if ret == 1 { + return; + } + + 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!() + } + } + ErrorWantWrite => { + info2!("want write"); + self.flush(); + } + _ => unreachable!() + } + } + } + + fn flush(&mut self) { + let len = self.wbio.read(self.buf); + self.stream.write(self.buf.slice_to(len)); + self.stream.flush(); + } } impl Decorator for SslStream { diff --git a/src/ssl/test.rs b/src/ssl/test.rs index 501c8626..a86772a7 100644 --- a/src/ssl/test.rs +++ b/src/ssl/test.rs @@ -12,5 +12,5 @@ fn test_new_ctx() { #[test] fn test_new_sslstream() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()); - let stream = SslStream::new(SslCtx::new(Sslv23), stream); + SslStream::new(SslCtx::new(Sslv23), stream); }