From 64106c4d3d4ddba8c7bc2af75376e6d3d3d75601 Mon Sep 17 00:00:00 2001 From: Date: Mon, 29 Jun 2015 20:16:15 +0000 Subject: Update documentation --- src/openssl/ssl/error.rs.html | 373 ++++++++ src/openssl/ssl/mod.rs.html | 2079 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2452 insertions(+) create mode 100644 src/openssl/ssl/error.rs.html create mode 100644 src/openssl/ssl/mod.rs.html (limited to 'src/openssl/ssl') diff --git a/src/openssl/ssl/error.rs.html b/src/openssl/ssl/error.rs.html new file mode 100644 index 0000000..683c375 --- /dev/null +++ b/src/openssl/ssl/error.rs.html @@ -0,0 +1,373 @@ + + + + + + + + + + error.rs.html -- source + + + + + + + + + + + + + + + +
  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
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+
+pub use self::SslError::*;
+pub use self::OpensslError::*;
+
+use libc::c_ulong;
+use std::error;
+use std::fmt;
+use std::ffi::CStr;
+use std::io;
+
+use ffi;
+
+/// 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>)
+}
+
+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",
+        }
+    }
+
+    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 = CStr::from_ptr(ffi::ERR_lib_error_string(err)).to_bytes().to_vec();
+        String::from_utf8(bytes).unwrap()
+    }
+}
+
+fn get_func(err: c_ulong) -> String {
+    unsafe {
+        let bytes = CStr::from_ptr(ffi::ERR_func_error_string(err)).to_bytes().to_vec();
+        String::from_utf8(bytes).unwrap()
+    }
+}
+
+fn get_reason(err: c_ulong) -> String {
+    unsafe {
+        let bytes = CStr::from_ptr(ffi::ERR_reason_error_string(err)).to_bytes().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[..], "SSL routines");
+    assert_eq!(&function[..], "SSL23_GET_SERVER_HELLO");
+    assert_eq!(&reason[..], "sslv3 alert handshake failure");
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/openssl/ssl/mod.rs.html b/src/openssl/ssl/mod.rs.html new file mode 100644 index 0000000..40cd850 --- /dev/null +++ b/src/openssl/ssl/mod.rs.html @@ -0,0 +1,2079 @@ + + + + + + + + + + mod.rs.html -- source + + + + + + + + + + + + + + + +
  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
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+
+use libc::{c_int, c_void, c_long};
+use std::any::TypeId;
+use std::collections::HashMap;
+use std::ffi::{CStr, CString};
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::mem;
+use std::net;
+use std::path::Path;
+use std::ptr;
+use std::sync::{Once, ONCE_INIT, Arc, Mutex};
+use std::ops::{Deref, DerefMut};
+use std::cmp;
+use std::any::Any;
+#[cfg(feature = "npn")]
+use libc::{c_uchar, c_uint};
+#[cfg(feature = "npn")]
+use std::slice;
+
+use bio::{MemBio};
+use ffi;
+use ssl::error::{SslError, SslSessionClosed, StreamError, OpenSslErrors};
+use x509::{X509StoreContext, X509FileType, X509};
+use crypto::pkey::PKey;
+
+pub mod error;
+#[cfg(test)]
+mod tests;
+
+static mut VERIFY_IDX: c_int = -1;
+
+fn init() {
+    static mut INIT: Once = ONCE_INIT;
+
+    unsafe {
+        INIT.call_once(|| {
+            ffi::init();
+
+            let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None,
+                                                           None, None);
+            assert!(verify_idx >= 0);
+            VERIFY_IDX = verify_idx;
+        });
+    }
+}
+
+bitflags! {
+    flags SslContextOptions: c_long {
+        const SSL_OP_LEGACY_SERVER_CONNECT = 0x00000004,
+        const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008,
+        const SSL_OP_TLSEXT_PADDING = 0x00000010,
+        const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 0x00000020,
+        const SSL_OP_SAFARI_ECDHE_ECDSA_BUG = 0x00000040,
+        const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 0x00000080,
+        const SSL_OP_TLS_D5_BUG = 0x00000100,
+        const SSL_OP_TLS_BLOCK_PADDING_BUG = 0x00000200,
+        const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800,
+        const SSL_OP_ALL = 0x80000BFF,
+        const SSL_OP_NO_QUERY_MTU = 0x00001000,
+        const SSL_OP_COOKIE_EXCHANGE = 0x00002000,
+        const SSL_OP_NO_TICKET = 0x00004000,
+        const SSL_OP_CISCO_ANYCONNECT = 0x00008000,
+        const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000,
+        const SSL_OP_NO_COMPRESSION = 0x00020000,
+        const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0x00040000,
+        const SSL_OP_SINGLE_ECDH_USE = 0x00080000,
+        const SSL_OP_SINGLE_DH_USE = 0x00100000,
+        const SSL_OP_CIPHER_SERVER_PREFERENCE = 0x00400000,
+        const SSL_OP_TLS_ROLLBACK_BUG = 0x00800000,
+        const SSL_OP_NO_SSLV2 = 0x00000000,
+        const SSL_OP_NO_SSLV3 = 0x02000000,
+        const SSL_OP_NO_TLSV1 = 0x04000000,
+        const SSL_OP_NO_TLSV1_2 = 0x08000000,
+        const SSL_OP_NO_TLSV1_1 = 0x10000000,
+        const SSL_OP_NO_DTLSV1 = 0x04000000,
+        const SSL_OP_NO_DTLSV1_2 = 0x08000000
+    }
+}
+
+/// Determines the SSL method supported
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub enum SslMethod {
+    #[cfg(feature = "sslv2")]
+    /// Only support the SSLv2 protocol, requires the `sslv2` feature.
+    Sslv2,
+    /// Support the SSLv2, SSLv3 and TLSv1 protocols.
+    Sslv23,
+    /// Only support the SSLv3 protocol.
+    Sslv3,
+    /// Only support the TLSv1 protocol.
+    Tlsv1,
+    #[cfg(feature = "tlsv1_1")]
+    /// Support TLSv1.1 protocol, requires the `tlsv1_1` feature.
+    Tlsv1_1,
+    #[cfg(feature = "tlsv1_2")]
+    /// Support TLSv1.2 protocol, requires the `tlsv1_2` feature.
+    Tlsv1_2,
+    #[cfg(feature = "dtlsv1")]
+    /// Support DTLSv1 protocol, requires the `dtlsv1` feature.
+    Dtlsv1,
+    #[cfg(feature = "dtlsv1_2")]
+    /// Support DTLSv1.2 protocol, requires the `dtlsv1_2` feature.
+    Dtlsv1_2,
+}
+
+impl SslMethod {
+    unsafe fn to_raw(&self) -> *const ffi::SSL_METHOD {
+        match *self {
+            #[cfg(feature = "sslv2")]
+            SslMethod::Sslv2 => ffi::SSLv2_method(),
+            SslMethod::Sslv3 => ffi::SSLv3_method(),
+            SslMethod::Tlsv1 => ffi::TLSv1_method(),
+            SslMethod::Sslv23 => ffi::SSLv23_method(),
+            #[cfg(feature = "tlsv1_1")]
+            SslMethod::Tlsv1_1 => ffi::TLSv1_1_method(),
+            #[cfg(feature = "tlsv1_2")]
+            SslMethod::Tlsv1_2 => ffi::TLSv1_2_method(),
+            #[cfg(feature = "dtlsv1")]
+            SslMethod::Dtlsv1 => ffi::DTLSv1_method(),
+            #[cfg(feature = "dtlsv1_2")]
+            SslMethod::Dtlsv1_2 => ffi::DTLSv1_2_method(),
+        }
+    }
+
+    #[cfg(feature = "dtlsv1")]
+    pub fn is_dtlsv1(&self) -> bool {
+        *self == SslMethod::Dtlsv1
+    }
+
+    #[cfg(feature = "dtlsv1_2")]
+    pub fn is_dtlsv1_2(&self) -> bool {
+        *self == SslMethod::Dtlsv1_2
+    }
+
+    pub fn is_dtls(&self) -> bool {
+        self.is_dtlsv1() || self.is_dtlsv1_2()
+    }
+
+    #[cfg(not(feature = "dtlsv1"))]
+    pub fn is_dtlsv1(&self) -> bool {
+        false
+    }
+
+    #[cfg(not(feature = "dtlsv1_2"))]
+    pub fn is_dtlsv1_2(&self) -> bool {
+        false
+    }
+}
+
+/// Determines the type of certificate verification used
+bitflags! {
+    flags SslVerifyMode: i32 {
+        /// Verify that the server's certificate is trusted
+        const SSL_VERIFY_PEER = ffi::SSL_VERIFY_PEER,
+        /// Do not verify the server's certificate
+        const SSL_VERIFY_NONE = ffi::SSL_VERIFY_NONE,
+        /// Terminate handshake if client did not return a certificate.
+        /// Use together with SSL_VERIFY_PEER.
+        const SSL_VERIFY_FAIL_IF_NO_PEER_CERT = ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+    }
+}
+
+lazy_static! {
+    static ref INDEXES: Mutex<HashMap<TypeId, c_int>> = Mutex::new(HashMap::new());
+}
+
+// Creates a static index for user data of type T
+// Registers a destructor for the data which will be called
+// when context is freed
+fn get_verify_data_idx<T: Any + 'static>() -> c_int {
+    extern fn free_data_box<T>(_parent: *mut c_void, ptr: *mut c_void,
+                               _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int,
+                               _argl: c_long, _argp: *mut c_void) {
+        if ptr != 0 as *mut _ {
+            let _: Box<T> = unsafe { mem::transmute(ptr) };
+        }
+    }
+
+    *INDEXES.lock().unwrap().entry(TypeId::of::<T>()).or_insert_with(|| {
+        unsafe {
+            let f: ffi::CRYPTO_EX_free = free_data_box::<T>;
+            let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, Some(f));
+            assert!(idx >= 0);
+            idx
+        }
+    })
+}
+
+/// Creates a static index for the list of NPN protocols.
+/// Registers a destructor for the data which will be called
+/// when the context is freed.
+#[cfg(feature = "npn")]
+fn get_npn_protos_idx() -> c_int {
+    static mut NPN_PROTOS_IDX: c_int = -1;
+    static mut INIT: Once = ONCE_INIT;
+
+    extern fn free_data_box(_parent: *mut c_void, ptr: *mut c_void,
+                            _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int,
+                            _argl: c_long, _argp: *mut c_void) {
+        if !ptr.is_null() {
+            let _: Box<Vec<u8>> = unsafe { mem::transmute(ptr) };
+        }
+    }
+
+    unsafe {
+        INIT.call_once(|| {
+            let f: ffi::CRYPTO_EX_free = free_data_box;
+            let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None,
+                                                    None, Some(f));
+            assert!(idx >= 0);
+            NPN_PROTOS_IDX = idx;
+        });
+        NPN_PROTOS_IDX
+    }
+}
+
+extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX)
+        -> c_int {
+    unsafe {
+        let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
+        let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
+        let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+        let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
+        let verify: Option<VerifyCallback> = mem::transmute(verify);
+
+        let ctx = X509StoreContext::new(x509_ctx);
+
+        match verify {
+            None => preverify_ok,
+            Some(verify) => verify(preverify_ok != 0, &ctx) as c_int
+        }
+    }
+}
+
+extern fn raw_verify_with_data<T>(preverify_ok: c_int,
+                                  x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int
+                                  where T: Any + 'static {
+    unsafe {
+        let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
+        let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
+        let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+
+        let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX);
+        let verify: Option<VerifyCallbackData<T>> = mem::transmute(verify);
+
+        let data = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<T>());
+        let data: Box<T> = mem::transmute(data);
+
+        let ctx = X509StoreContext::new(x509_ctx);
+
+        let res = match verify {
+            None => preverify_ok,
+            Some(verify) => verify(preverify_ok != 0, &ctx, &*data) as c_int
+        };
+
+        // Since data might be required on the next verification
+        // it is time to forget about it and avoid dropping
+        // data will be freed once OpenSSL considers it is time
+        // to free all context data
+        mem::forget(data);
+        res
+    }
+}
+
+/// The function is given as the callback to `SSL_CTX_set_next_proto_select_cb`.
+///
+/// It chooses the protocol that the client wishes to use, out of the given list of protocols
+/// supported by the server. It achieves this by delegating to the `SSL_select_next_proto`
+/// function. The list of protocols supported by the client is found in the extra data of the
+/// OpenSSL context.
+#[cfg(feature = "npn")]
+extern fn raw_next_proto_select_cb(ssl: *mut ffi::SSL,
+                                   out: *mut *mut c_uchar, outlen: *mut c_uchar,
+                                   inbuf: *const c_uchar, inlen: c_uint,
+                                   _arg: *mut c_void) -> c_int {
+    unsafe {
+        // First, get the list of protocols (that the client should support) saved in the context
+        // extra data.
+        let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+        let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_npn_protos_idx());
+        let protocols: &Vec<u8> = mem::transmute(protocols);
+        // Prepare the client list parameters to be passed to the OpenSSL function...
+        let client = protocols.as_ptr();
+        let client_len = protocols.len() as c_uint;
+        // Finally, let OpenSSL find a protocol to be used, by matching the given server and
+        // client lists.
+        ffi::SSL_select_next_proto(out, outlen, inbuf, inlen, client, client_len);
+    }
+
+    ffi::SSL_TLSEXT_ERR_OK
+}
+
+/// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`.
+///
+/// It causes the parameter `out` to point at a `*const c_uchar` instance that
+/// represents the list of protocols that the server should advertise as those
+/// that it supports.
+/// The list of supported protocols is found in the extra data of the OpenSSL
+/// context.
+#[cfg(feature = "npn")]
+extern fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL,
+                                       out: *mut *const c_uchar, outlen: *mut c_uint,
+                                       _arg: *mut c_void) -> c_int {
+    unsafe {
+        // First, get the list of (supported) protocols saved in the context extra data.
+        let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
+        let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_npn_protos_idx());
+        if protocols.is_null() {
+            *out = b"".as_ptr();
+            *outlen = 0;
+        } else {
+            // If the pointer is valid, put the pointer to the actual byte array into the
+            // output parameter `out`, as well as its length into `outlen`.
+            let protocols: &Vec<u8> = mem::transmute(protocols);
+            *out = protocols.as_ptr();
+            *outlen = protocols.len() as c_uint;
+        }
+    }
+
+    ffi::SSL_TLSEXT_ERR_OK
+}
+
+/// The signature of functions that can be used to manually verify certificates
+pub type VerifyCallback = fn(preverify_ok: bool,
+                             x509_ctx: &X509StoreContext) -> bool;
+
+/// The signature of functions that can be used to manually verify certificates
+/// when user-data should be carried for all verification process
+pub type VerifyCallbackData<T> = fn(preverify_ok: bool,
+                                    x509_ctx: &X509StoreContext,
+                                    data: &T) -> bool;
+
+// FIXME: macro may be instead of inlining?
+#[inline]
+fn wrap_ssl_result(res: c_int) -> Result<(),SslError> {
+    if res == 0 {
+        Err(SslError::get())
+    } else {
+        Ok(())
+    }
+}
+
+/// An SSL context object
+pub struct SslContext {
+    ctx: *mut ffi::SSL_CTX
+}
+
+unsafe impl Send for SslContext {}
+unsafe impl Sync for SslContext {}
+
+// TODO: add useful info here
+impl fmt::Debug for SslContext {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "SslContext")
+    }
+}
+
+impl Drop for SslContext {
+    fn drop(&mut self) {
+        unsafe { ffi::SSL_CTX_free(self.ctx) }
+    }
+}
+
+impl SslContext {
+    /// Creates a new SSL context.
+    pub fn new(method: SslMethod) -> Result<SslContext, SslError> {
+        init();
+
+        let ctx = unsafe { ffi::SSL_CTX_new(method.to_raw()) };
+        if ctx == ptr::null_mut() {
+            return Err(SslError::get());
+        }
+
+        let ctx = SslContext { ctx: ctx };
+
+        if method.is_dtls() {
+            ctx.set_read_ahead(1);
+        }
+
+        Ok(ctx)
+    }
+
+    /// Configures the certificate verification method for new connections.
+    pub fn set_verify(&mut self, mode: SslVerifyMode,
+                      verify: Option<VerifyCallback>) {
+        unsafe {
+            ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX,
+                                     mem::transmute(verify));
+            let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int =
+                                raw_verify;
+
+            ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+        }
+    }
+
+    /// Configures the certificate verification method for new connections also
+    /// carrying supplied data.
+    // Note: no option because there is no point to set data without providing
+    // a function handling it
+    pub fn set_verify_with_data<T>(&mut self, mode: SslVerifyMode,
+                                   verify: VerifyCallbackData<T>,
+                                   data: T)
+                                   where T: Any + 'static {
+        let data = Box::new(data);
+        unsafe {
+            ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX,
+                                     mem::transmute(Some(verify)));
+            ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::<T>(),
+                                     mem::transmute(data));
+            let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int =
+                                raw_verify_with_data::<T>;
+
+            ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(f));
+        }
+    }
+
+    /// Sets verification depth
+    pub fn set_verify_depth(&mut self, depth: u32) {
+        unsafe {
+            ffi::SSL_CTX_set_verify_depth(self.ctx, depth as c_int);
+        }
+    }
+
+    pub fn set_read_ahead(&self, m: u32) {
+        unsafe {
+            ffi::SSL_CTX_set_read_ahead(self.ctx, m as c_long);
+        }
+    }
+
+    #[allow(non_snake_case)]
+    /// Specifies the file that contains trusted CA certificates.
+    pub fn set_CA_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(),SslError> {
+        let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_load_verify_locations(self.ctx, file.as_ptr(), ptr::null())
+            })
+    }
+
+    /// Specifies the file that contains certificate
+    pub fn set_certificate_file<P: AsRef<Path>>(&mut self, file: P, file_type: X509FileType)
+                                                -> Result<(),SslError> {
+        let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_use_certificate_file(self.ctx, file.as_ptr(), file_type as c_int)
+            })
+    }
+
+    /// Specifies the certificate
+    pub fn set_certificate(&mut self, cert: &X509) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_use_certificate(self.ctx, cert.get_handle())
+            })
+    }
+
+    /// Adds a certificate to the certificate chain presented together with the
+    /// certificate specified using set_certificate()
+    pub fn add_extra_chain_cert(&mut self, cert: &X509) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_add_extra_chain_cert(self.ctx, cert.get_handle()) as c_int
+            })
+    }
+
+    /// Specifies the file that contains private key
+    pub fn set_private_key_file<P: AsRef<Path>>(&mut self, file: P,
+                                file_type: X509FileType) -> Result<(),SslError> {
+        let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_use_PrivateKey_file(self.ctx, file.as_ptr(), file_type as c_int)
+            })
+    }
+
+    /// Specifies the private key
+    pub fn set_private_key(&mut self, key: &PKey) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_use_PrivateKey(self.ctx, key.get_handle())
+            })
+    }
+
+    /// Check consistency of private key and certificate
+    pub fn check_private_key(&mut self) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                ffi::SSL_CTX_check_private_key(self.ctx)
+            })
+    }
+
+    pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(),SslError> {
+        wrap_ssl_result(
+            unsafe {
+                let cipher_list = CString::new(cipher_list.as_bytes()).unwrap();
+                ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list.as_ptr())
+            })
+    }
+
+    pub fn set_options(&mut self, option: SslContextOptions) -> SslContextOptions {
+        let raw_bits = option.bits();
+        let ret = unsafe {
+            ffi::SSL_CTX_set_options(self.ctx, raw_bits)
+        };
+        SslContextOptions::from_bits(ret).unwrap()
+    }
+
+    pub fn get_options(&mut self) -> SslContextOptions {
+        let ret = unsafe {
+            ffi::SSL_CTX_get_options(self.ctx)
+        };
+        SslContextOptions::from_bits(ret).unwrap()
+    }
+
+    pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions {
+        let raw_bits = option.bits();
+        let ret = unsafe {
+            ffi::SSL_CTX_clear_options(self.ctx, raw_bits)
+        };
+        SslContextOptions::from_bits(ret).unwrap()
+    }
+
+    /// Set the protocols to be used during Next Protocol Negotiation (the protocols
+    /// supported by the application).
+    ///
+    /// This method needs the `npn` feature.
+    #[cfg(feature = "npn")]
+    pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) {
+        // Firstly, convert the list of protocols to a byte-array that can be passed to OpenSSL
+        // APIs -- a list of length-prefixed strings.
+        let mut npn_protocols = Vec::new();
+        for protocol in protocols {
+            let len = protocol.len() as u8;
+            npn_protocols.push(len);
+            // If the length is greater than the max `u8`, this truncates the protocol name.
+            npn_protocols.extend(protocol[..len as usize].to_vec());
+        }
+        let protocols: Box<Vec<u8>> = Box::new(npn_protocols);
+
+        unsafe {
+            // Attach the protocol list to the OpenSSL context structure,
+            // so that we can refer to it within the callback.
+            ffi::SSL_CTX_set_ex_data(self.ctx, get_npn_protos_idx(),
+                                     mem::transmute(protocols));
+            // Now register the callback that performs the default protocol
+            // matching based on the client-supported list of protocols that
+            // has been saved.
+            ffi::SSL_CTX_set_next_proto_select_cb(self.ctx, raw_next_proto_select_cb, ptr::null_mut());
+            // Also register the callback to advertise these protocols, if a server socket is
+            // created with the context.
+            ffi::SSL_CTX_set_next_protos_advertised_cb(self.ctx, raw_next_protos_advertise_cb, ptr::null_mut());
+        }
+    }
+}
+
+#[allow(dead_code)]
+struct MemBioRef<'ssl> {
+    ssl: &'ssl Ssl,
+    bio: MemBio,
+}
+
+impl<'ssl> Deref for MemBioRef<'ssl> {
+    type Target = MemBio;
+
+    fn deref(&self) -> &MemBio {
+        &self.bio
+    }
+}
+
+impl<'ssl> DerefMut for MemBioRef<'ssl> {
+    fn deref_mut(&mut self) -> &mut MemBio {
+        &mut self.bio
+    }
+}
+
+pub struct Ssl {
+    ssl: *mut ffi::SSL
+}
+
+unsafe impl Send for Ssl {}
+unsafe impl Sync for Ssl {}
+
+// TODO: put useful information here
+impl fmt::Debug for Ssl {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "Ssl")
+    }
+}
+
+impl Drop for Ssl {
+    fn drop(&mut self) {
+        unsafe { ffi::SSL_free(self.ssl) }
+    }
+}
+
+impl Ssl {
+    pub fn new(ctx: &SslContext) -> Result<Ssl, SslError> {
+        let ssl = unsafe { ffi::SSL_new(ctx.ctx) };
+        if ssl == ptr::null_mut() {
+            return Err(SslError::get());
+        }
+        let ssl = Ssl { ssl: ssl };
+
+        let rbio = try!(MemBio::new());
+        let wbio = try!(MemBio::new());
+
+        unsafe { ffi::SSL_set_bio(ssl.ssl, rbio.unwrap(), wbio.unwrap()) }
+        Ok(ssl)
+    }
+
+    fn get_rbio<'a>(&'a self) -> MemBioRef<'a> {
+        unsafe { self.wrap_bio(ffi::SSL_get_rbio(self.ssl)) }
+    }
+
+    fn get_wbio<'a>(&'a self) -> MemBioRef<'a> {
+        unsafe { self.wrap_bio(ffi::SSL_get_wbio(self.ssl)) }
+    }
+
+    fn wrap_bio<'a>(&'a self, bio: *mut ffi::BIO) -> MemBioRef<'a> {
+        assert!(bio != ptr::null_mut());
+        MemBioRef {
+            ssl: self,
+            bio: MemBio::borrowed(bio)
+        }
+    }
+
+    fn connect(&self) -> c_int {
+        unsafe { ffi::SSL_connect(self.ssl) }
+    }
+
+    fn accept(&self) -> c_int {
+        unsafe { ffi::SSL_accept(self.ssl) }
+    }
+
+    fn read(&self, buf: &mut [u8]) -> c_int {
+        let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+        unsafe { ffi::SSL_read(self.ssl, buf.as_ptr() as *mut c_void, len) }
+    }
+
+    fn write(&self, buf: &[u8]) -> c_int {
+        let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+        unsafe { ffi::SSL_write(self.ssl, buf.as_ptr() as *const c_void, len) }
+    }
+
+    fn get_error(&self, ret: c_int) -> LibSslError {
+        let err = unsafe { ffi::SSL_get_error(self.ssl, ret) };
+        match LibSslError::from_i32(err as i32) {
+            Some(err) => err,
+            None => unreachable!()
+        }
+    }
+
+    /// Set the host name to be used with SNI (Server Name Indication).
+    pub fn set_hostname(&self, hostname: &str) -> Result<(), SslError> {
+        let ret = unsafe {
+                // This is defined as a macro:
+                //      #define SSL_set_tlsext_host_name(s,name) \
+                //          SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name)
+
+                let hostname = CString::new(hostname.as_bytes()).unwrap();
+                ffi::SSL_ctrl(self.ssl, ffi::SSL_CTRL_SET_TLSEXT_HOSTNAME,
+                              ffi::TLSEXT_NAMETYPE_host_name,
+                              hostname.as_ptr() as *mut c_void)
+        };
+
+        // For this case, 0 indicates failure.
+        if ret == 0 {
+            Err(SslError::get())
+        } else {
+            Ok(())
+        }
+    }
+
+    pub fn get_peer_certificate(&self) -> Option<X509> {
+        unsafe {
+            let ptr = ffi::SSL_get_peer_certificate(self.ssl);
+            if ptr.is_null() {
+                None
+            } else {
+                Some(X509::new(ptr, true))
+            }
+        }
+    }
+
+    /// Returns the protocol selected by performing Next Protocol Negotiation, if any.
+    ///
+    /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
+    /// to interpret it.
+    ///
+    /// This method needs the `npn` feature.
+    #[cfg(feature = "npn")]
+    pub fn get_selected_npn_protocol(&self) -> Option<&[u8]> {
+        unsafe {
+            let mut data: *const c_uchar = ptr::null();
+            let mut len: c_uint = 0;
+            // Get the negotiated protocol from the SSL instance.
+            // `data` will point at a `c_uchar` array; `len` will contain the length of this array.
+            ffi::SSL_get0_next_proto_negotiated(self.ssl, &mut data, &mut len);
+
+            if data.is_null() {
+                None
+            } else {
+                Some(slice::from_raw_parts(data, len as usize))
+            }
+        }
+    }
+
+    /// pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any).
+    pub fn pending(&self) -> usize {
+        unsafe {
+            ffi::SSL_pending(self.ssl) as usize
+        }
+    }
+}
+
+macro_rules! make_LibSslError {
+    ($($variant:ident = $value:ident),+) => {
+        #[derive(Debug)]
+        #[repr(i32)]
+        enum LibSslError {
+            $($variant = ffi::$value),+
+        }
+
+        impl LibSslError {
+            fn from_i32(val: i32) -> Option<LibSslError> {
+                match val {
+                    $(ffi::$value => Some(LibSslError::$variant),)+
+                    _ => None
+                }
+            }
+        }
+    }
+}
+
+make_LibSslError! {
+    ErrorNone = SSL_ERROR_NONE,
+    ErrorSsl = SSL_ERROR_SSL,
+    ErrorWantRead = SSL_ERROR_WANT_READ,
+    ErrorWantWrite = SSL_ERROR_WANT_WRITE,
+    ErrorWantX509Lookup = SSL_ERROR_WANT_X509_LOOKUP,
+    ErrorSyscall = SSL_ERROR_SYSCALL,
+    ErrorZeroReturn = SSL_ERROR_ZERO_RETURN,
+    ErrorWantConnect = SSL_ERROR_WANT_CONNECT,
+    ErrorWantAccept = SSL_ERROR_WANT_ACCEPT
+}
+
+/// A stream wrapper which handles SSL encryption for an underlying stream.
+#[derive(Clone)]
+pub struct SslStream<S> {
+    stream: S,
+    ssl: Arc<Ssl>,
+    buf: Vec<u8>
+}
+
+impl SslStream<net::TcpStream> {
+    /// Create a new independently owned handle to the underlying socket.
+    pub fn try_clone(&self) -> io::Result<SslStream<net::TcpStream>> {
+        Ok(SslStream {
+            stream: try!(self.stream.try_clone()),
+            ssl: self.ssl.clone(),
+            buf: self.buf.clone(),
+        })
+    }
+}
+
+impl<S> fmt::Debug for SslStream<S> where S: fmt::Debug {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "SslStream {{ stream: {:?}, ssl: {:?} }}", self.stream, self.ssl)
+    }
+}
+
+impl<S: Read+Write> SslStream<S> {
+    fn new_base(ssl:Ssl, stream: S) -> SslStream<S> {
+        SslStream {
+            stream: stream,
+            ssl: Arc::new(ssl),
+            // Maximum TLS record size is 16k
+            // We're just using this as a buffer, so there's no reason to pay
+            // to memset it
+            buf: {
+                const CAP: usize = 16 * 1024;
+                let mut v = Vec::with_capacity(CAP);
+                unsafe { v.set_len(CAP); }
+                v
+            }
+        }
+    }
+
+    pub fn new_server_from(ssl: Ssl, stream: S) -> Result<SslStream<S>, SslError> {
+        let mut ssl = SslStream::new_base(ssl, stream);
+        ssl.in_retry_wrapper(|ssl| { ssl.accept() }).and(Ok(ssl))
+    }
+
+    /// Attempts to create a new SSL stream from a given `Ssl` instance.
+    pub fn new_from(ssl: Ssl, stream: S) -> Result<SslStream<S>, SslError> {
+        let mut ssl = SslStream::new_base(ssl, stream);
+        ssl.in_retry_wrapper(|ssl| { ssl.connect() }).and(Ok(ssl))
+    }
+
+    /// Creates a new SSL stream
+    pub fn new(ctx: &SslContext, stream: S) -> Result<SslStream<S>, SslError> {
+        let ssl = try!(Ssl::new(ctx));
+        SslStream::new_from(ssl, stream)
+    }
+
+    /// Creates a new SSL server stream
+    pub fn new_server(ctx: &SslContext, stream: S) -> Result<SslStream<S>, SslError> {
+        let ssl = try!(Ssl::new(ctx));
+        SslStream::new_server_from(ssl, stream)
+    }
+
+    #[doc(hidden)]
+    pub fn get_inner(&mut self) -> &mut S {
+        self.get_mut()
+    }
+
+    /// Returns a reference to the underlying stream.
+    pub fn get_ref(&self) -> &S {
+        &self.stream
+    }
+
+    /// Return the certificate of the peer
+    pub fn get_peer_certificate(&self) -> Option<X509> {
+        self.ssl.get_peer_certificate()
+    }
+
+    /// Returns a mutable reference to the underlying stream.
+    ///
+    /// ## Warning
+    ///
+    /// It is inadvisable to read from or write to the underlying stream as it
+    /// will most likely desynchronize the SSL session.
+    pub fn get_mut(&mut self) -> &mut S {
+        &mut self.stream
+    }
+
+    fn in_retry_wrapper<F>(&mut self, mut blk: F)
+            -> Result<c_int, SslError> where F: FnMut(&Ssl) -> c_int {
+        loop {
+            let ret = blk(&self.ssl);
+            if ret > 0 {
+                return Ok(ret);
+            }
+
+            let e = self.ssl.get_error(ret);
+            match e {
+                LibSslError::ErrorWantRead => {
+                    try_ssl_stream!(self.flush());
+                    let len = try_ssl_stream!(self.stream.read(&mut self.buf[..]));
+                    if len == 0 {
+                        self.ssl.get_rbio().set_eof(true);
+                    } else {
+                        try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len]));
+                    }
+                }
+                LibSslError::ErrorWantWrite => { try_ssl_stream!(self.flush()) }
+                LibSslError::ErrorZeroReturn => return Err(SslSessionClosed),
+                LibSslError::ErrorSsl => return Err(SslError::get()),
+                LibSslError::ErrorSyscall if ret == 0 => return Ok(0),
+                err => panic!("unexpected error {:?} with ret {}", err, ret),
+            }
+        }
+    }
+
+    fn write_through(&mut self) -> io::Result<()> {
+        io::copy(&mut *self.ssl.get_wbio(), &mut self.stream).map(|_| ())
+    }
+
+    /// Get the compression currently in use.  The result will be
+    /// either None, indicating no compression is in use, or a string
+    /// with the compression name.
+    pub fn get_compression(&self) -> Option<String> {
+        let ptr = unsafe { ffi::SSL_get_current_compression(self.ssl.ssl) };
+        if ptr == ptr::null() {
+            return None;
+        }
+
+        let meth = unsafe { ffi::SSL_COMP_get_name(ptr) };
+        let s = unsafe {
+            String::from_utf8(CStr::from_ptr(meth).to_bytes().to_vec()).unwrap()
+        };
+
+        Some(s)
+    }
+
+    /// Returns the protocol selected by performing Next Protocol Negotiation, if any.
+    ///
+    /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
+    /// to interpret it.
+    ///
+    /// This method needs the `npn` feature.
+    #[cfg(feature = "npn")]
+    pub fn get_selected_npn_protocol(&self) -> Option<&[u8]> {
+        self.ssl.get_selected_npn_protocol()
+    }
+
+    /// pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any).
+    pub fn pending(&self) -> usize {
+        self.ssl.pending()
+    }
+}
+
+impl<S: Read+Write> Read for SslStream<S> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        match self.in_retry_wrapper(|ssl| { ssl.read(buf) }) {
+            Ok(len) => Ok(len as usize),
+            Err(SslSessionClosed) => Ok(0),
+            Err(StreamError(e)) => Err(e),
+            Err(e @ OpenSslErrors(_)) => {
+                Err(io::Error::new(io::ErrorKind::Other, e))
+            }
+        }
+    }
+}
+
+impl<S: Read+Write> Write for SslStream<S> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let count = match self.in_retry_wrapper(|ssl| ssl.write(buf)) {
+            Ok(len) => len as usize,
+            Err(SslSessionClosed) => 0,
+            Err(StreamError(e)) => return Err(e),
+            Err(e @ OpenSslErrors(_)) => return Err(io::Error::new(io::ErrorKind::Other, e)),
+        };
+        try!(self.write_through());
+        Ok(count)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        try!(self.write_through());
+        self.stream.flush()
+    }
+}
+
+/// A utility type to help in cases where the use of SSL is decided at runtime.
+#[derive(Debug)]
+pub enum MaybeSslStream<S> where S: Read+Write {
+    /// A connection using SSL
+    Ssl(SslStream<S>),
+    /// A connection not using SSL
+    Normal(S),
+}
+
+impl<S> Read for MaybeSslStream<S> where S: Read+Write {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        match *self {
+            MaybeSslStream::Ssl(ref mut s) => s.read(buf),
+            MaybeSslStream::Normal(ref mut s) => s.read(buf),
+        }
+    }
+}
+
+impl<S> Write for MaybeSslStream<S> where S: Read+Write {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match *self {
+            MaybeSslStream::Ssl(ref mut s) => s.write(buf),
+            MaybeSslStream::Normal(ref mut s) => s.write(buf),
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        match *self {
+            MaybeSslStream::Ssl(ref mut s) => s.flush(),
+            MaybeSslStream::Normal(ref mut s) => s.flush(),
+        }
+    }
+}
+
+impl<S> MaybeSslStream<S> where S: Read+Write {
+    /// Returns a reference to the underlying stream.
+    pub fn get_ref(&self) -> &S {
+        match *self {
+            MaybeSslStream::Ssl(ref s) => s.get_ref(),
+            MaybeSslStream::Normal(ref s) => s,
+        }
+    }
+
+    /// Returns a mutable reference to the underlying stream.
+    ///
+    /// ## Warning
+    ///
+    /// It is inadvisable to read from or write to the underlying stream.
+    pub fn get_mut(&mut self) -> &mut S {
+        match *self {
+            MaybeSslStream::Ssl(ref mut s) => s.get_mut(),
+            MaybeSslStream::Normal(ref mut s) => s,
+        }
+    }
+}
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3