use super::{Decodable, Encodable};
use crate::v4::{MAX_MESSAGE_SIZE, Result, UndecodedMessage};
use inherface::get_interfaces;
use log::{debug, info};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
#[derive(Debug)]
pub struct Socket {
socket: UdpSocket,
broadcast: Ipv4Addr,
}
pub type MessageBuffer = [u8; MAX_MESSAGE_SIZE];
impl Socket {
pub const EMPTY_MESSAGE_BUFFER: MessageBuffer = [0; MAX_MESSAGE_SIZE];
pub fn new(address: SocketAddrV4, interface: Option<&String>) -> Self {
let broadcast = Self::get_interface_broadcast(interface).unwrap_or(Ipv4Addr::BROADCAST);
let socket = UdpSocket::bind(address).expect("failed to bind to address");
info!("UDP socket bound on {}", address);
socket
.set_broadcast(true)
.expect("Failed to enable broadcasting");
Self { socket, broadcast }
}
fn get_interface_broadcast(maybe_interface_name: Option<&String>) -> Option<Ipv4Addr> {
let interface_name = maybe_interface_name?;
let interfaces = get_interfaces().ok()?;
let maybe_interface = interfaces.get(interface_name);
let maybe_addr = maybe_interface?
.v4_addr
.iter()
.find(|address| address.broadcast.is_some());
let maybe_broadcast = maybe_addr?.broadcast;
debug!(
"Found ipv4 broadcast address ({:?}) in list of interface addresses",
maybe_broadcast
);
maybe_broadcast
}
pub fn get_ip(&self) -> Ipv4Addr {
match self.socket.local_addr().unwrap().ip() {
std::net::IpAddr::V4(ip) => ip,
std::net::IpAddr::V6(_) => todo!("ipv6 is not supported yet"),
}
}
pub fn receive<D: Decodable<Output = D>>(&self) -> Result<(D, SocketAddr)> {
let mut buffer = Self::EMPTY_MESSAGE_BUFFER;
let (_, src) = match self.socket.recv_from(&mut buffer) {
Ok(values) => values,
Err(_) => return Err("Failed to receive data"),
};
let decoded = D::from_bytes(&UndecodedMessage::new(buffer));
debug!("Received dhcp message (from {}): {:?}", src, decoded);
Ok((decoded, src))
}
pub fn receive_raw(&self) -> Result<(UndecodedMessage, SocketAddr)> {
let mut buffer = Self::EMPTY_MESSAGE_BUFFER;
let (_, src) = match self.socket.recv_from(&mut buffer) {
Ok(values) => values,
Err(_) => return Err("Failed to receive data"),
};
debug!("Received dhcp message from {}", src);
Ok((UndecodedMessage::new(buffer), src))
}
pub fn receive_mock(partial_message: &[u8]) -> UndecodedMessage {
let mut buffer = Self::EMPTY_MESSAGE_BUFFER;
partial_message
.iter()
.enumerate()
.for_each(|(i, byte)| buffer[i] = *byte);
UndecodedMessage::new(buffer)
}
pub fn unicast<E: Encodable>(&self, encodable: &E, address: SocketAddrV4) -> Result<()> {
let encoded = encodable.to_bytes();
let ip = address.ip();
debug!("Sending dhcp message (to {:?}): {:?}", ip, encodable);
match self.socket.send_to(&encoded, address) {
Ok(_) => Ok(()),
Err(_) => Err("Failed to send data"),
}
}
pub fn broadcast<E: Encodable>(&self, encodable: &E, port: u16) -> Result<()> {
self.unicast(encodable, SocketAddrV4::new(self.broadcast, port))
}
}