2021-07-07 20:23:04 +02:00
|
|
|
use libc::{
|
2021-07-07 20:48:07 +02:00
|
|
|
msgctl, msgget, 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-07 20:48:07 +02:00
|
|
|
use std::{marker::PhantomData, num::ParseIntError, 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),
|
|
|
|
#[error("No message queue found with key {0}")]
|
|
|
|
KeyNotFound(i32),
|
|
|
|
#[error("IO Error: {0}")]
|
|
|
|
IoError(#[from] std::io::Error),
|
|
|
|
#[error("Parse Error: {0}")]
|
|
|
|
ParserError(#[from] ParseIntError),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn unlink_key(key: i32) -> Result<(), SysvMqError> {
|
|
|
|
let id = unsafe { msgget(key, 0) };
|
|
|
|
|
|
|
|
unlink_id(id)
|
|
|
|
}
|
|
|
|
|
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()
|
|
|
|
}
|
|
|
|
}
|