fix: BIO_set_retry_write when BIO_CTRL_FLUSH to allow writer returns WouldBlock on flush

This commit is contained in:
ihciah 2023-05-11 09:48:42 +00:00 committed by Kornel
parent b65a064e76
commit ed768854a4
2 changed files with 66 additions and 0 deletions

View File

@ -163,9 +163,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
}

View File

@ -417,6 +417,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() {