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::ptr;
use std::slice;
use std::sync::Arc;
use cvt_p;
use error::ErrorStack;
@ -22,15 +21,16 @@ pub struct StreamState<S> {
pub struct BioMethod(compat::BIO_METHOD);
impl BioMethod {
pub fn new<S: Read + Write>() -> BioMethod {
fn new<S: Read + Write>() -> BioMethod {
BioMethod(compat::BIO_METHOD::new::<S>())
}
}
unsafe impl Sync for BioMethod {}
unsafe impl Send for BioMethod {}
pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, Arc<BioMethod>), ErrorStack> {
let method = Arc::new(BioMethod::new::<S>());
pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> {
let method = BioMethod::new::<S>();
let state = Box::new(StreamState {
stream: stream,
@ -188,9 +188,7 @@ mod compat {
pub unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {}
pub struct BIO_METHOD {
inner: *mut ffi::BIO_METHOD,
}
pub struct BIO_METHOD(*mut ffi::BIO_METHOD);
impl 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,
b"rust\0".as_ptr() as *const _);
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_read(ptr, super::bread::<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 {
self.inner
self.0
}
}
impl Drop for BIO_METHOD {
fn drop(&mut self) {
unsafe {
ffi::BIO_meth_free(self.inner);
ffi::BIO_meth_free(self.0);
}
}
}
@ -227,19 +225,15 @@ mod compat {
#[allow(bad_style)]
mod compat {
use std::io::{Read, Write};
use std::cell::UnsafeCell;
use ffi;
use libc::{c_int, c_void};
pub struct BIO_METHOD {
inner: UnsafeCell<ffi::BIO_METHOD>,
}
pub struct BIO_METHOD(*mut ffi::BIO_METHOD);
impl BIO_METHOD {
pub fn new<S: Read + Write>() -> BIO_METHOD {
BIO_METHOD {
inner: UnsafeCell::new(ffi::BIO_METHOD {
let ptr = Box::new(ffi::BIO_METHOD {
type_: ffi::BIO_TYPE_NONE,
name: b"rust\0".as_ptr() as *const _,
bwrite: Some(super::bwrite::<S>),
@ -250,12 +244,21 @@ mod compat {
create: Some(super::create),
destroy: Some(super::destroy::<S>),
callback_ctrl: None,
}),
}
});
BIO_METHOD(Box::into_raw(ptr))
}
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::ptr;
use std::str;
use std::sync::{Mutex, Arc};
use std::sync::Mutex;
use libc::{c_uchar, c_uint};
use std::slice;
use std::marker::PhantomData;
@ -1023,6 +1023,9 @@ impl SslRef {
pub struct Ssl(*mut ffi::SSL);
unsafe impl Sync for Ssl {}
unsafe impl Send for Ssl {}
impl fmt::Debug for Ssl {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let mut builder = fmt.debug_struct("Ssl");
@ -1128,12 +1131,10 @@ impl Ssl {
/// A stream wrapper which handles SSL encryption for an underlying stream.
pub struct SslStream<S> {
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>,
}
unsafe impl<S: Send> Send for SslStream<S> {}
impl<S> fmt::Debug for SslStream<S>
where S: fmt::Debug
{

View File

@ -1083,3 +1083,11 @@ fn invalid_hostname() {
let s = TcpStream::connect("google.com:443").unwrap();
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>>();
}