]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/common/net.rs
Auto merge of #33922 - estebank:doc-comment, r=alexcrichton
[rust.git] / src / libstd / sys / common / net.rs
1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use prelude::v1::*;
12
13 use cmp;
14 use ffi::CString;
15 use fmt;
16 use io::{self, Error, ErrorKind};
17 use libc::{c_int, c_void};
18 use mem;
19 use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
20 use ptr;
21 use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
22 use sys::net::netc as c;
23 use sys_common::{AsInner, FromInner, IntoInner};
24 use time::Duration;
25
26 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
27           target_os = "ios", target_os = "macos",
28           target_os = "openbsd", target_os = "netbsd",
29           target_os = "solaris"))]
30 use sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
31 #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
32               target_os = "ios", target_os = "macos",
33               target_os = "openbsd", target_os = "netbsd",
34               target_os = "solaris")))]
35 use sys::net::netc::IPV6_ADD_MEMBERSHIP;
36 #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
37           target_os = "ios", target_os = "macos",
38           target_os = "openbsd", target_os = "netbsd",
39           target_os = "solaris"))]
40 use sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP;
41 #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd",
42               target_os = "ios", target_os = "macos",
43               target_os = "openbsd", target_os = "netbsd",
44               target_os = "solaris")))]
45 use sys::net::netc::IPV6_DROP_MEMBERSHIP;
46
47 ////////////////////////////////////////////////////////////////////////////////
48 // sockaddr and misc bindings
49 ////////////////////////////////////////////////////////////////////////////////
50
51 pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
52                      payload: T) -> io::Result<()> {
53     unsafe {
54         let payload = &payload as *const T as *const c_void;
55         cvt(c::setsockopt(*sock.as_inner(), opt, val, payload,
56                           mem::size_of::<T>() as c::socklen_t))?;
57         Ok(())
58     }
59 }
60
61 pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
62                        val: c_int) -> io::Result<T> {
63     unsafe {
64         let mut slot: T = mem::zeroed();
65         let mut len = mem::size_of::<T>() as c::socklen_t;
66         cvt(c::getsockopt(*sock.as_inner(), opt, val,
67                           &mut slot as *mut _ as *mut _,
68                           &mut len))?;
69         assert_eq!(len as usize, mem::size_of::<T>());
70         Ok(slot)
71     }
72 }
73
74 fn sockname<F>(f: F) -> io::Result<SocketAddr>
75     where F: FnOnce(*mut c::sockaddr, *mut c::socklen_t) -> c_int
76 {
77     unsafe {
78         let mut storage: c::sockaddr_storage = mem::zeroed();
79         let mut len = mem::size_of_val(&storage) as c::socklen_t;
80         cvt(f(&mut storage as *mut _ as *mut _, &mut len))?;
81         sockaddr_to_addr(&storage, len as usize)
82     }
83 }
84
85 fn sockaddr_to_addr(storage: &c::sockaddr_storage,
86                     len: usize) -> io::Result<SocketAddr> {
87     match storage.ss_family as c_int {
88         c::AF_INET => {
89             assert!(len as usize >= mem::size_of::<c::sockaddr_in>());
90             Ok(SocketAddr::V4(FromInner::from_inner(unsafe {
91                 *(storage as *const _ as *const c::sockaddr_in)
92             })))
93         }
94         c::AF_INET6 => {
95             assert!(len as usize >= mem::size_of::<c::sockaddr_in6>());
96             Ok(SocketAddr::V6(FromInner::from_inner(unsafe {
97                 *(storage as *const _ as *const c::sockaddr_in6)
98             })))
99         }
100         _ => {
101             Err(Error::new(ErrorKind::InvalidInput, "invalid argument"))
102         }
103     }
104 }
105
106 #[cfg(target_os = "android")]
107 fn to_ipv6mr_interface(value: u32) -> c_int {
108     value as c_int
109 }
110
111 #[cfg(not(target_os = "android"))]
112 fn to_ipv6mr_interface(value: u32) -> ::libc::c_uint {
113     value as ::libc::c_uint
114 }
115
116 ////////////////////////////////////////////////////////////////////////////////
117 // get_host_addresses
118 ////////////////////////////////////////////////////////////////////////////////
119
120 pub struct LookupHost {
121     original: *mut c::addrinfo,
122     cur: *mut c::addrinfo,
123 }
124
125 impl Iterator for LookupHost {
126     type Item = SocketAddr;
127     fn next(&mut self) -> Option<SocketAddr> {
128         loop {
129             unsafe {
130                 let cur = match self.cur.as_ref() {
131                     None => return None,
132                     Some(c) => c,
133                 };
134                 self.cur = cur.ai_next;
135                 match sockaddr_to_addr(mem::transmute(cur.ai_addr),
136                                        cur.ai_addrlen as usize)
137                 {
138                     Ok(addr) => return Some(addr),
139                     Err(_) => continue,
140                 }
141             }
142         }
143     }
144 }
145
146 unsafe impl Sync for LookupHost {}
147 unsafe impl Send for LookupHost {}
148
149 impl Drop for LookupHost {
150     fn drop(&mut self) {
151         unsafe { c::freeaddrinfo(self.original) }
152     }
153 }
154
155 pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
156     init();
157
158     let c_host = CString::new(host)?;
159     let hints = c::addrinfo {
160         ai_flags: 0,
161         ai_family: 0,
162         ai_socktype: c::SOCK_STREAM,
163         ai_protocol: 0,
164         ai_addrlen: 0,
165         ai_addr: ptr::null_mut(),
166         ai_canonname: ptr::null_mut(),
167         ai_next: ptr::null_mut()
168     };
169     let mut res = ptr::null_mut();
170     unsafe {
171         cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints,
172                                &mut res))?;
173         Ok(LookupHost { original: res, cur: res })
174     }
175 }
176
177 ////////////////////////////////////////////////////////////////////////////////
178 // TCP streams
179 ////////////////////////////////////////////////////////////////////////////////
180
181 pub struct TcpStream {
182     inner: Socket,
183 }
184
185 impl TcpStream {
186     pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
187         init();
188
189         let sock = Socket::new(addr, c::SOCK_STREAM)?;
190
191         let (addrp, len) = addr.into_inner();
192         cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?;
193         Ok(TcpStream { inner: sock })
194     }
195
196     pub fn socket(&self) -> &Socket { &self.inner }
197
198     pub fn into_socket(self) -> Socket { self.inner }
199
200     pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
201         self.inner.set_timeout(dur, c::SO_RCVTIMEO)
202     }
203
204     pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
205         self.inner.set_timeout(dur, c::SO_SNDTIMEO)
206     }
207
208     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
209         self.inner.timeout(c::SO_RCVTIMEO)
210     }
211
212     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
213         self.inner.timeout(c::SO_SNDTIMEO)
214     }
215
216     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
217         self.inner.read(buf)
218     }
219
220     pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
221         self.inner.read_to_end(buf)
222     }
223
224     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
225         let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
226         let ret = cvt(unsafe {
227             c::send(*self.inner.as_inner(),
228                     buf.as_ptr() as *const c_void,
229                     len,
230                     0)
231         })?;
232         Ok(ret as usize)
233     }
234
235     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
236         sockname(|buf, len| unsafe {
237             c::getpeername(*self.inner.as_inner(), buf, len)
238         })
239     }
240
241     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
242         sockname(|buf, len| unsafe {
243             c::getsockname(*self.inner.as_inner(), buf, len)
244         })
245     }
246
247     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
248         self.inner.shutdown(how)
249     }
250
251     pub fn duplicate(&self) -> io::Result<TcpStream> {
252         self.inner.duplicate().map(|s| TcpStream { inner: s })
253     }
254
255     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
256         self.inner.set_nodelay(nodelay)
257     }
258
259     pub fn nodelay(&self) -> io::Result<bool> {
260         self.inner.nodelay()
261     }
262
263     pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
264         setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
265     }
266
267     pub fn ttl(&self) -> io::Result<u32> {
268         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
269         Ok(raw as u32)
270     }
271
272     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
273         self.inner.take_error()
274     }
275
276     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
277         self.inner.set_nonblocking(nonblocking)
278     }
279 }
280
281 impl FromInner<Socket> for TcpStream {
282     fn from_inner(socket: Socket) -> TcpStream {
283         TcpStream { inner: socket }
284     }
285 }
286
287 impl fmt::Debug for TcpStream {
288     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
289         let mut res = f.debug_struct("TcpStream");
290
291         if let Ok(addr) = self.socket_addr() {
292             res.field("addr", &addr);
293         }
294
295         if let Ok(peer) = self.peer_addr() {
296             res.field("peer", &peer);
297         }
298
299         let name = if cfg!(windows) {"socket"} else {"fd"};
300         res.field(name, &self.inner.as_inner())
301             .finish()
302     }
303 }
304
305 ////////////////////////////////////////////////////////////////////////////////
306 // TCP listeners
307 ////////////////////////////////////////////////////////////////////////////////
308
309 pub struct TcpListener {
310     inner: Socket,
311 }
312
313 impl TcpListener {
314     pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
315         init();
316
317         let sock = Socket::new(addr, c::SOCK_STREAM)?;
318
319         // On platforms with Berkeley-derived sockets, this allows
320         // to quickly rebind a socket, without needing to wait for
321         // the OS to clean up the previous one.
322         if !cfg!(windows) {
323             setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR,
324                        1 as c_int)?;
325         }
326
327         // Bind our new socket
328         let (addrp, len) = addr.into_inner();
329         cvt(unsafe { c::bind(*sock.as_inner(), addrp, len) })?;
330
331         // Start listening
332         cvt(unsafe { c::listen(*sock.as_inner(), 128) })?;
333         Ok(TcpListener { inner: sock })
334     }
335
336     pub fn socket(&self) -> &Socket { &self.inner }
337
338     pub fn into_socket(self) -> Socket { self.inner }
339
340     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
341         sockname(|buf, len| unsafe {
342             c::getsockname(*self.inner.as_inner(), buf, len)
343         })
344     }
345
346     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
347         let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
348         let mut len = mem::size_of_val(&storage) as c::socklen_t;
349         let sock = self.inner.accept(&mut storage as *mut _ as *mut _,
350                                      &mut len)?;
351         let addr = sockaddr_to_addr(&storage, len as usize)?;
352         Ok((TcpStream { inner: sock, }, addr))
353     }
354
355     pub fn duplicate(&self) -> io::Result<TcpListener> {
356         self.inner.duplicate().map(|s| TcpListener { inner: s })
357     }
358
359     pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
360         setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
361     }
362
363     pub fn ttl(&self) -> io::Result<u32> {
364         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
365         Ok(raw as u32)
366     }
367
368     pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
369         setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int)
370     }
371
372     pub fn only_v6(&self) -> io::Result<bool> {
373         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)?;
374         Ok(raw != 0)
375     }
376
377     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
378         self.inner.take_error()
379     }
380
381     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
382         self.inner.set_nonblocking(nonblocking)
383     }
384 }
385
386 impl FromInner<Socket> for TcpListener {
387     fn from_inner(socket: Socket) -> TcpListener {
388         TcpListener { inner: socket }
389     }
390 }
391
392 impl fmt::Debug for TcpListener {
393     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394         let mut res = f.debug_struct("TcpListener");
395
396         if let Ok(addr) = self.socket_addr() {
397             res.field("addr", &addr);
398         }
399
400         let name = if cfg!(windows) {"socket"} else {"fd"};
401         res.field(name, &self.inner.as_inner())
402             .finish()
403     }
404 }
405
406 ////////////////////////////////////////////////////////////////////////////////
407 // UDP
408 ////////////////////////////////////////////////////////////////////////////////
409
410 pub struct UdpSocket {
411     inner: Socket,
412 }
413
414 impl UdpSocket {
415     pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
416         init();
417
418         let sock = Socket::new(addr, c::SOCK_DGRAM)?;
419         let (addrp, len) = addr.into_inner();
420         cvt(unsafe { c::bind(*sock.as_inner(), addrp, len) })?;
421         Ok(UdpSocket { inner: sock })
422     }
423
424     pub fn socket(&self) -> &Socket { &self.inner }
425
426     pub fn into_socket(self) -> Socket { self.inner }
427
428     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
429         sockname(|buf, len| unsafe {
430             c::getsockname(*self.inner.as_inner(), buf, len)
431         })
432     }
433
434     pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
435         let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
436         let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
437         let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
438
439         let n = cvt(unsafe {
440             c::recvfrom(*self.inner.as_inner(),
441                         buf.as_mut_ptr() as *mut c_void,
442                         len, 0,
443                         &mut storage as *mut _ as *mut _, &mut addrlen)
444         })?;
445         Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
446     }
447
448     pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
449         let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
450         let (dstp, dstlen) = dst.into_inner();
451         let ret = cvt(unsafe {
452             c::sendto(*self.inner.as_inner(),
453                       buf.as_ptr() as *const c_void, len,
454                       0, dstp, dstlen)
455         })?;
456         Ok(ret as usize)
457     }
458
459     pub fn duplicate(&self) -> io::Result<UdpSocket> {
460         self.inner.duplicate().map(|s| UdpSocket { inner: s })
461     }
462
463     pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
464         self.inner.set_timeout(dur, c::SO_RCVTIMEO)
465     }
466
467     pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
468         self.inner.set_timeout(dur, c::SO_SNDTIMEO)
469     }
470
471     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
472         self.inner.timeout(c::SO_RCVTIMEO)
473     }
474
475     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
476         self.inner.timeout(c::SO_SNDTIMEO)
477     }
478
479     pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
480         setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int)
481     }
482
483     pub fn broadcast(&self) -> io::Result<bool> {
484         let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)?;
485         Ok(raw != 0)
486     }
487
488     pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
489         setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int)
490     }
491
492     pub fn multicast_loop_v4(&self) -> io::Result<bool> {
493         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?;
494         Ok(raw != 0)
495     }
496
497     pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
498         setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int)
499     }
500
501     pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
502         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?;
503         Ok(raw as u32)
504     }
505
506     pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
507         setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int)
508     }
509
510     pub fn multicast_loop_v6(&self) -> io::Result<bool> {
511         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)?;
512         Ok(raw != 0)
513     }
514
515     pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
516                          -> io::Result<()> {
517         let mreq = c::ip_mreq {
518             imr_multiaddr: *multiaddr.as_inner(),
519             imr_interface: *interface.as_inner(),
520         };
521         setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq)
522     }
523
524     pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
525                          -> io::Result<()> {
526         let mreq = c::ipv6_mreq {
527             ipv6mr_multiaddr: *multiaddr.as_inner(),
528             ipv6mr_interface: to_ipv6mr_interface(interface),
529         };
530         setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq)
531     }
532
533     pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
534                           -> io::Result<()> {
535         let mreq = c::ip_mreq {
536             imr_multiaddr: *multiaddr.as_inner(),
537             imr_interface: *interface.as_inner(),
538         };
539         setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq)
540     }
541
542     pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
543                           -> io::Result<()> {
544         let mreq = c::ipv6_mreq {
545             ipv6mr_multiaddr: *multiaddr.as_inner(),
546             ipv6mr_interface: to_ipv6mr_interface(interface),
547         };
548         setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq)
549     }
550
551     pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
552         setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
553     }
554
555     pub fn ttl(&self) -> io::Result<u32> {
556         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
557         Ok(raw as u32)
558     }
559
560     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
561         self.inner.take_error()
562     }
563
564     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
565         self.inner.set_nonblocking(nonblocking)
566     }
567
568     pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
569         self.inner.read(buf)
570     }
571
572     pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
573         let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
574         let ret = cvt(unsafe {
575             c::send(*self.inner.as_inner(),
576                     buf.as_ptr() as *const c_void,
577                     len,
578                     0)
579         })?;
580         Ok(ret as usize)
581     }
582
583     pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
584         let (addrp, len) = addr.into_inner();
585         cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(|_| ())
586     }
587 }
588
589 impl FromInner<Socket> for UdpSocket {
590     fn from_inner(socket: Socket) -> UdpSocket {
591         UdpSocket { inner: socket }
592     }
593 }
594
595 impl fmt::Debug for UdpSocket {
596     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
597         let mut res = f.debug_struct("UdpSocket");
598
599         if let Ok(addr) = self.socket_addr() {
600             res.field("addr", &addr);
601         }
602
603         let name = if cfg!(windows) {"socket"} else {"fd"};
604         res.field(name, &self.inner.as_inner())
605             .finish()
606     }
607 }
608
609 #[cfg(test)]
610 mod tests {
611     use prelude::v1::*;
612
613     use super::*;
614     use collections::HashMap;
615
616     #[test]
617     fn no_lookup_host_duplicates() {
618         let mut addrs = HashMap::new();
619         let lh = match lookup_host("localhost") {
620             Ok(lh) => lh,
621             Err(e) => panic!("couldn't resolve `localhost': {}", e)
622         };
623         let _na = lh.map(|sa| *addrs.entry(sa).or_insert(0) += 1).count();
624         assert!(addrs.values().filter(|&&v| v > 1).count() == 0);
625     }
626 }