diff --git a/examples/src/main.rs b/examples/src/main.rs index 3a7eda9..57e73f0 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -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, stop_signal: Arc) { 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()); } }; } diff --git a/libcsp-rust/src/ffi.rs b/libcsp-rust/src/ffi.rs index c359535..8147c23 100644 --- a/libcsp-rust/src/ffi.rs +++ b/libcsp-rust/src/ffi.rs @@ -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 = ::core::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::core::mem::size_of::(), - 32usize, - concat!("Size of: ", stringify!(sem_t)) - ); - assert_eq!( - ::core::mem::align_of::(), - 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) - ) - ); - } } diff --git a/libcsp-rust/src/lib.rs b/libcsp-rust/src/lib.rs index 7d368ff..13c257a 100644 --- a/libcsp-rust/src/lib.rs +++ b/libcsp-rust/src/lib.rs @@ -155,6 +155,29 @@ impl CspPacketRef { } } +pub struct CspPacketRefGuard(Option); + +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 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 Option { + 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) { // 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, +) -> 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), + ) + } +}