use super::{encode, CommunicationError, Connected, Packet, Unconnected};
use std;
use std::net::{SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket};
pub const DEFAULT_PORT: u16 = 0;
pub struct Sender<M = Unconnected> {
socket: UdpSocket,
mode: M,
}
pub fn default_sender_socket_addr_v4() -> SocketAddrV4 {
SocketAddrV4::new(super::default_ipv4_addr(), DEFAULT_PORT)
}
impl<M> Sender<M> {
pub fn local_addr(&self) -> Result<SocketAddr, std::io::Error> {
self.socket.local_addr()
}
}
impl Sender<Unconnected> {
pub fn bind_to<A>(addr: A) -> Result<Self, std::io::Error>
where
A: ToSocketAddrs,
{
let socket = UdpSocket::bind(addr)?;
let mode = Unconnected;
let sender = Sender { socket, mode };
Ok(sender)
}
pub fn bind() -> Result<Self, std::io::Error> {
Self::bind_to(default_sender_socket_addr_v4())
}
pub fn connect<A>(self, addr: A) -> Result<Sender<Connected>, std::io::Error>
where
A: ToSocketAddrs,
{
let Sender { socket, .. } = self;
let mut addrs = addr.to_socket_addrs()?;
let addr = addrs.next().expect("could not resolve any `SocketAddr`s");
socket.connect(addr)?;
let mode = Connected { addr };
Ok(Sender { socket, mode })
}
pub fn send<P, A>(&self, packet: P, addr: A) -> Result<usize, CommunicationError>
where
P: Into<Packet>,
A: ToSocketAddrs,
{
let bytes = encode(packet.into())?;
let bytes_written = self.socket.send_to(&bytes, addr)?;
Ok(bytes_written)
}
}
impl Sender<Connected> {
pub fn remote_addr(&self) -> SocketAddr {
self.mode.addr
}
pub fn send<P>(&self, packet: P) -> Result<usize, CommunicationError>
where
P: Into<Packet>,
{
let bytes = encode(packet.into())?;
let bytes_written = self.socket.send(&bytes)?;
Ok(bytes_written)
}
}