use std::cell::UnsafeCell;
use std::io::{Error, ErrorKind, Result};
use std::net::SocketAddr;
use super::SocketAddrIterator;
use crate::error::LunaticError;
use crate::host;
#[derive(Debug)]
pub struct UdpSocket {
id: u64,
consumed: UnsafeCell<bool>,
}
impl Drop for UdpSocket {
fn drop(&mut self) {
if unsafe { !*self.consumed.get() } {
unsafe { host::api::networking::drop_udp_socket(self.id) };
}
}
}
impl UdpSocket {
pub fn bind<A>(addr: A) -> Result<Self>
where
A: super::ToSocketAddrs,
{
let mut id = 0;
for addr in addr.to_socket_addrs()? {
let result = match addr {
SocketAddr::V4(v4_addr) => {
let ip = v4_addr.ip().octets();
let port = v4_addr.port() as u32;
unsafe {
host::api::networking::udp_bind(
4,
ip.as_ptr(),
port,
0,
0,
&mut id as *mut u64,
)
}
}
SocketAddr::V6(v6_addr) => {
let ip = v6_addr.ip().octets();
let port = v6_addr.port() as u32;
let flow_info = v6_addr.flowinfo();
let scope_id = v6_addr.scope_id();
unsafe {
host::api::networking::udp_bind(
6,
ip.as_ptr(),
port,
flow_info,
scope_id,
&mut id as *mut u64,
)
}
}
};
if result == 0 {
return Ok(Self {
id,
consumed: UnsafeCell::new(false),
});
}
}
let lunatic_error = LunaticError::Error(id);
Err(Error::new(ErrorKind::Other, lunatic_error))
}
pub fn local_addr(&self) -> Result<SocketAddr> {
let mut dns_iter_or_error_id = 0;
let result = unsafe {
host::api::networking::udp_local_addr(self.id, &mut dns_iter_or_error_id as *mut u64)
};
if result == 0 {
let mut dns_iter = SocketAddrIterator::from(dns_iter_or_error_id);
let addr = dns_iter.next().expect("must contain one element");
Ok(addr)
} else {
let lunatic_error = LunaticError::Error(dns_iter_or_error_id);
Err(Error::new(ErrorKind::Other, lunatic_error))
}
}
pub fn peer_addr(&self) -> Result<SocketAddr> {
let mut dns_iter_or_error_id = 0;
let result = unsafe {
host::api::networking::udp_peer_addr(self.id, &mut dns_iter_or_error_id as *mut u64)
};
if result == 0 {
let mut dns_iter = SocketAddrIterator::from(dns_iter_or_error_id);
let addr = dns_iter.next().expect("must contain one element");
Ok(addr)
} else if result == 1 {
Err(Error::new(ErrorKind::NotConnected, "not connected"))
} else {
let lunatic_error = LunaticError::Error(dns_iter_or_error_id);
Err(Error::new(ErrorKind::Other, lunatic_error))
}
}
pub fn connect<A>(&self, addr: A) -> Result<()>
where
A: super::ToSocketAddrs,
{
let mut id = 0;
for addr in addr.to_socket_addrs()? {
let result = match addr {
SocketAddr::V4(v4_addr) => {
let ip = v4_addr.ip().octets();
let port = v4_addr.port() as u32;
unsafe {
host::api::networking::udp_connect(
self.id,
4,
ip.as_ptr(),
port,
0,
0,
0, &mut id as *mut u64,
)
}
}
SocketAddr::V6(v6_addr) => {
let ip = v6_addr.ip().octets();
let port = v6_addr.port() as u32;
let flow_info = v6_addr.flowinfo();
let scope_id = v6_addr.scope_id();
unsafe {
host::api::networking::udp_connect(
self.id,
6,
ip.as_ptr(),
port,
flow_info,
scope_id,
0, &mut id as *mut u64,
)
}
}
};
if result == 0 {
return Ok(());
}
}
let lunatic_error = LunaticError::Error(id);
Err(Error::new(ErrorKind::Other, lunatic_error))
}
pub fn send(&self, buf: &[u8]) -> Result<usize> {
let mut nsend_or_error_id: u64 = 0;
let result = unsafe {
host::api::networking::udp_send(
self.id,
buf.as_ptr(),
buf.len(),
&mut nsend_or_error_id as *mut u64,
)
};
if result == 0 {
Ok(nsend_or_error_id as usize)
} else {
let lunatic_error = LunaticError::Error(nsend_or_error_id);
Err(Error::new(ErrorKind::Other, lunatic_error))
}
}
pub fn send_to<A>(&self, buf: &[u8], addr: A) -> Result<usize>
where
A: super::ToSocketAddrs,
{
let mut nsend_or_error_id = 0;
for addr in addr.to_socket_addrs()? {
let result = match addr {
SocketAddr::V4(v4_addr) => {
let ip = v4_addr.ip().octets();
let port = v4_addr.port() as u32;
unsafe {
host::api::networking::udp_send_to(
self.id,
buf.as_ptr(),
buf.len(),
4,
ip.as_ptr(),
port,
0,
0,
&mut nsend_or_error_id as *mut u64,
)
}
}
SocketAddr::V6(v6_addr) => {
let ip = v6_addr.ip().octets();
let port = v6_addr.port() as u32;
let flow_info = v6_addr.flowinfo();
let scope_id = v6_addr.scope_id();
unsafe {
host::api::networking::udp_send_to(
self.id,
buf.as_ptr(),
buf.len(),
6,
ip.as_ptr(),
port,
flow_info,
scope_id,
&mut nsend_or_error_id as *mut u64,
)
}
}
};
if result == 0 {
return Ok(nsend_or_error_id as usize);
}
}
let lunatic_error = LunaticError::Error(nsend_or_error_id);
Err(Error::new(ErrorKind::Other, lunatic_error))
}
pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
let mut nrecv_or_error_id: u64 = 0;
let result = unsafe {
host::api::networking::udp_receive(
self.id,
buf.as_mut_ptr(),
buf.len(),
&mut nrecv_or_error_id as *mut u64,
)
};
if result == 0 {
Ok(nrecv_or_error_id as usize)
} else {
let lunatic_error = LunaticError::Error(nrecv_or_error_id);
Err(Error::new(ErrorKind::Other, lunatic_error))
}
}
pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
let mut dns_iter_id = 0;
let mut nrecv_or_error_id: u64 = 0;
let result = unsafe {
host::api::networking::udp_receive_from(
self.id,
buf.as_mut_ptr(),
buf.len(),
&mut nrecv_or_error_id as *mut u64,
&mut dns_iter_id as *mut u64,
)
};
if result == 0 {
let mut dns_iter = SocketAddrIterator::from(dns_iter_id);
let peer = dns_iter.next().expect("must contain one element");
Ok((nrecv_or_error_id as usize, peer))
} else {
let lunatic_error = LunaticError::Error(nrecv_or_error_id);
Err(Error::new(ErrorKind::Other, lunatic_error))
}
}
pub fn set_ttl(&self, ttl: u32) -> Result<()> {
unsafe { host::api::networking::set_udp_socket_ttl(self.id, ttl) };
Ok(())
}
pub fn set_broadcast(&self, broadcast: bool) -> Result<()> {
let api_broadcast = match broadcast {
true => 1,
false => 0,
};
unsafe { host::api::networking::set_udp_socket_broadcast(self.id, api_broadcast) };
Ok(())
}
pub fn ttl(&self) -> Result<u32> {
let result = unsafe { host::api::networking::get_udp_socket_ttl(self.id) };
Ok(result)
}
pub fn broadcast(&self) -> Result<bool> {
let result = unsafe { host::api::networking::get_udp_socket_broadcast(self.id) };
match result {
0 => Ok(false),
_ => Ok(true),
}
}
pub fn try_clone(&self) -> Result<UdpSocket> {
let result = unsafe { host::api::networking::clone_udp_socket(self.id) };
Ok(Self {
id: result,
consumed: UnsafeCell::new(false),
})
}
pub fn set_nonblocking(&self, _: bool) -> Result<()> {
Ok(())
}
pub fn take_error(&self) -> Result<Option<LunaticError>> {
Ok(None)
}
}