Skip to content

Commit 0c42f4e

Browse files
fix(cable): treat ECONNRESET / EPIPE on L2CAP read as a clean close
After a successful CTAP ceremony the peer typically tears down the BLE link without a clean L2CAP shutdown, so our read loop wakes up with ECONNRESET (or EPIPE / UnexpectedEof) rather than n=0. Treat those the same way we already treat a clean EOF: return Ok(None) when nothing is buffered, ConnectionLost when half a message is. Stops the spurious 'Failed to read L2CAP message: ConnectionReset' error log that fires after a successful MakeCredential.
1 parent fd614e2 commit 0c42f4e

1 file changed

Lines changed: 20 additions & 4 deletions

File tree

libwebauthn/src/transport/cable/l2cap.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,26 @@ impl CableDataChannel for L2capDataChannel {
104104
return Ok(Some(message));
105105
}
106106
let mut chunk = [0u8; 1024];
107-
let n = self.stream.read(&mut chunk).await.map_err(|e| {
108-
error!(?e, "Failed to read L2CAP message");
109-
TransportError::IoError(e.kind())
110-
})?;
107+
let n = match self.stream.read(&mut chunk).await {
108+
Ok(n) => n,
109+
// The peer tearing down after a successful ceremony surfaces as
110+
// ECONNRESET / EPIPE rather than a clean EOF; treat it like EOF
111+
// when nothing is half-buffered.
112+
Err(e)
113+
if matches!(
114+
e.kind(),
115+
std::io::ErrorKind::ConnectionReset
116+
| std::io::ErrorKind::BrokenPipe
117+
| std::io::ErrorKind::UnexpectedEof
118+
) =>
119+
{
120+
0
121+
}
122+
Err(e) => {
123+
error!(?e, "Failed to read L2CAP message");
124+
return Err(TransportError::IoError(e.kind()));
125+
}
126+
};
111127
if n == 0 {
112128
// Peer closed; only a clean close if nothing is half-buffered.
113129
if self.read_buf.is_empty() {

0 commit comments

Comments
 (0)