Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,18 @@ fn run<Device: AsyncRead + AsyncWrite + Unpin + Send + 'static>(
tokio::spawn(async move {
loop {
select! {
Ok(n) = device.read(&mut buffer) => {
read_result = device.read(&mut buffer) => {
let n = match read_result {
Ok(0) => {
log::info!("Device EOF, stopping IP stack");
return Ok(());
}
Ok(n) => n,
Err(e) => {
log::error!("Device read error: {e}");
return Err(e.into());
}
};
if let Err(e) = process_device_read(&buffer[offset..n], &mut sessions, &session_remove_tx, &up_pkt_sender, &config, &accept_sender).await {
let io_err: std::io::Error = e.into();
if io_err.kind() == std::io::ErrorKind::ConnectionRefused {
Expand Down Expand Up @@ -439,3 +450,25 @@ async fn process_upstream_recv<Device: AsyncWrite + Unpin + 'static>(

Ok(())
}

#[cfg(test)]
mod tests {
use std::time::Duration;

use tokio::{io::duplex, time::timeout};

use super::*;

#[tokio::test]
async fn device_eof_closes_accept_channel() {
let (device, peer) = duplex(64);
let mut ip_stack = IpStack::new(IpStackConfig::default(), device);

drop(peer);

let accept_result = timeout(Duration::from_secs(1), ip_stack.accept())
.await
.expect("accept should not hang after device EOF");
assert!(matches!(accept_result, Err(IpStackError::AcceptError)));
}
}
Loading