Fix Send + Sync-ness of SslStream

This commit is contained in:
Steven Fackler 2016-10-23 20:55:31 -07:00
parent cb44256876
commit ca71e00878
3 changed files with 45 additions and 33 deletions

View File

@ -7,7 +7,6 @@ use std::io::prelude::*;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::slice; use std::slice;
use std::sync::Arc;
use cvt_p; use cvt_p;
use error::ErrorStack; use error::ErrorStack;
@ -22,15 +21,16 @@ pub struct StreamState<S> {
pub struct BioMethod(compat::BIO_METHOD); pub struct BioMethod(compat::BIO_METHOD);
impl BioMethod { impl BioMethod {
pub fn new<S: Read + Write>() -> BioMethod { fn new<S: Read + Write>() -> BioMethod {
BioMethod(compat::BIO_METHOD::new::<S>()) BioMethod(compat::BIO_METHOD::new::<S>())
} }
} }
unsafe impl Sync for BioMethod {}
unsafe impl Send for BioMethod {} unsafe impl Send for BioMethod {}
pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), ErrorStack> { pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> {
let method = Arc::new(BioMethod::new::<S>()); let method = BioMethod::new::<S>();
let state = Box::new(StreamState { let state = Box::new(StreamState {
stream: stream, stream: stream,
@ -188,9 +188,7 @@ mod compat {
pub unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} pub unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {}
pub struct BIO_METHOD { pub struct BIO_METHOD(*mut ffi::BIO_METHOD);
inner: *mut ffi::BIO_METHOD,
}
impl BIO_METHOD { impl BIO_METHOD {
pub fn new<S: Read + Write>() -> BIO_METHOD { pub fn new<S: Read + Write>() -> BIO_METHOD {
@ -198,7 +196,7 @@ mod compat {
let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE,
b"rust\0".as_ptr() as *const _); b"rust\0".as_ptr() as *const _);
assert!(!ptr.is_null()); assert!(!ptr.is_null());
let ret = BIO_METHOD { inner: ptr }; let ret = BIO_METHOD(ptr);
assert!(ffi::BIO_meth_set_write(ptr, super::bwrite::<S>) != 0); assert!(ffi::BIO_meth_set_write(ptr, super::bwrite::<S>) != 0);
assert!(ffi::BIO_meth_set_read(ptr, super::bread::<S>) != 0); assert!(ffi::BIO_meth_set_read(ptr, super::bread::<S>) != 0);
assert!(ffi::BIO_meth_set_puts(ptr, super::bputs::<S>) != 0); assert!(ffi::BIO_meth_set_puts(ptr, super::bputs::<S>) != 0);
@ -210,14 +208,14 @@ mod compat {
} }
pub fn get(&self) -> *mut ffi::BIO_METHOD { pub fn get(&self) -> *mut ffi::BIO_METHOD {
self.inner self.0
} }
} }
impl Drop for BIO_METHOD { impl Drop for BIO_METHOD {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
ffi::BIO_meth_free(self.inner); ffi::BIO_meth_free(self.0);
} }
} }
} }
@ -227,19 +225,15 @@ mod compat {
#[allow(bad_style)] #[allow(bad_style)]
mod compat { mod compat {
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::cell::UnsafeCell;
use ffi; use ffi;
use libc::{c_int, c_void}; use libc::{c_int, c_void};
pub struct BIO_METHOD { pub struct BIO_METHOD(*mut ffi::BIO_METHOD);
inner: UnsafeCell<ffi::BIO_METHOD>,
}
impl BIO_METHOD { impl BIO_METHOD {
pub fn new<S: Read + Write>() -> BIO_METHOD { pub fn new<S: Read + Write>() -> BIO_METHOD {
BIO_METHOD { let ptr = Box::new(ffi::BIO_METHOD {
inner: UnsafeCell::new(ffi::BIO_METHOD {
type_: ffi::BIO_TYPE_NONE, type_: ffi::BIO_TYPE_NONE,
name: b"rust\0".as_ptr() as *const _, name: b"rust\0".as_ptr() as *const _,
bwrite: Some(super::bwrite::<S>), bwrite: Some(super::bwrite::<S>),
@ -250,12 +244,21 @@ mod compat {
create: Some(super::create), create: Some(super::create),
destroy: Some(super::destroy::<S>), destroy: Some(super::destroy::<S>),
callback_ctrl: None, callback_ctrl: None,
}), });
}
BIO_METHOD(Box::into_raw(ptr))
} }
pub fn get(&self) -> *mut ffi::BIO_METHOD { pub fn get(&self) -> *mut ffi::BIO_METHOD {
self.inner.get() self.0
}
}
impl Drop for BIO_METHOD {
fn drop(&mut self) {
unsafe {
Box::<ffi::BIO_METHOD>::from_raw(self.0);
}
} }
} }

View File

@ -13,7 +13,7 @@ use std::ops::{Deref, DerefMut};
use std::path::Path; use std::path::Path;
use std::ptr; use std::ptr;
use std::str; use std::str;
use std::sync::{Mutex, Arc}; use std::sync::Mutex;
use libc::{c_uchar, c_uint}; use libc::{c_uchar, c_uint};
use std::slice; use std::slice;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -1023,6 +1023,9 @@ impl SslRef {
pub struct Ssl(*mut ffi::SSL); pub struct Ssl(*mut ffi::SSL);
unsafe impl Sync for Ssl {}
unsafe impl Send for Ssl {}
impl fmt::Debug for Ssl { impl fmt::Debug for Ssl {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut builder = fmt.debug_struct("Ssl"); let mut builder = fmt.debug_struct("Ssl");
@ -1128,12 +1131,10 @@ impl Ssl {
/// A stream wrapper which handles SSL encryption for an underlying stream. /// A stream wrapper which handles SSL encryption for an underlying stream.
pub struct SslStream<S> { pub struct SslStream<S> {
ssl: Ssl, ssl: Ssl,
_method: Arc<BioMethod>, // NOTE: this *must* be after the Ssl field so things drop right _method: BioMethod, // NOTE: this *must* be after the Ssl field so things drop right
_p: PhantomData<S>, _p: PhantomData<S>,
} }
unsafe impl<S: Send> Send for SslStream<S> {}
impl<S> fmt::Debug for SslStream<S> impl<S> fmt::Debug for SslStream<S>
where S: fmt::Debug where S: fmt::Debug
{ {

View File

@ -1083,3 +1083,11 @@ fn invalid_hostname() {
let s = TcpStream::connect("google.com:443").unwrap(); let s = TcpStream::connect("google.com:443").unwrap();
assert!(ssl.connect(s).is_err()); assert!(ssl.connect(s).is_err());
} }
fn _check_kinds() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<SslStream<TcpStream>>();
is_sync::<SslStream<TcpStream>>();
}