Starting input system
This commit is contained in:
parent
5df672398b
commit
811aa8d117
|
@ -7,6 +7,7 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/messages/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/server/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/linux/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
|
|
@ -2,6 +2,18 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "client"
|
||||
version = "0.1.0"
|
||||
|
@ -10,19 +22,170 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.140"
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "input"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eeb3afdf1f8137428002b354eaf87aa629178995683941d94b04c6d145ec8937"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"input-sys",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"log",
|
||||
"udev",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "input-sys"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f6c2a17e8aba7217660e32863af87b0febad811d4b8620ef76b386603fddc2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.141"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
|
||||
|
||||
[[package]]
|
||||
name = "libudev-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "messages"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||
|
||||
[[package]]
|
||||
name = "server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"input",
|
||||
"libc",
|
||||
"linux",
|
||||
"messages",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "udev"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ebdbbd670373442a12fe9ef7aeb53aec4147a5a27a00bbc3ab639f08f48191a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libudev-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "linux"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.140"
|
|
@ -0,0 +1,13 @@
|
|||
pub fn read_i32(buf: &[u8]) -> i32 {
|
||||
(buf[3] as i32) << 24 |
|
||||
(buf[2] as i32) << 16 |
|
||||
(buf[1] as i32) << 8 |
|
||||
buf[0] as i32
|
||||
}
|
||||
|
||||
pub fn read_u32(buf: &[u8]) -> u32 {
|
||||
(buf[3] as u32) << 24 |
|
||||
(buf[2] as u32) << 16 |
|
||||
(buf[1] as u32) << 8 |
|
||||
buf[0] as u32
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
use std::io;
|
||||
use std::os::fd::RawFd;
|
||||
|
||||
use libc::epoll_event;
|
||||
|
||||
use crate::syscall;
|
||||
|
||||
const EVENTS_CAPACITY: usize = 1024;
|
||||
const WAIT_MAX_EVENTS: i32 = 1024;
|
||||
const WAIT_TIMEOUT: i32 = 1000;
|
||||
|
||||
#[repr(i32)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum EpollFlags {
|
||||
// Events
|
||||
In = libc::EPOLLIN,
|
||||
Err = libc::EPOLLERR,
|
||||
Hup = libc::EPOLLHUP,
|
||||
Out = libc::EPOLLOUT,
|
||||
Pri = libc::EPOLLPRI,
|
||||
RdHup = libc::EPOLLRDHUP,
|
||||
|
||||
// Flags
|
||||
Et = libc::EPOLLET,
|
||||
Exclusive = libc::EPOLLEXCLUSIVE,
|
||||
OneShot = libc::EPOLLONESHOT,
|
||||
WakeUp = libc::EPOLLWAKEUP,
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
pub enum EpollOp {
|
||||
Add = libc::EPOLL_CTL_ADD,
|
||||
Modify = libc::EPOLL_CTL_MOD,
|
||||
Delete = libc::EPOLL_CTL_DEL,
|
||||
}
|
||||
|
||||
pub struct Epoll {
|
||||
fd: RawFd,
|
||||
flag: u32,
|
||||
pub events: Vec<epoll_event>,
|
||||
}
|
||||
|
||||
impl Epoll {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
Self::with_flags(&[])
|
||||
}
|
||||
|
||||
pub fn with_flags(flags: &[EpollFlags]) -> io::Result<Self> {
|
||||
let flag = epoll_flags_as_u32(flags);
|
||||
|
||||
match epoll_create() {
|
||||
Ok(fd) => Ok(Epoll {
|
||||
fd,
|
||||
flag,
|
||||
events: Vec::with_capacity(EVENTS_CAPACITY),
|
||||
}),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_interest(&self, fd: RawFd, key: u64, flags: &[EpollFlags]) -> io::Result<()> {
|
||||
epoll_add_interest(self.fd, fd, self.create_epoll_event(key, flags))
|
||||
}
|
||||
|
||||
pub fn modify_interest(&self, fd: RawFd, key: u64, flags: &[EpollFlags]) -> io::Result<()> {
|
||||
epoll_modify_interest(self.fd, fd, self.create_epoll_event(key, flags))
|
||||
}
|
||||
|
||||
fn create_epoll_event(&self, key: u64, flags: &[EpollFlags]) -> epoll_event {
|
||||
epoll_event {
|
||||
events: self.flag | epoll_flags_as_u32(flags),
|
||||
u64: key as u64,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<()> {
|
||||
self.events.clear();
|
||||
match epoll_wait(self.fd, &mut self.events, WAIT_MAX_EVENTS, WAIT_TIMEOUT) {
|
||||
Ok(res) => {
|
||||
// safe as long as the kernel does nothing wrong - copied from mio
|
||||
unsafe { self.events.set_len(res) }
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EpollFlags {
|
||||
pub fn flag_match(&self, event: u32) -> bool {
|
||||
let expected_flag = *self as i32;
|
||||
event as i32 & expected_flag == expected_flag
|
||||
}
|
||||
}
|
||||
|
||||
fn epoll_create() -> io::Result<RawFd> {
|
||||
let fd = syscall!(epoll_create1(0))?;
|
||||
if let Ok(flags) = syscall!(fcntl(fd, libc::F_GETFD)) {
|
||||
let _ = syscall!(fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC));
|
||||
}
|
||||
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
fn epoll_wait(epoll_fd: RawFd, events: &mut Vec<epoll_event>, max_events: i32, timeout: i32) -> io::Result<usize> {
|
||||
match syscall!(epoll_wait(
|
||||
epoll_fd,
|
||||
events.as_mut_ptr() as *mut libc::epoll_event,
|
||||
max_events,
|
||||
timeout as libc::c_int
|
||||
)) {
|
||||
Ok(v) => Ok(v as usize),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
fn epoll_add_interest(epoll_fd: RawFd, fd: RawFd, event: epoll_event) -> io::Result<()> {
|
||||
epoll_ctl(epoll_fd, fd, event, EpollOp::Add)
|
||||
}
|
||||
|
||||
fn epoll_modify_interest(epoll_fd: RawFd, fd: RawFd, event: epoll_event) -> io::Result<()> {
|
||||
epoll_ctl(epoll_fd, fd, event, EpollOp::Modify)
|
||||
}
|
||||
|
||||
fn epoll_delete_interest(epoll_fd: RawFd, fd: RawFd) -> io::Result<()> {
|
||||
let event = epoll_event { events: 0, u64: 0 }; // event will be ignored
|
||||
epoll_ctl(epoll_fd, fd, event, EpollOp::Delete)
|
||||
}
|
||||
|
||||
fn epoll_ctl(epoll_fd: RawFd, fd: RawFd, mut event: epoll_event, op: EpollOp) -> io::Result<()> {
|
||||
syscall!(epoll_ctl(epoll_fd, op as i32, fd, &mut event))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn epoll_flags_as_u32(flags: &[EpollFlags]) -> u32 {
|
||||
let mut val = 0i32;
|
||||
flags.into_iter().for_each(|flag| val |= *flag as i32);
|
||||
val as u32
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
use std::ffi::{CStr, CString};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
|
||||
|
||||
use libc::inotify_event;
|
||||
|
||||
use crate::buf_utils::{read_i32, read_u32};
|
||||
use crate::syscall;
|
||||
|
||||
const INOTIFY_EVENT_BUFFER_CAPACITY: usize = 4096;
|
||||
const INOTIFY_EVENT_SIZE: usize = std::mem::size_of::<inotify_event>();
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(u32)]
|
||||
pub enum InotifyEvent {
|
||||
Access = libc::IN_ACCESS,
|
||||
Attrib = libc::IN_ATTRIB,
|
||||
CloseWrite = libc::IN_CLOSE_WRITE,
|
||||
CloseNoWrite = libc::IN_CLOSE_NOWRITE,
|
||||
Create = libc::IN_CREATE,
|
||||
Delete = libc::IN_DELETE,
|
||||
DeleteSelf = libc::IN_DELETE_SELF,
|
||||
Modify = libc::IN_MODIFY,
|
||||
MoveSelf = libc::IN_MOVE_SELF,
|
||||
MovedFrom = libc::IN_MOVED_FROM,
|
||||
MovedTo = libc::IN_MOVED_TO,
|
||||
Open = libc::IN_OPEN,
|
||||
}
|
||||
|
||||
const IN_ALL_EVENTS: [InotifyEvent; 12] = [
|
||||
InotifyEvent::Access,
|
||||
InotifyEvent::Attrib,
|
||||
InotifyEvent::CloseWrite,
|
||||
InotifyEvent::CloseNoWrite,
|
||||
InotifyEvent::Create,
|
||||
InotifyEvent::Delete,
|
||||
InotifyEvent::DeleteSelf,
|
||||
InotifyEvent::Modify,
|
||||
InotifyEvent::MoveSelf,
|
||||
InotifyEvent::MovedFrom,
|
||||
InotifyEvent::MovedTo,
|
||||
InotifyEvent::Open,
|
||||
];
|
||||
|
||||
pub struct Inotify {
|
||||
file: File,
|
||||
pub events: Vec<inotify_event>,
|
||||
}
|
||||
|
||||
pub struct Watch {
|
||||
wd: RawFd,
|
||||
}
|
||||
|
||||
impl Inotify {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
let fd = inotify_init()?;
|
||||
let file = unsafe { File::from_raw_fd(fd) };
|
||||
|
||||
Ok(Inotify {
|
||||
file,
|
||||
events: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn watch(&self, path: &str, events: &[InotifyEvent]) -> io::Result<Watch> {
|
||||
let wd = inotify_add_watch(self.file.as_raw_fd(), path, events)?;
|
||||
Ok(Watch { wd })
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<()> {
|
||||
let mut buf = [0u8; INOTIFY_EVENT_BUFFER_CAPACITY];
|
||||
let read_size = self.file.read(&mut buf)?; // Should block
|
||||
|
||||
self.events.clear();
|
||||
|
||||
// Read events
|
||||
for i in 0..(read_size / INOTIFY_EVENT_SIZE) {
|
||||
let offset = INOTIFY_EVENT_SIZE * i;
|
||||
let event_buf = &buf[offset..offset + INOTIFY_EVENT_SIZE];
|
||||
|
||||
self.events.push(inotify_event {
|
||||
wd: read_i32(&event_buf),
|
||||
mask: read_u32(&event_buf[4..]),
|
||||
cookie: read_u32(&event_buf[8..]),
|
||||
len: read_u32(&event_buf[12..]),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Watch {}
|
||||
|
||||
fn inotify_init() -> io::Result<RawFd> {
|
||||
syscall!(inotify_init())
|
||||
}
|
||||
|
||||
fn inotify_add_watch(fd: RawFd, path: &str, events: &[InotifyEvent]) -> io::Result<RawFd> {
|
||||
let c_path = CString::new(path).unwrap();
|
||||
let mask = events_as_mask(events);
|
||||
|
||||
let wd = syscall!(inotify_add_watch(fd, c_path.as_ptr(), mask))?;
|
||||
Ok(wd)
|
||||
}
|
||||
|
||||
fn inotify_rm_watch(fd: RawFd, wd: RawFd) -> io::Result<()> {
|
||||
syscall!(inotify_rm_watch(fd, wd))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn events_as_mask(events: &[InotifyEvent]) -> u32 {
|
||||
let mut mask = 0;
|
||||
events.into_iter().for_each(|event| mask |= *event as u32);
|
||||
mask
|
||||
}
|
||||
|
||||
pub fn mask_as_events(mask: u32) -> Vec<InotifyEvent> {
|
||||
let mut events = Vec::new();
|
||||
|
||||
for event in IN_ALL_EVENTS {
|
||||
let event_u32 = event as u32;
|
||||
if mask & event_u32 == event_u32 {
|
||||
events.push(event);
|
||||
}
|
||||
}
|
||||
|
||||
events
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
pub mod epoll;
|
||||
pub mod inotify;
|
||||
mod buf_utils;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! syscall {
|
||||
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
|
||||
let res = unsafe { libc::$fn($($arg, )*) };
|
||||
if res == -1 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}};
|
||||
}
|
|
@ -4,5 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.140"
|
||||
messages = { path = "../messages" }
|
||||
linux = { path = "../linux" }
|
||||
input = "0.8.2"
|
||||
libc = "0.2.141"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pub mod pointer;
|
|
@ -0,0 +1,29 @@
|
|||
pub enum PointerEvent {
|
||||
Motion(PointerMotionEvent),
|
||||
Button(PointerButtonEvent),
|
||||
Scroll(PointerScrollEvent),
|
||||
}
|
||||
|
||||
pub enum Axis {
|
||||
Horizontal = 0,
|
||||
Vertical = 1,
|
||||
}
|
||||
|
||||
pub struct PointerButtonEvent {
|
||||
pub button: u32,
|
||||
pub seat_button_count: u32,
|
||||
pub button_state: u32,
|
||||
}
|
||||
|
||||
pub struct PointerMotionEvent {
|
||||
pub dx: f64,
|
||||
pub dx_unaccelerated: f64,
|
||||
pub dy: f64,
|
||||
pub dy_unaccelerated: f64,
|
||||
}
|
||||
|
||||
pub struct PointerScrollEvent {
|
||||
pub axis: Axis,
|
||||
pub scroll_value: f64,
|
||||
pub scroll_value_v120: f64,
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
mod events;
|
||||
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io;
|
||||
use std::os::fd::OwnedFd;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::path::Path;
|
||||
|
||||
use input::{Libinput, LibinputInterface};
|
||||
use libc::{O_RDONLY, O_RDWR, O_WRONLY};
|
||||
|
||||
const UDEV_SEAT: &str = "seat0";
|
||||
|
||||
struct Interface;
|
||||
|
||||
impl LibinputInterface for Interface {
|
||||
fn open_restricted(&mut self, path: &Path, flags: i32) -> Result<OwnedFd, i32> {
|
||||
OpenOptions::new()
|
||||
.custom_flags(flags)
|
||||
.read((flags & O_RDONLY == O_RDONLY) | (flags & O_RDWR == O_RDWR))
|
||||
.write((flags & O_WRONLY == O_WRONLY) | (flags & O_RDWR == O_RDWR))
|
||||
.open(path)
|
||||
.map(|file| file.into())
|
||||
.map_err(|err| err.raw_os_error().unwrap())
|
||||
}
|
||||
|
||||
fn close_restricted(&mut self, fd: OwnedFd) {
|
||||
File::from(fd);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_inputs() -> io::Result<()> {
|
||||
let mut input = Libinput::new_with_udev(Interface);
|
||||
input.udev_assign_seat(UDEV_SEAT).unwrap();
|
||||
loop {
|
||||
input.dispatch().unwrap();
|
||||
for event in &mut input {
|
||||
// event.
|
||||
println!("Got event: {:?}", event);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,16 +5,20 @@ use std::net::SocketAddr;
|
|||
use messages::client_registration::ClientRegistration;
|
||||
use messages::serialization::{DeserializeMessage, read_message_data, SerializeMessage};
|
||||
|
||||
use crate::input::read_inputs;
|
||||
use crate::net::tcp_server::{NextIntent, TcpClient, TcpServer};
|
||||
|
||||
mod net;
|
||||
mod input;
|
||||
mod client;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let addr = SocketAddr::from(([127, 0, 0, 1], 4433));
|
||||
let mut server: TcpServer<KvmClient> = TcpServer::new(addr)?;
|
||||
// let addr = SocketAddr::from(([127, 0, 0, 1], 4433));
|
||||
// let mut server: TcpServer<KvmClient> = TcpServer::new(addr)?;
|
||||
//
|
||||
// server.listen()?;
|
||||
|
||||
server.listen()?;
|
||||
read_inputs()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
use std::io;
|
||||
use std::os::fd::RawFd;
|
||||
|
||||
use libc::{epoll_event};
|
||||
|
||||
const EVENTS_CAPACITY: usize = 1024;
|
||||
const WAIT_MAX_EVENTS: i32 = 1024;
|
||||
const WAIT_TIMEOUT: i32 = 1000;
|
||||
|
||||
pub struct Epoll {
|
||||
fd: RawFd,
|
||||
pub events: Vec<epoll_event>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(i32)]
|
||||
pub enum EpollEvent {
|
||||
Read = libc::EPOLLIN,
|
||||
Write = libc::EPOLLOUT,
|
||||
Disconnect = libc::EPOLLRDHUP,
|
||||
}
|
||||
|
||||
impl Epoll {
|
||||
pub fn create() -> io::Result<Self> {
|
||||
match epoll_create() {
|
||||
Ok(fd) => Ok(Epoll {
|
||||
fd,
|
||||
events: Vec::with_capacity(EVENTS_CAPACITY),
|
||||
}),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_interest(&self, fd: RawFd, key: u16, events: &[EpollEvent]) -> io::Result<()> {
|
||||
add_interest(self.fd, fd, create_oneshot_epoll_event(key, events))
|
||||
}
|
||||
|
||||
pub fn modify_interest(&self, fd: RawFd, key: u16, events: &[EpollEvent]) -> io::Result<()> {
|
||||
modify_interest(self.fd, fd, create_oneshot_epoll_event(key, events))
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<()> {
|
||||
self.events.clear();
|
||||
match epoll_wait(self.fd, &mut self.events, WAIT_MAX_EVENTS, WAIT_TIMEOUT) {
|
||||
Ok(res) => {
|
||||
// safe as long as the kernel does nothing wrong - copied from mio
|
||||
unsafe { self.events.set_len(res) }
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_epoll_event(event: u32, expected_event: EpollEvent) -> bool {
|
||||
let expected_event = expected_event as i32;
|
||||
event as i32 & expected_event == expected_event
|
||||
}
|
||||
|
||||
macro_rules! syscall {
|
||||
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
|
||||
let res = unsafe { libc::$fn($($arg, )*) };
|
||||
if res == -1 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
fn epoll_create() -> io::Result<RawFd> {
|
||||
let fd = syscall!(epoll_create1(0))?;
|
||||
if let Ok(flags) = syscall!(fcntl(fd, libc::F_GETFD)) {
|
||||
let _ = syscall!(fcntl(fd, libc::F_SETFD, flags | libc::FD_CLOEXEC));
|
||||
}
|
||||
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
fn epoll_wait(epoll_fd: RawFd, events: &mut Vec<epoll_event>, max_events: i32, timeout: i32) -> io::Result<usize> {
|
||||
match syscall!(epoll_wait(
|
||||
epoll_fd,
|
||||
events.as_mut_ptr() as *mut libc::epoll_event,
|
||||
max_events,
|
||||
timeout as libc::c_int
|
||||
)) {
|
||||
Ok(v) => Ok(v as usize),
|
||||
Err(e) => Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_interest(epoll_fd: RawFd, fd: RawFd, mut event: epoll_event) -> io::Result<()> {
|
||||
syscall!(epoll_ctl(epoll_fd, libc::EPOLL_CTL_ADD, fd, &mut event))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn modify_interest(epoll_fd: RawFd, fd: RawFd, mut event: epoll_event) -> io::Result<()> {
|
||||
syscall!(epoll_ctl(epoll_fd, libc::EPOLL_CTL_MOD, fd, &mut event))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_oneshot_epoll_event(key: u16, events: &[EpollEvent]) -> epoll_event {
|
||||
epoll_event {
|
||||
events: get_oneshot_events_flag(events),
|
||||
u64: key as u64,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_oneshot_events_flag(events: &[EpollEvent]) -> u32 {
|
||||
let mut flag: i32 = libc::EPOLLONESHOT;
|
||||
events.into_iter().for_each(|e| flag = flag | *e as i32);
|
||||
flag as u32
|
||||
}
|
|
@ -1,3 +1,2 @@
|
|||
pub mod tcp_server;
|
||||
|
||||
mod epoll;
|
||||
|
|
|
@ -4,11 +4,11 @@ use std::io::{Read, Write};
|
|||
use std::net::{SocketAddr, TcpListener, TcpStream};
|
||||
use std::os::fd::{AsRawFd, RawFd};
|
||||
|
||||
use crate::net::epoll::{Epoll, EpollEvent, match_epoll_event};
|
||||
use linux::epoll::{Epoll, EpollFlags};
|
||||
|
||||
// Based on: https://www.zupzup.org/epoll-with-rust/index.html
|
||||
|
||||
const KEY_NEW_CONNECTION: u16 = 0;
|
||||
const KEY_NEW_CONNECTION: u64 = 0;
|
||||
|
||||
pub trait TcpClient {
|
||||
fn new() -> Self;
|
||||
|
@ -28,13 +28,13 @@ pub struct TcpServer<T>
|
|||
listener: TcpListener,
|
||||
listener_fd: RawFd,
|
||||
epoll: Epoll,
|
||||
key: u16,
|
||||
request_contexts: HashMap<u16, TcpContext<T>>,
|
||||
key: u64,
|
||||
request_contexts: HashMap<u64, TcpContext<T>>,
|
||||
}
|
||||
|
||||
struct TcpContext<T>
|
||||
where T: TcpClient {
|
||||
key: u16,
|
||||
key: u64,
|
||||
stream: TcpStream,
|
||||
client: T,
|
||||
}
|
||||
|
@ -47,8 +47,8 @@ impl<T> TcpServer<T>
|
|||
|
||||
let listener_fd = listener.as_raw_fd();
|
||||
|
||||
let epoll = Epoll::create()?;
|
||||
epoll.add_interest(listener_fd, KEY_NEW_CONNECTION, &[EpollEvent::Read])?;
|
||||
let epoll = Epoll::with_flags(&[EpollFlags::OneShot])?;
|
||||
epoll.add_interest(listener_fd, KEY_NEW_CONNECTION, &[EpollFlags::In])?;
|
||||
|
||||
Ok(TcpServer {
|
||||
addr,
|
||||
|
@ -73,7 +73,7 @@ impl<T> TcpServer<T>
|
|||
let mut to_remove = Vec::new();
|
||||
|
||||
for (events, u64) in events {
|
||||
match *u64 as u16 {
|
||||
match *u64 {
|
||||
KEY_NEW_CONNECTION => self.accept_connection()?,
|
||||
key => {
|
||||
if let Some(context) = self.request_contexts.get_mut(&key) {
|
||||
|
@ -104,16 +104,16 @@ impl<T> TcpServer<T>
|
|||
|
||||
let context = TcpContext { key, stream, client };
|
||||
|
||||
self.epoll.add_interest(fd, key, &[EpollEvent::Read, EpollEvent::Disconnect])?;
|
||||
self.epoll.add_interest(fd, key, &[EpollFlags::In, EpollFlags::RdHup])?;
|
||||
self.request_contexts.insert(key, context);
|
||||
}
|
||||
Err(e) => eprintln!("Couldn't accept: {e}")
|
||||
};
|
||||
|
||||
self.epoll.modify_interest(self.listener_fd, KEY_NEW_CONNECTION, &[EpollEvent::Read])
|
||||
self.epoll.modify_interest(self.listener_fd, KEY_NEW_CONNECTION, &[EpollFlags::In])
|
||||
}
|
||||
|
||||
fn get_next_key(&mut self) -> u16 {
|
||||
fn get_next_key(&mut self) -> u64 {
|
||||
self.key += 1;
|
||||
self.key
|
||||
}
|
||||
|
@ -122,15 +122,15 @@ impl<T> TcpServer<T>
|
|||
fn handle_event<T>(epoll: &Epoll, context: &mut TcpContext<T>, event: u32) -> bool
|
||||
where T: TcpClient {
|
||||
match event {
|
||||
v if match_epoll_event(v, EpollEvent::Read) => {
|
||||
v if EpollFlags::In.flag_match(v) => {
|
||||
println!("Read");
|
||||
return handle_read_event(epoll, context);
|
||||
}
|
||||
v if match_epoll_event(v, EpollEvent::Write) => {
|
||||
v if EpollFlags::Out.flag_match(v) => {
|
||||
println!("Write");
|
||||
return handle_write_event(epoll, context);
|
||||
}
|
||||
v if match_epoll_event(v, EpollEvent::Disconnect) => {
|
||||
v if EpollFlags::RdHup.flag_match(v) => {
|
||||
println!("Disconnect");
|
||||
return true;
|
||||
}
|
||||
|
@ -171,14 +171,14 @@ fn handle_write_event<T>(epoll: &Epoll, context: &mut TcpContext<T>) -> bool
|
|||
fn set_interest<T>(epoll: &Epoll, context: &TcpContext<T>, next_intent: &NextIntent)
|
||||
where T: TcpClient {
|
||||
let event = match next_intent {
|
||||
NextIntent::Read => EpollEvent::Read,
|
||||
NextIntent::Write => EpollEvent::Write,
|
||||
NextIntent::Read => EpollFlags::In,
|
||||
NextIntent::Write => EpollFlags::Out,
|
||||
};
|
||||
|
||||
epoll.modify_interest(
|
||||
context.stream.as_raw_fd(),
|
||||
context.key,
|
||||
&[event, EpollEvent::Disconnect])
|
||||
&[event, EpollFlags::RdHup])
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue