How do you broadcast a UDP datagram and receive the responses in Rust?

Viewed 4609

I'm trying to implement the VXI11 protocol in Rust (to communicate with instruments like oscilloscopes, power supplies, etc) and I'm successfully sending a broadcast UDP message, but not receiving the responses. This is the code I use to set up the UDP socket:

    let socket:UdpSocket = UdpSocket::bind("0.0.0.0:0")?;
    socket.set_read_timeout(Some(Duration::new(5, 0)))?;
    socket.set_broadcast(true)?;
    socket.connect(("255.255.255.255", port))?;
    println!("Connected on port {}", port);
    println!("Broadcast: {:?}", socket.broadcast());
    println!("Timeout: {:?}", socket.read_timeout());

I've also tried "255.255.255.255:0" and "192.168.2.255:0" in the bind call with no luck. This is the code I use to receive the responses.

    let call:Vec<u8> = self.packer.get_buf()?;
    println!("Sending call, {} bytes", call.len());
    match self.socket.send(&call) {
        Ok(n) => {
            if n != call.len() {
                return Err(Error::new(ErrorKind::Other, "Sent the wrong number of bytes"))
            }
            else {
                // Do nothing because we sent the number of bytes we expected to send
            }
        },
        Err(e) => return Err(e),
    }

    println!("Awaiting responses...");   // self.recv_buff is a [u8; 8092]
    while let Ok((n, addr)) = self.socket.recv_from(&mut self.recv_buff) {
        println!("{} bytes response from {:?}", n, addr);
        // Remaining code not directly relevant to the question
    }

This is the STDOUT output:

Connected on port 111
Broadcast: Ok(true)
Timeout: Ok(Some(5s))
Sending call, 56 bytes
Awaiting responses...

I also know that the remote hosts are responding because I can see it in tcpdump. However, the Rust code just isn't receiving the responses. Anyone have any idea why this would be?

$ sudo tcpdump 'udp port 111'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlo1, link-type EN10MB (Ethernet), capture size 262144 bytes
11:00:54.094534 IP deathStar.51499 > 255.255.255.255.sunrpc: UDP, length 56
11:00:54.100199 IP 192.168.2.4.sunrpc > deathStar.51499: UDP, length 28
11:00:54.100755 IP 192.168.2.3.sunrpc > deathStar.51499: UDP, length 28
1 Answers

TL;DR Remove the UdpSocket::connect call and then try again. It will work then.

It looks like UdpSocket::connect is the root cause. Based on the documentation, UdpSocket::connect should be used if the socket has to process data from the concrete remote address. If the remote address isn't known then you can avoid connect call at all. Without the connect call, the socket will receive data from any remote address.

let socket:UdpSocket = UdpSocket::bind("0.0.0.0:0")?;
socket.set_read_timeout(Some(Duration::new(5, 0)))?;
socket.set_broadcast(true)?;
println!("Connected on port {}", port);
println!("Broadcast: {:?}", socket.broadcast());
println!("Timeout: {:?}", socket.read_timeout());

let call:Vec<u8> = self.packer.get_buf()?;
println!("Sending call, {} bytes", call.len());
match self.socket.send(&call) {
    Ok(n) => {
        if n != call.len() {
            return Err(Error::new(ErrorKind::Other, "Sent the wrong number of bytes"))
        }
        else {
            // Do nothing because we sent the number of bytes we expected to send
        }
    },
    Err(e) => return Err(e),
}

println!("Awaiting responses...");   // self.recv_buff is a [u8; 8092]
while let Ok((n, addr)) = self.socket.recv_from(&mut self.recv_buff) {
    println!("{} bytes response from {:?}", n, addr);
    // Remaining code not directly relevant to the question
}
Related