1
0
Fork 0
forked from wry/wry

autocommit 2022-02-24 16:30:11 CET

This commit is contained in:
Julian Orth 2022-02-24 16:30:11 +01:00
parent 666e475032
commit 7d28d30666
39 changed files with 1670 additions and 209 deletions

View file

@ -1,20 +1,27 @@
use crate::client::ClientError;
use crate::event_loop::{EventLoopDispatcher, EventLoopError, EventLoopId};
use crate::state::State;
use crate::ErrorFmt;
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, Errno, OwnedFd};
use uapi::{c, format_ustr, Errno, OwnedFd, Ustring};
#[derive(Debug, Error)]
pub enum AcceptorError {
#[error("XDG_RUNTIME_DIR is not set")]
XrdNotSet,
#[error("XDG_RUNTIME_DIR is too long to form a unix socket address")]
XrdTooLong,
#[error("XDG_RUNTIME_DIR ({0:?}) is too long to form a unix socket address")]
XrdTooLong(String),
#[error("Could not create a wayland socket")]
SocketFailed(#[source] std::io::Error),
#[error("Could not stat the existing socket")]
SocketStat(#[source] std::io::Error),
#[error("Could not start listening for incoming connections")]
ListenFailed(#[source] std::io::Error),
#[error("Could not open the lock file")]
OpenLockFile(#[source] std::io::Error),
#[error("Could not lock the lock file")]
LockLockFile(#[source] std::io::Error),
#[error("The wayland socket is in an error state")]
ErrorEvent,
#[error("Could not accept new connections")]
@ -30,76 +37,110 @@ pub enum AcceptorError {
}
pub struct Acceptor {
_unlinker: Unlinker,
id: EventLoopId,
fd: OwnedFd,
socket: AllocatedSocket,
global: Rc<State>,
}
struct Unlinker(String);
struct AllocatedSocket {
// wayland-x
name: Ustring,
// /run/user/1000/wayland-x
path: Ustring,
fd: Rc<OwnedFd>,
// /run/user/1000/wayland-x.lock
lock_path: Ustring,
_lock_fd: OwnedFd,
}
impl Drop for Unlinker {
impl Drop for AllocatedSocket {
fn drop(&mut self) {
let _ = uapi::unlink(self.0.as_str());
let _ = uapi::unlink(&self.path);
let _ = uapi::unlink(&self.lock_path);
}
}
fn socket_path(xrd: &str, id: u32) -> String {
format!("{}/wayland-{}", xrd, id)
}
fn bind_socket(fd: i32, xdr: &str) -> Result<u32, AcceptorError> {
fn bind_socket(fd: &Rc<OwnedFd>, xrd: &str, id: u32) -> Result<AllocatedSocket, AcceptorError> {
let mut addr: c::sockaddr_un = uapi::pod_zeroed();
addr.sun_family = c::AF_UNIX as _;
for i in 0..1000 {
let path = socket_path(xdr, i);
if path.len() + 1 > addr.sun_path.len() {
return Err(AcceptorError::XrdTooLong);
let name = format_ustr!("wayland-{}", id);
let path = format_ustr!("{}/{}", xrd, name.display());
let lock_path = format_ustr!("{}.lock", path.display());
if path.len() + 1 > addr.sun_path.len() {
return Err(AcceptorError::XrdTooLong(xrd.to_string()));
}
let lock_fd = match uapi::open(&*lock_path, c::O_CREAT | c::O_CLOEXEC | c::O_RDWR, 0o644) {
Ok(l) => l,
Err(e) => return Err(AcceptorError::OpenLockFile(e.into())),
};
if let Err(e) = uapi::flock(lock_fd.raw(), c::LOCK_EX | c::LOCK_NB) {
return Err(AcceptorError::LockLockFile(e.into()));
}
match uapi::lstat(&*path) {
Ok(_) => {
log::info!("Unlinking {}", path.display());
let _ = uapi::unlink(&*path);
}
let sun_path = uapi::as_bytes_mut(&mut addr.sun_path[..]);
sun_path[..path.len()].copy_from_slice(path.as_bytes());
sun_path[path.len()] = 0;
match uapi::bind(fd, &addr) {
Ok(()) => return Ok(i),
Err(Errno(c::EADDRINUSE)) => {
log::warn!("Socket {} is already in use", path);
Err(Errno(c::ENOENT)) => {}
Err(e) => return Err(AcceptorError::SocketStat(e.into())),
}
let sun_path = uapi::as_bytes_mut(&mut addr.sun_path[..]);
sun_path[..path.len()].copy_from_slice(path.as_bytes());
sun_path[path.len()] = 0;
if let Err(e) = uapi::bind(fd.raw(), &addr) {
return Err(AcceptorError::BindFailed(e.into()));
}
Ok(AllocatedSocket {
name,
path,
fd: fd.clone(),
lock_path,
_lock_fd: lock_fd,
})
}
fn allocate_socket() -> Result<AllocatedSocket, AcceptorError> {
let xrd = match std::env::var("XDG_RUNTIME_DIR") {
Ok(d) => d,
Err(_) => return Err(AcceptorError::XrdNotSet),
};
let fd = match uapi::socket(
c::AF_UNIX,
c::SOCK_STREAM | c::SOCK_NONBLOCK | c::SOCK_CLOEXEC,
0,
) {
Ok(f) => Rc::new(f),
Err(e) => return Err(AcceptorError::SocketFailed(e.into())),
};
for i in 1..1000 {
match bind_socket(&fd, &xrd, i) {
Ok(s) => return Ok(s),
Err(e) => {
log::warn!("Cannot use the wayland-{} socket: {}", i, ErrorFmt(e));
}
Err(e) => return Err(AcceptorError::BindFailed(e.into())),
}
}
Err(AcceptorError::AddressesInUse)
}
impl Acceptor {
pub fn install(global: &Rc<State>) -> Result<String, AcceptorError> {
let xrd = match std::env::var("XDG_RUNTIME_DIR") {
Ok(d) => d,
Err(_) => return Err(AcceptorError::XrdNotSet),
};
let fd = match uapi::socket(
c::AF_UNIX,
c::SOCK_STREAM | c::SOCK_NONBLOCK | c::SOCK_CLOEXEC,
0,
) {
Ok(f) => f,
Err(e) => return Err(AcceptorError::SocketFailed(e.into())),
};
let socket_id = bind_socket(fd.raw(), &xrd)?;
let socket_path = socket_path(&xrd, socket_id);
log::info!("bound to socket {}", socket_path);
let unlinker = Unlinker(socket_path.clone());
if let Err(e) = uapi::listen(fd.raw(), 4096) {
pub fn install(global: &Rc<State>) -> Result<Ustring, AcceptorError> {
let socket = allocate_socket()?;
log::info!("bound to socket {}", socket.path.display());
if let Err(e) = uapi::listen(socket.fd.raw(), 4096) {
return Err(AcceptorError::ListenFailed(e.into()));
}
let id = global.el.id();
let name = socket.name.to_owned();
let acc = Rc::new(Acceptor {
_unlinker: unlinker,
id,
fd,
socket,
global: global.clone(),
});
global.el.insert(id, Some(acc.fd.raw()), c::EPOLLIN, acc)?;
Ok(socket_path)
global
.el
.insert(id, Some(acc.socket.fd.raw()), c::EPOLLIN, acc)?;
Ok(name)
}
}
@ -110,7 +151,7 @@ impl EventLoopDispatcher for Acceptor {
}
loop {
let fd = match uapi::accept4(
self.fd.raw(),
self.socket.fd.raw(),
uapi::sockaddr_none_mut(),
c::SOCK_NONBLOCK | c::SOCK_CLOEXEC,
) {