Empty response from UDP recv w/ tokio and futures

I had a simple UDP ping server that used to work but no longer does since I upgraded to the latest tokio version. Originally I was using RecvDgram but when that always returns an empty response (0 bytes). I then built my own version of a future to see if that would help, but it’s the same result. I’m hoping you might have some tips or pointers on where I might be going wrong w/ my code or testing methodology.

Thanks!

Methodology
Here’s my test methodology in case the problem is there.
Simulated client command: echo -e "hello world" | nc -u 127.0.0.1 3999
If I use nc for the server too, it receives "hello world"
I use the same client for my udp server w/ tokio, I always get a response like this, showing 0 bytes read:

poll_recv_from ready: (0, V4(127.0.0.1:52978))
received 0 bytes from 127.0.0.1:52978

tcpdump seems to show that the packets are going through. The top line is for the nc listener, the bottom line for my server.

tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:41:41.800083 IP (tos 0x0, ttl 64, id 3279, offset 0, flags [DF], proto UDP (17), length 40)
    127.0.0.1.55181 > 127.0.0.1.3999: [bad udp cksum 0xfe27 -> 0x88be!] UDP, length 12
11:41:52.368481 IP (tos 0x0, ttl 64, id 6240, offset 0, flags [DF], proto UDP (17), length 40)
    127.0.0.1.54226 > 127.0.0.1.3999: [bad udp cksum 0xfe27 -> 0x8c79!] UDP, length 12

I just tried doing the same thing but sending the packet to my actual IP address instead of 127.0.0.1 and got the same problem, with 0 bytes returned.

Code
Here’s the code for my future. I create the socket w/ UdpSocket::bind(&sock_addr).

struct UdpRecv
{
    ctx: rsrc::IopCtx,
    buffer: Vec<u8>,
}

impl Future for UdpRecv
{
    type Item = rsrc::Event;
    type Error = rsrc::Event;

    fn poll(&mut self) -> Poll<rsrc::Event, rsrc::Event>
    {
print!("UdpRecv::poll()\n");
        let mut sock: UdpSocket = self.ctx.take_rsrc();
        let result = match sock.poll_recv_from(&mut self.buffer) {
            Ok(Async::Ready(ready_result)) => {
println!("poll_recv_from ready: {:?}", ready_result);
                ready_result
            }
            Ok(Async::NotReady) => {
println!("poll_recv_from notready");
                self.ctx.init_rsrc(Box::new(sock));
                task::current().notify();
                return Ok(Async::NotReady);
            }
            Err(e) => {
                panic!("io error: {:?}", e);
            }
        };
        let (nbytes, addr) = result;
        println!("received {} bytes from {}", nbytes, addr);
        let utf8 = String::from_utf8(self.buffer.clone()).unwrap();
        let str_result = Val::Str(Lstr::from(utf8));
        Ok(Async::Ready(rsrc::Event::Result(str_result, Some(Box::new(sock)))))
    }
}

You’re falling into a common trap :slight_smile:.

When you create a Vec<u8> with Vec::with_capacity(N) you’re creating a 0 length vector (but with at least N bytes of capacity). When you coerce it to a &mut [u8] (which is what’s fed to poll_recv_from), you end up creating an empty slice. The socket then, of course, cannot copy data into it.

Use vec![0; N] to zero fill the vec or call set_len() to manually set the length of the vec (be careful to then not read beyond the # of bytes you’ve received from the socket).

1 Like

Yes, you are absolutely correct again, thank you @vitalyd !

Here’s a little more context in case anyone else is looking at this problem. I checked my history expecting to see that I added Vec::with_capacity(2048) fairly recently, but it dated back to November 2017 when my recollection is that this code worked. I’m wondering if perhaps the code was ignoring the length of the buffer before or something or distinguishing between length and capacity and no longer is.