Connect working
This commit is contained in:
parent
d4d5547a79
commit
d04c4ef435
|
|
@ -1,13 +1,24 @@
|
||||||
#[doc(hidden)];
|
#[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_CTX = c_void;
|
||||||
pub type SSL_METHOD = c_void;
|
pub type SSL_METHOD = c_void;
|
||||||
pub type SSL = c_void;
|
pub type SSL = c_void;
|
||||||
pub type BIO = c_void;
|
pub type BIO = c_void;
|
||||||
pub type BIO_METHOD = 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"]
|
#[link_args = "-lssl"]
|
||||||
extern "C" { }
|
extern "C" { }
|
||||||
|
|
||||||
|
|
@ -22,8 +33,11 @@ externfn!(fn SSL_new(ctx: *SSL_CTX) -> *SSL)
|
||||||
externfn!(fn SSL_free(ssl: *SSL))
|
externfn!(fn SSL_free(ssl: *SSL))
|
||||||
externfn!(fn SSL_set_bio(ssl: *SSL, rbio: *BIO, wbio: *BIO))
|
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_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_s_mem() -> *BIO_METHOD)
|
||||||
externfn!(fn BIO_new(type_: *BIO_METHOD) -> *BIO)
|
externfn!(fn BIO_new(type_: *BIO_METHOD) -> *BIO)
|
||||||
externfn!(fn BIO_free(a: *BIO) -> c_int)
|
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)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ use std::rt::io::{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;
|
||||||
|
use std::vec;
|
||||||
|
use std::libc::{c_int, c_void};
|
||||||
|
|
||||||
mod ffi;
|
mod ffi;
|
||||||
|
|
||||||
|
|
@ -68,6 +70,17 @@ impl Drop for Ssl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum SslError {
|
||||||
|
ErrorNone,
|
||||||
|
ErrorSsl,
|
||||||
|
ErrorWantRead,
|
||||||
|
ErrorWantWrite,
|
||||||
|
ErrorWantX509Lookup,
|
||||||
|
ErrorZeroReturn,
|
||||||
|
ErrorWantConnect,
|
||||||
|
ErrorWantAccept,
|
||||||
|
}
|
||||||
|
|
||||||
impl Ssl {
|
impl Ssl {
|
||||||
fn new(ctx: &SslCtx) -> Ssl {
|
fn new(ctx: &SslCtx) -> Ssl {
|
||||||
let ssl = unsafe { ffi::SSL_new(ctx.ctx) };
|
let ssl = unsafe { ffi::SSL_new(ctx.ctx) };
|
||||||
|
|
@ -83,6 +96,24 @@ impl Ssl {
|
||||||
fn set_connect_state(&self) {
|
fn set_connect_state(&self) {
|
||||||
unsafe { ffi::SSL_set_connect_state(self.ssl); }
|
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 {
|
struct MemBio {
|
||||||
|
|
@ -102,11 +133,34 @@ impl MemBio {
|
||||||
|
|
||||||
MemBio { bio: bio }
|
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> {
|
pub struct SslStream<S> {
|
||||||
priv ctx: SslCtx,
|
priv ctx: SslCtx,
|
||||||
priv ssl: Ssl,
|
priv ssl: Ssl,
|
||||||
|
priv buf: ~[u8],
|
||||||
priv rbio: MemBio,
|
priv rbio: MemBio,
|
||||||
priv wbio: MemBio,
|
priv wbio: MemBio,
|
||||||
priv stream: S
|
priv stream: S
|
||||||
|
|
@ -122,16 +176,52 @@ impl<S: Stream> SslStream<S> {
|
||||||
ssl.set_bio(&rbio, &wbio);
|
ssl.set_bio(&rbio, &wbio);
|
||||||
ssl.set_connect_state();
|
ssl.set_connect_state();
|
||||||
|
|
||||||
let stream = SslStream {
|
let mut stream = SslStream {
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
ssl: ssl,
|
ssl: ssl,
|
||||||
|
buf: vec::from_elem(16 * 1024, 0u8),
|
||||||
rbio: rbio,
|
rbio: rbio,
|
||||||
wbio: wbio,
|
wbio: wbio,
|
||||||
stream: stream
|
stream: stream
|
||||||
}
|
};
|
||||||
|
|
||||||
|
stream.connect();
|
||||||
|
|
||||||
stream
|
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> {
|
impl<S: Stream> Decorator<S> for SslStream<S> {
|
||||||
|
|
|
||||||
|
|
@ -12,5 +12,5 @@ fn test_new_ctx() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_sslstream() {
|
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());
|
||||||
let stream = SslStream::new(SslCtx::new(Sslv23), stream);
|
SslStream::new(SslCtx::new(Sslv23), stream);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue