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 Result;
6 use errno::Errno;
7 
8 use libc::{self, c_char, c_long, mqd_t, size_t};
9 use std::ffi::CString;
10 use 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