async_net_mini/
udp.rs

1use std::io;
2use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
3#[cfg(unix)]
4use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, OwnedFd, RawFd};
5#[cfg(windows)]
6use std::os::windows::io::{AsRawSocket, AsSocket, BorrowedSocket, OwnedSocket, RawSocket};
7use std::sync::Arc;
8
9use async_io_mini::Async;
10
11/// A UDP socket.
12///
13/// After creating a [`UdpSocket`] by [`bind`][`UdpSocket::bind()`]ing it to a socket address, data
14/// can be [sent to] and [received from] any other socket address.
15///
16/// Cloning a [`UdpSocket`] creates another handle to the same socket. The socket will be closed
17/// when all handles to it are dropped.
18///
19/// Although UDP is a connectionless protocol, this implementation provides an interface to set an
20/// address where data should be sent and received from. After setting a remote address with
21/// [`connect()`][`UdpSocket::connect()`], data can be sent to and received from that address with
22/// [`send()`][`UdpSocket::send()`] and [`recv()`][`UdpSocket::recv()`].
23///
24/// As stated in the User Datagram Protocol's specification in [IETF RFC 768], UDP is an unordered,
25/// unreliable protocol. Refer to [`TcpListener`][`super::TcpListener`] and
26/// [`TcpStream`][`super::TcpStream`] for TCP primitives.
27///
28/// [received from]: UdpSocket::recv_from()
29/// [sent to]: UdpSocket::send_to()
30/// [IETF RFC 768]: https://tools.ietf.org/html/rfc768
31///
32/// # Examples
33///
34/// ```no_run
35/// use async_net::UdpSocket;
36///
37/// # futures_lite::future::block_on(async {
38/// let socket = UdpSocket::bind("127.0.0.1:8080").await?;
39/// let mut buf = vec![0u8; 20];
40///
41/// loop {
42///     // Receive a single datagram message.
43///     // If `buf` is too small to hold the entire message, it will be cut off.
44///     let (n, addr) = socket.recv_from(&mut buf).await?;
45///
46///     // Send the message back to the same address that has sent it.
47///     socket.send_to(&buf[..n], &addr).await?;
48/// }
49/// # std::io::Result::Ok(()) });
50/// ```
51#[derive(Clone, Debug)]
52pub struct UdpSocket {
53    inner: Arc<Async<std::net::UdpSocket>>,
54}
55
56impl UdpSocket {
57    fn new(inner: Arc<Async<std::net::UdpSocket>>) -> UdpSocket {
58        UdpSocket { inner }
59    }
60
61    /// Creates a new [`UdpSocket`] bound to the given address.
62    ///
63    /// Binding with a port number of 0 will request that the operating system assigns an available
64    /// port to this socket. The assigned port can be queried via the
65    /// [`local_addr()`][`UdpSocket::local_addr()`] method.
66    ///
67    /// If `addr` yields multiple addresses, binding will be attempted with each of the addresses
68    /// until one succeeds and returns the socket. If none of the addresses succeed in creating a
69    /// socket, the error from the last attempt is returned.
70    ///
71    /// # Examples
72    ///
73    /// Create a UDP socket bound to `127.0.0.1:3400`:
74    ///
75    /// ```no_run
76    /// use async_net::UdpSocket;
77    ///
78    /// # futures_lite::future::block_on(async {
79    /// let socket = UdpSocket::bind("127.0.0.1:3400").await?;
80    /// # std::io::Result::Ok(()) });
81    /// ```
82    ///
83    /// Create a UDP socket bound to `127.0.0.1:3400`. If that address is unavailable, then try
84    /// binding to `127.0.0.1:3401`:
85    ///
86    /// ```no_run
87    /// use async_net::{SocketAddr, UdpSocket};
88    ///
89    /// # futures_lite::future::block_on(async {
90    /// let addrs = [
91    ///     SocketAddr::from(([127, 0, 0, 1], 3400)),
92    ///     SocketAddr::from(([127, 0, 0, 1], 3401)),
93    /// ];
94    /// let socket = UdpSocket::bind(&addrs[..]).await?;
95    /// # std::io::Result::Ok(()) });
96    /// ```
97    pub async fn bind(addr: SocketAddr) -> io::Result<UdpSocket> {
98        Ok(UdpSocket::new(Arc::new(
99            Async::<std::net::UdpSocket>::bind(addr)?,
100        )))
101    }
102
103    /// Returns the local address this socket is bound to.
104    ///
105    /// This can be useful, for example, when binding to port 0 to figure out which port was
106    /// actually bound.
107    ///
108    /// # Examples
109    ///
110    /// Bind to port 0 and then see which port was assigned by the operating system:
111    ///
112    /// ```no_run
113    /// use async_net::{SocketAddr, UdpSocket};
114    ///
115    /// # futures_lite::future::block_on(async {
116    /// let socket = UdpSocket::bind("127.0.0.1:0").await?;
117    /// println!("Bound to {}", socket.local_addr()?);
118    /// # std::io::Result::Ok(()) });
119    /// ```
120    pub fn local_addr(&self) -> io::Result<SocketAddr> {
121        self.inner.get_ref().local_addr()
122    }
123
124    /// Returns the remote address this socket is connected to.
125    ///
126    /// # Examples
127    ///
128    /// ```no_run
129    /// use async_net::UdpSocket;
130    ///
131    /// # futures_lite::future::block_on(async {
132    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
133    /// socket.connect("192.168.0.1:41203").await?;
134    /// println!("Connected to {}", socket.peer_addr()?);
135    /// # std::io::Result::Ok(()) });
136    /// ```
137    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
138        self.inner.get_ref().peer_addr()
139    }
140
141    /// Connects the UDP socket to an address.
142    ///
143    /// When connected, methods [`send()`][`UdpSocket::send()`] and [`recv()`][`UdpSocket::recv()`]
144    /// will use the specified address for sending and receiving messages. Additionally, a filter
145    /// will be applied to [`recv_from()`][`UdpSocket::recv_from()`] so that it only receives
146    /// messages from that same address.
147    ///
148    /// If `addr` yields multiple addresses, connecting will be attempted with each of the
149    /// addresses until the operating system accepts one. If none of the addresses are accepted,
150    /// the error from the last attempt is returned.
151    ///
152    /// # Examples
153    ///
154    /// ```no_run
155    /// use async_net::UdpSocket;
156    ///
157    /// # futures_lite::future::block_on(async {
158    /// let socket = UdpSocket::bind("127.0.0.1:3400").await?;
159    /// socket.connect("127.0.0.1:8080").await?;
160    /// # std::io::Result::Ok(()) });
161    /// ```
162    pub async fn connect(&self, addr: SocketAddr) -> io::Result<()> {
163        self.inner.get_ref().connect(addr)
164    }
165
166    /// Receives a single datagram message.
167    ///
168    /// On success, returns the number of bytes received and the address message came from.
169    ///
170    /// This method must be called with a valid byte buffer of sufficient size to hold a message.
171    /// If the received message is too long to fit into the buffer, it may be truncated.
172    ///
173    /// # Examples
174    ///
175    /// ```no_run
176    /// use async_net::UdpSocket;
177    ///
178    /// # futures_lite::future::block_on(async {
179    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
180    ///
181    /// let mut buf = vec![0u8; 1024];
182    /// let (n, addr) = socket.recv_from(&mut buf).await?;
183    /// println!("Received {} bytes from {}", n, addr);
184    /// # std::io::Result::Ok(()) });
185    /// ```
186    pub async fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
187        self.inner.recv_from(buf).await
188    }
189
190    /// Receives a single datagram message without removing it from the queue.
191    ///
192    /// On success, returns the number of bytes peeked and the address message came from.
193    ///
194    /// This method must be called with a valid byte buffer of sufficient size to hold a message.
195    /// If the received message is too long to fit into the buffer, it may be truncated.
196    ///
197    /// Successive calls return the same message. This is accomplished by passing `MSG_PEEK` as a
198    /// flag to the underlying `recvfrom` system call.
199    ///
200    /// # Examples
201    ///
202    /// ```no_run
203    /// use async_net::UdpSocket;
204    ///
205    /// # futures_lite::future::block_on(async {
206    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
207    ///
208    /// let mut buf = vec![0u8; 1024];
209    /// let (n, addr) = socket.peek_from(&mut buf).await?;
210    /// println!("Peeked {} bytes from {}", n, addr);
211    /// # std::io::Result::Ok(()) });
212    /// ```
213    pub async fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
214        self.inner.get_ref().peek_from(buf)
215    }
216
217    /// Sends data to the given address.
218    ///
219    /// On success, returns the number of bytes sent.
220    ///
221    /// If `addr` yields multiple addresses, the message will only be sent to the first address.
222    ///
223    /// # Examples
224    ///
225    /// ```no_run
226    /// use async_net::UdpSocket;
227    ///
228    /// # futures_lite::future::block_on(async {
229    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
230    /// socket.send_to(b"hello", "127.0.0.1:4242").await?;
231    /// # std::io::Result::Ok(()) });
232    /// ```
233    pub async fn send_to(&self, buf: &[u8], addr: SocketAddr) -> io::Result<usize> {
234        self.inner.send_to(buf, addr).await
235    }
236
237    /// Receives a single datagram message from the connected address.
238    ///
239    /// On success, returns the number of bytes received.
240    ///
241    /// This method must be called with a valid byte buffer of sufficient size to hold a message.
242    /// If the received message is too long to fit into the buffer, it may be truncated.
243    ///
244    /// The [`connect()`][`UdpSocket::connect()`] method connects this socket to an address. This
245    /// method will fail if the socket is not connected.
246    ///
247    /// # Examples
248    ///
249    /// ```no_run
250    /// use async_net::UdpSocket;
251    ///
252    /// # futures_lite::future::block_on(async {
253    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
254    /// socket.connect("127.0.0.1:8080").await?;
255    ///
256    /// let mut buf = vec![0u8; 1024];
257    /// let n = socket.recv(&mut buf).await?;
258    /// println!("Received {} bytes", n);
259    /// # std::io::Result::Ok(()) });
260    /// ```
261    pub async fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
262        self.inner.recv(buf).await
263    }
264
265    /// Receives a single datagram from the connected address without removing it from the queue.
266    ///
267    /// On success, returns the number of bytes peeked.
268    ///
269    /// This method must be called with a valid byte buffer of sufficient size to hold a message.
270    /// If the received message is too long to fit into the buffer, it may be truncated.
271    ///
272    /// Successive calls return the same message. This is accomplished by passing `MSG_PEEK` as a
273    /// flag to the underlying `recv` system call.
274    ///
275    /// The [`connect()`][`UdpSocket::connect()`] method connects this socket to an address. This
276    /// method will fail if the socket is not connected.
277    ///
278    /// # Examples
279    ///
280    /// ```no_run
281    /// use async_net::UdpSocket;
282    ///
283    /// # futures_lite::future::block_on(async {
284    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
285    /// socket.connect("127.0.0.1:8080").await?;
286    ///
287    /// let mut buf = vec![0u8; 1024];
288    /// let n = socket.peek(&mut buf).await?;
289    /// println!("Peeked {} bytes", n);
290    /// # std::io::Result::Ok(()) });
291    /// ```
292    pub async fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
293        self.inner.peek(buf).await
294    }
295
296    /// Sends data to the connected address.
297    ///
298    /// The [`connect()`][`UdpSocket::connect()`] method connects this socket to an address. This
299    /// method will fail if the socket is not connected.
300    ///
301    /// # Examples
302    ///
303    /// ```no_run
304    /// use async_net::UdpSocket;
305    ///
306    /// # futures_lite::future::block_on(async {
307    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
308    /// socket.connect("127.0.0.1:8080").await?;
309    /// socket.send(b"hello").await?;
310    /// # std::io::Result::Ok(()) });
311    /// ```
312    pub async fn send(&self, buf: &[u8]) -> io::Result<usize> {
313        self.inner.send(buf).await
314    }
315
316    /// Gets the value of the `SO_BROADCAST` option for this socket.
317    ///
318    /// If set to `true`, this socket is allowed to send packets to a broadcast address.
319    ///
320    /// # Examples
321    ///
322    /// ```no_run
323    /// use async_net::UdpSocket;
324    ///
325    /// # futures_lite::future::block_on(async {
326    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
327    /// println!("SO_BROADCAST is set to {}", socket.broadcast()?);
328    /// # std::io::Result::Ok(()) });
329    /// ```
330    pub fn broadcast(&self) -> io::Result<bool> {
331        self.inner.get_ref().broadcast()
332    }
333
334    /// Sets the value of the `SO_BROADCAST` option for this socket.
335    ///
336    /// If set to `true`, this socket is allowed to send packets to a broadcast address.
337    ///
338    /// # Examples
339    ///
340    /// ```no_run
341    /// use async_net::UdpSocket;
342    ///
343    /// # futures_lite::future::block_on(async {
344    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
345    /// socket.set_broadcast(true)?;
346    /// # std::io::Result::Ok(()) });
347    /// ```
348    pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
349        self.inner.get_ref().set_broadcast(broadcast)
350    }
351
352    /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket.
353    ///
354    /// If set to `true`, multicast packets will be looped back to the local socket.
355    ///
356    /// Note that this option may not have any affect on IPv6 sockets.
357    ///
358    /// # Examples
359    ///
360    /// ```no_run
361    /// use async_net::UdpSocket;
362    ///
363    /// # futures_lite::future::block_on(async {
364    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
365    /// println!("IP_MULTICAST_LOOP is set to {}", socket.multicast_loop_v4()?);
366    /// # std::io::Result::Ok(()) });
367    /// ```
368    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
369        self.inner.get_ref().multicast_loop_v4()
370    }
371
372    /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket.
373    ///
374    /// If set to `true`, multicast packets will be looped back to the local socket.
375    ///
376    /// Note that this option may not have any affect on IPv6 sockets.
377    ///
378    /// # Examples
379    ///
380    /// ```no_run
381    /// use async_net::UdpSocket;
382    ///
383    /// # futures_lite::future::block_on(async {
384    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
385    /// socket.set_multicast_loop_v4(true)?;
386    /// # std::io::Result::Ok(()) });
387    /// ```
388    pub fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> {
389        self.inner
390            .get_ref()
391            .set_multicast_loop_v4(multicast_loop_v4)
392    }
393
394    /// Gets the value of the `IP_MULTICAST_TTL` option for this socket.
395    ///
396    /// Indicates the time-to-live value of outgoing multicast packets for this socket. The default
397    /// value is 1, which means that multicast packets don't leave the local network unless
398    /// explicitly requested.
399    ///
400    /// Note that this option may not have any effect on IPv6 sockets.
401    ///
402    /// # Examples
403    ///
404    /// ```no_run
405    /// use async_net::UdpSocket;
406    ///
407    /// # futures_lite::future::block_on(async {
408    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
409    /// println!("IP_MULTICAST_TTL is set to {}", socket.multicast_loop_v4()?);
410    /// # std::io::Result::Ok(()) });
411    /// ```
412    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
413        self.inner.get_ref().multicast_ttl_v4()
414    }
415
416    /// Sets the value of the `IP_MULTICAST_TTL` option for this socket.
417    ///
418    /// Indicates the time-to-live value of outgoing multicast packets for this socket. The default
419    /// value is 1, which means that multicast packets don't leave the local network unless
420    /// explicitly requested.
421    ///
422    /// Note that this option may not have any effect on IPv6 sockets.
423    ///
424    /// # Examples
425    ///
426    /// ```no_run
427    /// use async_net::UdpSocket;
428    ///
429    /// # futures_lite::future::block_on(async {
430    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
431    /// socket.set_multicast_ttl_v4(10)?;
432    /// # std::io::Result::Ok(()) });
433    /// ```
434    pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
435        self.inner.get_ref().set_multicast_ttl_v4(ttl)
436    }
437
438    /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket.
439    ///
440    /// Controls whether this socket sees the multicast packets it sends itself.
441    ///
442    /// Note that this option may not have any effect on IPv4 sockets.
443    ///
444    /// # Examples
445    ///
446    /// ```no_run
447    /// use async_net::UdpSocket;
448    ///
449    /// # futures_lite::future::block_on(async {
450    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
451    /// println!("IPV6_MULTICAST_LOOP is set to {}", socket.multicast_loop_v6()?);
452    /// # std::io::Result::Ok(()) });
453    /// ```
454    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
455        self.inner.get_ref().multicast_loop_v6()
456    }
457
458    /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket.
459    ///
460    /// Controls whether this socket sees the multicast packets it sends itself.
461    ///
462    /// Note that this option may not have any effect on IPv4 sockets.
463    ///
464    /// # Examples
465    ///
466    /// ```no_run
467    /// use async_net::UdpSocket;
468    ///
469    /// # futures_lite::future::block_on(async {
470    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
471    /// socket.set_multicast_loop_v6(true)?;
472    /// # std::io::Result::Ok(()) });
473    /// ```
474    pub fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> {
475        self.inner
476            .get_ref()
477            .set_multicast_loop_v6(multicast_loop_v6)
478    }
479
480    /// Gets the value of the `IP_TTL` option for this socket.
481    ///
482    /// This option configures the time-to-live field that is used in every packet sent from this
483    /// socket.
484    ///
485    /// # Examples
486    ///
487    /// ```no_run
488    /// use async_net::UdpSocket;
489    ///
490    /// # futures_lite::future::block_on(async {
491    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
492    /// println!("IP_TTL is set to {}", socket.ttl()?);
493    /// # std::io::Result::Ok(()) });
494    /// ```
495    pub fn ttl(&self) -> io::Result<u32> {
496        self.inner.get_ref().ttl()
497    }
498
499    /// Sets the value of the `IP_TTL` option for this socket.
500    ///
501    /// This option configures the time-to-live field that is used in every packet sent from this
502    /// socket.
503    ///
504    /// # Examples
505    ///
506    /// ```no_run
507    /// use async_net::UdpSocket;
508    ///
509    /// # futures_lite::future::block_on(async {
510    /// let socket = UdpSocket::bind("127.0.0.1:34254").await?;
511    /// socket.set_ttl(100)?;
512    /// # std::io::Result::Ok(()) });
513    /// ```
514    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
515        self.inner.get_ref().set_ttl(ttl)
516    }
517
518    /// Executes an operation of the `IP_ADD_MEMBERSHIP` type.
519    ///
520    /// This method specifies a new multicast group for this socket to join. Argument `multiaddr`
521    /// must be a valid multicast address, and `interface` is the address of the local interface
522    /// with which the system should join the multicast group. If it's equal to `INADDR_ANY` then
523    /// an appropriate interface is chosen by the system.
524    pub fn join_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> {
525        self.inner
526            .get_ref()
527            .join_multicast_v4(&multiaddr, &interface)
528    }
529
530    /// Executes an operation of the `IP_DROP_MEMBERSHIP` type.
531    ///
532    /// This method leaves a multicast group. Argument `multiaddr` must be a valid multicast
533    /// address, and `interface` is the index of the interface to leave.
534    pub fn leave_multicast_v4(&self, multiaddr: Ipv4Addr, interface: Ipv4Addr) -> io::Result<()> {
535        self.inner
536            .get_ref()
537            .leave_multicast_v4(&multiaddr, &interface)
538    }
539
540    /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type.
541    ///
542    /// This method specifies a new multicast group for this socket to join. Argument `multiaddr`
543    /// must be a valid multicast address, and `interface` is the index of the interface to join
544    /// (or 0 to indicate any interface).
545    pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
546        self.inner.get_ref().join_multicast_v6(multiaddr, interface)
547    }
548
549    /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type.
550    ///
551    /// This method leaves a multicast group. Argument `multiaddr` must be a valid multicast
552    /// address, and `interface` is the index of the interface to leave.
553    pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
554        self.inner
555            .get_ref()
556            .leave_multicast_v6(multiaddr, interface)
557    }
558}
559
560impl From<Async<std::net::UdpSocket>> for UdpSocket {
561    fn from(socket: Async<std::net::UdpSocket>) -> UdpSocket {
562        UdpSocket::new(Arc::new(socket))
563    }
564}
565
566impl TryFrom<std::net::UdpSocket> for UdpSocket {
567    type Error = io::Error;
568
569    fn try_from(socket: std::net::UdpSocket) -> io::Result<UdpSocket> {
570        Ok(UdpSocket::new(Arc::new(Async::new(socket)?)))
571    }
572}
573
574impl From<UdpSocket> for Arc<Async<std::net::UdpSocket>> {
575    fn from(val: UdpSocket) -> Self {
576        val.inner
577    }
578}
579
580#[cfg(unix)]
581impl AsRawFd for UdpSocket {
582    fn as_raw_fd(&self) -> RawFd {
583        self.inner.as_raw_fd()
584    }
585}
586
587#[cfg(unix)]
588impl AsFd for UdpSocket {
589    fn as_fd(&self) -> BorrowedFd<'_> {
590        self.inner.get_ref().as_fd()
591    }
592}
593
594#[cfg(unix)]
595impl TryFrom<OwnedFd> for UdpSocket {
596    type Error = io::Error;
597
598    fn try_from(value: OwnedFd) -> Result<Self, Self::Error> {
599        Self::try_from(std::net::UdpSocket::from(value))
600    }
601}
602
603#[cfg(windows)]
604impl AsRawSocket for UdpSocket {
605    fn as_raw_socket(&self) -> RawSocket {
606        self.inner.as_raw_socket()
607    }
608}
609
610#[cfg(windows)]
611impl AsSocket for UdpSocket {
612    fn as_socket(&self) -> BorrowedSocket<'_> {
613        self.inner.get_ref().as_socket()
614    }
615}
616
617#[cfg(windows)]
618impl TryFrom<OwnedSocket> for UdpSocket {
619    type Error = io::Error;
620
621    fn try_from(value: OwnedSocket) -> Result<Self, Self::Error> {
622        Self::try_from(std::net::UdpSocket::from(value))
623    }
624}