Commit a7dab362 authored by Steven Fackler's avatar Steven Fackler
Browse files

Sketched out implementation

doesn't work
parent d04c4ef4
Loading
Loading
Loading
Loading
+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;
@@ -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)
+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;
@@ -70,6 +70,7 @@ impl Drop for Ssl {
    }
}

#[deriving(Eq, TotalEq, ToStr)]
enum SslError {
    ErrorNone,
    ErrorSsl,
@@ -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 {
@@ -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,
@@ -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();
    }
}
+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};

@@ -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();
}