Skip to content

Commit 49547eb

Browse files
committed
Fix unspecified support for same host connections
This adds a test and fixes behaivor where a client may want to connect to a server listening on an unspecified ip (0.0.0.0). This is probably not the exact correct implementation but this will just route it through the loopback path. [Playground example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=63aad6ad0374fa62e93d83ec813faca8)
1 parent ed131c6 commit 49547eb

File tree

5 files changed

+43
-7
lines changed

5 files changed

+43
-7
lines changed

src/host.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ pub fn matches(bind: SocketAddr, dst: SocketAddr) -> bool {
488488
/// Returns true if loopback is supported between two addresses, or
489489
/// if the IPs are the same (in which case turmoil treats it like loopback)
490490
pub(crate) fn is_same(src: SocketAddr, dst: SocketAddr) -> bool {
491-
dst.ip().is_loopback() || src.ip() == dst.ip()
491+
dst.ip().is_loopback() || dst.ip().is_unspecified() || src.ip() == dst.ip()
492492
}
493493

494494
#[cfg(test)]

src/net/tcp/listener.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,9 @@ impl TcpListener {
9292
let host = world.current_host_mut();
9393

9494
let mut my_addr = self.local_addr;
95-
if origin.ip().is_loopback() {
95+
if origin.ip().is_loopback() || origin.ip().is_unspecified() {
9696
my_addr.set_ip(origin.ip());
9797
}
98-
if my_addr.ip().is_unspecified() {
99-
my_addr.set_ip(host.addr);
100-
}
10198

10299
let pair = SocketPair::new(my_addr, origin);
103100
let rx = host.tcp.new_stream(pair);

src/net/tcp/stream.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl TcpStream {
6767

6868
let host = world.current_host_mut();
6969
let mut local_addr = SocketAddr::new(host.addr, host.assign_ephemeral_port());
70-
if dst.ip().is_loopback() {
70+
if dst.ip().is_loopback() || dst.ip().is_unspecified() {
7171
local_addr.set_ip(dst.ip());
7272
}
7373

src/net/udp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ impl UdpSocket {
336336

337337
fn send(&self, world: &mut World, dst: SocketAddr, packet: Datagram) -> Result<()> {
338338
let mut src = self.local_addr;
339-
if dst.ip().is_loopback() {
339+
if dst.ip().is_loopback() || dst.ip().is_unspecified() {
340340
src.set_ip(dst.ip());
341341
}
342342
if src.ip().is_unspecified() {

tests/tcp.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,3 +1374,42 @@ fn try_write() -> Result {
13741374

13751375
sim.run()
13761376
}
1377+
1378+
#[test]
1379+
fn connect_0000() -> Result {
1380+
init_tracing();
1381+
1382+
let mut sim = Builder::new().build();
1383+
sim.client("client", async move {
1384+
let listener = TcpListener::bind((Ipv4Addr::UNSPECIFIED, 1234))
1385+
.await
1386+
.unwrap();
1387+
1388+
tokio::spawn(async move {
1389+
let (socket, _) = listener.accept().await.unwrap();
1390+
1391+
let written = socket.try_write(b"hello!").unwrap();
1392+
assert_eq!(written, 6);
1393+
});
1394+
1395+
let mut socket = TcpStream::connect((Ipv4Addr::UNSPECIFIED, 1234))
1396+
.await
1397+
.unwrap();
1398+
let mut buf: [u8; 6] = [0; 6];
1399+
socket.read_exact(&mut buf).await?;
1400+
assert_eq!(&buf, b"hello!");
1401+
1402+
Ok(())
1403+
});
1404+
1405+
sim.run()
1406+
}
1407+
1408+
fn init_tracing() {
1409+
use tracing_subscriber::filter::EnvFilter;
1410+
1411+
let _ = tracing_subscriber::fmt()
1412+
.with_env_filter(EnvFilter::from_default_env())
1413+
.with_test_writer()
1414+
.try_init();
1415+
}

0 commit comments

Comments
 (0)