My Firmware

My Firmware

Embedded development

© 2020

Unexpected errors when sending UDP datagrams in Rust

Recently I’ve been developing a some control programs for robots using Rust. For networking such programs usually use UDP to reduce protocol overhead, since UDP doesn’t resend packet on delivery failure. However I’ve stumbled upon some unexpected behaviour of Rust’s UDPSocket send_to when the target host was down.

Generally in C there is no error when the host is down, which was the assumption that I used during development. send_to returns a Result type, in the docs of the method we can see that it should return Err only when there is a mismatch in IP versions, so naturally, knowing that only IPv4 will be used I unwrapped the result. That completely unexpectedly resulted in program crashes when the host was down. When I was debugging the problem I used a program shown below:

fn main() {
    let socket = UdpSocket::bind("0.0.0.0:12345").expect("Cannot bind port.");
    socket.set_nonblocking(true).unwrap();

    loop {
        match socket.send_to(&[], "10.15.0.2:12345") {
            Ok(size) => println!("sent {}", size),
            Err(err) => {
                println!("Errored when sending {}.", err)
            }
        }
        std::thread::sleep(Duration::from_millis(100));
    }
}

At first it sends datagrams without an error, but a while later some errors appear. First it is No route to host (os error 65) which is followed by Host is down (os error 64). This is then the culprit of those mysterious crashes that shouldn’t happen when using UDP. On the other hand I most likely should have used proper error handling.