Skip to main content

mio/net/
udp.rs

1//! Primitives for working with UDP.
2//!
3//! The types provided in this module are non-blocking by default and are
4//! designed to be portable across all supported Mio platforms. As long as the
5//! [portability guidelines] are followed, the behavior should be identical no
6//! matter the target platform.
7//!
8//! [portability guidelines]: ../struct.Poll.html#portability
9
10use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
11#[cfg(any(unix, target_os = "wasi"))]
12use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
13// TODO: once <https://github.com/rust-lang/rust/issues/126198> is fixed this
14// can use `std::os::fd` and be merged with the above.
15#[cfg(target_os = "hermit")]
16use std::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
17#[cfg(windows)]
18use std::os::windows::io::{
19    AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
20};
21use std::{fmt, io, net};
22
23use crate::io_source::IoSource;
24use crate::{event, sys, Interest, Registry, Token};
25
26/// A User Datagram Protocol socket.
27///
28/// This is an implementation of a bound UDP socket. This supports both IPv4 and
29/// IPv6 addresses, and there is no corresponding notion of a server because UDP
30/// is a datagram protocol.
31///
32/// # Examples
33///
34#[cfg_attr(feature = "os-poll", doc = "```")]
35#[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
36/// # use std::error::Error;
37/// #
38/// # fn main() -> Result<(), Box<dyn Error>> {
39/// # // Temporarily disabled on WASI pending https://github.com/WebAssembly/wasi-libc/pull/740:
40/// # if cfg!(target_os = "wasi") { return Ok(()) }
41/// // An Echo program:
42/// // SENDER -> sends a message.
43/// // ECHOER -> listens and prints the message received.
44///
45/// use mio::net::UdpSocket;
46/// use mio::{Events, Interest, Poll, Token};
47/// use std::time::Duration;
48///
49/// const SENDER: Token = Token(0);
50/// const ECHOER: Token = Token(1);
51///
52/// // This operation will fail if the address is in use, so we select different ports for each
53/// // socket.
54/// let mut sender_socket = UdpSocket::bind("127.0.0.1:0".parse()?)?;
55/// let mut echoer_socket = UdpSocket::bind("127.0.0.1:0".parse()?)?;
56///
57/// // If we do not use connect here, SENDER and ECHOER would need to call send_to and recv_from
58/// // respectively.
59/// sender_socket.connect(echoer_socket.local_addr()?)?;
60///
61/// // We need a Poll to check if SENDER is ready to be written into, and if ECHOER is ready to be
62/// // read from.
63/// let mut poll = Poll::new()?;
64///
65/// // We register our sockets here so that we can check if they are ready to be written/read.
66/// poll.registry().register(&mut sender_socket, SENDER, Interest::WRITABLE)?;
67/// poll.registry().register(&mut echoer_socket, ECHOER, Interest::READABLE)?;
68///
69/// let msg_to_send = [9; 9];
70/// let mut buffer = [0; 9];
71///
72/// let mut events = Events::with_capacity(128);
73/// loop {
74///     poll.poll(&mut events, Some(Duration::from_millis(100)))?;
75///     for event in events.iter() {
76///         match event.token() {
77///             // Our SENDER is ready to be written into.
78///             SENDER => {
79///                 let bytes_sent = sender_socket.send(&msg_to_send)?;
80///                 assert_eq!(bytes_sent, 9);
81///                 println!("sent {:?} -> {:?} bytes", msg_to_send, bytes_sent);
82///             },
83///             // Our ECHOER is ready to be read from.
84///             ECHOER => {
85///                 let num_recv = echoer_socket.recv(&mut buffer)?;
86///                 println!("echo {:?} -> {:?}", buffer, num_recv);
87///                 buffer = [0; 9];
88///                 # _ = buffer; // Silence unused assignment warning.
89///                 # return Ok(());
90///             }
91///             _ => unreachable!()
92///         }
93///     }
94/// }
95/// # }
96/// ```
97pub struct UdpSocket {
98    inner: IoSource<net::UdpSocket>,
99}
100
101impl UdpSocket {
102    /// Creates a UDP socket from the given address.
103    ///
104    /// # Examples
105    ///
106    #[cfg_attr(feature = "os-poll", doc = "```")]
107    #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
108    /// # use std::error::Error;
109    /// #
110    /// # fn main() -> Result<(), Box<dyn Error>> {
111    /// use mio::net::UdpSocket;
112    ///
113    /// // We must bind it to an open address.
114    /// let socket = match UdpSocket::bind("127.0.0.1:0".parse()?) {
115    ///     Ok(new_socket) => new_socket,
116    ///     Err(fail) => {
117    ///         // We panic! here, but you could try to bind it again on another address.
118    ///         panic!("Failed to bind socket. {:?}", fail);
119    ///     }
120    /// };
121    ///
122    /// // Our socket was created, but we should not use it before checking it's readiness.
123    /// #    drop(socket); // Silence unused variable warning.
124    /// #    Ok(())
125    /// # }
126    /// ```
127    pub fn bind(addr: SocketAddr) -> io::Result<UdpSocket> {
128        sys::udp::bind(addr).map(UdpSocket::from_std)
129    }
130
131    /// Creates a new `UdpSocket` from a standard `net::UdpSocket`.
132    ///
133    /// This function is intended to be used to wrap a UDP socket from the
134    /// standard library in the Mio equivalent. The conversion assumes nothing
135    /// about the underlying socket; it is left up to the user to set it in
136    /// non-blocking mode.
137    pub fn from_std(socket: net::UdpSocket) -> UdpSocket {
138        UdpSocket {
139            inner: IoSource::new(socket),
140        }
141    }
142
143    /// Returns the socket address that this socket was created from.
144    ///
145    /// # Examples
146    ///
147    // This assertion is almost, but not quite, universal.  It fails on
148    // shared-IP FreeBSD jails.  It's hard for mio to know whether we're jailed,
149    // so simply disable the test on FreeBSD.
150    #[cfg_attr(all(feature = "os-poll", not(target_os = "freebsd")), doc = "```")]
151    #[cfg_attr(
152        any(not(feature = "os-poll"), target_os = "freebsd"),
153        doc = "```ignore"
154    )]
155    /// # use std::error::Error;
156    /// #
157    /// # fn main() -> Result<(), Box<dyn Error>> {
158    /// use mio::net::UdpSocket;
159    ///
160    /// let addr = "127.0.0.1:0".parse()?;
161    /// let socket = UdpSocket::bind(addr)?;
162    /// assert_eq!(socket.local_addr()?.ip(), addr.ip());
163    /// #    Ok(())
164    /// # }
165    /// ```
166    pub fn local_addr(&self) -> io::Result<SocketAddr> {
167        self.inner.local_addr()
168    }
169
170    /// Returns the socket address of the remote peer this socket was connected to.
171    ///
172    /// # Examples
173    ///
174    #[cfg_attr(feature = "os-poll", doc = "```")]
175    #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
176    /// # use std::error::Error;
177    /// #
178    /// # fn main() -> Result<(), Box<dyn Error>> {
179    /// use mio::net::UdpSocket;
180    ///
181    /// let addr = "127.0.0.1:0".parse()?;
182    /// let peer_addr = "127.0.0.1:11100".parse()?;
183    /// let socket = UdpSocket::bind(addr)?;
184    /// socket.connect(peer_addr)?;
185    /// assert_eq!(socket.peer_addr()?.ip(), peer_addr.ip());
186    /// #    Ok(())
187    /// # }
188    /// ```
189    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
190        self.inner.peer_addr()
191    }
192
193    /// Sends data on the socket to the given address. On success, returns the
194    /// number of bytes written.
195    ///
196    /// Address type can be any implementor of `ToSocketAddrs` trait. See its
197    /// documentation for concrete examples.
198    ///
199    /// # Examples
200    ///
201    /// ```no_run
202    /// # use std::error::Error;
203    /// # fn main() -> Result<(), Box<dyn Error>> {
204    /// use mio::net::UdpSocket;
205    ///
206    /// let socket = UdpSocket::bind("127.0.0.1:0".parse()?)?;
207    ///
208    /// // We must check if the socket is writable before calling send_to,
209    /// // or we could run into a WouldBlock error.
210    ///
211    /// let bytes_sent = socket.send_to(&[9; 9], "127.0.0.1:11100".parse()?)?;
212    /// assert_eq!(bytes_sent, 9);
213    /// #
214    /// #    Ok(())
215    /// # }
216    /// ```
217    pub fn send_to(&self, buf: &[u8], target: SocketAddr) -> io::Result<usize> {
218        self.inner.do_io(|inner| inner.send_to(buf, target))
219    }
220
221    /// Receives data from the socket. On success, returns the number of bytes
222    /// read and the address from whence the data came.
223    ///
224    /// # Notes
225    ///
226    /// On Windows, if the data is larger than the buffer specified, the buffer
227    /// is filled with the first part of the data, and recv_from returns the error
228    /// WSAEMSGSIZE(10040). The excess data is lost.
229    /// Make sure to always use a sufficiently large buffer to hold the
230    /// maximum UDP packet size, which can be up to 65536 bytes in size.
231    ///
232    /// # Examples
233    ///
234    /// ```no_run
235    /// # use std::error::Error;
236    /// #
237    /// # fn main() -> Result<(), Box<dyn Error>> {
238    /// use mio::net::UdpSocket;
239    ///
240    /// let socket = UdpSocket::bind("127.0.0.1:0".parse()?)?;
241    ///
242    /// // We must check if the socket is readable before calling recv_from,
243    /// // or we could run into a WouldBlock error.
244    ///
245    /// let mut buf = [0; 9];
246    /// let (num_recv, from_addr) = socket.recv_from(&mut buf)?;
247    /// println!("Received {:?} -> {:?} bytes from {:?}", buf, num_recv, from_addr);
248    /// #
249    /// #    Ok(())
250    /// # }
251    /// ```
252    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
253        self.inner.do_io(|inner| inner.recv_from(buf))
254    }
255
256    /// Receives data from the socket, without removing it from the input queue.
257    /// On success, returns the number of bytes read and the address from whence
258    /// the data came.
259    ///
260    /// # Notes
261    ///
262    /// On Windows, if the data is larger than the buffer specified, the buffer
263    /// is filled with the first part of the data, and peek_from returns the error
264    /// WSAEMSGSIZE(10040). The excess data is lost.
265    /// Make sure to always use a sufficiently large buffer to hold the
266    /// maximum UDP packet size, which can be up to 65536 bytes in size.
267    ///
268    /// # Examples
269    ///
270    /// ```no_run
271    /// # use std::error::Error;
272    /// #
273    /// # fn main() -> Result<(), Box<dyn Error>> {
274    /// use mio::net::UdpSocket;
275    ///
276    /// let socket = UdpSocket::bind("127.0.0.1:0".parse()?)?;
277    ///
278    /// // We must check if the socket is readable before calling recv_from,
279    /// // or we could run into a WouldBlock error.
280    ///
281    /// let mut buf = [0; 9];
282    /// let (num_recv, from_addr) = socket.peek_from(&mut buf)?;
283    /// println!("Received {:?} -> {:?} bytes from {:?}", buf, num_recv, from_addr);
284    /// #
285    /// #    Ok(())
286    /// # }
287    /// ```
288    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
289        self.inner.do_io(|inner| inner.peek_from(buf))
290    }
291
292    /// Sends data on the socket to the address previously bound via connect(). On success,
293    /// returns the number of bytes written.
294    pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
295        self.inner.do_io(|inner| inner.send(buf))
296    }
297
298    /// Receives data from the socket previously bound with connect(). On success, returns
299    /// the number of bytes read.
300    ///
301    /// # Notes
302    ///
303    /// On Windows, if the data is larger than the buffer specified, the buffer
304    /// is filled with the first part of the data, and recv returns the error
305    /// WSAEMSGSIZE(10040). The excess data is lost.
306    /// Make sure to always use a sufficiently large buffer to hold the
307    /// maximum UDP packet size, which can be up to 65536 bytes in size.
308    pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
309        self.inner.do_io(|inner| inner.recv(buf))
310    }
311
312    /// Receives data from the socket, without removing it from the input queue.
313    /// On success, returns the number of bytes read.
314    ///
315    /// # Notes
316    ///
317    /// On Windows, if the data is larger than the buffer specified, the buffer
318    /// is filled with the first part of the data, and peek returns the error
319    /// WSAEMSGSIZE(10040). The excess data is lost.
320    /// Make sure to always use a sufficiently large buffer to hold the
321    /// maximum UDP packet size, which can be up to 65536 bytes in size.
322    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
323        self.inner.do_io(|inner| inner.peek(buf))
324    }
325
326    /// Connects the UDP socket setting the default destination for `send()`
327    /// and limiting packets that are read via `recv` from the address specified
328    /// in `addr`.
329    ///
330    /// This may return a `WouldBlock` in which case the socket connection
331    /// cannot be completed immediately, it usually means there are insufficient
332    /// entries in the routing cache.
333    pub fn connect(&self, addr: SocketAddr) -> io::Result<()> {
334        self.inner.connect(addr)
335    }
336
337    /// Sets the value of the `SO_BROADCAST` option for this socket.
338    ///
339    /// When enabled, this socket is allowed to send packets to a broadcast
340    /// address.
341    ///
342    /// # Examples
343    ///
344    #[cfg_attr(feature = "os-poll", doc = "```")]
345    #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
346    /// # use std::error::Error;
347    /// #
348    /// # fn main() -> Result<(), Box<dyn Error>> {
349    /// # // WASI does not yet support broadcast.
350    /// # if cfg!(target_os = "wasi") { return Ok(()) }
351    /// use mio::net::UdpSocket;
352    ///
353    /// let broadcast_socket = UdpSocket::bind("127.0.0.1:0".parse()?)?;
354    /// if broadcast_socket.broadcast()? == false {
355    ///     broadcast_socket.set_broadcast(true)?;
356    /// }
357    ///
358    /// assert_eq!(broadcast_socket.broadcast()?, true);
359    /// #
360    /// #    Ok(())
361    /// # }
362    /// ```
363    pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
364        self.inner.set_broadcast(on)
365    }
366
367    /// Gets the value of the `SO_BROADCAST` option for this socket.
368    ///
369    /// For more information about this option, see
370    /// [`set_broadcast`][link].
371    ///
372    /// [link]: #method.set_broadcast
373    ///
374    /// # Examples
375    ///
376    #[cfg_attr(feature = "os-poll", doc = "```")]
377    #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
378    /// # use std::error::Error;
379    /// #
380    /// # fn main() -> Result<(), Box<dyn Error>> {
381    /// # // WASI does not yet support broadcast.
382    /// # if cfg!(target_os = "wasi") { return Ok(()) }
383    /// use mio::net::UdpSocket;
384    ///
385    /// let broadcast_socket = UdpSocket::bind("127.0.0.1:0".parse()?)?;
386    /// assert_eq!(broadcast_socket.broadcast()?, false);
387    /// #
388    /// #    Ok(())
389    /// # }
390    /// ```
391    pub fn broadcast(&self) -> io::Result<bool> {
392        self.inner.broadcast()
393    }
394
395    /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket.
396    ///
397    /// If enabled, multicast packets will be looped back to the local socket.
398    /// Note that this may not have any affect on IPv6 sockets.
399    pub fn set_multicast_loop_v4(&self, on: bool) -> io::Result<()> {
400        self.inner.set_multicast_loop_v4(on)
401    }
402
403    /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket.
404    ///
405    /// For more information about this option, see
406    /// [`set_multicast_loop_v4`][link].
407    ///
408    /// [link]: #method.set_multicast_loop_v4
409    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
410        self.inner.multicast_loop_v4()
411    }
412
413    /// Sets the value of the `IP_MULTICAST_TTL` option for this socket.
414    ///
415    /// Indicates the time-to-live value of outgoing multicast packets for
416    /// this socket. The default value is 1 which means that multicast packets
417    /// don't leave the local network unless explicitly requested.
418    ///
419    /// Note that this may not have any affect on IPv6 sockets.
420    pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
421        self.inner.set_multicast_ttl_v4(ttl)
422    }
423
424    /// Gets the value of the `IP_MULTICAST_TTL` option for this socket.
425    ///
426    /// For more information about this option, see
427    /// [`set_multicast_ttl_v4`][link].
428    ///
429    /// [link]: #method.set_multicast_ttl_v4
430    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
431        self.inner.multicast_ttl_v4()
432    }
433
434    /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket.
435    ///
436    /// Controls whether this socket sees the multicast packets it sends itself.
437    /// Note that this may not have any affect on IPv4 sockets.
438    pub fn set_multicast_loop_v6(&self, on: bool) -> io::Result<()> {
439        self.inner.set_multicast_loop_v6(on)
440    }
441
442    /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket.
443    ///
444    /// For more information about this option, see
445    /// [`set_multicast_loop_v6`][link].
446    ///
447    /// [link]: #method.set_multicast_loop_v6
448    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
449        self.inner.multicast_loop_v6()
450    }
451
452    /// Sets the value for the `IP_TTL` option on this socket.
453    ///
454    /// This value sets the time-to-live field that is used in every packet sent
455    /// from this socket.
456    ///
457    /// # Examples
458    ///
459    #[cfg_attr(feature = "os-poll", doc = "```")]
460    #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
461    /// # use std::error::Error;
462    /// #
463    /// # fn main() -> Result<(), Box<dyn Error>> {
464    /// use mio::net::UdpSocket;
465    ///
466    /// let socket = UdpSocket::bind("127.0.0.1:0".parse()?)?;
467    /// if socket.ttl()? < 255 {
468    ///     socket.set_ttl(255)?;
469    /// }
470    ///
471    /// assert_eq!(socket.ttl()?, 255);
472    /// #
473    /// #    Ok(())
474    /// # }
475    /// ```
476    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
477        self.inner.set_ttl(ttl)
478    }
479
480    /// Gets the value of the `IP_TTL` option for this socket.
481    ///
482    /// For more information about this option, see [`set_ttl`][link].
483    ///
484    /// [link]: #method.set_ttl
485    ///
486    /// # Examples
487    ///
488    #[cfg_attr(feature = "os-poll", doc = "```")]
489    #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")]
490    /// # use std::error::Error;
491    /// #
492    /// # fn main() -> Result<(), Box<dyn Error>> {
493    /// use mio::net::UdpSocket;
494    ///
495    /// let socket = UdpSocket::bind("127.0.0.1:0".parse()?)?;
496    /// socket.set_ttl(255)?;
497    ///
498    /// assert_eq!(socket.ttl()?, 255);
499    /// #
500    /// #    Ok(())
501    /// # }
502    /// ```
503    pub fn ttl(&self) -> io::Result<u32> {
504        self.inner.ttl()
505    }
506
507    /// Executes an operation of the `IP_ADD_MEMBERSHIP` type.
508    ///
509    /// This function specifies a new multicast group for this socket to join.
510    /// The address must be a valid multicast address, and `interface` is the
511    /// address of the local interface with which the system should join the
512    /// multicast group. If it's equal to `INADDR_ANY` then an appropriate
513    /// interface is chosen by the system.
514    #[allow(clippy::trivially_copy_pass_by_ref)]
515    pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
516        self.inner.join_multicast_v4(multiaddr, interface)
517    }
518
519    /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type.
520    ///
521    /// This function specifies a new multicast group for this socket to join.
522    /// The address must be a valid multicast address, and `interface` is the
523    /// index of the interface to join/leave (or 0 to indicate any interface).
524    #[allow(clippy::trivially_copy_pass_by_ref)]
525    pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
526        self.inner.join_multicast_v6(multiaddr, interface)
527    }
528
529    /// Executes an operation of the `IP_DROP_MEMBERSHIP` type.
530    ///
531    /// For more information about this option, see
532    /// [`join_multicast_v4`][link].
533    ///
534    /// [link]: #method.join_multicast_v4
535    #[allow(clippy::trivially_copy_pass_by_ref)]
536    pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
537        self.inner.leave_multicast_v4(multiaddr, interface)
538    }
539
540    /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type.
541    ///
542    /// For more information about this option, see
543    /// [`join_multicast_v6`][link].
544    ///
545    /// [link]: #method.join_multicast_v6
546    #[allow(clippy::trivially_copy_pass_by_ref)]
547    pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
548        self.inner.leave_multicast_v6(multiaddr, interface)
549    }
550
551    /// Get the value of the `IPV6_V6ONLY` option on this socket.
552    #[allow(clippy::trivially_copy_pass_by_ref)]
553    pub fn only_v6(&self) -> io::Result<bool> {
554        sys::udp::only_v6(&self.inner)
555    }
556
557    /// Get the value of the `SO_ERROR` option on this socket.
558    ///
559    /// This will retrieve the stored error in the underlying socket, clearing
560    /// the field in the process. This can be useful for checking errors between
561    /// calls.
562    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
563        self.inner.take_error()
564    }
565
566    /// Execute an I/O operation ensuring that the socket receives more events
567    /// if it hits a [`WouldBlock`] error.
568    ///
569    /// # Notes
570    ///
571    /// This method is required to be called for **all** I/O operations to
572    /// ensure the user will receive events once the socket is ready again after
573    /// returning a [`WouldBlock`] error.
574    ///
575    /// [`WouldBlock`]: io::ErrorKind::WouldBlock
576    ///
577    /// # Examples
578    ///
579    #[cfg_attr(unix, doc = "```no_run")]
580    #[cfg_attr(windows, doc = "```ignore")]
581    /// # use std::error::Error;
582    /// #
583    /// # fn main() -> Result<(), Box<dyn Error>> {
584    /// use std::io;
585    /// #[cfg(any(unix, target_os = "wasi"))]
586    /// use std::os::fd::AsRawFd;
587    /// #[cfg(windows)]
588    /// use std::os::windows::io::AsRawSocket;
589    /// use mio::net::UdpSocket;
590    ///
591    /// let address = "127.0.0.1:8080".parse().unwrap();
592    /// let dgram = UdpSocket::bind(address)?;
593    ///
594    /// // Wait until the dgram is readable...
595    ///
596    /// // Read from the dgram using a direct libc call, of course the
597    /// // `io::Read` implementation would be easier to use.
598    /// let mut buf = [0; 512];
599    /// let n = dgram.try_io(|| {
600    ///     let buf_ptr = &mut buf as *mut _ as *mut _;
601    ///     #[cfg(unix)]
602    ///     let res = unsafe { libc::recv(dgram.as_raw_fd(), buf_ptr, buf.len(), 0) };
603    ///     #[cfg(windows)]
604    ///     let res = unsafe { libc::recvfrom(dgram.as_raw_socket() as usize, buf_ptr, buf.len() as i32, 0, std::ptr::null_mut(), std::ptr::null_mut()) };
605    ///     if res != -1 {
606    ///         Ok(res as usize)
607    ///     } else {
608    ///         // If EAGAIN or EWOULDBLOCK is set by libc::recv, the closure
609    ///         // should return `WouldBlock` error.
610    ///         Err(io::Error::last_os_error())
611    ///     }
612    /// })?;
613    /// eprintln!("read {} bytes", n);
614    /// # Ok(())
615    /// # }
616    /// ```
617    pub fn try_io<F, T>(&self, f: F) -> io::Result<T>
618    where
619        F: FnOnce() -> io::Result<T>,
620    {
621        self.inner.do_io(|_| f())
622    }
623}
624
625impl event::Source for UdpSocket {
626    fn register(
627        &mut self,
628        registry: &Registry,
629        token: Token,
630        interests: Interest,
631    ) -> io::Result<()> {
632        self.inner.register(registry, token, interests)
633    }
634
635    fn reregister(
636        &mut self,
637        registry: &Registry,
638        token: Token,
639        interests: Interest,
640    ) -> io::Result<()> {
641        self.inner.reregister(registry, token, interests)
642    }
643
644    fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
645        self.inner.deregister(registry)
646    }
647}
648
649impl fmt::Debug for UdpSocket {
650    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
651        self.inner.fmt(f)
652    }
653}
654
655#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
656impl IntoRawFd for UdpSocket {
657    fn into_raw_fd(self) -> RawFd {
658        self.inner.into_inner().into_raw_fd()
659    }
660}
661
662#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
663impl AsRawFd for UdpSocket {
664    fn as_raw_fd(&self) -> RawFd {
665        self.inner.as_raw_fd()
666    }
667}
668
669#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
670impl FromRawFd for UdpSocket {
671    /// Converts a `RawFd` to a `UdpSocket`.
672    ///
673    /// # Notes
674    ///
675    /// The caller is responsible for ensuring that the socket is in
676    /// non-blocking mode.
677    unsafe fn from_raw_fd(fd: RawFd) -> UdpSocket {
678        UdpSocket::from_std(FromRawFd::from_raw_fd(fd))
679    }
680}
681
682#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
683impl From<UdpSocket> for OwnedFd {
684    fn from(udp_socket: UdpSocket) -> Self {
685        udp_socket.inner.into_inner().into()
686    }
687}
688
689#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
690impl AsFd for UdpSocket {
691    fn as_fd(&self) -> BorrowedFd<'_> {
692        self.inner.as_fd()
693    }
694}
695
696#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
697impl From<OwnedFd> for UdpSocket {
698    /// Converts a `RawFd` to a `UdpSocket`.
699    ///
700    /// # Notes
701    ///
702    /// The caller is responsible for ensuring that the socket is in
703    /// non-blocking mode.
704    fn from(fd: OwnedFd) -> Self {
705        UdpSocket::from_std(From::from(fd))
706    }
707}
708
709#[cfg(windows)]
710impl IntoRawSocket for UdpSocket {
711    fn into_raw_socket(self) -> RawSocket {
712        self.inner.into_inner().into_raw_socket()
713    }
714}
715
716#[cfg(windows)]
717impl AsRawSocket for UdpSocket {
718    fn as_raw_socket(&self) -> RawSocket {
719        self.inner.as_raw_socket()
720    }
721}
722
723#[cfg(windows)]
724impl FromRawSocket for UdpSocket {
725    /// Converts a `RawSocket` to a `UdpSocket`.
726    ///
727    /// # Notes
728    ///
729    /// The caller is responsible for ensuring that the socket is in
730    /// non-blocking mode.
731    unsafe fn from_raw_socket(socket: RawSocket) -> UdpSocket {
732        UdpSocket::from_std(FromRawSocket::from_raw_socket(socket))
733    }
734}
735
736#[cfg(windows)]
737impl From<UdpSocket> for OwnedSocket {
738    fn from(udp_socket: UdpSocket) -> Self {
739        udp_socket.inner.into_inner().into()
740    }
741}
742
743#[cfg(windows)]
744impl AsSocket for UdpSocket {
745    fn as_socket(&self) -> BorrowedSocket<'_> {
746        self.inner.as_socket()
747    }
748}
749
750#[cfg(windows)]
751impl From<OwnedSocket> for UdpSocket {
752    /// Converts a `RawSocket` to a `UdpSocket`.
753    ///
754    /// # Notes
755    ///
756    /// The caller is responsible for ensuring that the socket is in
757    /// non-blocking mode.
758    fn from(socket: OwnedSocket) -> Self {
759        UdpSocket::from_std(From::from(socket))
760    }
761}
762
763impl From<UdpSocket> for net::UdpSocket {
764    fn from(socket: UdpSocket) -> Self {
765        // Safety: This is safe since we are extracting the raw fd from a well-constructed
766        // mio::net::UdpSocket which ensures that we actually pass in a valid file
767        // descriptor/socket
768        unsafe {
769            #[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
770            {
771                net::UdpSocket::from_raw_fd(socket.into_raw_fd())
772            }
773            #[cfg(windows)]
774            {
775                net::UdpSocket::from_raw_socket(socket.into_raw_socket())
776            }
777        }
778    }
779}