1#[cfg(target_arch = "x86_64")]
2
3pub mod errors;
4mod header;
5
6use std::{
7 io::{
8 Write,
9 Read,
10 Stdin,
11 Stdout,
12 self,
13 },
14 process::{
15 Command,
16 Child,
17 ChildStdout,
18 ChildStdin,
19 ChildStderr,
20 Stdio,
21 },
22};
23use anyhow::anyhow;
24use crate::{
25 errors::*,
26 header::*,
27};
28
29pub trait QIO {
30 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>;
32
33 fn write(&mut self, buf: &[u8]) -> io::Result<usize>;
38}
39
40#[inline(always)]
41fn inner_read(read: &mut impl Read, buf: &mut [u8]) -> io::Result<usize> {
42 let mut hbuf = [0u8; HEADER_LEN];
43 read.read_exact(&mut hbuf)?;
44
45 let msg_len = header_len(&hbuf) as usize;
46 read.read_exact(&mut buf[..msg_len])?;
47
48 return Ok(msg_len);
49}
50
51#[inline(always)]
52fn inner_write(
53 written: &mut impl Write,
54 data_buf: &[u8],
55) -> io::Result<usize> {
56 let header = header(data_buf);
57 written.write_all(&header)?;
58 written.write_all(&data_buf)?;
59 written.flush()?;
60 return Ok(data_buf.len() + HEADER_LEN);
61}
62
63#[derive(Debug)]
64pub struct QrexecServer {
65 pub read: Stdin,
66 pub written: Stdout,
67}
68
69impl QIO for QrexecServer {
70 #[inline(always)]
71 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
72 return inner_read(&mut self.read, buf);
73 }
74
75 #[inline(always)]
76 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
77 return inner_write(&mut self.written, buf);
78 }
79}
80
81impl QrexecServer {
82 pub fn new() -> Self {
83 let read = io::stdin();
84 let written = io::stdout();
85 Self {
86 read, written,
87 }
88 }
89}
90
91#[derive(Debug)]
99pub struct QrexecClient {
100 pub child: Child,
101 pub read: ChildStdout,
102 pub written: ChildStdin,
103 pub stderr: ChildStderr,
104}
105
106impl QrexecClient {
107 pub fn new<const BUF_LEN: usize>(
123 target_vmname: &str,
124 rpc_service: &str,
125 local_program: Option<&str>,
126 local_program_args: Option<&[&str]>,
127 ) -> QRXRes<Self> {
128 let mut child = Command::new("qrexec-client-vm");
129 child.stdout(Stdio::piped())
130 .stdin(Stdio::piped())
131 .stderr(Stdio::piped());
132
133 child.args([
134 &format!("--buffer-size={}", &BUF_LEN.to_string()),
135 target_vmname, rpc_service]);
136
137 if let Some(local_program) = local_program {
138 child.arg(local_program);
139 }
140
141 if let Some(args) = local_program_args {
142 child.args(args);
143 }
144
145 let mut child = child.spawn()?;
146
147 return Ok(Self {
148 read: child.stdout.take().ok_or(
149 anyhow!(STDOUT_ERR))?,
150 written: child.stdin.take().ok_or(
151 anyhow!(STDIN_ERR))?,
152 stderr: child.stderr.take().ok_or(
153 anyhow!(STDERR_ERR))?,
154 child,
155 })
156 }
157}
158
159impl QIO for QrexecClient {
160 #[inline(always)]
161 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
162 return inner_read(&mut self.read, buf);
163 }
164
165 #[inline(always)]
166 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
167 return inner_write(&mut self.written, buf);
168 }
169}
170
171impl Drop for QrexecClient {
172 fn drop(&mut self) {
173 let _ = self.child.kill();
174 }
175}