Skip to content

Commit acd6627

Browse files
authored
net: add UdpSocket::peek methods (#7068)
1 parent 2353806 commit acd6627

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

tokio/src/net/udp.rs

+142
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,148 @@ impl UdpSocket {
15031503
.await
15041504
}
15051505

1506+
/// Receives a single datagram from the connected address without removing it from the queue.
1507+
/// On success, returns the number of bytes read from whence the data came.
1508+
///
1509+
/// # Notes
1510+
///
1511+
/// On Windows, if the data is larger than the buffer specified, the buffer
1512+
/// is filled with the first part of the data, and `peek_from` returns the error
1513+
/// `WSAEMSGSIZE(10040)`. The excess data is lost.
1514+
/// Make sure to always use a sufficiently large buffer to hold the
1515+
/// maximum UDP packet size, which can be up to 65536 bytes in size.
1516+
///
1517+
/// MacOS will return an error if you pass a zero-sized buffer.
1518+
///
1519+
/// If you're merely interested in learning the sender of the data at the head of the queue,
1520+
/// try [`peek_sender`].
1521+
///
1522+
/// Note that the socket address **cannot** be implicitly trusted, because it is relatively
1523+
/// trivial to send a UDP datagram with a spoofed origin in a [packet injection attack].
1524+
/// Because UDP is stateless and does not validate the origin of a packet,
1525+
/// the attacker does not need to be able to intercept traffic in order to interfere.
1526+
/// It is important to be aware of this when designing your application-level protocol.
1527+
///
1528+
/// # Examples
1529+
///
1530+
/// ```no_run
1531+
/// use tokio::net::UdpSocket;
1532+
/// use std::io;
1533+
///
1534+
/// #[tokio::main]
1535+
/// async fn main() -> io::Result<()> {
1536+
/// let socket = UdpSocket::bind("127.0.0.1:8080").await?;
1537+
///
1538+
/// let mut buf = vec![0u8; 32];
1539+
/// let len = socket.peek(&mut buf).await?;
1540+
///
1541+
/// println!("peeked {:?} bytes", len);
1542+
///
1543+
/// Ok(())
1544+
/// }
1545+
/// ```
1546+
///
1547+
/// [`peek_sender`]: method@Self::peek_sender
1548+
/// [packet injection attack]: https://en.wikipedia.org/wiki/Packet_injection
1549+
pub async fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
1550+
self.io
1551+
.registration()
1552+
.async_io(Interest::READABLE, || self.io.peek(buf))
1553+
.await
1554+
}
1555+
1556+
/// Receives data from the connected address, without removing it from the input queue.
1557+
/// On success, returns the sending address of the datagram.
1558+
///
1559+
/// # Notes
1560+
///
1561+
/// Note that on multiple calls to a `poll_*` method in the `recv` direction, only the
1562+
/// `Waker` from the `Context` passed to the most recent call will be scheduled to
1563+
/// receive a wakeup
1564+
///
1565+
/// On Windows, if the data is larger than the buffer specified, the buffer
1566+
/// is filled with the first part of the data, and peek returns the error
1567+
/// `WSAEMSGSIZE(10040)`. The excess data is lost.
1568+
/// Make sure to always use a sufficiently large buffer to hold the
1569+
/// maximum UDP packet size, which can be up to 65536 bytes in size.
1570+
///
1571+
/// MacOS will return an error if you pass a zero-sized buffer.
1572+
///
1573+
/// If you're merely interested in learning the sender of the data at the head of the queue,
1574+
/// try [`poll_peek_sender`].
1575+
///
1576+
/// Note that the socket address **cannot** be implicitly trusted, because it is relatively
1577+
/// trivial to send a UDP datagram with a spoofed origin in a [packet injection attack].
1578+
/// Because UDP is stateless and does not validate the origin of a packet,
1579+
/// the attacker does not need to be able to intercept traffic in order to interfere.
1580+
/// It is important to be aware of this when designing your application-level protocol.
1581+
///
1582+
/// # Return value
1583+
///
1584+
/// The function returns:
1585+
///
1586+
/// * `Poll::Pending` if the socket is not ready to read
1587+
/// * `Poll::Ready(Ok(()))` reads data into `ReadBuf` if the socket is ready
1588+
/// * `Poll::Ready(Err(e))` if an error is encountered.
1589+
///
1590+
/// # Errors
1591+
///
1592+
/// This function may encounter any standard I/O error except `WouldBlock`.
1593+
///
1594+
/// [`poll_peek_sender`]: method@Self::poll_peek_sender
1595+
/// [packet injection attack]: https://en.wikipedia.org/wiki/Packet_injection
1596+
pub fn poll_peek(&self, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
1597+
#[allow(clippy::blocks_in_conditions)]
1598+
let n = ready!(self.io.registration().poll_read_io(cx, || {
1599+
// Safety: will not read the maybe uninitialized bytes.
1600+
let b = unsafe {
1601+
&mut *(buf.unfilled_mut() as *mut [std::mem::MaybeUninit<u8>] as *mut [u8])
1602+
};
1603+
1604+
self.io.peek(b)
1605+
}))?;
1606+
1607+
// Safety: We trust `recv` to have filled up `n` bytes in the buffer.
1608+
unsafe {
1609+
buf.assume_init(n);
1610+
}
1611+
buf.advance(n);
1612+
Poll::Ready(Ok(()))
1613+
}
1614+
1615+
/// Tries to receive data on the connected address without removing it from the input queue.
1616+
/// On success, returns the number of bytes read.
1617+
///
1618+
/// When there is no pending data, `Err(io::ErrorKind::WouldBlock)` is
1619+
/// returned. This function is usually paired with `readable()`.
1620+
///
1621+
/// # Notes
1622+
///
1623+
/// On Windows, if the data is larger than the buffer specified, the buffer
1624+
/// is filled with the first part of the data, and peek returns the error
1625+
/// `WSAEMSGSIZE(10040)`. The excess data is lost.
1626+
/// Make sure to always use a sufficiently large buffer to hold the
1627+
/// maximum UDP packet size, which can be up to 65536 bytes in size.
1628+
///
1629+
/// MacOS will return an error if you pass a zero-sized buffer.
1630+
///
1631+
/// If you're merely interested in learning the sender of the data at the head of the queue,
1632+
/// try [`try_peek_sender`].
1633+
///
1634+
/// Note that the socket address **cannot** be implicitly trusted, because it is relatively
1635+
/// trivial to send a UDP datagram with a spoofed origin in a [packet injection attack].
1636+
/// Because UDP is stateless and does not validate the origin of a packet,
1637+
/// the attacker does not need to be able to intercept traffic in order to interfere.
1638+
/// It is important to be aware of this when designing your application-level protocol.
1639+
///
1640+
/// [`try_peek_sender`]: method@Self::try_peek_sender
1641+
/// [packet injection attack]: https://en.wikipedia.org/wiki/Packet_injection
1642+
pub fn try_peek(&self, buf: &mut [u8]) -> io::Result<usize> {
1643+
self.io
1644+
.registration()
1645+
.try_io(Interest::READABLE, || self.io.peek(buf))
1646+
}
1647+
15061648
/// Receives data from the socket, without removing it from the input queue.
15071649
/// On success, returns the number of bytes read and the address from whence
15081650
/// the data came.

0 commit comments

Comments
 (0)