From fd6454f625bb7efde3772ae106180cc6ac7c02dd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Jan 2016 22:32:43 -0800 Subject: Add stream panic propagation behind a nightly feature gate --- openssl/src/ssl/bio.rs | 98 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 10 deletions(-) (limited to 'openssl/src/ssl/bio.rs') diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index a361ae81..aa445562 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -1,11 +1,12 @@ use libc::{c_char, c_int, c_long, c_void, strlen}; use ffi::{BIO, BIO_METHOD, BIO_CTRL_FLUSH, BIO_TYPE_NONE, BIO_new}; use ffi_extras::{BIO_clear_retry_flags, BIO_set_retry_read, BIO_set_retry_write}; +use std::any::Any; use std::io; use std::io::prelude::*; use std::mem; -use std::slice; use std::ptr; +use std::slice; use std::sync::Arc; use ssl::error::SslError; @@ -16,6 +17,7 @@ const NAME: [c_char; 5] = [114, 117, 115, 116, 0]; pub struct StreamState { pub stream: S, pub error: Option, + pub panic: Option>, } pub fn new(stream: S) -> Result<(*mut BIO, Arc), SslError> { @@ -35,6 +37,7 @@ pub fn new(stream: S) -> Result<(*mut BIO, Arc), Ss let state = Box::new(StreamState { stream: stream, error: None, + panic: None, }); unsafe { @@ -51,6 +54,12 @@ pub unsafe fn take_error(bio: *mut BIO) -> Option { state.error.take() } +#[cfg_attr(not(feature = "nightly"), allow(dead_code))] +pub unsafe fn take_panic(bio: *mut BIO) -> Option> { + let state = state::(bio); + state.panic.take() +} + pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S { let state: &'a StreamState = mem::transmute((*bio).ptr); &state.stream @@ -64,20 +73,69 @@ unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { mem::transmute((*bio).ptr) } +#[cfg(feature = "nightly")] +fn recover(f: F) -> Result> where F: FnOnce() -> T + ::std::panic::RecoverSafe { + ::std::panic::recover(f) +} + +#[cfg(not(feature = "nightly"))] +fn recover(f: F) -> Result> where F: FnOnce() -> T { + Ok(f()) +} + +#[cfg(feature = "nightly")] +use std::panic::AssertRecoverSafe; + +#[cfg(not(feature = "nightly"))] +struct AssertRecoverSafe(T); + +#[cfg(not(feature = "nightly"))] +impl AssertRecoverSafe { + fn new(t: T) -> Self { + AssertRecoverSafe(t) + } +} + +#[cfg(not(feature = "nightly"))] +impl ::std::ops::Deref for AssertRecoverSafe { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } +} + +#[cfg(not(feature = "nightly"))] +impl ::std::ops::DerefMut for AssertRecoverSafe { + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} + unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); let buf = slice::from_raw_parts(buf as *const _, len as usize); - match state.stream.write(buf) { - Ok(len) => len as c_int, - Err(err) => { + + let result = { + let mut youre_not_my_supervisor = AssertRecoverSafe::new(&mut *state); + recover(move || youre_not_my_supervisor.stream.write(buf)) + }; + + match result { + Ok(Ok(len)) => len as c_int, + Ok(Err(err)) => { if retriable_error(&err) { BIO_set_retry_write(bio); } state.error = Some(err); -1 } + Err(err) => { + state.panic = Some(err); + -1 + } } } @@ -86,15 +144,26 @@ unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) let state = state::(bio); let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize); - match state.stream.read(buf) { - Ok(len) => len as c_int, - Err(err) => { + + let result = { + let mut youre_not_my_supervisor = AssertRecoverSafe::new(&mut *state); + let mut fuuuu = AssertRecoverSafe::new(buf); + recover(move || youre_not_my_supervisor.stream.read(&mut *fuuuu)) + }; + + match result { + Ok(Ok(len)) => len as c_int, + Ok(Err(err)) => { if retriable_error(&err) { BIO_set_retry_read(bio); } state.error = Some(err); -1 } + Err(err) => { + state.panic = Some(err); + -1 + } } } @@ -116,12 +185,21 @@ unsafe extern "C" fn ctrl(bio: *mut BIO, -> c_long { if cmd == BIO_CTRL_FLUSH { let state = state::(bio); - match state.stream.flush() { - Ok(()) => 1, - Err(err) => { + let result = { + let mut youre_not_my_supervisor = AssertRecoverSafe::new(&mut *state); + recover(move || youre_not_my_supervisor.stream.flush()) + }; + + match result { + Ok(Ok(())) => 1, + Ok(Err(err)) => { state.error = Some(err); 0 } + Err(err) => { + state.panic = Some(err); + 0 + } } } else { 0 -- cgit v1.2.3