]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
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 | ||
c34b1796 | 13 | use ffi::{CStr, CString}; |
d9579d0f | 14 | use fmt; |
85aaf69f SL |
15 | use io::{self, Error, ErrorKind}; |
16 | use libc::{self, c_int, c_char, c_void, socklen_t}; | |
17 | use mem; | |
c34b1796 AL |
18 | use net::{SocketAddr, Shutdown, IpAddr}; |
19 | use str::from_utf8; | |
85aaf69f SL |
20 | use sys::c; |
21 | use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t}; | |
22 | use sys_common::{AsInner, FromInner, IntoInner}; | |
62682a34 | 23 | use time::Duration; |
85aaf69f SL |
24 | |
25 | //////////////////////////////////////////////////////////////////////////////// | |
26 | // sockaddr and misc bindings | |
27 | //////////////////////////////////////////////////////////////////////////////// | |
28 | ||
62682a34 | 29 | pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int, |
85aaf69f SL |
30 | payload: T) -> io::Result<()> { |
31 | unsafe { | |
32 | let payload = &payload as *const T as *const c_void; | |
33 | try!(cvt(libc::setsockopt(*sock.as_inner(), opt, val, payload, | |
34 | mem::size_of::<T>() as socklen_t))); | |
35 | Ok(()) | |
36 | } | |
37 | } | |
38 | ||
62682a34 | 39 | pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, |
c34b1796 | 40 | val: c_int) -> io::Result<T> { |
85aaf69f SL |
41 | unsafe { |
42 | let mut slot: T = mem::zeroed(); | |
43 | let mut len = mem::size_of::<T>() as socklen_t; | |
62682a34 SL |
44 | try!(cvt(c::getsockopt(*sock.as_inner(), opt, val, |
45 | &mut slot as *mut _ as *mut _, | |
46 | &mut len))); | |
47 | assert_eq!(len as usize, mem::size_of::<T>()); | |
85aaf69f SL |
48 | Ok(slot) |
49 | } | |
50 | } | |
51 | ||
52 | fn sockname<F>(f: F) -> io::Result<SocketAddr> | |
53 | where F: FnOnce(*mut libc::sockaddr, *mut socklen_t) -> c_int | |
54 | { | |
55 | unsafe { | |
56 | let mut storage: libc::sockaddr_storage = mem::zeroed(); | |
57 | let mut len = mem::size_of_val(&storage) as socklen_t; | |
58 | try!(cvt(f(&mut storage as *mut _ as *mut _, &mut len))); | |
59 | sockaddr_to_addr(&storage, len as usize) | |
60 | } | |
61 | } | |
62 | ||
63 | fn sockaddr_to_addr(storage: &libc::sockaddr_storage, | |
64 | len: usize) -> io::Result<SocketAddr> { | |
65 | match storage.ss_family as libc::c_int { | |
66 | libc::AF_INET => { | |
67 | assert!(len as usize >= mem::size_of::<libc::sockaddr_in>()); | |
c34b1796 | 68 | Ok(SocketAddr::V4(FromInner::from_inner(unsafe { |
85aaf69f | 69 | *(storage as *const _ as *const libc::sockaddr_in) |
c34b1796 | 70 | }))) |
85aaf69f SL |
71 | } |
72 | libc::AF_INET6 => { | |
73 | assert!(len as usize >= mem::size_of::<libc::sockaddr_in6>()); | |
c34b1796 | 74 | Ok(SocketAddr::V6(FromInner::from_inner(unsafe { |
85aaf69f | 75 | *(storage as *const _ as *const libc::sockaddr_in6) |
c34b1796 | 76 | }))) |
85aaf69f SL |
77 | } |
78 | _ => { | |
c34b1796 | 79 | Err(Error::new(ErrorKind::InvalidInput, "invalid argument")) |
85aaf69f SL |
80 | } |
81 | } | |
82 | } | |
83 | ||
84 | //////////////////////////////////////////////////////////////////////////////// | |
85 | // get_host_addresses | |
86 | //////////////////////////////////////////////////////////////////////////////// | |
87 | ||
88 | extern "system" { | |
89 | fn getaddrinfo(node: *const c_char, service: *const c_char, | |
90 | hints: *const libc::addrinfo, | |
91 | res: *mut *mut libc::addrinfo) -> c_int; | |
92 | fn freeaddrinfo(res: *mut libc::addrinfo); | |
93 | } | |
94 | ||
95 | pub struct LookupHost { | |
96 | original: *mut libc::addrinfo, | |
97 | cur: *mut libc::addrinfo, | |
98 | } | |
99 | ||
100 | impl Iterator for LookupHost { | |
101 | type Item = io::Result<SocketAddr>; | |
102 | fn next(&mut self) -> Option<io::Result<SocketAddr>> { | |
103 | unsafe { | |
104 | if self.cur.is_null() { return None } | |
105 | let ret = sockaddr_to_addr(mem::transmute((*self.cur).ai_addr), | |
106 | (*self.cur).ai_addrlen as usize); | |
107 | self.cur = (*self.cur).ai_next as *mut libc::addrinfo; | |
108 | Some(ret) | |
109 | } | |
110 | } | |
111 | } | |
112 | ||
113 | impl Drop for LookupHost { | |
114 | fn drop(&mut self) { | |
115 | unsafe { freeaddrinfo(self.original) } | |
116 | } | |
117 | } | |
118 | ||
119 | pub fn lookup_host(host: &str) -> io::Result<LookupHost> { | |
120 | init(); | |
121 | ||
122 | let c_host = try!(CString::new(host)); | |
123 | let mut res = 0 as *mut _; | |
124 | unsafe { | |
125 | try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _, | |
126 | &mut res))); | |
127 | Ok(LookupHost { original: res, cur: res }) | |
128 | } | |
129 | } | |
130 | ||
c34b1796 AL |
131 | //////////////////////////////////////////////////////////////////////////////// |
132 | // lookup_addr | |
133 | //////////////////////////////////////////////////////////////////////////////// | |
134 | ||
135 | extern "system" { | |
136 | fn getnameinfo(sa: *const libc::sockaddr, salen: socklen_t, | |
137 | host: *mut c_char, hostlen: libc::size_t, | |
138 | serv: *mut c_char, servlen: libc::size_t, | |
139 | flags: c_int) -> c_int; | |
140 | } | |
141 | ||
142 | const NI_MAXHOST: usize = 1025; | |
143 | ||
144 | pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> { | |
145 | init(); | |
146 | ||
147 | let saddr = SocketAddr::new(*addr, 0); | |
148 | let (inner, len) = saddr.into_inner(); | |
149 | let mut hostbuf = [0 as c_char; NI_MAXHOST]; | |
150 | ||
151 | let data = unsafe { | |
152 | try!(cvt_gai(getnameinfo(inner, len, | |
153 | hostbuf.as_mut_ptr(), NI_MAXHOST as libc::size_t, | |
154 | 0 as *mut _, 0, 0))); | |
155 | ||
156 | CStr::from_ptr(hostbuf.as_ptr()) | |
157 | }; | |
158 | ||
159 | match from_utf8(data.to_bytes()) { | |
160 | Ok(name) => Ok(name.to_string()), | |
161 | Err(_) => Err(io::Error::new(io::ErrorKind::Other, | |
162 | "failed to lookup address information")) | |
163 | } | |
164 | } | |
165 | ||
85aaf69f SL |
166 | //////////////////////////////////////////////////////////////////////////////// |
167 | // TCP streams | |
168 | //////////////////////////////////////////////////////////////////////////////// | |
169 | ||
170 | pub struct TcpStream { | |
171 | inner: Socket, | |
172 | } | |
173 | ||
174 | impl TcpStream { | |
175 | pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> { | |
176 | init(); | |
177 | ||
178 | let sock = try!(Socket::new(addr, libc::SOCK_STREAM)); | |
179 | ||
180 | let (addrp, len) = addr.into_inner(); | |
181 | try!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) })); | |
182 | Ok(TcpStream { inner: sock }) | |
183 | } | |
184 | ||
185 | pub fn socket(&self) -> &Socket { &self.inner } | |
186 | ||
187 | pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { | |
188 | setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY, | |
189 | nodelay as c_int) | |
190 | } | |
191 | ||
192 | pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> { | |
193 | let ret = setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_KEEPALIVE, | |
194 | seconds.is_some() as c_int); | |
195 | match seconds { | |
196 | Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)), | |
197 | None => ret, | |
198 | } | |
199 | } | |
200 | ||
201 | #[cfg(any(target_os = "macos", target_os = "ios"))] | |
202 | fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> { | |
203 | setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, | |
204 | seconds as c_int) | |
205 | } | |
d9579d0f AL |
206 | #[cfg(any(target_os = "freebsd", |
207 | target_os = "dragonfly", | |
208 | target_os = "linux"))] | |
85aaf69f SL |
209 | fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> { |
210 | setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, | |
211 | seconds as c_int) | |
212 | } | |
d9579d0f | 213 | |
85aaf69f SL |
214 | #[cfg(not(any(target_os = "macos", |
215 | target_os = "ios", | |
216 | target_os = "freebsd", | |
d9579d0f AL |
217 | target_os = "dragonfly", |
218 | target_os = "linux")))] | |
85aaf69f SL |
219 | fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> { |
220 | Ok(()) | |
221 | } | |
222 | ||
62682a34 SL |
223 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { |
224 | self.inner.set_timeout(dur, libc::SO_RCVTIMEO) | |
225 | } | |
226 | ||
227 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
228 | self.inner.set_timeout(dur, libc::SO_SNDTIMEO) | |
229 | } | |
230 | ||
231 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { | |
232 | self.inner.timeout(libc::SO_RCVTIMEO) | |
233 | } | |
234 | ||
235 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { | |
236 | self.inner.timeout(libc::SO_SNDTIMEO) | |
237 | } | |
238 | ||
85aaf69f SL |
239 | pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
240 | self.inner.read(buf) | |
241 | } | |
242 | ||
243 | pub fn write(&self, buf: &[u8]) -> io::Result<usize> { | |
244 | let ret = try!(cvt(unsafe { | |
245 | libc::send(*self.inner.as_inner(), | |
246 | buf.as_ptr() as *const c_void, | |
247 | buf.len() as wrlen_t, | |
248 | 0) | |
249 | })); | |
250 | Ok(ret as usize) | |
251 | } | |
252 | ||
253 | pub fn peer_addr(&self) -> io::Result<SocketAddr> { | |
254 | sockname(|buf, len| unsafe { | |
255 | libc::getpeername(*self.inner.as_inner(), buf, len) | |
256 | }) | |
257 | } | |
258 | ||
259 | pub fn socket_addr(&self) -> io::Result<SocketAddr> { | |
260 | sockname(|buf, len| unsafe { | |
261 | libc::getsockname(*self.inner.as_inner(), buf, len) | |
262 | }) | |
263 | } | |
264 | ||
265 | pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { | |
266 | use libc::consts::os::bsd44::SHUT_RDWR; | |
267 | ||
268 | let how = match how { | |
269 | Shutdown::Write => libc::SHUT_WR, | |
270 | Shutdown::Read => libc::SHUT_RD, | |
271 | Shutdown::Both => SHUT_RDWR, | |
272 | }; | |
273 | try!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) })); | |
274 | Ok(()) | |
275 | } | |
276 | ||
277 | pub fn duplicate(&self) -> io::Result<TcpStream> { | |
278 | self.inner.duplicate().map(|s| TcpStream { inner: s }) | |
279 | } | |
280 | } | |
281 | ||
c34b1796 AL |
282 | impl FromInner<Socket> for TcpStream { |
283 | fn from_inner(socket: Socket) -> TcpStream { | |
284 | TcpStream { inner: socket } | |
285 | } | |
286 | } | |
287 | ||
d9579d0f AL |
288 | impl fmt::Debug for TcpStream { |
289 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
290 | let mut res = f.debug_struct("TcpStream"); | |
291 | ||
292 | if let Ok(addr) = self.socket_addr() { | |
62682a34 | 293 | res.field("addr", &addr); |
d9579d0f AL |
294 | } |
295 | ||
296 | if let Ok(peer) = self.peer_addr() { | |
62682a34 | 297 | res.field("peer", &peer); |
d9579d0f AL |
298 | } |
299 | ||
300 | let name = if cfg!(windows) {"socket"} else {"fd"}; | |
62682a34 SL |
301 | res.field(name, &self.inner.as_inner()) |
302 | .finish() | |
d9579d0f AL |
303 | } |
304 | } | |
305 | ||
85aaf69f SL |
306 | //////////////////////////////////////////////////////////////////////////////// |
307 | // TCP listeners | |
308 | //////////////////////////////////////////////////////////////////////////////// | |
309 | ||
310 | pub struct TcpListener { | |
311 | inner: Socket, | |
312 | } | |
313 | ||
314 | impl TcpListener { | |
315 | pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> { | |
316 | init(); | |
317 | ||
318 | let sock = try!(Socket::new(addr, libc::SOCK_STREAM)); | |
319 | ||
320 | // On platforms with Berkeley-derived sockets, this allows | |
321 | // to quickly rebind a socket, without needing to wait for | |
322 | // the OS to clean up the previous one. | |
323 | if !cfg!(windows) { | |
324 | try!(setsockopt(&sock, libc::SOL_SOCKET, libc::SO_REUSEADDR, | |
325 | 1 as c_int)); | |
326 | } | |
327 | ||
328 | // Bind our new socket | |
329 | let (addrp, len) = addr.into_inner(); | |
330 | try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) })); | |
331 | ||
332 | // Start listening | |
333 | try!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) })); | |
334 | Ok(TcpListener { inner: sock }) | |
335 | } | |
336 | ||
337 | pub fn socket(&self) -> &Socket { &self.inner } | |
338 | ||
339 | pub fn socket_addr(&self) -> io::Result<SocketAddr> { | |
340 | sockname(|buf, len| unsafe { | |
341 | libc::getsockname(*self.inner.as_inner(), buf, len) | |
342 | }) | |
343 | } | |
344 | ||
345 | pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { | |
346 | let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; | |
347 | let mut len = mem::size_of_val(&storage) as socklen_t; | |
348 | let sock = try!(self.inner.accept(&mut storage as *mut _ as *mut _, | |
349 | &mut len)); | |
350 | let addr = try!(sockaddr_to_addr(&storage, len as usize)); | |
351 | Ok((TcpStream { inner: sock, }, addr)) | |
352 | } | |
353 | ||
354 | pub fn duplicate(&self) -> io::Result<TcpListener> { | |
355 | self.inner.duplicate().map(|s| TcpListener { inner: s }) | |
356 | } | |
357 | } | |
358 | ||
c34b1796 AL |
359 | impl FromInner<Socket> for TcpListener { |
360 | fn from_inner(socket: Socket) -> TcpListener { | |
361 | TcpListener { inner: socket } | |
362 | } | |
363 | } | |
364 | ||
d9579d0f AL |
365 | impl fmt::Debug for TcpListener { |
366 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
367 | let mut res = f.debug_struct("TcpListener"); | |
368 | ||
369 | if let Ok(addr) = self.socket_addr() { | |
62682a34 | 370 | res.field("addr", &addr); |
d9579d0f AL |
371 | } |
372 | ||
373 | let name = if cfg!(windows) {"socket"} else {"fd"}; | |
62682a34 SL |
374 | res.field(name, &self.inner.as_inner()) |
375 | .finish() | |
d9579d0f AL |
376 | } |
377 | } | |
378 | ||
85aaf69f SL |
379 | //////////////////////////////////////////////////////////////////////////////// |
380 | // UDP | |
381 | //////////////////////////////////////////////////////////////////////////////// | |
382 | ||
383 | pub struct UdpSocket { | |
384 | inner: Socket, | |
385 | } | |
386 | ||
387 | impl UdpSocket { | |
388 | pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> { | |
389 | init(); | |
390 | ||
391 | let sock = try!(Socket::new(addr, libc::SOCK_DGRAM)); | |
392 | let (addrp, len) = addr.into_inner(); | |
393 | try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) })); | |
394 | Ok(UdpSocket { inner: sock }) | |
395 | } | |
396 | ||
397 | pub fn socket(&self) -> &Socket { &self.inner } | |
398 | ||
399 | pub fn socket_addr(&self) -> io::Result<SocketAddr> { | |
400 | sockname(|buf, len| unsafe { | |
401 | libc::getsockname(*self.inner.as_inner(), buf, len) | |
402 | }) | |
403 | } | |
404 | ||
405 | pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { | |
406 | let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; | |
407 | let mut addrlen = mem::size_of_val(&storage) as socklen_t; | |
408 | ||
409 | let n = try!(cvt(unsafe { | |
410 | libc::recvfrom(*self.inner.as_inner(), | |
411 | buf.as_mut_ptr() as *mut c_void, | |
412 | buf.len() as wrlen_t, 0, | |
413 | &mut storage as *mut _ as *mut _, &mut addrlen) | |
414 | })); | |
415 | Ok((n as usize, try!(sockaddr_to_addr(&storage, addrlen as usize)))) | |
416 | } | |
417 | ||
418 | pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> { | |
419 | let (dstp, dstlen) = dst.into_inner(); | |
420 | let ret = try!(cvt(unsafe { | |
421 | libc::sendto(*self.inner.as_inner(), | |
422 | buf.as_ptr() as *const c_void, buf.len() as wrlen_t, | |
423 | 0, dstp, dstlen) | |
424 | })); | |
425 | Ok(ret as usize) | |
426 | } | |
427 | ||
428 | pub fn set_broadcast(&self, on: bool) -> io::Result<()> { | |
429 | setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_BROADCAST, | |
430 | on as c_int) | |
431 | } | |
432 | ||
433 | pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> { | |
434 | setsockopt(&self.inner, libc::IPPROTO_IP, | |
435 | libc::IP_MULTICAST_LOOP, on as c_int) | |
436 | } | |
437 | ||
438 | pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> { | |
439 | match *multi { | |
440 | IpAddr::V4(..) => { | |
441 | self.set_membership(multi, libc::IP_ADD_MEMBERSHIP) | |
442 | } | |
443 | IpAddr::V6(..) => { | |
444 | self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP) | |
445 | } | |
446 | } | |
447 | } | |
448 | pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> { | |
449 | match *multi { | |
450 | IpAddr::V4(..) => { | |
451 | self.set_membership(multi, libc::IP_DROP_MEMBERSHIP) | |
452 | } | |
453 | IpAddr::V6(..) => { | |
454 | self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP) | |
455 | } | |
456 | } | |
457 | } | |
458 | fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> { | |
459 | match *addr { | |
460 | IpAddr::V4(ref addr) => { | |
461 | let mreq = libc::ip_mreq { | |
462 | imr_multiaddr: *addr.as_inner(), | |
463 | // interface == INADDR_ANY | |
464 | imr_interface: libc::in_addr { s_addr: 0x0 }, | |
465 | }; | |
466 | setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq) | |
467 | } | |
468 | IpAddr::V6(ref addr) => { | |
469 | let mreq = libc::ip6_mreq { | |
470 | ipv6mr_multiaddr: *addr.as_inner(), | |
471 | ipv6mr_interface: 0, | |
472 | }; | |
473 | setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq) | |
474 | } | |
475 | } | |
476 | } | |
477 | ||
478 | pub fn multicast_time_to_live(&self, ttl: i32) -> io::Result<()> { | |
479 | setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, | |
480 | ttl as c_int) | |
481 | } | |
482 | ||
483 | pub fn time_to_live(&self, ttl: i32) -> io::Result<()> { | |
484 | setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int) | |
485 | } | |
486 | ||
487 | pub fn duplicate(&self) -> io::Result<UdpSocket> { | |
488 | self.inner.duplicate().map(|s| UdpSocket { inner: s }) | |
489 | } | |
62682a34 SL |
490 | |
491 | pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
492 | self.inner.set_timeout(dur, libc::SO_RCVTIMEO) | |
493 | } | |
494 | ||
495 | pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> { | |
496 | self.inner.set_timeout(dur, libc::SO_SNDTIMEO) | |
497 | } | |
498 | ||
499 | pub fn read_timeout(&self) -> io::Result<Option<Duration>> { | |
500 | self.inner.timeout(libc::SO_RCVTIMEO) | |
501 | } | |
502 | ||
503 | pub fn write_timeout(&self) -> io::Result<Option<Duration>> { | |
504 | self.inner.timeout(libc::SO_SNDTIMEO) | |
505 | } | |
85aaf69f | 506 | } |
c34b1796 AL |
507 | |
508 | impl FromInner<Socket> for UdpSocket { | |
509 | fn from_inner(socket: Socket) -> UdpSocket { | |
510 | UdpSocket { inner: socket } | |
511 | } | |
512 | } | |
d9579d0f AL |
513 | |
514 | impl fmt::Debug for UdpSocket { | |
515 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
516 | let mut res = f.debug_struct("UdpSocket"); | |
517 | ||
518 | if let Ok(addr) = self.socket_addr() { | |
62682a34 | 519 | res.field("addr", &addr); |
d9579d0f AL |
520 | } |
521 | ||
522 | let name = if cfg!(windows) {"socket"} else {"fd"}; | |
62682a34 SL |
523 | res.field(name, &self.inner.as_inner()) |
524 | .finish() | |
d9579d0f AL |
525 | } |
526 | } |