diff options
| author | Steven Fackler <[email protected]> | 2015-12-15 19:42:12 -0800 |
|---|---|---|
| committer | Steven Fackler <[email protected]> | 2015-12-15 19:42:12 -0800 |
| commit | cf075d8e6b7f5849a40659f380a660dc226a9118 (patch) | |
| tree | 630ed9e2a3fcd047fd95a778977585803cd5a94a /openssl/src/ssl/error.rs | |
| parent | Merge branch 'release-v0.7.1' into release (diff) | |
| parent | Release v0.7.2 (diff) | |
| download | rust-openssl-0.7.2.tar.xz rust-openssl-0.7.2.zip | |
Merge branch 'release-v0.7.2' into releasev0.7.2
Diffstat (limited to 'openssl/src/ssl/error.rs')
| -rw-r--r-- | openssl/src/ssl/error.rs | 174 |
1 files changed, 154 insertions, 20 deletions
diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs index 0126b277..126747d8 100644 --- a/openssl/src/ssl/error.rs +++ b/openssl/src/ssl/error.rs @@ -3,12 +3,141 @@ 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; +/// An SSL error. +#[derive(Debug)] +pub enum Error { + /// The SSL session has been closed by the other end + ZeroReturn, + /// An attempt to read data from the underlying socket returned + /// `WouldBlock`. Wait for read readiness and reattempt the operation. + WantRead(io::Error), + /// An attempt to write data from the underlying socket returned + /// `WouldBlock`. Wait for write readiness and reattempt the operation. + WantWrite(io::Error), + /// The client certificate callback requested to be called again. + WantX509Lookup, + /// An error reported by the underlying stream. + Stream(io::Error), + /// An error in the OpenSSL library. + Ssl(Vec<OpenSslError>), +} + +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(()) + } + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + match *self { + Error::ZeroReturn => "The SSL session was closed by the other end", + Error::WantRead(_) => "A read attempt returned a `WouldBlock` error", + Error::WantWrite(_) => "A write attempt returned a `WouldBlock` error", + Error::WantX509Lookup => "The client certificate callback requested to be called again", + Error::Stream(_) => "The underlying stream reported an error", + Error::Ssl(_) => "The OpenSSL library reported an error", + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::WantRead(ref err) => Some(err), + Error::WantWrite(ref err) => Some(err), + Error::Stream(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 { @@ -115,24 +244,38 @@ pub enum OpensslError { } } -fn get_lib(err: c_ulong) -> 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 bytes = CStr::from_ptr(ffi::ERR_lib_error_string(err)).to_bytes().to_vec(); - String::from_utf8(bytes).unwrap() + 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) -> String { +fn get_func(err: c_ulong) -> &'static str { unsafe { - let bytes = CStr::from_ptr(ffi::ERR_func_error_string(err)).to_bytes().to_vec(); - String::from_utf8(bytes).unwrap() + 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) -> String { +fn get_reason(err: c_ulong) -> &'static str { unsafe { - let bytes = CStr::from_ptr(ffi::ERR_reason_error_string(err)).to_bytes().to_vec(); - String::from_utf8(bytes).unwrap() + let cstr = ffi::ERR_reason_error_string(err); + let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); + str::from_utf8(bytes).unwrap() } } @@ -144,7 +287,7 @@ impl SslError { loop { match unsafe { ffi::ERR_get_error() } { 0 => break, - err => errs.push(SslError::from_error_code(err)) + err => errs.push(OpensslError::from_error_code(err)) } } OpenSslErrors(errs) @@ -152,16 +295,7 @@ impl SslError { /// Creates an `SslError` from the raw numeric error code. pub fn from_error(err: c_ulong) -> SslError { - OpenSslErrors(vec![SslError::from_error_code(err)]) - } - - fn from_error_code(err: c_ulong) -> OpensslError { - ffi::init(); - UnknownError { - library: get_lib(err), - function: get_func(err), - reason: get_reason(err) - } + OpenSslErrors(vec![OpensslError::from_error_code(err)]) } } |