diff options
| author | Jamie Turner <[email protected]> | 2015-09-19 20:50:06 -0700 |
|---|---|---|
| committer | Jamie Turner <[email protected]> | 2015-10-20 23:14:26 -0700 |
| commit | c37767df8fc1775858cd573cbe4d5e3a17fbd370 (patch) | |
| tree | a80fcebc4891737bc833a51b4cf5034dcb63ab6f /openssl/src/ssl/tests.rs | |
| parent | Merge pull request #290 from jimmycuadra/master (diff) | |
| download | rust-openssl-c37767df8fc1775858cd573cbe4d5e3a17fbd370.tar.xz rust-openssl-c37767df8fc1775858cd573cbe4d5e3a17fbd370.zip | |
Nonblocking streams support.
Diffstat (limited to 'openssl/src/ssl/tests.rs')
| -rw-r--r-- | openssl/src/ssl/tests.rs | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/openssl/src/ssl/tests.rs b/openssl/src/ssl/tests.rs index 033a3b86..8335bc53 100644 --- a/openssl/src/ssl/tests.rs +++ b/openssl/src/ssl/tests.rs @@ -819,3 +819,135 @@ fn test_sslv2_connect_failure() { let (_s, tcp) = Server::new_tcp(&["-no_ssl2", "-www"]); SslStream::connect_generic(&SslContext::new(Sslv2).unwrap(), tcp).err().unwrap(); } + +#[cfg(target_os = "linux")] +mod nonblocking_tests { + extern crate nix; + + use std::io::Write; + use std::net::TcpStream; + use std::os::unix::io::AsRawFd; + + use super::Server; + use self::nix::sys::epoll; + use self::nix::fcntl; + use ssl; + use ssl::error::NonblockingSslError; + use ssl::SslMethod; + use ssl::SslMethod::Sslv23; + use ssl::{SslContext, NonblockingSslStream}; + + fn wait_io(stream: &NonblockingSslStream<TcpStream>, read: bool, timeout_ms: isize) -> bool { + let fd = stream.as_raw_fd(); + let ep = epoll::epoll_create().unwrap(); + let event = if read { + epoll::EpollEvent { + events: epoll::EPOLLIN | epoll::EPOLLERR, + data: 0, + } + } else { + epoll::EpollEvent { + events: epoll::EPOLLOUT, + data: 0, + } + }; + epoll::epoll_ctl(ep, epoll::EpollOp::EpollCtlAdd, fd, &event).unwrap(); + let mut events = [event]; + let count = epoll::epoll_wait(ep, &mut events, timeout_ms).unwrap(); + epoll::epoll_ctl(ep, epoll::EpollOp::EpollCtlDel, fd, &event).unwrap(); + assert!(count <= 1); + count == 1 + } + + fn make_nonblocking(stream: &TcpStream) { + let fd = stream.as_raw_fd(); + fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFL(fcntl::O_NONBLOCK)).unwrap(); + } + + #[test] + fn test_write_nonblocking() { + let (_s, stream) = Server::new(); + make_nonblocking(&stream); + let mut stream = NonblockingSslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + + let mut iterations = 0; + loop { + iterations += 1; + if iterations > 7 { + // Probably a safe assumption for the foreseeable future of openssl. + panic!("Too many read/write round trips in handshake!!"); + } + let result = stream.write("hello".as_bytes()); + match result { + Ok(_) => { + break; + }, + Err(NonblockingSslError::WantRead) => { + assert!(wait_io(&stream, true, 1000)); + }, + Err(NonblockingSslError::WantWrite) => { + assert!(wait_io(&stream, false, 1000)); + }, + Err(other) => { + panic!("Unexpected SSL Error: {:?}", other); + }, + } + } + + // Second write should succeed immediately--plenty of space in kernel buffer, + // and handshake just completed. + stream.write(" there".as_bytes()).unwrap(); + } + + #[test] + fn test_read_nonblocking() { + let (_s, stream) = Server::new(); + make_nonblocking(&stream); + let mut stream = NonblockingSslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + + let mut iterations = 0; + loop { + iterations += 1; + if iterations > 7 { + // Probably a safe assumption for the foreseeable future of openssl. + panic!("Too many read/write round trips in handshake!!"); + } + let result = stream.write("GET /\r\n\r\n".as_bytes()); + match result { + Ok(n) => { + assert_eq!(n, 9); + break; + }, + Err(NonblockingSslError::WantRead) => { + assert!(wait_io(&stream, true, 1000)); + }, + Err(NonblockingSslError::WantWrite) => { + assert!(wait_io(&stream, false, 1000)); + }, + Err(other) => { + panic!("Unexpected SSL Error: {:?}", other); + }, + } + } + let mut input_buffer = [0u8; 1500]; + let result = stream.read(&mut input_buffer); + let bytes_read = match result { + Ok(n) => { + // This branch is unlikely, but on an overloaded VM with + // unlucky context switching, the response could actually + // be in the receive buffer before we issue the read() syscall... + n + }, + Err(NonblockingSslError::WantRead) => { + assert!(wait_io(&stream, true, 3000)); + // Second read should return application data. + stream.read(&mut input_buffer).unwrap() + }, + Err(other) => { + panic!("Unexpected SSL Error: {:?}", other); + }, + }; + assert!(bytes_read >= 5); + assert_eq!(&input_buffer[..5], b"HTTP/"); + } +} |