sysvmq: Implement send and receive [wip]

Implement sending to and receiving from SysV IPC message queues. While
at it refactor the library.
This commit is contained in:
finga 2023-10-27 19:08:26 +02:00
parent 2c4d04b374
commit 47d3b77f39
3 changed files with 95 additions and 27 deletions

View file

@ -8,8 +8,19 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- A basic test to test the happy path of a queue.
- The function `SysvMq::send()` to send messages to a queue.
- The function `SysvMq::recv()` to receive messages from a queue.
- The function `SysvMq::destroy()` to destroy a queue.
### Changed
- Remove `PhantomData` from the `SysvMq` struct.
- The function `SysvMq::create()` is replaced by `new()`.
- Remove generic type for `SysvMq`.
- Rename `unlink_id()` to `destroy()`.
- Update to the latest verscion of `nix`.
- Fix several clippy findings in preperation to enable several lint
groups.

View file

@ -1,8 +1,9 @@
use libc::{
msgctl, msgget, msqid_ds, IPC_CREAT, IPC_INFO, IPC_NOWAIT, IPC_RMID, MSG_INFO,g MSG_STAT,
c_void, msgctl, msgget, msgrcv, msgsnd, msqid_ds, IPC_CREAT, IPC_INFO, IPC_NOWAIT, IPC_RMID,
MSG_INFO, MSG_STAT,
};
use nix::errno::{errno, Errno};
use std::{marker::PhantomData, mem::MaybeUninit, ptr};
use std::{mem::MaybeUninit, ptr};
use thiserror::Error;
#[derive(Debug, Error)]
@ -11,14 +12,21 @@ pub enum SysvMqError {
ErrnoError(&'static str),
}
fn msgctl_wrapper(msqid: i32, cmd: i32, buf: *mut msqid_ds) -> Result<i32, SysvMqError> {
match unsafe { msgctl(msqid, cmd, buf) } {
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
result => Ok(result),
}
}
#[allow(clippy::doc_markdown)]
/// Unlink (delete) an existing SysV IPC message queue.
/// Destroy an SysV IPC message queue by id.
///
/// # Errors
///
/// Return an `SysvMqError` when no queue with the given key can be
/// found.
pub fn unlink_id(id: i32) -> Result<(), SysvMqError> {
pub fn destroy(id: i32) -> Result<(), SysvMqError> {
let res = unsafe { msgctl(id, IPC_RMID, ptr::null::<msqid_ds>().cast_mut()) };
match res {
@ -83,28 +91,29 @@ pub fn msg_info(id: i32) {
println!("info: {msg_info:?}");
}
pub struct SysvMq<T> {
pub id: i32,
pub key: i32,
pub struct SysvMq {
id: i32,
key: i32,
message_mask: i32,
mode: i32,
types: PhantomData<T>,
}
impl<T> SysvMq<T> {
impl SysvMq {
/// Create a new message queye with the given key.
///
/// # Errors
///
/// Return an `SysvMqError` when no queue with the given key can be
/// created.
pub fn create(&mut self, key: i32) -> Result<&Self, SysvMqError> {
self.key = key;
self.id = unsafe { msgget(self.key, IPC_CREAT | self.mode) };
pub fn new(key: i32) -> Result<Self, SysvMqError> {
let mut mq = Self::default();
match self.id {
mq.key = key;
mq.id = unsafe { msgget(mq.key, IPC_CREAT | mq.mode) };
match mq.id {
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
_ => Ok(self),
_ => Ok(mq),
}
}
@ -124,30 +133,62 @@ impl<T> SysvMq<T> {
}
}
pub fn mode(&mut self, mode: i32) -> &Self {
/// Set the mode
pub fn mode(&mut self, mode: i32) {
self.mode = mode;
self
}
pub fn nonblocking(&mut self) -> &Self {
pub fn nonblocking(&mut self) {
self.message_mask |= IPC_NOWAIT;
self
}
#[must_use]
pub const fn new() -> Self {
pub fn send(&mut self, msg: &[u8]) -> Result<(), SysvMqError> {
match unsafe {
msgsnd(
self.id,
msg.as_ptr().cast::<c_void>(),
msg.len(),
self.message_mask,
)
} {
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
_ => Ok(()),
}
}
pub fn recv(&mut self, msg: &mut [u8]) -> Result<(), SysvMqError> {
match unsafe {
msgrcv(
self.id,
msg.as_mut_ptr().cast::<c_void>(),
msg.len(),
0,
self.message_mask,
)
} {
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
_ => Ok(()),
}
}
/// Destroy an existing SysV IPC message queue.
///
/// # Errors
///
/// Return an `SysvMqError` when no queue with the given key can be
/// found.
pub fn destroy(&mut self) -> Result<(), SysvMqError> {
destroy(self.id)
}
}
impl Default for SysvMq {
fn default() -> Self {
Self {
id: -1,
key: 0,
message_mask: 0,
mode: 0o644,
types: PhantomData,
}
}
}
impl<T> Default for SysvMq<T> {
fn default() -> Self {
Self::new()
}
}

View file

@ -0,0 +1,16 @@
use sysvmq::SysvMq;
#[test]
fn new_send_recv_delete() {
let mut sysvmq = SysvMq::new(0).expect("could not create SysV message queue with key 0");
let msg = b"this is a test";
let mut buf = [0u8; 14];
sysvmq
.send(msg)
.expect("could not send message to SysV message queue");
sysvmq.recv(&mut buf);
sysvmq
.destroy()
.expect("could not destroy SysV message queue");
assert_eq!(msg, &buf);
}