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