summaryrefslogtreecommitdiffstats
path: root/third_party/rust/audioipc/src/msg.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/audioipc/src/msg.rs
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/audioipc/src/msg.rs')
-rw-r--r--third_party/rust/audioipc/src/msg.rs115
1 files changed, 115 insertions, 0 deletions
diff --git a/third_party/rust/audioipc/src/msg.rs b/third_party/rust/audioipc/src/msg.rs
new file mode 100644
index 0000000000..e50734d3e4
--- /dev/null
+++ b/third_party/rust/audioipc/src/msg.rs
@@ -0,0 +1,115 @@
+// Copyright © 2017 Mozilla Foundation
+//
+// This program is made available under an ISC-style license. See the
+// accompanying file LICENSE for details.
+
+use iovec::unix;
+use iovec::IoVec;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::{cmp, io, mem, ptr};
+
+// Extend sys::os::unix::net::UnixStream to support sending and receiving a single file desc.
+// We can extend UnixStream by using traits, eliminating the need to introduce a new wrapped
+// UnixStream type.
+pub trait RecvMsg {
+ fn recv_msg(
+ &mut self,
+ iov: &mut [&mut IoVec],
+ cmsg: &mut [u8],
+ ) -> io::Result<(usize, usize, i32)>;
+}
+
+pub trait SendMsg {
+ fn send_msg(&mut self, iov: &[&IoVec], cmsg: &[u8]) -> io::Result<usize>;
+}
+
+impl<T: AsRawFd> RecvMsg for T {
+ fn recv_msg(
+ &mut self,
+ iov: &mut [&mut IoVec],
+ cmsg: &mut [u8],
+ ) -> io::Result<(usize, usize, i32)> {
+ #[cfg(target_os = "linux")]
+ let flags = libc::MSG_CMSG_CLOEXEC;
+ #[cfg(not(target_os = "linux"))]
+ let flags = 0;
+ recv_msg_with_flags(self.as_raw_fd(), iov, cmsg, flags)
+ }
+}
+
+impl<T: AsRawFd> SendMsg for T {
+ fn send_msg(&mut self, iov: &[&IoVec], cmsg: &[u8]) -> io::Result<usize> {
+ send_msg_with_flags(self.as_raw_fd(), iov, cmsg, 0)
+ }
+}
+
+fn cvt(r: libc::ssize_t) -> io::Result<usize> {
+ if r == -1 {
+ Err(io::Error::last_os_error())
+ } else {
+ Ok(r as usize)
+ }
+}
+
+// Convert return of -1 into error message, handling retry on EINTR
+fn cvt_r<F: FnMut() -> libc::ssize_t>(mut f: F) -> io::Result<usize> {
+ loop {
+ match cvt(f()) {
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ other => return other,
+ }
+ }
+}
+
+pub fn recv_msg_with_flags(
+ socket: RawFd,
+ bufs: &mut [&mut IoVec],
+ cmsg: &mut [u8],
+ flags: libc::c_int,
+) -> io::Result<(usize, usize, libc::c_int)> {
+ let slice = unix::as_os_slice_mut(bufs);
+ let len = cmp::min(<libc::c_int>::max_value() as usize, slice.len());
+ let (control, controllen) = if cmsg.is_empty() {
+ (ptr::null_mut(), 0)
+ } else {
+ (cmsg.as_ptr() as *mut _, cmsg.len())
+ };
+
+ let mut msghdr: libc::msghdr = unsafe { mem::zeroed() };
+ msghdr.msg_name = ptr::null_mut();
+ msghdr.msg_namelen = 0;
+ msghdr.msg_iov = slice.as_mut_ptr();
+ msghdr.msg_iovlen = len as _;
+ msghdr.msg_control = control;
+ msghdr.msg_controllen = controllen as _;
+
+ let n = cvt_r(|| unsafe { libc::recvmsg(socket, &mut msghdr as *mut _, flags) })?;
+
+ let controllen = msghdr.msg_controllen as usize;
+ Ok((n, controllen, msghdr.msg_flags))
+}
+
+pub fn send_msg_with_flags(
+ socket: RawFd,
+ bufs: &[&IoVec],
+ cmsg: &[u8],
+ flags: libc::c_int,
+) -> io::Result<usize> {
+ let slice = unix::as_os_slice(bufs);
+ let len = cmp::min(<libc::c_int>::max_value() as usize, slice.len());
+ let (control, controllen) = if cmsg.is_empty() {
+ (ptr::null_mut(), 0)
+ } else {
+ (cmsg.as_ptr() as *mut _, cmsg.len())
+ };
+
+ let mut msghdr: libc::msghdr = unsafe { mem::zeroed() };
+ msghdr.msg_name = ptr::null_mut();
+ msghdr.msg_namelen = 0;
+ msghdr.msg_iov = slice.as_ptr() as *mut _;
+ msghdr.msg_iovlen = len as _;
+ msghdr.msg_control = control;
+ msghdr.msg_controllen = controllen as _;
+
+ cvt_r(|| unsafe { libc::sendmsg(socket, &msghdr as *const _, flags) })
+}