UdpSocket can't receive data frequently

Hey guys, I’m working on a “DNS relay” program which receives DNS requests from clients then forward them to a real DNS server and finally send the response back to clients. The idea is really simple but I hit an issue that it seems the std::net::UdpSocket can’t receive data from time to time.
Here is a test program to demonstrate the issue. The program blocks on “recv_from” frequently. I’m a newbie of Rust so I believe I must make some stupid mistake here… can someone help to take a look? Thanks in advance.

#[macro_use] extern crate log;
extern crate env_logger;
extern crate mio;

use std::time::Duration;
use std::net::SocketAddr;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::io::ErrorKind::WouldBlock;
use log::LevelFilter;
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio::net::UdpSocket;

const SERV: Token = Token(0);
const BUF_SIZE: usize = 4096;

fn handle_request(ss: &UdpSocket) {
    let mut buf: [u8;BUF_SIZE] = [0;BUF_SIZE];
    let mut rbuf: [u8;BUF_SIZE] = [0;BUF_SIZE];
    let mut len = 0;
    let mut source = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
    loop {
        let (num_recv, from_addr) = match ss.recv_from(&mut buf) {
            Ok(o) => o,
            Err(e) => {
                if e.kind() != WouldBlock {
                    warn!("Reading server socket failed: {}", e);
                    return;
                }
                break;
            },
        };

        len += num_recv;
        source = from_addr;
    }

    info!("Received {} bytes from: {}", len, source);
    let cs = std::net::UdpSocket::bind("0.0.0.0:0").unwrap();
    cs.set_nonblocking(false).unwrap();
    cs.send_to(&mut buf[0..len], "192.168.88.1:53").unwrap();
    let (rlen, _source) = cs.recv_from(&mut rbuf).unwrap();
    info!("Response is received. Bytes: {}", rlen);
}

fn main() {
    env_logger::init();
    log::set_max_level(LevelFilter::Trace);

    let s_socket = UdpSocket::bind(&"0.0.0.0:5300".parse().unwrap()).unwrap();
    let poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(128);
    poll.register(&s_socket, SERV, Ready::readable(), PollOpt::edge()).unwrap();

    info!("Let's roll!");
    loop {
        poll.poll(&mut events, Some(Duration::from_millis(100))).unwrap();
        for event in events.iter() {
            match event.token() {
                SERV => {
                    if event.readiness().is_readable() {
                        handle_request(&s_socket);
                    }
                },
                _ => unreachable!()
            }
        }
    }
}

You loop recv on your main socket on port 5300 until it is exhausted. While this is correct, your implementation is completely wrong. What you are basically doing is overwriting the beginning of buf and source with every received packet and only using the last one received. Even if this was correctly implemented it is the wrong thing to do. An individual DNS packet is a unit and must not be concatenated with other ones.

Once your recv loop is complete, you use a blocking socket to forward the packet to your actual DNS server. There is no way of knowing how long this will take.

What you should be doing is creating a mio::net::UdpSocket and register it with mio::Poll with every received packet on 5300 and storing the socket in a Slab

Thanks a lot SergejJurecko! Yeah, the key error is that “reading” loop. It always overwirtes the buf and also creates a wrong “len”. My issue is gone after fixing that.
Regarding the synchronized socket send/recv after the loop, yeah I know they are blocking, I was just trying to make it looks simpler. In my real program, polling is also used to handle the send/recv.
Anyway, thanks again.