Skip to content

Commit

Permalink
fix: BIO_set_retry_write when BIO_CTRL_FLUSH to allow writer returns …
Browse files Browse the repository at this point in the history
…WouldBlock on flush
  • Loading branch information
ihciah committed May 12, 2023
1 parent 7cfe206 commit c55c73d
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 0 deletions.
4 changes: 4 additions & 0 deletions boring/src/ssl/bio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,13 @@ unsafe extern "C" fn ctrl<S: Write>(
let state = state::<S>(bio);

if cmd == BIO_CTRL_FLUSH {
BIO_clear_retry_flags(bio);
match catch_unwind(AssertUnwindSafe(|| state.stream.flush())) {
Ok(Ok(())) => 1,
Ok(Err(err)) => {
if retriable_error(&err) {
BIO_set_retry_write(bio);
}
state.error = Some(err);
0
}
Expand Down
62 changes: 62 additions & 0 deletions boring/src/ssl/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,68 @@ fn test_select_cert_alpn_extension() {
);
}

#[test]
fn test_io_retry() {
#[derive(Debug)]
struct RetryStream {
inner: TcpStream,
first_read: bool,
first_write: bool,
first_flush: bool,
}

impl Read for RetryStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if mem::replace(&mut self.first_read, false) {
Err(io::Error::new(io::ErrorKind::WouldBlock, "first read"))
} else {
self.inner.read(buf)
}
}
}

impl Write for RetryStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if mem::replace(&mut self.first_write, false) {
Err(io::Error::new(io::ErrorKind::WouldBlock, "first write"))
} else {
self.inner.write(buf)
}
}

fn flush(&mut self) -> io::Result<()> {
if mem::replace(&mut self.first_flush, false) {
Err(io::Error::new(io::ErrorKind::WouldBlock, "first flush"))
} else {
self.inner.flush()
}
}
}

let server = Server::builder().build();

let stream = RetryStream {
inner: server.connect_tcp(),
first_read: true,
first_write: true,
first_flush: true,
};

let ctx = SslContext::builder(SslMethod::tls()).unwrap();
let mut s = match Ssl::new(&ctx.build()).unwrap().connect(stream) {
Ok(mut s) => return s.read_exact(&mut [0]).unwrap(),
Err(HandshakeError::WouldBlock(s)) => s,
Err(_) => panic!("should not fail on setup"),
};
loop {
match s.handshake() {
Ok(mut s) => return s.read_exact(&mut [0]).unwrap(),
Err(HandshakeError::WouldBlock(mid_s)) => s = mid_s,
Err(_) => panic!("should not fail on handshake"),
}
}
}

#[test]
#[should_panic(expected = "blammo")]
fn write_panic() {
Expand Down

0 comments on commit c55c73d

Please sign in to comment.