Skip to content

Commit fdca8c2

Browse files
authored
Auto merge of #34700 - inejge:ai-hints, r=alexcrichton
Use hints with getaddrinfo() in std::net::lookup_host() As noted in #24250, `std::net::lookup_host()` repeats each IPv[46] address in the result set. The number of repetitions is OS-dependent; e.g., Linux and FreeBSD give three copies, OpenBSD gives two. Filtering the duplicates can be done by the user if `lookup_host()` is used explicitly, but not with functions like `TcpStream::connect()`. What happens with the latter is that any unsuccessful connection attempt will be repeated as many times as there are duplicates of the address. The program: ```rust use std::net::TcpStream; fn main() { let _stream = TcpStream::connect("localhost:4444").unwrap(); } ``` results in the following capture: [capture-before.txt](https://github.com/rust-lang/rust/files/352004/capture-before.txt) assuming that "localhost" resolves both to ::1 and 127.0.0.1, and that the listening program opens just an IPv4 socket (e.g., `nc -l 127.0.0.1 4444`.) The reason for this behavior is explained in [this comment](#24250 (comment)): `getaddrinfo()` is not constrained. Various OSS projects (I checked out Postfix, OpenLDAP, Apache HTTPD and BIND) which use `getaddrinfo()` generally constrain the result set by using a non-NULL `hints` parameter and setting at least `ai_socktype` to `SOCK_STREAM`. `SOCK_DGRAM` would also work. Other parameters are unnecessary for pure name resolution. The patch in this PR initializes a `hints` struct and passes it to `getaddrinfo()`, which eliminates the duplicates. The same test program as above with this change produces: [capture-after.txt](https://github.com/rust-lang/rust/files/352042/capture-after.txt) All `libstd` tests pass with this patch.
2 parents 5e18b4b + 66bf109 commit fdca8c2

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

src/libstd/sys/common/net.rs

+19
Original file line numberDiff line numberDiff line change
@@ -601,3 +601,22 @@ impl fmt::Debug for UdpSocket {
601601
.finish()
602602
}
603603
}
604+
605+
#[cfg(test)]
606+
mod tests {
607+
use prelude::v1::*;
608+
609+
use super::*;
610+
use collections::HashMap;
611+
612+
#[test]
613+
fn no_lookup_host_duplicates() {
614+
let mut addrs = HashMap::new();
615+
let lh = match lookup_host("localhost") {
616+
Ok(lh) => lh,
617+
Err(e) => panic!("couldn't resolve `localhost': {}", e)
618+
};
619+
let _na = lh.map(|sa| *addrs.entry(sa).or_insert(0) += 1).count();
620+
assert!(addrs.values().filter(|&&v| v > 1).count() == 0);
621+
}
622+
}

0 commit comments

Comments
 (0)