Add depth limits to write recursion
An infinite recursion case can occur here if the operating system
does not allocate the require space to write to. Lets not make that
already bad situation worse.
@@ -84,12 +84,27 @@ impl Display for ForwardingProtocolError {
/// Writes data to a stream keeping in mind that we may encounter
/// a buffer limit and have to partially complete our write
pub fn write_all_spinlock(stream: &mut TcpStream, buffer: &[u8]) -> Result<(), IoError> {
+ write_all_spinlock_internal(stream, buffer, 0)
+}
+
+fn write_all_spinlock_internal(
+ stream: &mut TcpStream,
+ buffer: &[u8],
+ depth: u8,
+) -> Result<(), IoError> {
assert!(!buffer.is_empty());
+ if depth > 100 {
+ return Err(IoError::new(
+ std::io::ErrorKind::WriteZero,
+ format_err!("Operating system won't allocate buffer space"),
+ ));
+ }
+
stream.set_nonblocking(true)?;
let res = stream.write(buffer);
match res {
Ok(bytes) => {
- trace!("Spinlock wrote {} bytes", buffer.len());
+ trace!("Spinlock wrote {} bytes of {}", bytes, buffer.len());
if buffer.len() == bytes {
Ok(())
} else if bytes == 0 {
@@ -98,14 +113,20 @@ pub fn write_all_spinlock(stream: &mut TcpStream, buffer: &[u8]) -> Result<(), I
format_err!("Probably a dead connection"),
))
} else {
- write_all_spinlock(stream, &buffer[bytes..])
+ trace!("Did not write all, recursing",);
+ write_all_spinlock_internal(stream, &buffer[bytes..], depth + 1)
}
}
Err(e) => {
- error!("Problem {:?} in spinlock writing {} bytes", e, buffer.len());
+ error!(
+ "Problem {:?} in spinlock trying to write {} bytes",
+ e,
+ buffer.len()
+ );
if e.kind() == WouldBlock {
+ // wait for the operating system to clear up some buffer space
thread::sleep(SPINLOCK_TIME);
- write_all_spinlock(stream, &buffer)
+ write_all_spinlock_internal(stream, &buffer, depth + 1)
} else {
error!("Socket write error is {:?}", e);
Err(e)
