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, 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 // x32 compatibility
38 // See https://sourceware.org/bugzilla/show_bug.cgi?id=21279
39 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
40 pub type mq_attr_member_t = i64;
41 #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
42 pub type mq_attr_member_t = libc::c_long;
43
44 impl MqAttr {
new(mq_flags: mq_attr_member_t, mq_maxmsg: mq_attr_member_t, mq_msgsize: mq_attr_member_t, mq_curmsgs: mq_attr_member_t) -> MqAttr45 pub fn new(mq_flags: mq_attr_member_t,
46 mq_maxmsg: mq_attr_member_t,
47 mq_msgsize: mq_attr_member_t,
48 mq_curmsgs: mq_attr_member_t)
49 -> MqAttr
50 {
51 let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
52 unsafe {
53 let p = attr.as_mut_ptr();
54 (*p).mq_flags = mq_flags;
55 (*p).mq_maxmsg = mq_maxmsg;
56 (*p).mq_msgsize = mq_msgsize;
57 (*p).mq_curmsgs = mq_curmsgs;
58 MqAttr { mq_attr: attr.assume_init() }
59 }
60 }
61
flags(&self) -> mq_attr_member_t62 pub fn flags(&self) -> mq_attr_member_t {
63 self.mq_attr.mq_flags
64 }
65 }
66
67
68 /// Open a message queue
69 ///
70 /// See also [`mq_open(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html)
71 // The mode.bits cast is only lossless on some OSes
72 #[allow(clippy::cast_lossless)]
mq_open(name: &CString, oflag: MQ_OFlag, mode: Mode, attr: Option<&MqAttr>) -> Result<mqd_t>73 pub fn mq_open(name: &CString,
74 oflag: MQ_OFlag,
75 mode: Mode,
76 attr: Option<&MqAttr>)
77 -> Result<mqd_t> {
78 let res = match attr {
79 Some(mq_attr) => unsafe {
80 libc::mq_open(name.as_ptr(),
81 oflag.bits(),
82 mode.bits() as libc::c_int,
83 &mq_attr.mq_attr as *const libc::mq_attr)
84 },
85 None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) },
86 };
87 Errno::result(res)
88 }
89
90 /// Remove a message queue
91 ///
92 /// See also [`mq_unlink(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html)
mq_unlink(name: &CString) -> Result<()>93 pub fn mq_unlink(name: &CString) -> Result<()> {
94 let res = unsafe { libc::mq_unlink(name.as_ptr()) };
95 Errno::result(res).map(drop)
96 }
97
98 /// Close a message queue
99 ///
100 /// See also [`mq_close(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html)
mq_close(mqdes: mqd_t) -> Result<()>101 pub fn mq_close(mqdes: mqd_t) -> Result<()> {
102 let res = unsafe { libc::mq_close(mqdes) };
103 Errno::result(res).map(drop)
104 }
105
106 /// Receive a message from a message queue
107 ///
108 /// 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>109 pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result<usize> {
110 let len = message.len() as size_t;
111 let res = unsafe {
112 libc::mq_receive(mqdes,
113 message.as_mut_ptr() as *mut c_char,
114 len,
115 msg_prio as *mut u32)
116 };
117 Errno::result(res).map(|r| r as usize)
118 }
119
120 /// Send a message to a message queue
121 ///
122 /// 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<()>123 pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> {
124 let res = unsafe {
125 libc::mq_send(mqdes,
126 message.as_ptr() as *const c_char,
127 message.len(),
128 msq_prio)
129 };
130 Errno::result(res).map(drop)
131 }
132
133 /// Get message queue attributes
134 ///
135 /// See also [`mq_getattr(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html)
mq_getattr(mqd: mqd_t) -> Result<MqAttr>136 pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> {
137 let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
138 let res = unsafe { libc::mq_getattr(mqd, attr.as_mut_ptr()) };
139 Errno::result(res).map(|_| unsafe{MqAttr { mq_attr: attr.assume_init() }})
140 }
141
142 /// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored
143 /// Returns the old attributes
144 /// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use
145 ///
146 /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html)
mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr>147 pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> {
148 let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
149 let res = unsafe {
150 libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, attr.as_mut_ptr())
151 };
152 Errno::result(res).map(|_| unsafe{ MqAttr { mq_attr: attr.assume_init() }})
153 }
154
155 /// Convenience function.
156 /// Sets the `O_NONBLOCK` attribute for a given message queue descriptor
157 /// Returns the old attributes
mq_set_nonblock(mqd: mqd_t) -> Result<MqAttr>158 pub fn mq_set_nonblock(mqd: mqd_t) -> Result<MqAttr> {
159 let oldattr = mq_getattr(mqd)?;
160 let newattr = MqAttr::new(mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()),
161 oldattr.mq_attr.mq_maxmsg,
162 oldattr.mq_attr.mq_msgsize,
163 oldattr.mq_attr.mq_curmsgs);
164 mq_setattr(mqd, &newattr)
165 }
166
167 /// Convenience function.
168 /// Removes `O_NONBLOCK` attribute for a given message queue descriptor
169 /// Returns the old attributes
mq_remove_nonblock(mqd: mqd_t) -> Result<MqAttr>170 pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<MqAttr> {
171 let oldattr = mq_getattr(mqd)?;
172 let newattr = MqAttr::new(0,
173 oldattr.mq_attr.mq_maxmsg,
174 oldattr.mq_attr.mq_msgsize,
175 oldattr.mq_attr.mq_curmsgs);
176 mq_setattr(mqd, &newattr)
177 }
178