Compare commits
3 commits
4978f37168
...
602799fa11
Author | SHA1 | Date | |
---|---|---|---|
finga | 602799fa11 | ||
finga | 599c585b42 | ||
finga | 31b2ebbf9e |
52
Cargo.lock
generated
52
Cargo.lock
generated
|
@ -88,9 +88,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
|
@ -129,9 +129,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.6"
|
||||
version = "4.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
|
||||
checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -139,9 +139,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.6"
|
||||
version = "4.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
|
||||
checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -151,9 +151,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.4.2"
|
||||
version = "4.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
|
||||
checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
|
@ -163,9 +163,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.1"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
|
||||
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
|
@ -222,16 +222,16 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
|||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.57"
|
||||
version = "0.1.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
|
||||
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -356,9 +356,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.1"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaac441002f822bc9705a681810a4dd2963094b9ca0ddc41cb963a4c189189ea"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -368,9 +368,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5011c7e263a695dc8ca064cddb722af1be54e517a280b12a5356f98366899e5d"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -385,9 +385,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.19"
|
||||
version = "0.38.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
|
@ -433,18 +433,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.49"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.49"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -549,10 +549,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.48.0"
|
||||
name = "windows-core"
|
||||
version = "0.51.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
|
28
src/main.rs
28
src/main.rs
|
@ -1,5 +1,7 @@
|
|||
use anyhow::Result;
|
||||
use clap::{ArgAction, Parser};
|
||||
use clap::Parser;
|
||||
use log::Level;
|
||||
use std::env;
|
||||
|
||||
mod posix;
|
||||
mod sysv;
|
||||
|
@ -30,6 +32,8 @@ enum SysvCommand {
|
|||
Info(sysv::Info),
|
||||
List(sysv::List),
|
||||
Unlink(sysv::Unlink),
|
||||
Send(sysv::Send),
|
||||
Recv(sysv::Recv),
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
|
@ -39,9 +43,9 @@ enum SysvCommand {
|
|||
subcommand_required = true
|
||||
)]
|
||||
struct Opts {
|
||||
/// Produce verbose output, multiple -v options increase the verbosity (max. 3)
|
||||
#[clap(short, long, global = true, action = ArgAction::Count)]
|
||||
verbose: u32,
|
||||
/// Set a log level
|
||||
#[arg(short, long, value_name = "LEVEL", default_value_t = Level::Info)]
|
||||
pub log_level: Level,
|
||||
/// Backend to be used
|
||||
#[clap(subcommand)]
|
||||
backend: Backend,
|
||||
|
@ -50,15 +54,11 @@ struct Opts {
|
|||
fn main() -> Result<()> {
|
||||
let opts: Opts = Opts::parse();
|
||||
|
||||
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(
|
||||
match opts.verbose {
|
||||
0 => "warn",
|
||||
1 => "info",
|
||||
2 => "debug",
|
||||
_ => "trace",
|
||||
},
|
||||
))
|
||||
.init();
|
||||
if env::var("RUST_LOG").is_err() {
|
||||
env::set_var("RUST_LOG", format!("{}", opts.log_level));
|
||||
}
|
||||
|
||||
env_logger::init();
|
||||
|
||||
match opts.backend {
|
||||
Backend::Posix(p) => match p {
|
||||
|
@ -74,6 +74,8 @@ fn main() -> Result<()> {
|
|||
SysvCommand::Info(i) => i.run()?,
|
||||
SysvCommand::List(l) => l.run()?,
|
||||
SysvCommand::Unlink(u) => u.run()?,
|
||||
SysvCommand::Send(s) => s.run()?,
|
||||
SysvCommand::Recv(r) => r.run()?,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
mod create;
|
||||
mod info;
|
||||
mod list;
|
||||
mod recv;
|
||||
mod send;
|
||||
mod unlink;
|
||||
|
||||
pub use create::Create;
|
||||
pub use info::Info;
|
||||
pub use list::List;
|
||||
pub use recv::Recv;
|
||||
pub use send::Send;
|
||||
pub use unlink::Unlink;
|
||||
|
|
42
src/sysv/recv.rs
Normal file
42
src/sysv/recv.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use anyhow::Result;
|
||||
// use chrono::DateTime;
|
||||
use clap::Parser;
|
||||
// use humantime::Duration;
|
||||
use log::info;
|
||||
use sysvmq::SysvMq;
|
||||
|
||||
/// Send a message to a message queue
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Recv {
|
||||
// /// Set a different priority, priority >= 0
|
||||
// #[clap(short, long, default_value = "0")]
|
||||
// priority: u32,
|
||||
// /// Do not block
|
||||
// #[clap(short, long)]
|
||||
// non_blocking: bool,
|
||||
// /// Timeout, example "5h 23min 42ms"
|
||||
// #[clap(short = 'o', long, conflicts_with = "deadline")]
|
||||
// timeout: Option<String>,
|
||||
// /// Deadline until messages are sent (format: "%Y-%m-%d %H:%M:%S")
|
||||
// #[clap(short, long, conflicts_with = "timeout")]
|
||||
// deadline: Option<String>,
|
||||
// /// Name of the queue
|
||||
// #[clap(value_name = "QUEUE")]
|
||||
// queue: String,
|
||||
/// Key of of the queue to write to
|
||||
#[clap(value_name = "Key")]
|
||||
key: i32,
|
||||
// /// Message to be sent to the queue
|
||||
// #[clap(value_name = "MESSAGE")]
|
||||
// msg: String,
|
||||
}
|
||||
|
||||
impl Recv {
|
||||
pub fn run(&self) -> Result<()> {
|
||||
let mq = SysvMq::<String>::new();
|
||||
|
||||
mq.open(self.key)?.recv();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
42
src/sysv/send.rs
Normal file
42
src/sysv/send.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use anyhow::Result;
|
||||
// use chrono::DateTime;
|
||||
use clap::Parser;
|
||||
// use humantime::Duration;
|
||||
use log::info;
|
||||
use sysvmq::SysvMq;
|
||||
|
||||
/// Send a message to a message queue
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Send {
|
||||
// /// Set a different priority, priority >= 0
|
||||
// #[clap(short, long, default_value = "0")]
|
||||
// priority: u32,
|
||||
// /// Do not block
|
||||
// #[clap(short, long)]
|
||||
// non_blocking: bool,
|
||||
// /// Timeout, example "5h 23min 42ms"
|
||||
// #[clap(short = 'o', long, conflicts_with = "deadline")]
|
||||
// timeout: Option<String>,
|
||||
// /// Deadline until messages are sent (format: "%Y-%m-%d %H:%M:%S")
|
||||
// #[clap(short, long, conflicts_with = "timeout")]
|
||||
// deadline: Option<String>,
|
||||
// /// Name of the queue
|
||||
// #[clap(value_name = "QUEUE")]
|
||||
// queue: String,
|
||||
/// Key of of the queue to write to
|
||||
#[clap(value_name = "Key")]
|
||||
key: i32,
|
||||
/// Message to be sent to the queue
|
||||
#[clap(value_name = "MESSAGE")]
|
||||
msg: String,
|
||||
}
|
||||
|
||||
impl Send {
|
||||
pub fn run(&self) -> Result<()> {
|
||||
let mq = SysvMq::<String>::new();
|
||||
|
||||
mq.open(self.key)?.send(self.msg.as_bytes());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -8,8 +8,37 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Basic tests to create, send, receive and delete a message queue as
|
||||
well as changing the mode of a queue.
|
||||
- The functions `SysvMq::stat()`, `SysvMq::info()`,
|
||||
`SysvMq::msg_stat()` and `SysvMq::msg_info()` are added to receive
|
||||
parameters of a queue.
|
||||
- The function `new()` passes now a key which is used for the new
|
||||
message queue.
|
||||
- A basic test to test the happy path of a queue.
|
||||
- The function `get()` to gather facts from a message queue.
|
||||
- The function `set()` to set facts of a message queue.
|
||||
- The function `create()` to create a message queue.
|
||||
- The functions `send()` and `SysvMq::send()` to send messages to a
|
||||
queue.
|
||||
- The functions `recv()` and `SysvMq::recv()` to receive messages from
|
||||
a queue.
|
||||
- The function `SysvMq::delete()` to delete a queue.
|
||||
|
||||
### Changed
|
||||
|
||||
- The function `SysvMq::mode()` now also updates the message queue
|
||||
accordingly.
|
||||
- Remove `PhantomData` from the `SysvMq` struct.
|
||||
- The function `SysvMq::create()` is replaced by `SysvMq::new()`.
|
||||
- Remove generic type for `SysvMq`.
|
||||
- Rename `unlink_id()` to `delete()`.
|
||||
- Update to the latest verscion of `nix`.
|
||||
- Fix several clippy findings in preperation to enable several lint
|
||||
groups.
|
||||
|
||||
### Removed
|
||||
|
||||
- The function `id_from_key()` was removed.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "sysvmq"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
authors = ["finga <mqrs@onders.org>"]
|
||||
repository = "https://git.onders.org/finga/mqrs"
|
||||
license = "GPL-3.0-or-later"
|
||||
|
|
|
@ -1,24 +1,111 @@
|
|||
#![allow(clippy::doc_markdown)]
|
||||
//! This library provides a convenient API to SysV IPC message queues.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! use sysvmq::SysvMq;
|
||||
//!
|
||||
//! let mut mq = SysvMq::new(0).expect("could not create message queue");
|
||||
//! mq.send(b"hello queue").expect("could not send message to message queue");
|
||||
//! mq.delete().expect("could not delete message queue");
|
||||
//! ```
|
||||
|
||||
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,
|
||||
IPC_SET, IPC_STAT, MSG_INFO, MSG_STAT,
|
||||
};
|
||||
use nix::errno::{errno, Errno};
|
||||
use std::{marker::PhantomData, mem::MaybeUninit, ptr};
|
||||
use std::{convert::TryFrom, mem::MaybeUninit, ptr};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
/// An enum containing all errors
|
||||
pub enum SysvMqError {
|
||||
#[error("SysV message queue: {0}")]
|
||||
ErrnoError(&'static str),
|
||||
#[error("Cannot convert integer")]
|
||||
From(#[from] std::num::TryFromIntError),
|
||||
}
|
||||
|
||||
#[allow(clippy::doc_markdown)]
|
||||
/// Unlink (delete) an existing SysV IPC message queue.
|
||||
/// Create a new SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return an `SysvMqError` when no queue with the given key can be
|
||||
/// Return `SysvMqError` when the queue cannot be created.
|
||||
pub fn create(key: i32, mode: i32) -> Result<i32, SysvMqError> {
|
||||
let mq = unsafe { msgget(key, IPC_CREAT | mode) };
|
||||
|
||||
match mq {
|
||||
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
||||
id => Ok(id),
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a message to a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the message cannot be sent to the queue.
|
||||
pub fn send(id: i32, msg: &[u8], mask: i32) -> Result<(), SysvMqError> {
|
||||
match unsafe { msgsnd(id, msg.as_ptr().cast::<c_void>(), msg.len(), mask) } {
|
||||
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Receive a message from a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the message cannot be received from the
|
||||
/// queue.
|
||||
pub fn recv(id: i32, msg: &mut [u8], mask: i32) -> Result<(), SysvMqError> {
|
||||
match unsafe { msgrcv(id, msg.as_mut_ptr().cast::<c_void>(), msg.len(), 0, mask) } {
|
||||
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get parameters about a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the parameters cannot be gathered.
|
||||
pub fn get(id: i32, cmd: i32) -> Result<msqid_ds, SysvMqError> {
|
||||
let mut ipc_info = MaybeUninit::<msqid_ds>::uninit();
|
||||
let ret;
|
||||
|
||||
let ipc_info = unsafe {
|
||||
ret = msgctl(id, cmd, ipc_info.as_mut_ptr());
|
||||
ipc_info.assume_init()
|
||||
};
|
||||
|
||||
match ret {
|
||||
0 => Ok(ipc_info),
|
||||
_ => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set parameters about a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the parameters cannot be set.
|
||||
pub fn set(id: i32, cmd: i32, data: &mut msqid_ds) -> Result<(), SysvMqError> {
|
||||
match unsafe { msgctl(id, cmd, data) } {
|
||||
0 => Ok(()),
|
||||
_ => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Delete a SysV IPC message queue by id.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when no queue with the given key can be
|
||||
/// found.
|
||||
pub fn unlink_id(id: i32) -> Result<(), SysvMqError> {
|
||||
pub fn delete(id: i32) -> Result<(), SysvMqError> {
|
||||
let res = unsafe { msgctl(id, IPC_RMID, ptr::null::<msqid_ds>().cast_mut()) };
|
||||
|
||||
match res {
|
||||
|
@ -27,127 +114,137 @@ pub fn unlink_id(id: i32) -> Result<(), SysvMqError> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::doc_markdown)]
|
||||
/// Get the id of an existing SysV IPC message queue by passing its
|
||||
/// key.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return an `SysvMqError` when no queue with the given key can be
|
||||
/// found.
|
||||
pub fn id_from_key(key: i32) -> Result<i32, SysvMqError> {
|
||||
let id = unsafe { msgget(key, 0) };
|
||||
#[derive(Clone)]
|
||||
/// Struct representation of a Message Queue
|
||||
pub struct SysvMq {
|
||||
pub key: i32,
|
||||
pub id: i32,
|
||||
pub mask: i32,
|
||||
pub mode: i32,
|
||||
}
|
||||
|
||||
match id {
|
||||
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
||||
id => Ok(id),
|
||||
impl Default for SysvMq {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
key: 0,
|
||||
id: -1,
|
||||
mask: 0,
|
||||
mode: 0o644,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::doc_markdown)]
|
||||
/// Get the info about an existing SysV IPC message queue.
|
||||
pub fn ipc_info(id: i32) {
|
||||
let mut ipc_info = MaybeUninit::<msqid_ds>::uninit();
|
||||
|
||||
let ipc_info = unsafe {
|
||||
msgctl(id, IPC_INFO, ipc_info.as_mut_ptr());
|
||||
ipc_info.assume_init()
|
||||
};
|
||||
|
||||
println!("info: {ipc_info:?}");
|
||||
}
|
||||
|
||||
#[allow(clippy::doc_markdown)]
|
||||
/// Get the stats about an existing SysV IPC message queue.
|
||||
pub fn stat_info(id: i32) {
|
||||
let mut stat_info = MaybeUninit::<msqid_ds>::uninit();
|
||||
|
||||
let stat_info = unsafe {
|
||||
msgctl(id, MSG_STAT, stat_info.as_mut_ptr());
|
||||
stat_info.assume_init()
|
||||
};
|
||||
|
||||
println!("info: {stat_info:?}");
|
||||
}
|
||||
|
||||
#[allow(clippy::doc_markdown)]
|
||||
/// Get the message info about an existing SysV IPC message queue.
|
||||
pub fn msg_info(id: i32) {
|
||||
let mut msg_info = MaybeUninit::<msqid_ds>::uninit();
|
||||
|
||||
let msg_info = unsafe {
|
||||
msgctl(id, MSG_INFO, msg_info.as_mut_ptr());
|
||||
msg_info.assume_init()
|
||||
};
|
||||
|
||||
println!("info: {msg_info:?}");
|
||||
}
|
||||
|
||||
pub struct SysvMq<T> {
|
||||
pub id: i32,
|
||||
pub key: i32,
|
||||
message_mask: i32,
|
||||
mode: i32,
|
||||
types: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> SysvMq<T> {
|
||||
/// Create a new message queye with the given key.
|
||||
impl SysvMq {
|
||||
/// Create a new message SysV IPC message queue 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) };
|
||||
|
||||
match self.id {
|
||||
-1 => Err(SysvMqError::ErrnoError(Errno::from_i32(errno()).desc())),
|
||||
_ => Ok(self),
|
||||
}
|
||||
/// Return `SysvMqError` when the queue cannot be created.
|
||||
pub fn new(key: i32) -> Result<Self, SysvMqError> {
|
||||
let mut mq = Self::default();
|
||||
mq.key = key;
|
||||
mq.id = create(mq.key, mq.mode)?;
|
||||
Ok(mq)
|
||||
}
|
||||
|
||||
/// Open an existing message queye with the given key.
|
||||
/// Open an existing SysV IPC message queye with the given key.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the queue cannot be opened.
|
||||
pub fn open(key: i32, id: i32) -> Result<Self, SysvMqError> {
|
||||
let mut mq = Self::default();
|
||||
mq.key = key;
|
||||
mq.id = id;
|
||||
mq.mode = i32::from(get(mq.id, IPC_STAT)?.msg_perm.mode);
|
||||
Ok(mq)
|
||||
}
|
||||
|
||||
/// Set the mode of a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the mode of the queue cannot be set.
|
||||
pub fn mode(&mut self, mode: i32) -> Result<(), SysvMqError> {
|
||||
self.mode = mode;
|
||||
let mut stats = get(self.id, IPC_STAT)?;
|
||||
stats.msg_perm.mode = u16::try_from(self.mode)?;
|
||||
set(self.id, IPC_SET, &mut stats)
|
||||
}
|
||||
|
||||
/// Set the mask of a SysV IPC message queue to nonblocking
|
||||
/// (`IPC_NOWAIT`).
|
||||
pub fn nonblocking(&mut self) {
|
||||
self.mask |= IPC_NOWAIT;
|
||||
}
|
||||
|
||||
/// Send a message to a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the message cannot be sent to the queue.
|
||||
pub fn send(&mut self, msg: &[u8]) -> Result<(), SysvMqError> {
|
||||
send(self.id, msg, self.mask)
|
||||
}
|
||||
|
||||
/// Receive a message from a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the message cannot be received from the
|
||||
/// queue.
|
||||
pub fn recv(&mut self, msg: &mut [u8]) -> Result<(), SysvMqError> {
|
||||
recv(self.id, msg, self.mask)
|
||||
}
|
||||
|
||||
/// Receive stats from a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the stats cannot be gathered from
|
||||
/// the queue.
|
||||
pub fn stat(&self) -> Result<msqid_ds, SysvMqError> {
|
||||
get(self.id, IPC_STAT)
|
||||
}
|
||||
|
||||
/// Receive info from a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the info cannot be gathered from the
|
||||
/// queue.
|
||||
pub fn info(&self) -> Result<msqid_ds, SysvMqError> {
|
||||
get(self.id, IPC_INFO)
|
||||
}
|
||||
|
||||
/// Receive message stats from a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the message stats cannot be gathered
|
||||
/// from the queue.
|
||||
pub fn msg_stat(&self) -> Result<msqid_ds, SysvMqError> {
|
||||
get(self.id, MSG_STAT)
|
||||
}
|
||||
|
||||
/// Receive message info from a SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return `SysvMqError` when the message info cannot be gathered
|
||||
/// from the queue.
|
||||
pub fn msg_info(&self) -> Result<msqid_ds, SysvMqError> {
|
||||
get(self.id, MSG_INFO)
|
||||
}
|
||||
|
||||
/// Delete an existing SysV IPC message queue.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Return an `SysvMqError` when no queue with the given key can be
|
||||
/// found.
|
||||
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 |= IPC_NOWAIT;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
id: -1,
|
||||
key: 0,
|
||||
message_mask: 0,
|
||||
mode: 0o644,
|
||||
types: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for SysvMq<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
pub fn delete(&mut self) -> Result<(), SysvMqError> {
|
||||
delete(self.id)
|
||||
}
|
||||
}
|
||||
|
|
68
sysvmq/tests/main.rs
Normal file
68
sysvmq/tests/main.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use sysvmq::SysvMq;
|
||||
|
||||
#[test]
|
||||
fn new_send_recv_delete() {
|
||||
let mut mq = 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];
|
||||
mq.send(msg)
|
||||
.expect("could not send message to SysV message queue");
|
||||
mq.recv(&mut buf)
|
||||
.expect("could not receive message from SysV message queue");
|
||||
mq.delete().expect("could not destroy SysV message queue");
|
||||
assert_eq!(msg, &buf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn separate_send_recv_clone() {
|
||||
let mut sender = SysvMq::new(0).expect("could not create SysV message queue with key 0");
|
||||
let mut receiver = sender.clone();
|
||||
let msg = b"this is another test";
|
||||
let mut buf = [0u8; 20];
|
||||
sender
|
||||
.send(msg)
|
||||
.expect("could not send message to SysV message queue");
|
||||
receiver
|
||||
.recv(&mut buf)
|
||||
.expect("could not receive message from SysV message queue");
|
||||
sender
|
||||
.delete()
|
||||
.expect("could not destroy SysV message queue");
|
||||
assert_eq!(msg, &buf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn separate_send_recv_open() {
|
||||
let mut sender = SysvMq::new(0).expect("could not create SysV message queue with key 0");
|
||||
let mut receiver = SysvMq::open(sender.key, sender.id)
|
||||
.expect("could not create second handle to SysV message queue");
|
||||
let msg = b"this is another test";
|
||||
let mut buf = [0u8; 20];
|
||||
sender
|
||||
.send(msg)
|
||||
.expect("could not send message to SysV message queue");
|
||||
receiver
|
||||
.recv(&mut buf)
|
||||
.expect("could not receive message from SysV message queue");
|
||||
sender
|
||||
.delete()
|
||||
.expect("could not destroy SysV message queue");
|
||||
assert_eq!(msg, &buf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn change_mode() {
|
||||
let mut mq = SysvMq::new(0).expect("could not create SysV message queue with key 0");
|
||||
let init_stats = mq
|
||||
.stat()
|
||||
.expect("could not get stats from SysV message queue");
|
||||
mq.mode(0o666)
|
||||
.expect("could not set mode of SysV message queue");
|
||||
let new_stats = mq
|
||||
.stat()
|
||||
.expect("could not get stats from SysV message queue");
|
||||
mq.delete().expect("could not destroy SysV message queue");
|
||||
|
||||
assert_eq!(0o644, init_stats.msg_perm.mode);
|
||||
assert_eq!(0o666, new_stats.msg_perm.mode);
|
||||
}
|
Loading…
Reference in a new issue