I'm using mio::udp::UdpSocket to receive a response to a request from a client. It looks like I'm getting partial UDP packets on the triggered event. I'm not sure if this is a bug in the mio library or not.
I've tried PollOpt::level(), all(), empty(), edge(), etc. I think I generally want level() based on the poll() docs, but none of them work. By adding a sleep of 20 ms I get the full packets.
As reference, when using the blocking std::net::UdpSocket I see no issues. Honestly, if the std::net::SocketOpts was stable I'd just use that. The intention of using mio is to gain timeout on the socket, it looks like net2 is going to replace std::net, but even net2 doesn't have timeout on recv.
Here's the code for the eventloop:
sleep_ms(20);
let mut event_loop: EventLoop<Response> = try!(EventLoop::new());
if event_loop.timeout_ms((), 5000).is_err() { return Err(ClientError::TimerError) };
try!(event_loop.register_opt(&self.socket, RESPONSE, EventSet::readable(), PollOpt::all()));
let mut response: Response = Response::new(&self.socket);
try!(event_loop.run_once(&mut response));
Here's the code for the Handler:
fn ready(&mut self, _: &mut EventLoop<Self>, token: Token, events: EventSet) {
match token {
RESPONSE => {
if !events.is_readable() {
debug!("got woken up, but not readable: {:?}", token);
return
}
let recv_result = self.socket.recv_from(&mut self.buf);
if recv_result.is_err() {
// debug b/c we're returning the error explicitly
debug!("could not recv_from on {:?}: {:?}", self.socket, recv_result);
self.error = Some(recv_result.unwrap_err().into());
return
}
if recv_result.as_ref().unwrap().is_none() {
// debug b/c we're returning the error explicitly
debug!("no return address on recv_from: {:?}", self.socket);
self.error = Some(ClientError::NoAddress);
return
}
let addr = Some(recv_result.unwrap().unwrap());
debug!("bytes: {:?} from: {:?}", self.buf.len(), addr);
},
_ => error!("unrecognized token: {:?}", token),
}
}
Just to follow up, the bug in the above logic, is that run_once() runs for a tick, not for one 'event', which was a bad assumption (though to be fair, the interface is currently not documented well).
In any case, this is not a partial packet issue, it's an issue of the packet not being delivered before the run_once() logic ran, didn't see anything on the socket and immediately returned.
I've changed my handler to do an event_loop.shutdown() after receiving the packet and using run() instead of run_once().