Which I/O errors can be handled in an UdpSocket.recv_from() loop?

I have this tokio task which should receive datagram messages until told to shutdown:

tokio::spawn(async move {
  let mut buf = vec![0_u8; 1500];
  loop {
    tokio::select! {
      biased;

      _ = &mut recv_shutdown => break,

      result = socket.recv_from(&mut buf) => {
        match result {
          Ok((nbytes, origin)) => {
            // ...
          }
          Err(e) => {}
        }
      }
    }
  }
});

What should I do with the io::Error in this situation? Which variants are considered normal and which ones should break the loop?

If you're writing C and use non-blocking IO, then an EAGAIN or EWOULDBLOCK error would signal you to retry the read.
I am not a 100% sure, but I think Tokio already handles this internally, so any io::Error is actually an error. @alice, your thoughts?

I have very little experience with sockets.

In the case that a message is too long to fit in the buffer, is it guaranteed that it will only discard the excess bytes, or can an error be returned, like UnexpectedEof?

Also, do I need to think about the Interrupted variant? If I understand it correctly, it can happen if signals are used, right?

Generally, Tokio can return the same set of errors as what the OS returns from the underlying syscall, except for WouldBlock. For the recv methods on udp sockets, you can find this list in the man page. If you get an error that you don't know how to handle, you should assume that it is fatal and that a new socket should be created.

(Note that both EAGAIN and EWOULDBLOCK become a WouldBlock error kind in the standard library.)

I don't think interrupted errors can happen on non-blocking sockets. If there are extra bytes, then they are discarded and no error is returned.

1 Like

Thanks!

What confuses me about the case of excess bytes is that the docs say:

The function must be called with valid byte array buf of sufficient size to hold the message bytes. If a message is too long to fit in the supplied buffer, excess bytes may be discarded.

The use of "may" makes me think that maybe it's OS-specific behavior and that the programmer should be aware of it.

You may be interested in https://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch22lev1sec3.html - there were OSes that didn't truncate, but instead returned the excess to later read calls.

1 Like

I have never heard of any OS that implements it in any other way but discarding extra data, but it sounds like those exist.

Thanks for clarifying things. I think I'll just log the error and break the loop then...