Commit 44010d7f authored by Steven Fackler's avatar Steven Fackler Committed by GitHub
Browse files

Merge pull request #490 from sfackler/shutdown

Add a shutdown method
parents eb655bdd 39279455
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+30 −0
Original line number Diff line number Diff line
@@ -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;
+33 −1
Original line number Diff line number Diff line
@@ -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>() {}