]> git.proxmox.com Git - pve-lxc-syscalld.git/blob - src/client.rs
working on receiving data for the syscalls
[pve-lxc-syscalld.git] / src / client.rs
1 use std::sync::Arc;
2
3 use failure::Error;
4
5 use crate::lxcseccomp::ProxyMessageBuffer;
6 use crate::socket::AsyncSeqPacketSocket;
7 use crate::syscall::SyscallStatus;
8
9 pub struct Client {
10 socket: AsyncSeqPacketSocket,
11 }
12
13 impl Client {
14 pub fn new(socket: AsyncSeqPacketSocket) -> Arc<Self> {
15 Arc::new(Self { socket })
16 }
17
18 /// Wrap futures returning a `Result` so if they fail we `shutdown()` the socket to drop the
19 /// client.
20 async fn wrap_error<F>(self: Arc<Self>, fut: F)
21 where
22 F: std::future::Future<Output = Result<(), Error>>,
23 {
24 if let Err(err) = fut.await {
25 eprintln!("client error, dropping connection: {}", err);
26 if let Err(err) = self.socket.shutdown(nix::sys::socket::Shutdown::Both) {
27 eprintln!(" (error shutting down client socket: {})", err);
28 }
29 }
30 }
31
32 pub async fn main(self: Arc<Self>) {
33 self.clone().wrap_error(self.main_do()).await
34 }
35
36 async fn main_do(self: Arc<Self>) -> Result<(), Error> {
37 loop {
38 let mut msg = ProxyMessageBuffer::new(64);
39
40 if !msg.recv(&self.socket).await? {
41 eprintln!("client disconnected");
42 break Ok(());
43 }
44
45 // Note: our spawned tasks here must not access our socket, as we cannot guarantee
46 // they'll be woken up if another task errors into `wrap_error()`.
47 tokio::spawn(self.clone().wrap_error(self.clone().__handle_syscall(msg)));
48 }
49 }
50
51 // Note: we must not use the socket for anything other than sending the result!
52 async fn __handle_syscall(self: Arc<Self>, mut msg: ProxyMessageBuffer) -> Result<(), Error> {
53 let result = match Self::handle_syscall(&msg).await {
54 Ok(r) => r,
55 Err(err) => {
56 if let Some(errno) = err.downcast_ref::<nix::errno::Errno>() {
57 SyscallStatus::Err(*errno as _)
58 } else if let Some(nix::Error::Sys(errno)) = err.downcast_ref::<nix::Error>() {
59 SyscallStatus::Err(*errno as _)
60 } else if let Some(ioerr) = err.downcast_ref::<std::io::Error>() {
61 if let Some(errno) = ioerr.raw_os_error() {
62 SyscallStatus::Err(errno)
63 } else {
64 return Err(err);
65 }
66 } else {
67 return Err(err);
68 }
69 }
70 };
71
72 let resp = msg.response_mut();
73 match result {
74 SyscallStatus::Ok(val) => {
75 resp.val = val;
76 resp.error = 0;
77 }
78 SyscallStatus::Err(err) => {
79 resp.val = -1;
80 resp.error = -err;
81 }
82 }
83
84 msg.respond(&self.socket).await.map_err(Error::from)
85 }
86
87 async fn handle_syscall(msg: &ProxyMessageBuffer) -> Result<SyscallStatus, Error> {
88 match msg.request().data.nr as i64 {
89 libc::SYS_mknod => crate::sys_mknod::mknod(msg).await,
90 libc::SYS_mknodat => crate::sys_mknod::mknodat(msg).await,
91 _ => Ok(SyscallStatus::Err(libc::ENOSYS)),
92 }
93 }
94 }