mirror of
https://gitlab.com/marcandre.lureau/qemu-display.git
synced 2024-11-10 01:50:00 +00:00
qemu-display: add simple win32-test
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
0728a62a58
commit
e75fbd1539
@ -28,3 +28,10 @@ async-lock = "2.3.0"
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
uds_windows = "1.0.1"
|
||||
windows = { version = "0.39.0", features = ["Win32_Networking_WinSock", "Win32_Foundation", "Win32_System_IO", "Win32_System_Threading"] }
|
||||
|
||||
[target.'cfg(windows)'.dev-dependencies]
|
||||
qapi = { version = "0.9.0", features = ["qmp"] }
|
||||
serde = { version = "^1.0.27", features = ["derive"] }
|
||||
base64 = "0.13"
|
||||
async-std = { version = "1.12.0", features = ["attributes"] }
|
||||
tracing-subscriber = { version = "0.3.11", features = ["env-filter" , "fmt"], default-features = false }
|
||||
|
135
qemu-display/examples/win32-test.rs
Normal file
135
qemu-display/examples/win32-test.rs
Normal file
@ -0,0 +1,135 @@
|
||||
#![allow(non_snake_case, non_camel_case_types)]
|
||||
|
||||
use std::env::args;
|
||||
use std::error::Error;
|
||||
use std::os::windows::io::AsRawSocket;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use qapi::{qmp, Qmp};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uds_windows::UnixStream;
|
||||
use windows::Win32::Networking::WinSock::{WSADuplicateSocketW, SOCKET, WSAPROTOCOL_INFOW};
|
||||
|
||||
use qemu_display::Display;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct get_win32_socket {
|
||||
#[serde(rename = "info")]
|
||||
pub info: ::std::string::String,
|
||||
#[serde(rename = "fdname")]
|
||||
pub fdname: ::std::string::String,
|
||||
}
|
||||
|
||||
impl qmp::QmpCommand for get_win32_socket {}
|
||||
impl qapi::Command for get_win32_socket {
|
||||
const NAME: &'static str = "get-win32-socket";
|
||||
const ALLOW_OOB: bool = false;
|
||||
|
||||
type Ok = qapi::Empty;
|
||||
}
|
||||
|
||||
fn wsa_last_err() -> std::io::Error {
|
||||
use windows::Win32::Networking::WinSock::WSAGetLastError;
|
||||
|
||||
let err = unsafe { WSAGetLastError() };
|
||||
std::io::Error::from_raw_os_error(err.0)
|
||||
}
|
||||
|
||||
// Get the process ID of the connected peer
|
||||
fn unix_stream_get_peer_pid(stream: &UnixStream) -> Result<u32, std::io::Error> {
|
||||
use windows::Win32::Networking::WinSock::{WSAIoctl, IOC_OUT, IOC_VENDOR, SOCKET_ERROR};
|
||||
|
||||
macro_rules! _WSAIOR {
|
||||
($x:expr, $y:expr) => {
|
||||
IOC_OUT | $x | $y
|
||||
};
|
||||
}
|
||||
|
||||
let socket = stream.as_raw_socket();
|
||||
const SIO_AF_UNIX_GETPEERPID: u32 = _WSAIOR!(IOC_VENDOR, 256);
|
||||
let mut ret = 0 as u32;
|
||||
let mut bytes = 0;
|
||||
|
||||
let r = unsafe {
|
||||
WSAIoctl(
|
||||
SOCKET(socket as _),
|
||||
SIO_AF_UNIX_GETPEERPID,
|
||||
0 as *mut _,
|
||||
0,
|
||||
&mut ret as *mut _ as *mut _,
|
||||
std::mem::size_of_val(&ret) as u32,
|
||||
&mut bytes,
|
||||
0 as *mut _,
|
||||
None,
|
||||
)
|
||||
};
|
||||
|
||||
if r == SOCKET_ERROR {
|
||||
return Err(wsa_last_err());
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn duplicate_socket(pid: u32, sock: SOCKET) -> Result<Vec<u8>, std::io::Error> {
|
||||
let mut info = unsafe { std::mem::zeroed() };
|
||||
if unsafe { WSADuplicateSocketW(sock, pid, &mut info) } != 0 {
|
||||
return Err(wsa_last_err());
|
||||
}
|
||||
let info = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
&info as *const _ as *const u8,
|
||||
std::mem::size_of::<WSAPROTOCOL_INFOW>(),
|
||||
)
|
||||
};
|
||||
Ok(info.to_vec())
|
||||
}
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let socket_addr = args().nth(1).expect("argument: QMP socket path");
|
||||
let stream = UnixStream::connect(socket_addr).expect("failed to connect to socket");
|
||||
let pid = unix_stream_get_peer_pid(&stream).expect("failed to get peer PID");
|
||||
|
||||
let mut qmp = Qmp::from_stream(&stream);
|
||||
|
||||
let info = qmp.handshake().expect("handshake failed");
|
||||
println!("QMP info: {:#?}", info);
|
||||
|
||||
let (p0, p1) = UnixStream::pair().expect("failed to make a socketpair");
|
||||
let info =
|
||||
duplicate_socket(pid, SOCKET(p0.as_raw_socket() as _)).expect("Failed to pass socket");
|
||||
let info = base64::encode(info);
|
||||
qmp.execute(&get_win32_socket {
|
||||
info,
|
||||
fdname: "fdname".into(),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
qmp.execute(&qmp::add_client {
|
||||
skipauth: None,
|
||||
tls: None,
|
||||
protocol: "@dbus-display".into(),
|
||||
fdname: "fdname".into(),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let conn = zbus::ConnectionBuilder::unix_stream(p1)
|
||||
.p2p()
|
||||
.build()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let display = Display::new(&conn, Option::<String>::None).await.unwrap();
|
||||
loop {
|
||||
qmp.nop().unwrap();
|
||||
for event in qmp.events() {
|
||||
println!("Got event: {:#?}", event);
|
||||
}
|
||||
|
||||
sleep(Duration::from_secs(1));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user