]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys_common/net.rs
b841afe1a5141dfd2db749ad09077400c8cc1933
[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 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", target_os = "l4re"))]
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", target_os = "l4re")))]
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", target_os = "l4re"))]
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", target_os = "l4re")))]
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 = self.cur.as_ref()?;
140                 self.cur = cur.ai_next;
141                 match sockaddr_to_addr(mem::transmute(cur.ai_addr),
142                                        cur.ai_addrlen as usize)
143                 {
144                     Ok(addr) => return Some(addr),
145                     Err(_) => continue,
146                 }
147             }
148         }
149     }
150 }
151
152 unsafe impl Sync for LookupHost {}
153 unsafe impl Send for LookupHost {}
154
155 impl Drop for LookupHost {
156     fn drop(&mut self) {
157         unsafe { c::freeaddrinfo(self.original) }
158     }
159 }
160
161 pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
162     init();
163
164     let c_host = CString::new(host)?;
165     let mut hints: c::addrinfo = unsafe { mem::zeroed() };
166     hints.ai_socktype = c::SOCK_STREAM;
167     let mut res = ptr::null_mut();
168     unsafe {
169         cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)).map(|_| {
170             LookupHost { original: res, cur: res }
171         })
172     }
173 }
174
175 ////////////////////////////////////////////////////////////////////////////////
176 // TCP streams
177 ////////////////////////////////////////////////////////////////////////////////
178
179 pub struct TcpStream {
180     inner: Socket,
181 }
182
183 impl TcpStream {
184     pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
185         init();
186
187         let sock = Socket::new(addr, c::SOCK_STREAM)?;
188
189         let (addrp, len) = addr.into_inner();
190         cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?;
191         Ok(TcpStream { inner: sock })
192     }
193
194     pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result<TcpStream> {
195         init();
196
197         let sock = Socket::new(addr, c::SOCK_STREAM)?;
198         sock.connect_timeout(addr, timeout)?;
199         Ok(TcpStream { inner: sock })
200     }
201
202     pub fn socket(&self) -> &Socket { &self.inner }
203
204     pub fn into_socket(self) -> Socket { self.inner }
205
206     pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
207         self.inner.set_timeout(dur, c::SO_RCVTIMEO)
208     }
209
210     pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
211         self.inner.set_timeout(dur, c::SO_SNDTIMEO)
212     }
213
214     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
215         self.inner.timeout(c::SO_RCVTIMEO)
216     }
217
218     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
219         self.inner.timeout(c::SO_SNDTIMEO)
220     }
221
222     pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
223         self.inner.peek(buf)
224     }
225
226     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
227         self.inner.read(buf)
228     }
229
230     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
231         let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
232         let ret = cvt(unsafe {
233             c::send(*self.inner.as_inner(),
234                     buf.as_ptr() as *const c_void,
235                     len,
236                     MSG_NOSIGNAL)
237         })?;
238         Ok(ret as usize)
239     }
240
241     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
242         sockname(|buf, len| unsafe {
243             c::getpeername(*self.inner.as_inner(), buf, len)
244         })
245     }
246
247     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
248         sockname(|buf, len| unsafe {
249             c::getsockname(*self.inner.as_inner(), buf, len)
250         })
251     }
252
253     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
254         self.inner.shutdown(how)
255     }
256
257     pub fn duplicate(&self) -> io::Result<TcpStream> {
258         self.inner.duplicate().map(|s| TcpStream { inner: s })
259     }
260
261     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
262         self.inner.set_nodelay(nodelay)
263     }
264
265     pub fn nodelay(&self) -> io::Result<bool> {
266         self.inner.nodelay()
267     }
268
269     pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
270         setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
271     }
272
273     pub fn ttl(&self) -> io::Result<u32> {
274         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
275         Ok(raw as u32)
276     }
277
278     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
279         self.inner.take_error()
280     }
281
282     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
283         self.inner.set_nonblocking(nonblocking)
284     }
285 }
286
287 impl FromInner<Socket> for TcpStream {
288     fn from_inner(socket: Socket) -> TcpStream {
289         TcpStream { inner: socket }
290     }
291 }
292
293 impl fmt::Debug for TcpStream {
294     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
295         let mut res = f.debug_struct("TcpStream");
296
297         if let Ok(addr) = self.socket_addr() {
298             res.field("addr", &addr);
299         }
300
301         if let Ok(peer) = self.peer_addr() {
302             res.field("peer", &peer);
303         }
304
305         let name = if cfg!(windows) {"socket"} else {"fd"};
306         res.field(name, &self.inner.as_inner())
307             .finish()
308     }
309 }
310
311 ////////////////////////////////////////////////////////////////////////////////
312 // TCP listeners
313 ////////////////////////////////////////////////////////////////////////////////
314
315 pub struct TcpListener {
316     inner: Socket,
317 }
318
319 impl TcpListener {
320     pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
321         init();
322
323         let sock = Socket::new(addr, c::SOCK_STREAM)?;
324
325         // On platforms with Berkeley-derived sockets, this allows
326         // to quickly rebind a socket, without needing to wait for
327         // the OS to clean up the previous one.
328         if !cfg!(windows) {
329             setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR,
330                        1 as c_int)?;
331         }
332
333         // Bind our new socket
334         let (addrp, len) = addr.into_inner();
335         cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
336
337         // Start listening
338         cvt(unsafe { c::listen(*sock.as_inner(), 128) })?;
339         Ok(TcpListener { inner: sock })
340     }
341
342     pub fn socket(&self) -> &Socket { &self.inner }
343
344     pub fn into_socket(self) -> Socket { self.inner }
345
346     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
347         sockname(|buf, len| unsafe {
348             c::getsockname(*self.inner.as_inner(), buf, len)
349         })
350     }
351
352     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
353         let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
354         let mut len = mem::size_of_val(&storage) as c::socklen_t;
355         let sock = self.inner.accept(&mut storage as *mut _ as *mut _,
356                                      &mut len)?;
357         let addr = sockaddr_to_addr(&storage, len as usize)?;
358         Ok((TcpStream { inner: sock, }, addr))
359     }
360
361     pub fn duplicate(&self) -> io::Result<TcpListener> {
362         self.inner.duplicate().map(|s| TcpListener { inner: s })
363     }
364
365     pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
366         setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
367     }
368
369     pub fn ttl(&self) -> io::Result<u32> {
370         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
371         Ok(raw as u32)
372     }
373
374     pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
375         setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int)
376     }
377
378     pub fn only_v6(&self) -> io::Result<bool> {
379         let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)?;
380         Ok(raw != 0)
381     }
382
383     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
384         self.inner.take_error()
385     }
386
387     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
388         self.inner.set_nonblocking(nonblocking)
389     }
390 }
391
392 impl FromInner<Socket> for TcpListener {
393     fn from_inner(socket: Socket) -> TcpListener {
394         TcpListener { inner: socket }
395     }
396 }
397
398 impl fmt::Debug for TcpListener {
399     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400         let mut res = f.debug_struct("TcpListener");
401
402         if let Ok(addr) = self.socket_addr() {
403             res.field("addr", &addr);
404         }
405
406         let name = if cfg!(windows) {"socket"} else {"fd"};
407         res.field(name, &self.inner.as_inner())
408             .finish()
409     }
410 }
411
412 ////////////////////////////////////////////////////////////////////////////////
413 // UDP
414 ////////////////////////////////////////////////////////////////////////////////
415
416 pub struct UdpSocket {
417     inner: Socket,
418 }
419
420 impl UdpSocket {
421     pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
422         init();
423
424         let sock = Socket::new(addr, c::SOCK_DGRAM)?;
425         let (addrp, len) = addr.into_inner();
426         cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
427         Ok(UdpSocket { inner: sock })
428     }
429
430     pub fn socket(&self) -> &Socket { &self.inner }
431
432     pub fn into_socket(self) -> Socket { self.inner }
433
434     pub fn socket_addr(&self) -> io::Result<SocketAddr> {
435         sockname(|buf, len| unsafe {
436             c::getsockname(*self.inner.as_inner(), buf, len)
437         })
438     }
439
440     pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
441         self.inner.recv_from(buf)
442     }
443
444     pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
445         self.inner.peek_from(buf)
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                       MSG_NOSIGNAL, 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 peek(&self, buf: &mut [u8]) -> io::Result<usize> {
573         self.inner.peek(buf)
574     }
575
576     pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
577         let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
578         let ret = cvt(unsafe {
579             c::send(*self.inner.as_inner(),
580                     buf.as_ptr() as *const c_void,
581                     len,
582                     MSG_NOSIGNAL)
583         })?;
584         Ok(ret as usize)
585     }
586
587     pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
588         let (addrp, len) = addr.into_inner();
589         cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(|_| ())
590     }
591 }
592
593 impl FromInner<Socket> for UdpSocket {
594     fn from_inner(socket: Socket) -> UdpSocket {
595         UdpSocket { inner: socket }
596     }
597 }
598
599 impl fmt::Debug for UdpSocket {
600     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
601         let mut res = f.debug_struct("UdpSocket");
602
603         if let Ok(addr) = self.socket_addr() {
604             res.field("addr", &addr);
605         }
606
607         let name = if cfg!(windows) {"socket"} else {"fd"};
608         res.field(name, &self.inner.as_inner())
609             .finish()
610     }
611 }
612
613 #[cfg(test)]
614 mod tests {
615     use super::*;
616     use collections::HashMap;
617
618     #[test]
619     fn no_lookup_host_duplicates() {
620         let mut addrs = HashMap::new();
621         let lh = match lookup_host("localhost") {
622             Ok(lh) => lh,
623             Err(e) => panic!("couldn't resolve `localhost': {}", e)
624         };
625         let _na = lh.map(|sa| *addrs.entry(sa).or_insert(0) += 1).count();
626         assert!(addrs.values().filter(|&&v| v > 1).count() == 0);
627     }
628 }