1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
pub use self::SslError::*;
pub use self::OpensslError::*;
use libc::c_ulong;
use std::error;
use std::ffi::c_str_to_bytes;
use std::io::IoError;
use ffi;
#[derive(Show, Clone, PartialEq, Eq)]
pub enum SslError {
StreamError(IoError),
SslSessionClosed,
OpenSslErrors(Vec<OpensslError>)
}
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
}
}
}
#[derive(Show, Clone, PartialEq, Eq)]
pub enum OpensslError {
UnknownError {
library: String,
function: String,
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 {
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)
}
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");
}