]> git.proxmox.com Git - rustc.git/blob - src/libstd/sys_common/net.rs
New upstream version 1.19.0+dfsg1
[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 match cvt_gai(c::getaddrinfo(c_host.as_ptr(), ptr::null(), &hints, &mut res)) {
181 Ok(_) => {
182 Ok(LookupHost { original: res, cur: res })
183 },
184 #[cfg(unix)]
185 Err(e) => {
186 // The lookup failure could be caused by using a stale /etc/resolv.conf.
187 // See https://github.com/rust-lang/rust/issues/41570.
188 // We therefore force a reload of the nameserver information.
189 c::res_init();
190 Err(e)
191 },
192 // the cfg is needed here to avoid an "unreachable pattern" warning
193 #[cfg(not(unix))]
194 Err(e) => Err(e),
195 }
196 }
197 }
198
199 ////////////////////////////////////////////////////////////////////////////////
200 // TCP streams
201 ////////////////////////////////////////////////////////////////////////////////
202
203 pub struct TcpStream {
204 inner: Socket,
205 }
206
207 impl TcpStream {
208 pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
209 init();
210
211 let sock = Socket::new(addr, c::SOCK_STREAM)?;
212
213 let (addrp, len) = addr.into_inner();
214 cvt_r(|| unsafe { c::connect(*sock.as_inner(), addrp, len) })?;
215 Ok(TcpStream { inner: sock })
216 }
217
218 pub fn socket(&self) -> &Socket { &self.inner }
219
220 pub fn into_socket(self) -> Socket { self.inner }
221
222 pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
223 self.inner.set_timeout(dur, c::SO_RCVTIMEO)
224 }
225
226 pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
227 self.inner.set_timeout(dur, c::SO_SNDTIMEO)
228 }
229
230 pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
231 self.inner.timeout(c::SO_RCVTIMEO)
232 }
233
234 pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
235 self.inner.timeout(c::SO_SNDTIMEO)
236 }
237
238 pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
239 self.inner.peek(buf)
240 }
241
242 pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
243 self.inner.read(buf)
244 }
245
246 pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
247 self.inner.read_to_end(buf)
248 }
249
250 pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
251 let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
252 let ret = cvt(unsafe {
253 c::send(*self.inner.as_inner(),
254 buf.as_ptr() as *const c_void,
255 len,
256 MSG_NOSIGNAL)
257 })?;
258 Ok(ret as usize)
259 }
260
261 pub fn peer_addr(&self) -> io::Result<SocketAddr> {
262 sockname(|buf, len| unsafe {
263 c::getpeername(*self.inner.as_inner(), buf, len)
264 })
265 }
266
267 pub fn socket_addr(&self) -> io::Result<SocketAddr> {
268 sockname(|buf, len| unsafe {
269 c::getsockname(*self.inner.as_inner(), buf, len)
270 })
271 }
272
273 pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
274 self.inner.shutdown(how)
275 }
276
277 pub fn duplicate(&self) -> io::Result<TcpStream> {
278 self.inner.duplicate().map(|s| TcpStream { inner: s })
279 }
280
281 pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
282 self.inner.set_nodelay(nodelay)
283 }
284
285 pub fn nodelay(&self) -> io::Result<bool> {
286 self.inner.nodelay()
287 }
288
289 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
290 setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
291 }
292
293 pub fn ttl(&self) -> io::Result<u32> {
294 let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
295 Ok(raw as u32)
296 }
297
298 pub fn take_error(&self) -> io::Result<Option<io::Error>> {
299 self.inner.take_error()
300 }
301
302 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
303 self.inner.set_nonblocking(nonblocking)
304 }
305 }
306
307 impl FromInner<Socket> for TcpStream {
308 fn from_inner(socket: Socket) -> TcpStream {
309 TcpStream { inner: socket }
310 }
311 }
312
313 impl fmt::Debug for TcpStream {
314 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
315 let mut res = f.debug_struct("TcpStream");
316
317 if let Ok(addr) = self.socket_addr() {
318 res.field("addr", &addr);
319 }
320
321 if let Ok(peer) = self.peer_addr() {
322 res.field("peer", &peer);
323 }
324
325 let name = if cfg!(windows) {"socket"} else {"fd"};
326 res.field(name, &self.inner.as_inner())
327 .finish()
328 }
329 }
330
331 ////////////////////////////////////////////////////////////////////////////////
332 // TCP listeners
333 ////////////////////////////////////////////////////////////////////////////////
334
335 pub struct TcpListener {
336 inner: Socket,
337 }
338
339 impl TcpListener {
340 pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
341 init();
342
343 let sock = Socket::new(addr, c::SOCK_STREAM)?;
344
345 // On platforms with Berkeley-derived sockets, this allows
346 // to quickly rebind a socket, without needing to wait for
347 // the OS to clean up the previous one.
348 if !cfg!(windows) {
349 setsockopt(&sock, c::SOL_SOCKET, c::SO_REUSEADDR,
350 1 as c_int)?;
351 }
352
353 // Bind our new socket
354 let (addrp, len) = addr.into_inner();
355 cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
356
357 // Start listening
358 cvt(unsafe { c::listen(*sock.as_inner(), 128) })?;
359 Ok(TcpListener { inner: sock })
360 }
361
362 pub fn socket(&self) -> &Socket { &self.inner }
363
364 pub fn into_socket(self) -> Socket { self.inner }
365
366 pub fn socket_addr(&self) -> io::Result<SocketAddr> {
367 sockname(|buf, len| unsafe {
368 c::getsockname(*self.inner.as_inner(), buf, len)
369 })
370 }
371
372 pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
373 let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() };
374 let mut len = mem::size_of_val(&storage) as c::socklen_t;
375 let sock = self.inner.accept(&mut storage as *mut _ as *mut _,
376 &mut len)?;
377 let addr = sockaddr_to_addr(&storage, len as usize)?;
378 Ok((TcpStream { inner: sock, }, addr))
379 }
380
381 pub fn duplicate(&self) -> io::Result<TcpListener> {
382 self.inner.duplicate().map(|s| TcpListener { inner: s })
383 }
384
385 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
386 setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
387 }
388
389 pub fn ttl(&self) -> io::Result<u32> {
390 let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
391 Ok(raw as u32)
392 }
393
394 pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
395 setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY, only_v6 as c_int)
396 }
397
398 pub fn only_v6(&self) -> io::Result<bool> {
399 let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_V6ONLY)?;
400 Ok(raw != 0)
401 }
402
403 pub fn take_error(&self) -> io::Result<Option<io::Error>> {
404 self.inner.take_error()
405 }
406
407 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
408 self.inner.set_nonblocking(nonblocking)
409 }
410 }
411
412 impl FromInner<Socket> for TcpListener {
413 fn from_inner(socket: Socket) -> TcpListener {
414 TcpListener { inner: socket }
415 }
416 }
417
418 impl fmt::Debug for TcpListener {
419 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
420 let mut res = f.debug_struct("TcpListener");
421
422 if let Ok(addr) = self.socket_addr() {
423 res.field("addr", &addr);
424 }
425
426 let name = if cfg!(windows) {"socket"} else {"fd"};
427 res.field(name, &self.inner.as_inner())
428 .finish()
429 }
430 }
431
432 ////////////////////////////////////////////////////////////////////////////////
433 // UDP
434 ////////////////////////////////////////////////////////////////////////////////
435
436 pub struct UdpSocket {
437 inner: Socket,
438 }
439
440 impl UdpSocket {
441 pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
442 init();
443
444 let sock = Socket::new(addr, c::SOCK_DGRAM)?;
445 let (addrp, len) = addr.into_inner();
446 cvt(unsafe { c::bind(*sock.as_inner(), addrp, len as _) })?;
447 Ok(UdpSocket { inner: sock })
448 }
449
450 pub fn socket(&self) -> &Socket { &self.inner }
451
452 pub fn into_socket(self) -> Socket { self.inner }
453
454 pub fn socket_addr(&self) -> io::Result<SocketAddr> {
455 sockname(|buf, len| unsafe {
456 c::getsockname(*self.inner.as_inner(), buf, len)
457 })
458 }
459
460 pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
461 self.inner.recv_from(buf)
462 }
463
464 pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
465 self.inner.peek_from(buf)
466 }
467
468 pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
469 let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
470 let (dstp, dstlen) = dst.into_inner();
471 let ret = cvt(unsafe {
472 c::sendto(*self.inner.as_inner(),
473 buf.as_ptr() as *const c_void, len,
474 MSG_NOSIGNAL, dstp, dstlen)
475 })?;
476 Ok(ret as usize)
477 }
478
479 pub fn duplicate(&self) -> io::Result<UdpSocket> {
480 self.inner.duplicate().map(|s| UdpSocket { inner: s })
481 }
482
483 pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
484 self.inner.set_timeout(dur, c::SO_RCVTIMEO)
485 }
486
487 pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
488 self.inner.set_timeout(dur, c::SO_SNDTIMEO)
489 }
490
491 pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
492 self.inner.timeout(c::SO_RCVTIMEO)
493 }
494
495 pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
496 self.inner.timeout(c::SO_SNDTIMEO)
497 }
498
499 pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
500 setsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST, broadcast as c_int)
501 }
502
503 pub fn broadcast(&self) -> io::Result<bool> {
504 let raw: c_int = getsockopt(&self.inner, c::SOL_SOCKET, c::SO_BROADCAST)?;
505 Ok(raw != 0)
506 }
507
508 pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
509 setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP, multicast_loop_v4 as c_int)
510 }
511
512 pub fn multicast_loop_v4(&self) -> io::Result<bool> {
513 let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_LOOP)?;
514 Ok(raw != 0)
515 }
516
517 pub fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> {
518 setsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL, multicast_ttl_v4 as c_int)
519 }
520
521 pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
522 let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_MULTICAST_TTL)?;
523 Ok(raw as u32)
524 }
525
526 pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
527 setsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP, multicast_loop_v6 as c_int)
528 }
529
530 pub fn multicast_loop_v6(&self) -> io::Result<bool> {
531 let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IPV6, c::IPV6_MULTICAST_LOOP)?;
532 Ok(raw != 0)
533 }
534
535 pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
536 -> io::Result<()> {
537 let mreq = c::ip_mreq {
538 imr_multiaddr: *multiaddr.as_inner(),
539 imr_interface: *interface.as_inner(),
540 };
541 setsockopt(&self.inner, c::IPPROTO_IP, c::IP_ADD_MEMBERSHIP, mreq)
542 }
543
544 pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
545 -> io::Result<()> {
546 let mreq = c::ipv6_mreq {
547 ipv6mr_multiaddr: *multiaddr.as_inner(),
548 ipv6mr_interface: to_ipv6mr_interface(interface),
549 };
550 setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq)
551 }
552
553 pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr)
554 -> io::Result<()> {
555 let mreq = c::ip_mreq {
556 imr_multiaddr: *multiaddr.as_inner(),
557 imr_interface: *interface.as_inner(),
558 };
559 setsockopt(&self.inner, c::IPPROTO_IP, c::IP_DROP_MEMBERSHIP, mreq)
560 }
561
562 pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32)
563 -> io::Result<()> {
564 let mreq = c::ipv6_mreq {
565 ipv6mr_multiaddr: *multiaddr.as_inner(),
566 ipv6mr_interface: to_ipv6mr_interface(interface),
567 };
568 setsockopt(&self.inner, c::IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, mreq)
569 }
570
571 pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
572 setsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL, ttl as c_int)
573 }
574
575 pub fn ttl(&self) -> io::Result<u32> {
576 let raw: c_int = getsockopt(&self.inner, c::IPPROTO_IP, c::IP_TTL)?;
577 Ok(raw as u32)
578 }
579
580 pub fn take_error(&self) -> io::Result<Option<io::Error>> {
581 self.inner.take_error()
582 }
583
584 pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
585 self.inner.set_nonblocking(nonblocking)
586 }
587
588 pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
589 self.inner.read(buf)
590 }
591
592 pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
593 self.inner.peek(buf)
594 }
595
596 pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
597 let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t;
598 let ret = cvt(unsafe {
599 c::send(*self.inner.as_inner(),
600 buf.as_ptr() as *const c_void,
601 len,
602 MSG_NOSIGNAL)
603 })?;
604 Ok(ret as usize)
605 }
606
607 pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
608 let (addrp, len) = addr.into_inner();
609 cvt_r(|| unsafe { c::connect(*self.inner.as_inner(), addrp, len) }).map(|_| ())
610 }
611 }
612
613 impl FromInner<Socket> for UdpSocket {
614 fn from_inner(socket: Socket) -> UdpSocket {
615 UdpSocket { inner: socket }
616 }
617 }
618
619 impl fmt::Debug for UdpSocket {
620 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
621 let mut res = f.debug_struct("UdpSocket");
622
623 if let Ok(addr) = self.socket_addr() {
624 res.field("addr", &addr);
625 }
626
627 let name = if cfg!(windows) {"socket"} else {"fd"};
628 res.field(name, &self.inner.as_inner())
629 .finish()
630 }
631 }
632
633 #[cfg(test)]
634 mod tests {
635 use super::*;
636 use collections::HashMap;
637
638 #[test]
639 fn no_lookup_host_duplicates() {
640 let mut addrs = HashMap::new();
641 let lh = match lookup_host("localhost") {
642 Ok(lh) => lh,
643 Err(e) => panic!("couldn't resolve `localhost': {}", e)
644 };
645 let _na = lh.map(|sa| *addrs.entry(sa).or_insert(0) += 1).count();
646 assert!(addrs.values().filter(|&&v| v > 1).count() == 0);
647 }
648 }