2021-07-07 20:23:04 +02:00
|
|
|
use libc::{
|
2021-07-09 00:31:51 +02:00
|
|
|
msgctl, msgget, msginfo, msqid_ds, IPC_CREAT, IPC_EXCL, IPC_INFO, IPC_NOWAIT, IPC_PRIVATE,
|
|
|
|
IPC_RMID, IPC_SET, IPC_STAT, MSG_COPY, MSG_EXCEPT, MSG_INFO, MSG_NOERROR, MSG_STAT,
|
2021-07-07 20:23:04 +02:00
|
|
|
};
|
|
|
|
use nix::errno::{errno, Errno};
|
2021-07-09 00:31:51 +02:00
|
|
|
use std::{marker::PhantomData, mem::MaybeUninit, ptr};
|
2021-07-07 20:23:04 +02:00
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
#[derive(Debug, Error)]
|
|
|
|
pub enum SysvMqError {
|
|
|
|
#[error("SysV message queue: {0}")]
|
|
|
|
ErrnoError(&'static str),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// IPC bit flags
|
|
|
|
#[repr(i32)]
|
|
|
|
pub enum Flags {
|
|
|
|
/// Create key if key does not exist.
|
|
|
|
CreateKey = IPC_CREAT,
|
|
|
|
/// Fail if key exists.
|
|
|
|
Exclusive = IPC_EXCL,
|
|
|
|
/// Return error on wait.
|
|
|
|
NoWait = IPC_NOWAIT,
|
|
|
|
/// No error if message is too big.
|
|
|
|
NoError = MSG_NOERROR,
|
|
|
|
/// Receive any message except of specified type.
|
|
|
|
Except = MSG_EXCEPT,
|
|
|
|
/// Copy (not remove) all queue messages.
|
|
|
|
Copy = MSG_COPY,
|
|
|
|
/// Private key (Special key value).
|
|
|
|
Private = IPC_PRIVATE,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Commands for `msgctl()`
|
|
|
|
#[repr(i32)]
|
|
|
|
pub enum ControlCommands {
|
|
|
|
/// Remove identifier (Control command for `msgctl`, `semctl`, and `shmctl`).
|
|
|
|
Remove = IPC_RMID,
|
|
|
|
/// Set `ipc_perm` options (Control command for `msgctl`, `semctl`, and `shmctl`).
|
|
|
|
SetPerm = IPC_SET,
|
|
|
|
/// Get `ipc_perm` options (Control command for `msgctl`, `semctl`, and `shmctl`).
|
|
|
|
GetPerm = IPC_STAT,
|
|
|
|
/// See ipcs (Control command for `msgctl`, `semctl`, and `shmctl`).
|
|
|
|
IpcInfo = IPC_INFO,
|
|
|
|
/// IPCS control command.
|
|
|
|
Stat = MSG_STAT,
|
|
|
|
/// IPCS control command.
|
|
|
|
MsgInfo = MSG_INFO,
|
|
|
|
}
|
|
|
|
|
2021-07-07 20:48:07 +02:00
|
|
|
pub fn unlink_id(id: i32) -> Result<(), SysvMqError> {
|
|
|
|
let res = unsafe {
|
|
|
|
msgctl(
|
|
|
|
id,
|
|
|
|
ControlCommands::Remove as i32,
|
|
|
|
ptr::null::<msqid_ds>() as *mut msqid_ds,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
match res {
|
|
|
|
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
|
|
|
_ => Ok(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-08 14:20:53 +02:00
|
|
|
pub fn id_from_key(key: i32) -> Result<i32, SysvMqError> {
|
2021-07-07 20:48:07 +02:00
|
|
|
let id = unsafe { msgget(key, 0) };
|
|
|
|
|
2021-07-08 14:20:53 +02:00
|
|
|
match id {
|
|
|
|
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
|
|
|
id => Ok(id),
|
|
|
|
}
|
2021-07-07 20:48:07 +02:00
|
|
|
}
|
|
|
|
|
2021-07-09 00:31:51 +02:00
|
|
|
pub fn ipc_info(id: i32) -> Result<(), SysvMqError> {
|
|
|
|
let mut msginfo = MaybeUninit::<msginfo>::uninit();
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
msgctl(
|
|
|
|
id,
|
|
|
|
ControlCommands::IpcInfo as i32,
|
|
|
|
msginfo.as_mut_ptr() as *mut msqid_ds,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let msginfo = unsafe { msginfo.assume_init() };
|
|
|
|
|
|
|
|
println!("info: {:?}", msginfo);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn stat_info(id: i32) -> Result<(), SysvMqError> {
|
|
|
|
let mut msginfo = MaybeUninit::<msqid_ds>::uninit();
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
msgctl(id, ControlCommands::Stat as i32, msginfo.as_mut_ptr());
|
|
|
|
}
|
|
|
|
|
|
|
|
let msginfo = unsafe { msginfo.assume_init() };
|
|
|
|
|
|
|
|
println!("info: {:?}", msginfo);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn msg_info(id: i32) -> Result<(), SysvMqError> {
|
|
|
|
let mut msginfo = MaybeUninit::<msginfo>::uninit();
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
msgctl(
|
|
|
|
id,
|
|
|
|
ControlCommands::MsgInfo as i32,
|
|
|
|
msginfo.as_mut_ptr() as *mut msqid_ds,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let msginfo = unsafe { msginfo.assume_init() };
|
|
|
|
|
|
|
|
println!("info: {:?}", msginfo);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-07-07 20:23:04 +02:00
|
|
|
pub struct SysvMq<T> {
|
|
|
|
pub id: i32,
|
|
|
|
pub key: i32,
|
|
|
|
message_mask: i32,
|
|
|
|
mode: i32,
|
|
|
|
types: PhantomData<T>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> SysvMq<T> {
|
|
|
|
pub fn create(&mut self, key: i32) -> Result<&Self, SysvMqError> {
|
|
|
|
self.key = key;
|
|
|
|
self.id = unsafe { msgget(self.key, Flags::CreateKey as i32 | self.mode) };
|
|
|
|
|
|
|
|
match self.id {
|
|
|
|
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
|
|
|
_ => Ok(self),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn open(mut self, key: i32) -> Result<Self, SysvMqError> {
|
|
|
|
self.key = key;
|
|
|
|
self.id = unsafe { msgget(self.key, self.mode) };
|
|
|
|
|
|
|
|
match self.id {
|
|
|
|
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
|
|
|
_ => Ok(self),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn mode(&mut self, mode: i32) -> &Self {
|
|
|
|
self.mode = mode;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn nonblocking(&mut self) -> &Self {
|
|
|
|
self.message_mask |= Flags::NoWait as i32;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
SysvMq {
|
|
|
|
id: -1,
|
|
|
|
key: 0,
|
|
|
|
message_mask: 0,
|
|
|
|
mode: 0o644,
|
|
|
|
types: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Default for SysvMq<T> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|