commit
44010d7f19
|
|
@ -1556,6 +1556,7 @@ extern {
|
|||
#[cfg(not(ossl101))]
|
||||
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_shutdown(ssl: *mut SSL) -> c_int;
|
||||
|
||||
#[cfg(not(osslconf = "OPENSSL_NO_COMP"))]
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
|
|
@ -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)]
|
||||
mod compat {
|
||||
use std::ptr;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use ssl;
|
|||
use ssl::SSL_VERIFY_PEER;
|
||||
use ssl::{SslMethod, HandshakeError};
|
||||
use ssl::error::Error;
|
||||
use ssl::{SslContext, SslStream, Ssl};
|
||||
use ssl::{SslContext, SslStream, Ssl, ShutdownResult};
|
||||
use x509::X509StoreContextRef;
|
||||
use x509::X509FileType;
|
||||
use x509::X509;
|
||||
|
|
@ -1084,6 +1084,38 @@ fn invalid_hostname() {
|
|||
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 is_send<T: Send>() {}
|
||||
fn is_sync<T: Sync>() {}
|
||||
|
|
|
|||
Loading…
Reference in New Issue