aboutsummaryrefslogtreecommitdiff
path: root/openssl/src/error.rs
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2017-02-19 16:05:58 -0800
committerSteven Fackler <[email protected]>2017-02-19 16:05:58 -0800
commit268288337bc7b798ecc9a5f4f3fc3687d5dd5cd7 (patch)
tree5bb58616ad178aa0edea738cd651024e351bafe6 /openssl/src/error.rs
parentAdd a fixme to drop const prefixes (diff)
downloadrust-openssl-268288337bc7b798ecc9a5f4f3fc3687d5dd5cd7.tar.xz
rust-openssl-268288337bc7b798ecc9a5f4f3fc3687d5dd5cd7.zip
Expose more error information
Diffstat (limited to 'openssl/src/error.rs')
-rw-r--r--openssl/src/error.rs96
1 files changed, 79 insertions, 17 deletions
diff --git a/openssl/src/error.rs b/openssl/src/error.rs
index 26b96408..ad1793f3 100644
--- a/openssl/src/error.rs
+++ b/openssl/src/error.rs
@@ -1,9 +1,11 @@
-use libc::c_ulong;
+use libc::{c_ulong, c_char, c_int};
use std::fmt;
use std::error;
use std::ffi::CStr;
use std::io;
use std::str;
+use std::ptr;
+use std::borrow::Cow;
use ffi;
@@ -62,28 +64,63 @@ impl From<ErrorStack> for fmt::Error {
/// An error reported from OpenSSL.
#[derive(Clone)]
-pub struct Error(c_ulong);
+pub struct Error {
+ code: c_ulong,
+ file: *const c_char,
+ line: c_int,
+ data: Option<Cow<'static, str>>,
+}
+
+unsafe impl Sync for Error {}
+unsafe impl Send for Error {}
impl Error {
/// Returns the first error on the OpenSSL error stack.
pub fn get() -> Option<Error> {
- ffi::init();
-
- match unsafe { ffi::ERR_get_error() } {
- 0 => None,
- err => Some(Error(err)),
+ unsafe {
+ ffi::init();
+
+ let mut file = ptr::null();
+ let mut line = 0;
+ let mut data = ptr::null();
+ let mut flags = 0;
+ match ffi::ERR_get_error_line_data(&mut file, &mut line, &mut data, &mut flags) {
+ 0 => None,
+ code => {
+ // The memory referenced by data is only valid until that slot is overwritten
+ // in the error stack, so we'll need to copy it off if it's dynamic
+ let data = if flags & ffi::ERR_TXT_STRING != 0 {
+ let bytes = CStr::from_ptr(data as *const _).to_bytes();
+ let data = str::from_utf8(bytes).unwrap();
+ let data = if flags & ffi::ERR_TXT_MALLOCED != 0 {
+ Cow::Owned(data.to_string())
+ } else {
+ Cow::Borrowed(data)
+ };
+ Some(data)
+ } else {
+ None
+ };
+ Some(Error {
+ code: code,
+ file: file,
+ line: line,
+ data: data,
+ })
+ }
+ }
}
}
/// Returns the raw OpenSSL error code for this error.
pub fn code(&self) -> c_ulong {
- self.0
+ self.code
}
/// Returns the name of the library reporting the error, if available.
pub fn library(&self) -> Option<&'static str> {
unsafe {
- let cstr = ffi::ERR_lib_error_string(self.0);
+ let cstr = ffi::ERR_lib_error_string(self.code);
if cstr.is_null() {
return None;
}
@@ -95,7 +132,7 @@ impl Error {
/// Returns the name of the function reporting the error.
pub fn function(&self) -> Option<&'static str> {
unsafe {
- let cstr = ffi::ERR_func_error_string(self.0);
+ let cstr = ffi::ERR_func_error_string(self.code);
if cstr.is_null() {
return None;
}
@@ -107,7 +144,7 @@ impl Error {
/// Returns the reason for the error.
pub fn reason(&self) -> Option<&'static str> {
unsafe {
- let cstr = ffi::ERR_reason_error_string(self.0);
+ let cstr = ffi::ERR_reason_error_string(self.code);
if cstr.is_null() {
return None;
}
@@ -115,6 +152,25 @@ impl Error {
Some(str::from_utf8(bytes).unwrap())
}
}
+
+ /// Returns the name of the source file which encountered the error.
+ pub fn file(&self) -> &'static str {
+ unsafe {
+ assert!(!self.file.is_null());
+ let bytes = CStr::from_ptr(self.file as *const _).to_bytes();
+ str::from_utf8(bytes).unwrap()
+ }
+ }
+
+ /// Returns the line in the source file which encountered the error.
+ pub fn line(&self) -> c_int {
+ self.line
+ }
+
+ /// Returns additional data describing the error.
+ pub fn data(&self) -> Option<&str> {
+ self.data.as_ref().map(|s| &**s)
+ }
}
impl fmt::Debug for Error {
@@ -130,30 +186,36 @@ impl fmt::Debug for Error {
if let Some(reason) = self.reason() {
builder.field("reason", &reason);
}
+ builder.field("file", &self.file());
+ builder.field("line", &self.line());
+ if let Some(data) = self.data() {
+ builder.field("data", &data);
+ }
builder.finish()
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(fmt, "error:{:08X}", self.0));
+ try!(write!(fmt, "error:{:08X}", self.code()));
match self.library() {
Some(l) => try!(write!(fmt, ":{}", l)),
- None => try!(write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.0))),
+ None => try!(write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.code()))),
}
match self.function() {
Some(f) => try!(write!(fmt, ":{}", f)),
- None => try!(write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.0))),
+ None => try!(write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.code()))),
}
match self.reason() {
- Some(r) => write!(fmt, ":{}", r),
- None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.0)),
+ Some(r) => try!(write!(fmt, ":{}", r)),
+ None => try!(write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.code()))),
}
+ write!(fmt, ":{}:{}:{}", self.file(), self.line(), self.data().unwrap_or(""))
}
}
impl error::Error for Error {
fn description(&self) -> &str {
- "An OpenSSL error"
+ "an OpenSSL error"
}
}