diff options
| author | Steven Fackler <[email protected]> | 2015-02-07 21:28:54 -0800 |
|---|---|---|
| committer | Steven Fackler <[email protected]> | 2015-02-07 21:30:05 -0800 |
| commit | ec65b0c67b452539fded5e06cbb6ce1d165074e0 (patch) | |
| tree | c50c22c2ce4ca095149c96a0f3a3b935b4012a5c /openssl/src/ssl/error.rs | |
| parent | Fix deprecation warnings in openssl-sys (diff) | |
| download | rust-openssl-ec65b0c67b452539fded5e06cbb6ce1d165074e0.tar.xz rust-openssl-ec65b0c67b452539fded5e06cbb6ce1d165074e0.zip | |
Move docs to this repo and auto build
Diffstat (limited to 'openssl/src/ssl/error.rs')
| -rw-r--r-- | openssl/src/ssl/error.rs | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs new file mode 100644 index 00000000..027554c5 --- /dev/null +++ b/openssl/src/ssl/error.rs @@ -0,0 +1,122 @@ +pub use self::SslError::*; +pub use self::OpensslError::*; + +use libc::c_ulong; +use std::error; +use std::fmt; +use std::ffi::c_str_to_bytes; +use std::old_io::IoError; + +use ffi; + +/// An SSL error +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SslError { + /// The underlying stream reported an error + StreamError(IoError), + /// The SSL session has been closed by the other end + SslSessionClosed, + /// An error in the OpenSSL library + OpenSslErrors(Vec<OpensslError>) +} + +impl fmt::Display for SslError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(error::Error::description(self)) + } +} + +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", + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + StreamError(ref err) => Some(err as &error::Error), + _ => None + } + } +} + +/// 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 + } +} + +fn get_lib(err: c_ulong) -> String { + unsafe { + let bytes = c_str_to_bytes(&ffi::ERR_lib_error_string(err)).to_vec(); + String::from_utf8(bytes).unwrap() + } +} + +fn get_func(err: c_ulong) -> String { + unsafe { + let bytes = c_str_to_bytes(&ffi::ERR_func_error_string(err)).to_vec(); + String::from_utf8(bytes).unwrap() + } +} + +fn get_reason(err: c_ulong) -> String { + unsafe { + let bytes = c_str_to_bytes(&ffi::ERR_reason_error_string(err)).to_vec(); + String::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(SslError::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![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) + } + } +} + +#[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.as_slice(), "SSL routines"); + assert_eq!(function.as_slice(), "SSL23_GET_SERVER_HELLO"); + assert_eq!(reason.as_slice(), "sslv3 alert handshake failure"); +} |