Skip to content

Commit

Permalink
WIP port from nix to rustix
Browse files Browse the repository at this point in the history
  • Loading branch information
ids1024 committed Oct 4, 2023
1 parent 8581b9d commit 4dcef4b
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 107 deletions.
13 changes: 7 additions & 6 deletions wayland-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ log = { version = "0.4", optional = true }
scoped-tls = "1.0"
downcast-rs = "1.2"
raw-window-handle = { version = "0.5.0", optional = true }
libc = "0.2.148"

[dependencies.smallvec]
version = "1.9"
Expand All @@ -29,15 +30,15 @@ features = [
"const_new", # 1.51
]

[dependencies.nix]
version = "0.26.0"
default-features = false
[dependencies.rustix]
# version = "0.38.0"
git = "https://github.com/ids1024/rustix"
branch = "peercred"
features = [
"event",
"fs",
"poll",
"socket",
"uio",
"net",
"process",
]

[build-dependencies]
Expand Down
23 changes: 13 additions & 10 deletions wayland-backend/src/rs/server_impl/client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{
ffi::CString,
os::unix::io::OwnedFd,
os::unix::io::{AsFd, BorrowedFd, OwnedFd},
os::unix::{io::RawFd, net::UnixStream},
sync::Arc,
};
Expand Down Expand Up @@ -295,13 +295,10 @@ impl<D> Client<D> {

#[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) fn get_credentials(&self) -> Credentials {
use std::os::unix::io::AsRawFd;
let creds = nix::sys::socket::getsockopt(
self.socket.as_raw_fd(),
nix::sys::socket::sockopt::PeerCredentials,
)
.expect("getsockopt failed!?");
Credentials { pid: creds.pid(), uid: creds.uid(), gid: creds.gid() }
let creds =
rustix::net::sockopt::get_socket_peercred(&self.socket).expect("getsockopt failed!?");
let pid = rustix::process::Pid::as_raw(Some(creds.pid));
Credentials { pid, uid: creds.uid.as_raw(), gid: creds.gid.as_raw() }
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
Expand Down Expand Up @@ -336,7 +333,7 @@ impl<D> Client<D> {
&mut self,
) -> std::io::Result<(Message<u32, OwnedFd>, Object<Data<D>>)> {
if self.killed {
return Err(nix::errno::Errno::EPIPE.into());
return Err(rustix::io::Errno::PIPE.into());
}
loop {
let map = &self.map;
Expand All @@ -358,7 +355,7 @@ impl<D> Client<D> {
}
Err(MessageParseError::Malformed) => {
self.kill(DisconnectReason::ConnectionClosed);
return Err(nix::errno::Errno::EPROTO.into());
return Err(rustix::io::Errno::PROTO.into());
}
};

Expand Down Expand Up @@ -659,6 +656,12 @@ impl<D> Client<D> {
}
}

impl<D> AsFd for Client<D> {
fn as_fd(&self) -> BorrowedFd<'_> {
self.socket.as_fd()
}
}

#[derive(Debug)]
pub(crate) struct ClientStore<D: 'static> {
clients: Vec<Option<Client<D>>>,
Expand Down
20 changes: 9 additions & 11 deletions wayland-backend/src/rs/server_impl/common_poll.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
os::unix::io::{AsRawFd, FromRawFd},
os::unix::io::{AsFd, AsRawFd},
os::unix::io::{BorrowedFd, OwnedFd},
sync::{Arc, Mutex},
};
Expand All @@ -16,7 +16,7 @@ use crate::{
};

#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::sys::epoll::*;
use rustix::event::epoll;

#[cfg(any(
target_os = "dragonfly",
Expand All @@ -35,7 +35,7 @@ pub struct InnerBackend<D: 'static> {
impl<D> InnerBackend<D> {
pub fn new() -> Result<Self, InitError> {
#[cfg(any(target_os = "linux", target_os = "android"))]
let poll_fd = epoll_create1(EpollCreateFlags::EPOLL_CLOEXEC)
let poll_fd = epoll::create(epoll::CreateFlags::CLOEXEC)
.map_err(Into::into)
.map_err(InitError::Io)?;

Expand All @@ -47,9 +47,7 @@ impl<D> InnerBackend<D> {
))]
let poll_fd = kqueue().map_err(Into::into).map_err(InitError::Io)?;

Ok(Self {
state: Arc::new(Mutex::new(State::new(unsafe { OwnedFd::from_raw_fd(poll_fd) }))),
})
Ok(Self { state: Arc::new(Mutex::new(State::new(poll_fd))) })
}

pub fn flush(&self, client: Option<ClientId>) -> std::io::Result<()> {
Expand Down Expand Up @@ -83,15 +81,15 @@ impl<D> InnerBackend<D> {
let poll_fd = self.poll_fd();
let mut dispatched = 0;
loop {
let mut events = [EpollEvent::empty(); 32];
let nevents = epoll_wait(poll_fd.as_raw_fd(), &mut events, 0)?;
let mut events = epoll::EventVec::with_capacity(32);
epoll::wait(poll_fd.as_fd(), &mut events, 0)?;

if nevents == 0 {
if events.is_empty() {
break;
}

for event in events.iter().take(nevents) {
let id = InnerClientId::from_u64(event.data());
for event in events.iter() {
let id = InnerClientId::from_u64(event.data.u64());
// remove the cb while we call it, to gracefully handle reentrancy
if let Ok(count) = self.dispatch_events_for(data, id) {
dispatched += count;
Expand Down
17 changes: 9 additions & 8 deletions wayland-backend/src/rs/server_impl/handle.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use std::{
ffi::CString,
os::unix::io::OwnedFd,
os::unix::{
io::{AsRawFd, RawFd},
net::UnixStream,
},
os::unix::{io::RawFd, net::UnixStream},
sync::{Arc, Mutex, Weak},
};

Expand Down Expand Up @@ -314,15 +311,19 @@ impl<D> ErasedState for State<D> {
stream: UnixStream,
data: Arc<dyn ClientData>,
) -> std::io::Result<InnerClientId> {
let client_fd = stream.as_raw_fd();
let id = self.clients.create_client(stream, data);
let client = self.clients.get_client(id.clone()).unwrap();

// register the client to the internal epoll
#[cfg(any(target_os = "linux", target_os = "android"))]
let ret = {
use nix::sys::epoll::*;
let mut evt = EpollEvent::new(EpollFlags::EPOLLIN, id.as_u64());
epoll_ctl(self.poll_fd.as_raw_fd(), EpollOp::EpollCtlAdd, client_fd, &mut evt)
use rustix::event::epoll;
epoll::add(
&self.poll_fd,
&client,
epoll::EventData::new_u64(id.as_u64()),
epoll::EventFlags::IN,
)
};

#[cfg(any(
Expand Down
50 changes: 26 additions & 24 deletions wayland-backend/src/rs/socket.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! Wayland socket manipulation
use std::io::{ErrorKind, IoSlice, IoSliceMut, Result as IoResult};
use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
use std::os::unix::io::{AsFd, BorrowedFd, IntoRawFd, OwnedFd};
use std::os::unix::io::{AsRawFd, RawFd};
use std::os::unix::net::UnixStream;

use nix::sys::socket;
use rustix::net::{
recvmsg, sendmsg, RecvAncillaryBuffer, RecvFlags, SendAncillaryBuffer, SendFlags,
};

use crate::protocol::{ArgumentType, Message};

Expand Down Expand Up @@ -35,15 +37,12 @@ impl Socket {
/// slice should not be longer than `MAX_BYTES_OUT` otherwise the receiving
/// end may lose some data.
pub fn send_msg(&self, bytes: &[u8], fds: &[RawFd]) -> IoResult<usize> {
let flags = socket::MsgFlags::MSG_DONTWAIT | socket::MsgFlags::MSG_NOSIGNAL;
let flags = SendFlags::DONTWAIT | SendFlags::NOSIGNAL;
let iov = [IoSlice::new(bytes)];

if !fds.is_empty() {
let cmsgs = [socket::ControlMessage::ScmRights(fds)];
Ok(socket::sendmsg::<()>(self.stream.as_raw_fd(), &iov, &cmsgs, flags, None)?)
} else {
Ok(socket::sendmsg::<()>(self.stream.as_raw_fd(), &iov, &[], flags, None)?)
}
let mut cmsg_space = vec![0; rustix::cmsg_space!(ScmRights(fds.len()))];
let mut cmsg_buffer = SendAncillaryBuffer::new(&mut cmsg_space);
Ok(sendmsg(&self, &iov, &mut cmsg_buffer, flags)?)
}

/// Receive a single message from the socket
Expand All @@ -58,25 +57,28 @@ impl Socket {
/// slice `MAX_FDS_OUT` long, otherwise some data of the received message may
/// be lost.
pub fn rcv_msg(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> IoResult<(usize, usize)> {
let mut cmsg = nix::cmsg_space!([RawFd; MAX_FDS_OUT]);
let mut cmsg_space = vec![0; rustix::cmsg_space!(ScmRights(MAX_FDS_OUT))];
let mut cmsg_buffer = RecvAncillaryBuffer::new(&mut cmsg_space);
let mut iov = [IoSliceMut::new(buffer)];
let msg = socket::recvmsg::<()>(
self.stream.as_raw_fd(),
let msg = recvmsg(
&self.stream,
&mut iov[..],
Some(&mut cmsg),
socket::MsgFlags::MSG_DONTWAIT
| socket::MsgFlags::MSG_CMSG_CLOEXEC
| socket::MsgFlags::MSG_NOSIGNAL,
&mut cmsg_buffer,
RecvFlags::DONTWAIT | RecvFlags::CMSG_CLOEXEC,
)?;

let mut fd_count = 0;
let received_fds = msg.cmsgs().flat_map(|cmsg| match cmsg {
socket::ControlMessageOwned::ScmRights(s) => s,
_ => Vec::new(),
});
let received_fds = cmsg_buffer
.drain()
.filter_map(|cmsg| match cmsg {
rustix::net::RecvAncillaryMessage::ScmRights(fds) => Some(fds),
_ => None,
})
.flatten();
for (fd, place) in received_fds.zip(fds.iter_mut()) {
fd_count += 1;
*place = fd;
// TODO use OwnedFd?
*place = fd.into_raw_fd();
}
Ok((msg.bytes, fd_count))
}
Expand Down Expand Up @@ -141,7 +143,7 @@ impl BufferedSocket {
let written = self.socket.send_msg(bytes, fds)?;
for &fd in fds {
// once the fds are sent, we can close them
let _ = ::nix::unistd::close(fd);
let _ = unsafe { libc::close(fd) };
}
written
};
Expand Down Expand Up @@ -192,7 +194,7 @@ impl BufferedSocket {
if !self.attempt_write_message(msg)? {
// If this fails again, this means the message is too big
// to be transmitted at all
return Err(::nix::errno::Errno::E2BIG.into());
return Err(rustix::io::Errno::TOOBIG.into());
}
}
Ok(())
Expand All @@ -215,7 +217,7 @@ impl BufferedSocket {
};
if in_bytes == 0 {
// the other end of the socket was closed
return Err(::nix::errno::Errno::EPIPE.into());
return Err(rustix::io::Errno::PIPE.into());
}
// advance the storage
self.in_data.advance(in_bytes / 4 + usize::from(in_bytes % 4 > 0));
Expand Down
6 changes: 3 additions & 3 deletions wayland-backend/src/types/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ pub enum DisconnectReason {
#[derive(Debug, Clone, Copy)]
pub struct Credentials {
/// pid of the client
pub pid: nix::libc::pid_t,
pub pid: libc::pid_t,
/// uid of the client
pub uid: nix::libc::uid_t,
pub uid: libc::uid_t,
/// gid of the client
pub gid: nix::libc::gid_t,
pub gid: libc::gid_t,
}
2 changes: 1 addition & 1 deletion wayland-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ readme = "README.md"
wayland-backend = { version = "0.3.1", path = "../wayland-backend" }
wayland-scanner = { version = "0.31.0", path = "../wayland-scanner" }
bitflags = "2"
nix = { version = "0.26.0", default-features = false }
rustix = { version = "0.38.0", features = ["event"] }
log = { version = "0.4", optional = true }

[dev-dependencies]
Expand Down
27 changes: 14 additions & 13 deletions wayland-client/src/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ use wayland_backend::{
protocol::{ObjectInfo, ProtocolError},
};

use nix::{fcntl, Error};

use crate::{protocol::wl_display::WlDisplay, EventQueue, Proxy};

/// The Wayland connection
Expand Down Expand Up @@ -50,21 +48,23 @@ impl Connection {
let stream = if let Ok(txt) = env::var("WAYLAND_SOCKET") {
// We should connect to the provided WAYLAND_SOCKET
let fd = txt.parse::<i32>().map_err(|_| ConnectError::InvalidFd)?;
let fd = unsafe { OwnedFd::from_raw_fd(fd) };
// remove the variable so any child processes don't see it
env::remove_var("WAYLAND_SOCKET");
// set the CLOEXEC flag on this FD
let flags = fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD);
let flags = rustix::io::fcntl_getfd(&fd);
let result = flags
.map(|f| fcntl::FdFlag::from_bits(f).unwrap() | fcntl::FdFlag::FD_CLOEXEC)
.and_then(|f| fcntl::fcntl(fd, fcntl::FcntlArg::F_SETFD(f)));
.map(|f| f | rustix::io::FdFlags::CLOEXEC)
.and_then(|f| rustix::io::fcntl_setfd(&fd, f));
match result {
Ok(_) => {
// setting the O_CLOEXEC worked
unsafe { FromRawFd::from_raw_fd(fd) }
// XXX
use rustix::fd::IntoRawFd;
unsafe { FromRawFd::from_raw_fd(fd.into_raw_fd()) }
}
Err(_) => {
// something went wrong in F_GETFD or F_SETFD
let _ = ::nix::unistd::close(fd);
return Err(ConnectError::InvalidFd);
}
}
Expand Down Expand Up @@ -156,7 +156,7 @@ impl Connection {
crate::protocol::wl_display::Request::Sync {},
Some(done.clone()),
)
.map_err(|_| WaylandError::Io(Error::EPIPE.into()))?;
.map_err(|_| WaylandError::Io(rustix::io::Errno::PIPE.into()))?;

let mut dispatched = 0;

Expand Down Expand Up @@ -220,15 +220,16 @@ impl Connection {
}

pub(crate) fn blocking_read(guard: ReadEventsGuard) -> Result<usize, WaylandError> {
let mut fds = [nix::poll::PollFd::new(
guard.connection_fd().as_raw_fd(),
nix::poll::PollFlags::POLLIN | nix::poll::PollFlags::POLLERR,
let fd = guard.connection_fd();
let mut fds = [rustix::event::PollFd::new(
&fd,
rustix::event::PollFlags::IN | rustix::event::PollFlags::ERR,
)];

loop {
match nix::poll::poll(&mut fds, -1) {
match rustix::event::poll(&mut fds, -1) {
Ok(_) => break,
Err(nix::errno::Errno::EINTR) => continue,
Err(rustix::io::Errno::INTR) => continue,
Err(e) => return Err(WaylandError::Io(e.into())),
}
}
Expand Down
3 changes: 1 addition & 2 deletions wayland-client/src/event_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
use std::sync::{atomic::Ordering, Arc, Condvar, Mutex};
use std::task;

use nix::Error;
use wayland_backend::{
client::{Backend, ObjectData, ObjectId, ReadEventsGuard, WaylandError},
protocol::{Argument, Message},
Expand Down Expand Up @@ -424,7 +423,7 @@ impl<State> EventQueue<State> {
crate::protocol::wl_display::Request::Sync {},
Some(done.clone()),
)
.map_err(|_| WaylandError::Io(Error::EPIPE.into()))?;
.map_err(|_| WaylandError::Io(rustix::io::Errno::PIPE.into()))?;

let mut dispatched = 0;

Expand Down
Loading

0 comments on commit 4dcef4b

Please sign in to comment.