use cty::{c_int, c_uchar, c_void};
use embedded_nal::{nb::Error, SocketAddr, UdpClientStack};
pub(crate) unsafe extern "C" fn udp_recv<T: UdpClientStack>(
ctx: *mut c_void,
buf: *mut c_uchar,
len: usize,
) -> c_int {
let buf_slice = unsafe { core::slice::from_raw_parts_mut(buf, len) };
let context = unsafe { (ctx as *mut UdpContext<T>).as_mut() };
let Some(context) = context else {
log::error!("failed to retrieve UdpContext (null pointer exception)!");
return -1;
};
let (socket, stack) = match context.get_socket_and_stack() {
Ok(ret) => ret,
Err(e) => {
log::error!("failed to create udp socket: {e:?}");
return -1;
}
};
let res = stack.receive(socket, buf_slice);
match res {
Ok((n, _)) => n as c_int,
Err(Error::WouldBlock) => embedded_mbedtls_sys::MBEDTLS_ERR_SSL_WANT_READ,
Err(Error::Other(e)) => {
log::warn!("udp receive failed: {e:?}");
-1
}
}
}
pub(crate) unsafe extern "C" fn udp_send<T: UdpClientStack>(
ctx: *mut c_void,
buf: *const c_uchar,
len: usize,
) -> c_int {
let buf_slice = unsafe { core::slice::from_raw_parts(buf, len) };
let context = unsafe { (ctx as *mut UdpContext<T>).as_mut() };
let Some(context) = context else {
log::error!("failed to retrieve UdpContext (null pointer exception)!");
return -1;
};
let (socket, stack) = match context.get_socket_and_stack() {
Ok(ret) => ret,
Err(e) => {
log::error!("failed to create udp socket: {e:?}");
return -1;
}
};
let res = stack.send(socket, buf_slice);
if let Err(e) = res {
match e {
embedded_nal::nb::Error::Other(e) => {
log::warn!("udp send failed: {:?}", e);
return -1;
}
embedded_nal::nb::Error::WouldBlock => {
return embedded_mbedtls_sys::MBEDTLS_ERR_SSL_WANT_WRITE
}
}
}
len as c_int }
pub struct UdpContext<U: UdpClientStack> {
socket: Option<U::UdpSocket>,
stack: U,
server_addr: SocketAddr,
}
impl<U: UdpClientStack> UdpContext<U> {
pub(crate) fn new(net_stack: U, server_addr: SocketAddr) -> Self {
Self {
socket: None,
stack: net_stack,
server_addr,
}
}
pub(crate) fn get_socket_and_stack(&mut self) -> Result<(&mut U::UdpSocket, &mut U), U::Error> {
let socket = if self.socket.is_none() {
let s = self.socket.insert(self.stack.socket()?);
self.stack.connect(s, self.server_addr)?;
s
} else {
self.socket.as_mut().unwrap()
};
Ok((socket, &mut self.stack))
}
}