diff options
| author | bors <bors@rust-lang.org> | 2016-07-08 19:07:45 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2016-07-08 19:07:45 -0700 |
| commit | fdca8c2fbdf502d457c2e810e491c32ee1d65fe2 (patch) | |
| tree | e65d6061ba8b0b205b7aaa92668d61d9dcd88a7a /src/libstd | |
| parent | 5e18b4bad8450622aef8e077d3470f5626403588 (diff) | |
| parent | 66bf1092a58fb50279d263ba9e831435ace8e844 (diff) | |
| download | rust-fdca8c2fbdf502d457c2e810e491c32ee1d65fe2.tar.gz rust-fdca8c2fbdf502d457c2e810e491c32ee1d65fe2.zip | |
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](https://github.com/rust-lang/rust/issues/24250#issuecomment-92240152): `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.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/sys/common/net.rs | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 26925b12f93..8b7af17f92b 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -601,3 +601,22 @@ impl fmt::Debug for UdpSocket { .finish() } } + +#[cfg(test)] +mod tests { + use prelude::v1::*; + + use super::*; + use collections::HashMap; + + #[test] + fn no_lookup_host_duplicates() { + let mut addrs = HashMap::new(); + let lh = match lookup_host("localhost") { + Ok(lh) => lh, + Err(e) => panic!("couldn't resolve `localhost': {}", e) + }; + let _na = lh.map(|sa| *addrs.entry(sa).or_insert(0) += 1).count(); + assert!(addrs.values().filter(|&&v| v > 1).count() == 0); + } +} |
