use std::ffi;
use crate::TOKIO_RUNTIME;
pub struct udp_socket(tailscale::UdpSocket);
#[unsafe(no_mangle)]
pub extern "C" fn ts_udp_bind(
dev: &crate::device,
addr: &crate::sockaddr,
) -> Option<Box<udp_socket>> {
let addr = addr.try_into().ok()?;
match TOKIO_RUNTIME.block_on(dev.0.udp_bind(addr)) {
Ok(sock) => Some(Box::new(udp_socket(sock))),
Err(e) => {
tracing::error!(error = %e, "binding udp socket");
None
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_udp_close(sock: Box<udp_socket>) {
drop(sock);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ts_udp_sendto(
sock: &udp_socket,
addr: &crate::sockaddr,
msg: *const u8,
len: usize,
) -> ffi::c_int {
let msg = unsafe { core::slice::from_raw_parts(msg, len) };
let Ok(addr) = addr.try_into() else {
return -1;
};
if let Err(e) = sock.0.send_to_blocking(addr, msg) {
tracing::error!(err = %e, "udp_send failed");
return -1;
}
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn ts_udp_recvfrom(
sock: &udp_socket,
addr: Option<&mut crate::sockaddr>,
buf: *mut u8,
len: usize,
) -> ffi::c_int {
let buf = unsafe { core::slice::from_raw_parts_mut(buf, len) };
match sock.0.recv_from_blocking(buf) {
Err(e) => {
tracing::error!(err = %e, "udp_recv failed");
-1
}
Ok((who, len)) => {
tracing::trace!(%who);
if let Some(addr) = addr {
*addr = who.into();
}
len as _
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn ts_udp_local_addr(sock: &udp_socket) -> crate::sockaddr {
sock.0.local_addr().into()
}