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