Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some changes to RawFdContainer #386

Merged
merged 1 commit into from
May 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 69 additions & 45 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
use std::mem::forget;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};

#[cfg(not(unix))]
type RawFd = std::os::raw::c_int;

#[cfg(feature = "allow-unsafe-code")]
mod unsafe_code {
use std::mem::forget;
Expand Down Expand Up @@ -93,55 +86,86 @@ mod unsafe_code {
#[cfg(feature = "allow-unsafe-code")]
pub use unsafe_code::CSlice;

/// A simple wrapper around RawFd that closes the fd on drop.
#[derive(Debug, Hash, PartialEq, Eq)]
pub struct RawFdContainer(RawFd);
#[cfg(unix)]
mod raw_fd_container {
use std::mem::forget;
#[cfg(unix)]
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};

/// A simple wrapper around RawFd that closes the fd on drop.
///
/// On non-unix systems, this type is empty and does not provide
/// any method.
#[derive(Debug, Hash, PartialEq, Eq)]
pub struct RawFdContainer(RawFd);

impl Drop for RawFdContainer {
fn drop(&mut self) {
#[cfg(unix)]
{
use nix::unistd::close;
close(self.0).expect("Close failed in some RawFdContainer");
impl Drop for RawFdContainer {
fn drop(&mut self) {
let _ = nix::unistd::close(self.0);
}
}
}

impl RawFdContainer {
/// Create a new `RawFdContainer` for the given `RawFd`.
///
/// The `RawFdContainer` takes ownership of the `RawFd` and closes it on drop.
///
/// This function panics on non-unix systems.
pub fn new(fd: RawFd) -> RawFdContainer {
if cfg!(unix) {
impl RawFdContainer {
/// Create a new `RawFdContainer` for the given `RawFd`.
///
/// The `RawFdContainer` takes ownership of the `RawFd` and closes it on drop.
pub fn new(fd: RawFd) -> Self {
RawFdContainer(fd)
} else {
unimplemented!("RawFdContainer is only implemented on Unix-like systems");
}

/// Tries to clone the `RawFdContainer` creating a new FD
/// with `dup`. The new `RawFdContainer` will take ownership
/// of the `dup`ed version, whereas the original `RawFdContainer`
/// will keep the ownership of its FD.
pub fn try_clone(&self) -> Result<Self, std::io::Error> {
Ok(Self::new(
nix::unistd::dup(self.0).map_err(|_| std::io::Error::last_os_error())?,
))
}

/// Get the `RawFd` out of this `RawFdContainer`.
///
/// This function would be an implementation of `IntoRawFd` if that were possible. However, it
/// causes a conflict with an `impl` from libcore...
pub fn into_raw_fd(self) -> RawFd {
let fd = self.0;
forget(self);
fd
}

/// Consumes the `RawFdContainer` and closes the wrapped FD with
/// the `close` system call.
///
/// This is similar to dropping the `RawFdContainer`, but it allows
/// the caller to handle errors.
pub fn close(self) -> Result<(), std::io::Error> {
let fd = self.into_raw_fd();
nix::unistd::close(fd).map_err(|_| std::io::Error::last_os_error())
}
}

/// Get the `RawFd` out of this `RawFdContainer`.
///
/// This function would be an implementation of `IntoRawFd` if that were possible. However, it
/// causes a conflict with an `impl` from libcore...
pub fn into_raw_fd(self) -> RawFd {
let fd = self.0;
forget(self);
fd
impl<T: IntoRawFd> From<T> for RawFdContainer {
fn from(fd: T) -> Self {
Self::new(fd.into_raw_fd())
}
}
}

#[cfg(unix)]
impl<T: IntoRawFd> From<T> for RawFdContainer {
fn from(fd: T) -> RawFdContainer {
RawFdContainer::new(fd.into_raw_fd())
impl AsRawFd for RawFdContainer {
fn as_raw_fd(&self) -> RawFd {
self.0
}
}
}

#[cfg(unix)]
impl AsRawFd for RawFdContainer {
fn as_raw_fd(&self) -> RawFd {
self.0
}
#[cfg(not(unix))]
mod raw_fd_container {
/// A simple wrapper around RawFd that closes the fd on drop.
///
/// On non-unix systems, this type is empty and does not provide
/// any method.
#[allow(missing_copy_implementations)]
#[derive(Debug, Hash, PartialEq, Eq)]
pub struct RawFdContainer(());
}

pub use raw_fd_container::RawFdContainer;
39 changes: 23 additions & 16 deletions src/xcb_ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,19 +212,26 @@ impl XCBConnection {
)
}
} else {
// Convert the FDs into an array of ints. libxcb will close the FDs.
let mut fds: Vec<_> = fds.into_iter().map(RawFdContainer::into_raw_fd).collect();
let num_fds = fds.len().try_into().unwrap();
let fds_ptr = fds.as_mut_ptr();
unsafe {
raw_ffi::xcb_send_request_with_fds64(
self.conn.as_ptr(),
flags,
&mut new_bufs_ffi[2],
&protocol_request,
num_fds,
fds_ptr,
)
#[cfg(unix)]
{
// Convert the FDs into an array of ints. libxcb will close the FDs.
let mut fds: Vec<_> = fds.into_iter().map(RawFdContainer::into_raw_fd).collect();
let num_fds = fds.len().try_into().unwrap();
let fds_ptr = fds.as_mut_ptr();
unsafe {
raw_ffi::xcb_send_request_with_fds64(
self.conn.as_ptr(),
flags,
&mut new_bufs_ffi[2],
&protocol_request,
num_fds,
fds_ptr,
)
}
}
#[cfg(not(unix))]
{
unreachable!("it is not possible to create a `RawFdContainer` on non-unix");
}
};
if seqno == 0 {
Expand Down Expand Up @@ -451,10 +458,10 @@ impl RequestConnection for XCBConnection {
let fd_ptr = (unsafe { buffer.as_ptr().add(buffer.len()) }) as *const RawFd;

// The number of FDs is in the second byte (= buffer[1]) in all replies.
let vector = unsafe { std::slice::from_raw_parts(fd_ptr, usize::from(buffer[1])) };
let vector = vector.iter().map(|&fd| RawFdContainer::new(fd)).collect();
let fd_slice = unsafe { std::slice::from_raw_parts(fd_ptr, usize::from(buffer[1])) };
let fd_vec = fd_slice.iter().map(|&fd| RawFdContainer::new(fd)).collect();

Ok(ReplyOrError::Reply((buffer, vector)))
Ok(ReplyOrError::Reply((buffer, fd_vec)))
}

#[cfg(not(unix))]
Expand Down
2 changes: 2 additions & 0 deletions src/xcb_ffi/raw_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ extern "C" {
vector: *mut iovec,
request: *const xcb_protocol_request_t,
) -> u64;
#[cfg(unix)]
pub(crate) fn xcb_send_request_with_fds64(
c: *mut xcb_connection_t,
flags: c_int,
Expand Down Expand Up @@ -305,6 +306,7 @@ mod mock {
unimplemented!();
}

#[cfg(unix)]
pub(crate) unsafe fn xcb_send_request_with_fds64(
_c: *mut xcb_connection_t,
_flags: c_int,
Expand Down