use std::io;
use mio::udp::UdpSocket;
use socket::GafferState;
use addr::ToSingleSocketAddr;
use packet::{
CompleteGafferPacket,
GafferPacket,
GAFFER_MTU,
};
#[allow(dead_code)]
pub struct GafferSocket {
udp_socket: UdpSocket,
state: GafferState,
recv_buffer: [u8; GAFFER_MTU]
}
impl GafferSocket {
pub fn bind<A: ToSingleSocketAddr>(addr: A) -> io::Result<Self> {
let first_addr = addr.to_single_socket_addr().unwrap();
UdpSocket::bind(&first_addr).map(|sock| {
GafferSocket {
udp_socket: sock,
state: GafferState::new(),
recv_buffer: [0; GAFFER_MTU]
}
})
}
pub fn recv(&mut self) -> io::Result<Option<GafferPacket>> {
self.udp_socket.recv_from(&mut self.recv_buffer)
.and_then(|opt| {
match opt {
Some((len, addr)) => {
CompleteGafferPacket::deserialize(self.recv_buffer[..len].to_vec())
.map(|packet| Some(self.state.receive(addr, packet)))
},
None => Ok(None)
}
})
}
pub fn send(&mut self, p: GafferPacket) -> io::Result<Option<usize>> {
let dropped_packets = self.state.dropped_packets(p.addr);
for packet in dropped_packets.into_iter() {
try!(self.single_send(packet));
}
self.single_send(p)
}
fn single_send(&mut self, p: GafferPacket) -> io::Result<Option<usize>> {
let (destination, payload) = self.state.preprocess_packet(p);
self.udp_socket.send_to(payload.as_ref(), &destination)
}
}
#[cfg(test)]
mod tests{
use super::*;
use packet::GafferPacket;
#[test]
fn recv_doesnt_block() {
let mut sock = GafferSocket::bind("0.0.0.0:45213").unwrap();
let payload = sock.recv();
assert!(payload.is_ok());
assert_eq!(payload.unwrap(), None);
}
#[test]
fn recv_can_recv() {
let mut send_sock = GafferSocket::bind("0.0.0.0:45214").unwrap();
let mut recv_sock = GafferSocket::bind("0.0.0.0:45215").unwrap();
let send_res = send_sock.send(GafferPacket::new("127.0.0.1:45215", vec![1, 2, 3]));
assert!(send_res.is_ok());
assert!(send_res.unwrap().is_some());
let packet = recv_sock.recv();
assert!(packet.is_ok());
let packet_payload = packet.unwrap();
assert!(packet_payload.is_some());
let unwrap_pkt = packet_payload.unwrap();
assert_eq!(unwrap_pkt.payload, vec![1, 2, 3]);
let addr = unwrap_pkt.addr;
assert_eq!(addr.to_string(), "127.0.0.1:45214");
}
}