diff options
Diffstat (limited to 'openssl/src/ssl/error.rs')
| -rw-r--r-- | openssl/src/ssl/error.rs | 274 |
1 files changed, 10 insertions, 264 deletions
diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs index 2459a473..95213361 100644 --- a/openssl/src/ssl/error.rs +++ b/openssl/src/ssl/error.rs @@ -1,15 +1,8 @@ -pub use self::SslError::*; -pub use self::OpensslError::*; - -use libc::c_ulong; use std::error; use std::error::Error as StdError; use std::fmt; -use std::ffi::CStr; use std::io; -use std::str; - -use ffi; +use error::ErrorStack; /// An SSL error. #[derive(Debug)] @@ -27,30 +20,16 @@ pub enum Error { /// An error reported by the underlying stream. Stream(io::Error), /// An error in the OpenSSL library. - Ssl(Vec<OpenSslError>), + Ssl(ErrorStack), } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(fmt.write_str(self.description())); - match *self { - Error::Stream(ref err) => write!(fmt, ": {}", err), - Error::WantRead(ref err) => write!(fmt, ": {}", err), - Error::WantWrite(ref err) => write!(fmt, ": {}", err), - Error::Ssl(ref errs) => { - let mut first = true; - for err in errs { - if first { - try!(fmt.write_str(": ")); - first = false; - } else { - try!(fmt.write_str(", ")); - } - try!(fmt.write_str(&err.reason())) - } - Ok(()) - } - _ => Ok(()), + if let Some(err) = self.cause() { + write!(fmt, ": {}", err) + } else { + Ok(()) } } } @@ -72,247 +51,14 @@ impl error::Error for Error { Error::WantRead(ref err) => Some(err), Error::WantWrite(ref err) => Some(err), Error::Stream(ref err) => Some(err), + Error::Ssl(ref err) => Some(err), _ => None, } } } -/// An error reported from OpenSSL. -pub struct OpenSslError(c_ulong); - -impl OpenSslError { - /// Returns the contents of the OpenSSL error stack. - pub fn get_stack() -> Vec<OpenSslError> { - ffi::init(); - - let mut errs = vec![]; - loop { - match unsafe { ffi::ERR_get_error() } { - 0 => break, - err => errs.push(OpenSslError(err)), - } - } - errs - } - - /// Returns the raw OpenSSL error code for this error. - pub fn error_code(&self) -> c_ulong { - self.0 - } - - /// Returns the name of the library reporting the error. - pub fn library(&self) -> &'static str { - get_lib(self.0) - } - - /// Returns the name of the function reporting the error. - pub fn function(&self) -> &'static str { - get_func(self.0) - } - - /// Returns the reason for the error. - pub fn reason(&self) -> &'static str { - get_reason(self.0) - } -} - -impl fmt::Debug for OpenSslError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("OpenSslError") - .field("library", &self.library()) - .field("function", &self.function()) - .field("reason", &self.reason()) - .finish() - } -} - -impl fmt::Display for OpenSslError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(&self.reason()) - } -} - -impl error::Error for OpenSslError { - fn description(&self) -> &str { - "An OpenSSL error" - } -} - -/// An SSL error -#[derive(Debug)] -pub enum SslError { - /// The underlying stream reported an error - StreamError(io::Error), - /// The SSL session has been closed by the other end - SslSessionClosed, - /// An error in the OpenSSL library - OpenSslErrors(Vec<OpensslError>), -} - -/// An error on a nonblocking stream. -#[derive(Debug)] -pub enum NonblockingSslError { - /// A standard SSL error occurred. - SslError(SslError), - /// The OpenSSL library wants data from the remote socket; - /// the caller should wait for read readiness. - WantRead, - /// The OpenSSL library wants to send data to the remote socket; - /// the caller should wait for write readiness. - WantWrite, -} - -impl fmt::Display for SslError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - try!(fmt.write_str(error::Error::description(self))); - if let OpenSslErrors(ref errs) = *self { - let mut first = true; - for err in errs { - if first { - try!(fmt.write_str(": ")); - first = false; - } else { - try!(fmt.write_str(", ")); - } - match *err { - UnknownError { ref reason, .. } => try!(fmt.write_str(reason)), - } - } - } - - Ok(()) - } -} - -impl error::Error for SslError { - fn description(&self) -> &str { - match *self { - StreamError(_) => "The underlying stream reported an error", - SslSessionClosed => "The SSL session has been closed by the other end", - OpenSslErrors(_) => "An error in the OpenSSL library", - } +impl From<ErrorStack> for Error { + fn from(e: ErrorStack) -> Error { + Error::Ssl(e) } - - fn cause(&self) -> Option<&error::Error> { - match *self { - StreamError(ref err) => Some(err as &error::Error), - _ => None, - } - } -} - -impl fmt::Display for NonblockingSslError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.write_str(error::Error::description(self)) - } -} - -impl error::Error for NonblockingSslError { - fn description(&self) -> &str { - match *self { - NonblockingSslError::SslError(ref e) => e.description(), - NonblockingSslError::WantRead => { - "The OpenSSL library wants data from the remote socket" - } - NonblockingSslError::WantWrite => { - "The OpenSSL library want to send data to the remote socket" - } - } - } - - fn cause(&self) -> Option<&error::Error> { - match *self { - NonblockingSslError::SslError(ref e) => e.cause(), - _ => None, - } - } -} - -impl From<SslError> for NonblockingSslError { - fn from(e: SslError) -> NonblockingSslError { - NonblockingSslError::SslError(e) - } -} - -/// An error from the OpenSSL library -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum OpensslError { - /// An unknown error - UnknownError { - /// The library reporting the error - library: String, - /// The function reporting the error - function: String, - /// The reason for the error - reason: String, - }, -} - -impl OpensslError { - pub fn from_error_code(err: c_ulong) -> OpensslError { - ffi::init(); - UnknownError { - library: get_lib(err).to_owned(), - function: get_func(err).to_owned(), - reason: get_reason(err).to_owned(), - } - } -} - -fn get_lib(err: c_ulong) -> &'static str { - unsafe { - let cstr = ffi::ERR_lib_error_string(err); - let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); - str::from_utf8(bytes).unwrap() - } -} - -fn get_func(err: c_ulong) -> &'static str { - unsafe { - let cstr = ffi::ERR_func_error_string(err); - let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); - str::from_utf8(bytes).unwrap() - } -} - -fn get_reason(err: c_ulong) -> &'static str { - unsafe { - let cstr = ffi::ERR_reason_error_string(err); - let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); - str::from_utf8(bytes).unwrap() - } -} - -impl SslError { - /// Creates a new `OpenSslErrors` with the current contents of the error - /// stack. - pub fn get() -> SslError { - let mut errs = vec![]; - loop { - match unsafe { ffi::ERR_get_error() } { - 0 => break, - err => errs.push(OpensslError::from_error_code(err)), - } - } - OpenSslErrors(errs) - } - - /// Creates an `SslError` from the raw numeric error code. - pub fn from_error(err: c_ulong) -> SslError { - OpenSslErrors(vec![OpensslError::from_error_code(err)]) - } -} - -#[test] -fn test_uknown_error_should_have_correct_messages() { - let errs = match SslError::from_error(336032784) { - OpenSslErrors(errs) => errs, - _ => panic!("This should always be an `OpenSslErrors` variant."), - }; - - let UnknownError { ref library, ref function, ref reason } = errs[0]; - - assert_eq!(&library[..], "SSL routines"); - assert_eq!(&function[..], "SSL23_GET_SERVER_HELLO"); - assert_eq!(&reason[..], "sslv3 alert handshake failure"); } |