1 //! Posix Message Queue functions
2 //!
3 //! [Further reading and details on the C API](http://man7.org/linux/man-pages/man7/mq_overview.7.html)
4
5 use crate::Result;
6 use crate::errno::Errno;
7
8 use libc::{self, c_char, c_long, mqd_t, size_t};
9 use std::ffi::CString;
10 use crate::sys::stat::Mode;
11 use std::mem;
12
13 libc_bitflags!{
14 pub struct MQ_OFlag: libc::c_int {
15 O_RDONLY;
16 O_WRONLY;
17 O_RDWR;
18 O_CREAT;
19 O_EXCL;
20 O_NONBLOCK;
21 O_CLOEXEC;
22 }
23 }
24
25 libc_bitflags!{
26 pub struct FdFlag: libc::c_int {
27 FD_CLOEXEC;
28 }
29 }
30
31 #[repr(C)]
32 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
33 pub struct MqAttr {
34 mq_attr: libc::mq_attr,
35 }
36
37 impl MqAttr {
new(mq_flags: c_long, mq_maxmsg: c_long, mq_msgsize: c_long, mq_curmsgs: c_long) -> MqAttr38 pub fn new(mq_flags: c_long,
39 mq_maxmsg: c_long,
40 mq_msgsize: c_long,
41 mq_curmsgs: c_long)
42 -> MqAttr
43 {
44 let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
45 unsafe {
46 let p = attr.as_mut_ptr();
47 (*p).mq_flags = mq_flags;
48 (*p).mq_maxmsg = mq_maxmsg;
49 (*p).mq_msgsize = mq_msgsize;
50 (*p).mq_curmsgs = mq_curmsgs;
51 MqAttr { mq_attr: attr.assume_init() }
52 }
53 }
54
flags(&self) -> c_long55 pub fn flags(&self) -> c_long {
56 self.mq_attr.mq_flags
57 }
58 }
59
60
61 /// Open a message queue
62 ///
63 /// See also [`mq_open(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html)
64 // The mode.bits cast is only lossless on some OSes
65 #[allow(clippy::cast_lossless)]
mq_open(name: &CString, oflag: MQ_OFlag, mode: Mode, attr: Option<&MqAttr>) -> Result<mqd_t>66 pub fn mq_open(name: &CString,
67 oflag: MQ_OFlag,
68 mode: Mode,
69 attr: Option<&MqAttr>)
70 -> Result<mqd_t> {
71 let res = match attr {
72 Some(mq_attr) => unsafe {
73 libc::mq_open(name.as_ptr(),
74 oflag.bits(),
75 mode.bits() as libc::c_int,
76 &mq_attr.mq_attr as *const libc::mq_attr)
77 },
78 None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) },
79 };
80 Errno::result(res)
81 }
82
83 /// Remove a message queue
84 ///
85 /// See also [`mq_unlink(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html)
mq_unlink(name: &CString) -> Result<()>86 pub fn mq_unlink(name: &CString) -> Result<()> {
87 let res = unsafe { libc::mq_unlink(name.as_ptr()) };
88 Errno::result(res).map(drop)
89 }
90
91 /// Close a message queue
92 ///
93 /// See also [`mq_close(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html)
mq_close(mqdes: mqd_t) -> Result<()>94 pub fn mq_close(mqdes: mqd_t) -> Result<()> {
95 let res = unsafe { libc::mq_close(mqdes) };
96 Errno::result(res).map(drop)
97 }
98
99 /// Receive a message from a message queue
100 ///
101 /// See also [`mq_receive(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html)
mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result<usize>102 pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result<usize> {
103 let len = message.len() as size_t;
104 let res = unsafe {
105 libc::mq_receive(mqdes,
106 message.as_mut_ptr() as *mut c_char,
107 len,
108 msg_prio as *mut u32)
109 };
110 Errno::result(res).map(|r| r as usize)
111 }
112
113 /// Send a message to a message queue
114 ///
115 /// See also [`mq_send(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html)
mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()>116 pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> {
117 let res = unsafe {
118 libc::mq_send(mqdes,
119 message.as_ptr() as *const c_char,
120 message.len(),
121 msq_prio)
122 };
123 Errno::result(res).map(drop)
124 }
125
126 /// Get message queue attributes
127 ///
128 /// See also [`mq_getattr(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html)
mq_getattr(mqd: mqd_t) -> Result<MqAttr>129 pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> {
130 let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
131 let res = unsafe { libc::mq_getattr(mqd, attr.as_mut_ptr()) };
132 Errno::result(res).map(|_| unsafe{MqAttr { mq_attr: attr.assume_init() }})
133 }
134
135 /// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored
136 /// Returns the old attributes
137 /// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use
138 ///
139 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html)
mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr>140 pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> {
141 let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
142 let res = unsafe {
143 libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, attr.as_mut_ptr())
144 };
145 Errno::result(res).map(|_| unsafe{ MqAttr { mq_attr: attr.assume_init() }})
146 }
147
148 /// Convenience function.
149 /// Sets the `O_NONBLOCK` attribute for a given message queue descriptor
150 /// Returns the old attributes
mq_set_nonblock(mqd: mqd_t) -> Result<MqAttr>151 pub fn mq_set_nonblock(mqd: mqd_t) -> Result<MqAttr> {
152 let oldattr = mq_getattr(mqd)?;
153 let newattr = MqAttr::new(c_long::from(MQ_OFlag::O_NONBLOCK.bits()),
154 oldattr.mq_attr.mq_maxmsg,
155 oldattr.mq_attr.mq_msgsize,
156 oldattr.mq_attr.mq_curmsgs);
157 mq_setattr(mqd, &newattr)
158 }
159
160 /// Convenience function.
161 /// Removes `O_NONBLOCK` attribute for a given message queue descriptor
162 /// Returns the old attributes
mq_remove_nonblock(mqd: mqd_t) -> Result<MqAttr>163 pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<MqAttr> {
164 let oldattr = mq_getattr(mqd)?;
165 let newattr = MqAttr::new(0,
166 oldattr.mq_attr.mq_maxmsg,
167 oldattr.mq_attr.mq_msgsize,
168 oldattr.mq_attr.mq_curmsgs);
169 mq_setattr(mqd, &newattr)
170 }
171