introduce read guard

This commit is contained in:
Robin Müller 2024-06-01 02:21:20 +02:00
parent 0e2f585330
commit 2ba21f9011
Signed by: muellerr
GPG Key ID: A649FB78196E3849
3 changed files with 71 additions and 49 deletions

View File

@ -9,10 +9,10 @@ use std::{
};
use libcsp_rust::{
csp_accept_guarded, csp_bind, csp_buffer_free, csp_buffer_get, csp_conn_dport,
csp_conn_print_table, csp_connect_guarded, csp_iflist_print, csp_init, csp_listen, csp_ping,
csp_read, csp_reboot, csp_route_work, csp_send, csp_service_handler, ConnectOpts, CspSocket,
MsgPriority, SocketFlags, CSP_ANY, CSP_LOOPBACK,
csp_accept_guarded, csp_bind, csp_buffer_get, csp_conn_dport, csp_conn_print_table,
csp_connect_guarded, csp_iflist_print, csp_init, csp_listen, csp_ping, csp_read,
csp_read_guarded, csp_reboot, csp_route_work, csp_send, csp_service_handler, ConnectOpts,
CspSocket, MsgPriority, SocketFlags, CSP_ANY, CSP_LOOPBACK,
};
const MY_SERVER_PORT: i32 = 10;
@ -115,23 +115,22 @@ fn server(server_received: Arc<AtomicU32>, stop_signal: Arc<AtomicBool>) {
break;
}
// SAFETY: Connection is active while we read here.
let packet = csp_read(&mut conn.0, Duration::from_millis(100));
// Guarded packet is cleaned up automatically.
let packet = csp_read_guarded(&mut conn.0, Duration::from_millis(100));
if packet.is_none() {
break;
}
let mut packet = packet.unwrap();
let packet = packet.unwrap();
match csp_conn_dport(&conn.0) {
MY_SERVER_PORT => {
server_received.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let cstr = CStr::from_bytes_with_nul(packet.packet_data())
let cstr = CStr::from_bytes_with_nul(packet.as_ref().packet_data())
.expect("invalid packet data format, is not C string");
// Process packet here.
println!("packet received on MY_SERVER_PORT: {:?}", cstr);
csp_buffer_free(packet);
}
_ => {
csp_service_handler(&mut packet);
csp_service_handler(packet.take());
}
};
}

View File

@ -265,7 +265,7 @@ extern "C" {
dst: u16,
dst_port: u8,
timeout: u32,
outbuf: *mut ::core::ffi::c_void,
outbuf: *const ::core::ffi::c_void,
outlen: ::core::ffi::c_int,
inbuf: *mut ::core::ffi::c_void,
inlen: ::core::ffi::c_int,
@ -290,7 +290,7 @@ extern "C" {
pub fn csp_transaction_persistent(
conn: *mut csp_conn_t,
timeout: u32,
outbuf: *mut ::core::ffi::c_void,
outbuf: *const ::core::ffi::c_void,
outlen: ::core::ffi::c_int,
inbuf: *mut ::core::ffi::c_void,
inlen: ::core::ffi::c_int,
@ -900,39 +900,4 @@ mod tests {
)
);
}
#[test]
fn bindgen_test_layout_sem_t() {
const UNINIT: ::core::mem::MaybeUninit<sem_t> = ::core::mem::MaybeUninit::uninit();
let ptr = UNINIT.as_ptr();
assert_eq!(
::core::mem::size_of::<sem_t>(),
32usize,
concat!("Size of: ", stringify!(sem_t))
);
assert_eq!(
::core::mem::align_of::<sem_t>(),
8usize,
concat!("Alignment of ", stringify!(sem_t))
);
assert_eq!(
unsafe { ::core::ptr::addr_of!((*ptr).__size) as usize - ptr as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(sem_t),
"::",
stringify!(__size)
)
);
assert_eq!(
unsafe { ::core::ptr::addr_of!((*ptr).__align) as usize - ptr as usize },
0usize,
concat!(
"Offset of field: ",
stringify!(sem_t),
"::",
stringify!(__align)
)
);
}
}

View File

@ -155,6 +155,29 @@ impl CspPacketRef {
}
}
pub struct CspPacketRefGuard(Option<CspPacketRef>);
impl Drop for CspPacketRefGuard {
fn drop(&mut self) {
if let Some(packet) = self.0.take() {
csp_buffer_free(packet)
}
}
}
impl CspPacketRefGuard {
/// Take the packet out of the guard, preventing it from being freed.
pub fn take(mut self) -> CspPacketRef {
self.0.take().unwrap()
}
}
impl AsRef<CspPacketRef> for CspPacketRefGuard {
fn as_ref(&self) -> &CspPacketRef {
self.0.as_ref().unwrap()
}
}
impl CspPacketMut {
pub fn packet_data(&self) -> &[u8] {
unsafe { &(*self.0).packet_data_union.data[..self.packet_length()] }
@ -323,13 +346,19 @@ pub fn csp_read(conn: &mut CspConnRef, timeout: Duration) -> Option<CspPacketRef
Some(CspPacketRef(unsafe { &mut *opt_packet }))
}
/// Rust wrapper for [ffi::csp_read] which returns a guarded packet reference. This packet
/// will cleaned up automatically with [csp_buffer_free] on drop.
pub fn csp_read_guarded(conn: &mut CspConnRef, timeout: Duration) -> Option<CspPacketRefGuard> {
Some(CspPacketRefGuard(Some(csp_read(conn, timeout)?)))
}
/// Rust wrapper for [ffi::csp_conn_dport].
pub fn csp_conn_dport(conn: &CspConnRef) -> i32 {
// SAFETY: FFI call.
unsafe { ffi::csp_conn_dport(conn.0) }
}
pub fn csp_service_handler(packet: &mut CspPacketRef) {
pub fn csp_service_handler(packet: CspPacketRef) {
// SAFETY: FFI call.
unsafe { ffi::csp_service_handler(&mut *packet.0) }
}
@ -446,8 +475,37 @@ pub fn csp_iflist_print() {
unsafe { ffi::csp_iflist_print() }
}
/// Rust wrapper for [ffi::csp_buffer_free].
pub fn csp_buffer_free(packet: impl Into<CspPacketRef>) {
// SAFETY: FFI call and the Rust type system actually ensure the correct type
// is free'd here.
// is free'd here, while also taking the packet by value.
unsafe { ffi::csp_buffer_free(packet.into().0 as *mut libc::c_void) }
}
/// Rust wrapper for [ffi::csp_transaction_persistent].
///
/// # Parameters
///
/// * `in_len`: Use [None] if the length is unknown, and the expected reply length otherwise.
///
/// # Returns
///
/// 1 or reply size on success, 0 otherwise.
pub fn csp_transaction_persistent(
conn: &mut CspConnRef,
timeout: Duration,
out_data: &[u8],
in_data: &mut [u8],
in_len: Option<usize>,
) -> i32 {
unsafe {
ffi::csp_transaction_persistent(
conn.0,
timeout.as_millis() as u32,
out_data.as_ptr() as *const core::ffi::c_void,
out_data.len() as i32,
in_data.as_ptr() as *mut core::ffi::c_void,
in_len.map(|v| v as i32).unwrap_or(-1),
)
}
}