commit
44010d7f19
|
|
@ -1556,6 +1556,7 @@ extern {
|
||||||
#[cfg(not(ossl101))]
|
#[cfg(not(ossl101))]
|
||||||
pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM;
|
pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM;
|
||||||
pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long;
|
pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long;
|
||||||
|
pub fn SSL_shutdown(ssl: *mut SSL) -> c_int;
|
||||||
|
|
||||||
#[cfg(not(osslconf = "OPENSSL_NO_COMP"))]
|
#[cfg(not(osslconf = "OPENSSL_NO_COMP"))]
|
||||||
pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char;
|
pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char;
|
||||||
|
|
|
||||||
|
|
@ -1278,6 +1278,26 @@ impl<S: Read + Write> SslStream<S> {
|
||||||
Err(self.make_error(ret))
|
Err(self.make_error(ret))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shuts down the session.
|
||||||
|
///
|
||||||
|
/// The shutdown process consists of two steps. The first step sends a
|
||||||
|
/// close notify message to the peer, after which `ShutdownResult::Sent`
|
||||||
|
/// is returned. The second step awaits the receipt of a close notify
|
||||||
|
/// message from the peer, after which `ShutdownResult::Received` is
|
||||||
|
/// returned.
|
||||||
|
///
|
||||||
|
/// While the connection may be closed after the first step, it is
|
||||||
|
/// recommended to fully shut the session down. In particular, it must
|
||||||
|
/// be fully shut down if the connection is to be used for further
|
||||||
|
/// communication in the future.
|
||||||
|
pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> {
|
||||||
|
match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } {
|
||||||
|
0 => Ok(ShutdownResult::Sent),
|
||||||
|
1 => Ok(ShutdownResult::Received),
|
||||||
|
n => Err(self.make_error(n)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> SslStream<S> {
|
impl<S> SslStream<S> {
|
||||||
|
|
@ -1383,6 +1403,16 @@ impl<S: Read + Write> Write for SslStream<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The result of a shutdown request.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum ShutdownResult {
|
||||||
|
/// A close notify message has been sent to the peer.
|
||||||
|
Sent,
|
||||||
|
|
||||||
|
/// A close notify response message has been received from the peer.
|
||||||
|
Received,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(ossl110)]
|
#[cfg(ossl110)]
|
||||||
mod compat {
|
mod compat {
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ use ssl;
|
||||||
use ssl::SSL_VERIFY_PEER;
|
use ssl::SSL_VERIFY_PEER;
|
||||||
use ssl::{SslMethod, HandshakeError};
|
use ssl::{SslMethod, HandshakeError};
|
||||||
use ssl::error::Error;
|
use ssl::error::Error;
|
||||||
use ssl::{SslContext, SslStream, Ssl};
|
use ssl::{SslContext, SslStream, Ssl, ShutdownResult};
|
||||||
use x509::X509StoreContextRef;
|
use x509::X509StoreContextRef;
|
||||||
use x509::X509FileType;
|
use x509::X509FileType;
|
||||||
use x509::X509;
|
use x509::X509;
|
||||||
|
|
@ -1084,6 +1084,38 @@ fn invalid_hostname() {
|
||||||
assert!(ssl.connect(s).is_err());
|
assert!(ssl.connect(s).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn shutdown() {
|
||||||
|
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||||
|
let port = listener.local_addr().unwrap().port();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let stream = listener.accept().unwrap().0;
|
||||||
|
let mut ctx = SslContext::new(SslMethod::tls()).unwrap();
|
||||||
|
ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM).unwrap();
|
||||||
|
ctx.set_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM).unwrap();
|
||||||
|
let ssl = Ssl::new(&ctx).unwrap();
|
||||||
|
let mut stream = ssl.accept(stream).unwrap();
|
||||||
|
|
||||||
|
stream.write_all(b"hello").unwrap();
|
||||||
|
let mut buf = [0; 1];
|
||||||
|
assert_eq!(stream.read(&mut buf).unwrap(), 0);
|
||||||
|
assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received);
|
||||||
|
});
|
||||||
|
|
||||||
|
let stream = TcpStream::connect(("127.0.0.1", port)).unwrap();
|
||||||
|
let ctx = SslContext::new(SslMethod::tls()).unwrap();
|
||||||
|
let ssl = Ssl::new(&ctx).unwrap();
|
||||||
|
let mut stream = ssl.connect(stream).unwrap();
|
||||||
|
|
||||||
|
let mut buf = [0; 5];
|
||||||
|
stream.read_exact(&mut buf).unwrap();
|
||||||
|
assert_eq!(b"hello", &buf);
|
||||||
|
|
||||||
|
assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Sent);
|
||||||
|
assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received);
|
||||||
|
}
|
||||||
|
|
||||||
fn _check_kinds() {
|
fn _check_kinds() {
|
||||||
fn is_send<T: Send>() {}
|
fn is_send<T: Send>() {}
|
||||||
fn is_sync<T: Sync>() {}
|
fn is_sync<T: Sync>() {}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue