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!()
}
}
}
}