aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2013-10-05 15:49:46 -0700
committerSteven Fackler <[email protected]>2013-10-05 15:49:46 -0700
commitd04c4ef435949622d6784d42c5b9ce1d4d5bc6d2 (patch)
treec5ce91aefa5ea2249532f79fda223c1c0dfd4661
parentSslStream sketch (diff)
downloadrust-openssl-d04c4ef435949622d6784d42c5b9ce1d4d5bc6d2.tar.xz
rust-openssl-d04c4ef435949622d6784d42c5b9ce1d4d5bc6d2.zip
Connect working
-rw-r--r--src/ssl/ffi.rs18
-rw-r--r--src/ssl/lib.rs94
-rw-r--r--src/ssl/test.rs2
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<S> {
priv ctx: SslCtx,
priv ssl: Ssl,
+ priv buf: ~[u8],
priv rbio: MemBio,
priv wbio: MemBio,
priv stream: S
@@ -122,16 +176,52 @@ impl<S: Stream> SslStream<S> {
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<S: Stream> Decorator<S> for SslStream<S> {
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);
}