-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: UdpSocket::peek_sender()
#5491
Comments
Is there a PR/proposal to add this to libstd? I think this could also be useful there. |
That would most likely require an RFC which I don't have the bandwidth to deal with. If someone else wants to do that or has an end-run around the RFC process, by all means. As far as I can tell, the API of I would be happy to open a PR to any of the non- |
Since Tokio does use |
The socket2 crate would certainly be the obvious place to start. |
I can open a PR to |
rust-lang/socket2#389 has been merged, not sure when 0.5 will be released though. |
socket2 0.5 has been released. |
@Darksonn @notgull I just noticed that using |
If possible, we would like to avoid doing an MSRV bump just for the sake of a dependency. |
Yeah, that just means backporting my addition to 0.4. |
I think that adding I/O safety (https://rust-lang.github.io/rfcs/3128-io-safety.html) trait implementations directly to Tokio would also be worth doing, which would also require a MSRV bump. It makes working with raw(-ish) fd much less error prone. |
We're currently looking into implementing the I/O safety traits conditionally using a build script to detect the Rust version. See #5514 for this, or the thread in #tokio-dev on discord. |
Opened #5520 contingent on |
Is your feature request related to a problem? Please describe.
For implementing a UDP-based gossip protocol, I would prefer not to require a separate connected socket per peer connection. While
recv_from()
andsend_to()
get me most of the way there, there's a piece of the puzzle missing.When handling a datagram on a bound socket, it can be important to know the sender of the next datagram in the queue without consuming it, e.g. to know if we even want to read the datagram into application memory or not, or to call up application state for that particular peer such as a DTLS session.
For DTLS specifically, the OpenSSL implementation provides its own read buffer per session, so we want to get the peer address of the datagram, call up the session, and then read the datagram into the DTLS read buffer, preferably without any redundant copies.
UdpSocket::peek_from()
is almost what we need, but the Windows-specific behavior is problematic: we're forced to provide a buffer large enough to read the whole datagram whether we actually want to yet or not, or else the sender information will be discarded due to theWSAEMSGSIZE
error.Describe the solution you'd like
I experimented with directly calling
recvfrom()
on Windows and found that it does populate thesockaddr
out-pointer even when it returnsWSAEMSGSIZE
, so I'd propose thatUdpSocket
gain a new method:For non-Windows platforms this can trivially be implemented in terms of
peek_from()
, but on Windows this should make a directrecvfrom()
call, passing a zero-size buffer, setting theMSG_PEEK
flag, and suppressing theWSAEMSGSIZE
error.Part of the purpose of opening this issue is to get feedback on where this should live, since I understand that most of the I/O methods in Tokio invoke methods in Mio which in turn invoke their
std
counterparts. I would prefer not to have to go through the process of championing an RFC because I simply don't have the time or energy to endure that process these days.Describe alternatives you've considered
Ideally
peek_from()
could just suppress theWSAEMSGSIZE
error in the name of consistency as that's a Windows-specific idiosyncrasy, but that would be up tostd::net::UdpSocket::peek_from()
, and it would be a behavior change.I can just use
recv_from()
, read the datagram and get the sender every time, then copy the data into the DTLS read buffer if applicable, but that's a redundant copy which could be up to 64KiB in size every datagram. That's a potential vector for a denial-of-service attack; in practice our application limits datagrams to a more reasonable size just under the Ethernet MTU, but still a redundant copy of every datagram can add up if they're all 1+ KiB.I can just make the
recvfrom
call directly in my application, however that's suboptimal as it requires upholding a number ofunsafe
invariants. Anyone else implementing this themselves would be at risk of making any number of mistakes that could result in undefined or just wrong behavior. As noted on the Gist I actually forgot to convert theport
value from big-endian, so even my first attempt had a pretty significant bug.socket2
is probably the most appropriate non-std
place for this to live, but for convenience I would like to see it available in Tokio as well, as shuttling back and forth betweensocket2::Socket
andtokio::net::UdpSocket
is still potentially quite error-prone.Additional context
I had previously spoken to @Noah-Kennedy on the Tokio Discord about this so I'd like his input here.
The text was updated successfully, but these errors were encountered: