mirror of
https://gitlab.com/marcandre.lureau/qemu-display.git
synced 2025-03-07 15:25:04 +00:00
qemu-display: start win32 support
This commit is contained in:
parent
ecbeb857c5
commit
1a24e051d0
@ -7,6 +7,7 @@ edition = "2018"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
cfg-if = "1.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
derivative = "2.2.0"
|
derivative = "2.2.0"
|
||||||
zbus = { version = "2.0", features = ["xml"] }
|
zbus = { version = "2.0", features = ["xml"] }
|
||||||
@ -23,3 +24,7 @@ usbredirhost = "0.0.1"
|
|||||||
async-broadcast = "0.3.3"
|
async-broadcast = "0.3.3"
|
||||||
async-trait = "0.1.48"
|
async-trait = "0.1.48"
|
||||||
async-lock = "2.3.0"
|
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"] }
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
use std::os::unix::{io::AsRawFd, net::UnixStream};
|
#[cfg(windows)]
|
||||||
use zbus::{dbus_interface, dbus_proxy, zvariant::Fd, Connection};
|
use crate::win32::Fd;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::net::UnixStream;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use uds_windows::UnixStream;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use zbus::zvariant::Fd;
|
||||||
|
use zbus::{dbus_interface, dbus_proxy, Connection};
|
||||||
|
|
||||||
|
use crate::util;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -236,9 +244,8 @@ impl Audio {
|
|||||||
|
|
||||||
pub async fn register_out_listener<H: AudioOutHandler>(&mut self, handler: H) -> Result<()> {
|
pub async fn register_out_listener<H: AudioOutHandler>(&mut self, handler: H) -> Result<()> {
|
||||||
let (p0, p1) = UnixStream::pair()?;
|
let (p0, p1) = UnixStream::pair()?;
|
||||||
self.proxy
|
let p0 = util::prepare_uds_pass(&p0)?;
|
||||||
.register_out_listener(p0.as_raw_fd().into())
|
self.proxy.register_out_listener(p0).await?;
|
||||||
.await?;
|
|
||||||
let c = zbus::ConnectionBuilder::unix_stream(p1)
|
let c = zbus::ConnectionBuilder::unix_stream(p1)
|
||||||
.p2p()
|
.p2p()
|
||||||
.serve_at(
|
.serve_at(
|
||||||
@ -253,9 +260,8 @@ impl Audio {
|
|||||||
|
|
||||||
pub async fn register_in_listener<H: AudioInHandler>(&mut self, handler: H) -> Result<()> {
|
pub async fn register_in_listener<H: AudioInHandler>(&mut self, handler: H) -> Result<()> {
|
||||||
let (p0, p1) = UnixStream::pair()?;
|
let (p0, p1) = UnixStream::pair()?;
|
||||||
self.proxy
|
let p0 = util::prepare_uds_pass(&p0)?;
|
||||||
.register_in_listener(p0.as_raw_fd().into())
|
self.proxy.register_in_listener(p0).await?;
|
||||||
.await?;
|
|
||||||
let c = zbus::ConnectionBuilder::unix_stream(p1)
|
let c = zbus::ConnectionBuilder::unix_stream(p1)
|
||||||
.p2p()
|
.p2p()
|
||||||
.serve_at(
|
.serve_at(
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
|
#[cfg(windows)]
|
||||||
|
use crate::win32::Fd;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use zbus::{
|
#[cfg(unix)]
|
||||||
dbus_proxy,
|
use zbus::zvariant::Fd;
|
||||||
zvariant::{Fd, ObjectPath},
|
use zbus::{dbus_proxy, zvariant::ObjectPath};
|
||||||
};
|
|
||||||
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
#[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Chardev")]
|
#[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Chardev")]
|
||||||
pub trait Chardev {
|
pub trait Chardev {
|
||||||
/// Register method
|
/// Register method
|
||||||
|
#[cfg(unix)]
|
||||||
fn register(&self, stream: Fd) -> zbus::Result<()>;
|
fn register(&self, stream: Fd) -> zbus::Result<()>;
|
||||||
|
|
||||||
/// SendBreak method
|
/// SendBreak method
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
use std::{
|
#[cfg(windows)]
|
||||||
cell::RefCell,
|
use crate::win32::Fd;
|
||||||
convert::TryFrom,
|
#[cfg(unix)]
|
||||||
os::unix::{io::AsRawFd, net::UnixStream},
|
use std::os::unix::net::UnixStream;
|
||||||
};
|
use std::{cell::RefCell, convert::TryFrom};
|
||||||
use zbus::{
|
#[cfg(windows)]
|
||||||
dbus_proxy,
|
use uds_windows::UnixStream;
|
||||||
zvariant::{Fd, ObjectPath},
|
#[cfg(unix)]
|
||||||
Connection,
|
use zbus::zvariant::Fd;
|
||||||
};
|
use zbus::{dbus_proxy, zvariant::ObjectPath, Connection};
|
||||||
|
|
||||||
use crate::{ConsoleListener, ConsoleListenerHandler, KeyboardProxy, MouseProxy, Result};
|
use crate::{util, ConsoleListener, ConsoleListenerHandler, KeyboardProxy, MouseProxy, Result};
|
||||||
|
|
||||||
#[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Console")]
|
#[dbus_proxy(default_service = "org.qemu", interface = "org.qemu.Display1.Console")]
|
||||||
pub trait Console {
|
pub trait Console {
|
||||||
@ -87,7 +87,8 @@ impl Console {
|
|||||||
|
|
||||||
pub async fn register_listener<H: ConsoleListenerHandler>(&self, handler: H) -> Result<()> {
|
pub async fn register_listener<H: ConsoleListenerHandler>(&self, handler: H) -> Result<()> {
|
||||||
let (p0, p1) = UnixStream::pair()?;
|
let (p0, p1) = UnixStream::pair()?;
|
||||||
self.proxy.register_listener(p0.as_raw_fd().into()).await?;
|
let p0 = util::prepare_uds_pass(&p0)?;
|
||||||
|
self.proxy.register_listener(p0).await?;
|
||||||
let c = zbus::ConnectionBuilder::unix_stream(p1)
|
let c = zbus::ConnectionBuilder::unix_stream(p1)
|
||||||
.p2p()
|
.p2p()
|
||||||
.serve_at("/org/qemu/Display1/Listener", ConsoleListener::new(handler))?
|
.serve_at("/org/qemu/Display1/Listener", ConsoleListener::new(handler))?
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
#[cfg(windows)]
|
||||||
|
use crate::win32::Fd;
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use std::{
|
use std::ops::Drop;
|
||||||
ops::Drop,
|
#[cfg(unix)]
|
||||||
os::unix::io::{AsRawFd, IntoRawFd, RawFd},
|
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||||
};
|
use zbus::dbus_interface;
|
||||||
use zbus::{dbus_interface, zvariant::Fd};
|
#[cfg(unix)]
|
||||||
|
use zbus::zvariant::Fd;
|
||||||
|
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
@ -29,6 +32,7 @@ pub struct Update {
|
|||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ScanoutDMABUF {
|
pub struct ScanoutDMABUF {
|
||||||
pub fd: RawFd,
|
pub fd: RawFd,
|
||||||
@ -40,6 +44,10 @@ pub struct ScanoutDMABUF {
|
|||||||
pub y0_top: bool,
|
pub y0_top: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ScanoutDMABUF {}
|
||||||
|
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
pub struct Cursor {
|
pub struct Cursor {
|
||||||
@ -51,6 +59,7 @@ pub struct Cursor {
|
|||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
impl Drop for ScanoutDMABUF {
|
impl Drop for ScanoutDMABUF {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.fd >= 0 {
|
if self.fd >= 0 {
|
||||||
@ -61,6 +70,7 @@ impl Drop for ScanoutDMABUF {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
impl IntoRawFd for ScanoutDMABUF {
|
impl IntoRawFd for ScanoutDMABUF {
|
||||||
fn into_raw_fd(mut self) -> RawFd {
|
fn into_raw_fd(mut self) -> RawFd {
|
||||||
std::mem::replace(&mut self.fd, -1)
|
std::mem::replace(&mut self.fd, -1)
|
||||||
@ -148,6 +158,22 @@ impl<H: ConsoleListenerHandler> ConsoleListener<H> {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
#[dbus_interface(name = "ScanoutDMABUF")]
|
||||||
|
async fn scanout_dmabuf(
|
||||||
|
&mut self,
|
||||||
|
_fd: Fd,
|
||||||
|
_width: u32,
|
||||||
|
_height: u32,
|
||||||
|
_stride: u32,
|
||||||
|
_fourcc: u32,
|
||||||
|
_modifier: u64,
|
||||||
|
_y0_top: bool,
|
||||||
|
) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
#[dbus_interface(name = "ScanoutDMABUF")]
|
#[dbus_interface(name = "ScanoutDMABUF")]
|
||||||
async fn scanout_dmabuf(
|
async fn scanout_dmabuf(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -12,7 +12,9 @@ use zbus::{
|
|||||||
};
|
};
|
||||||
use zvariant::OwnedObjectPath;
|
use zvariant::OwnedObjectPath;
|
||||||
|
|
||||||
use crate::{Audio, Chardev, Clipboard, Error, Result, UsbRedir, VMProxy};
|
#[cfg(unix)]
|
||||||
|
use crate::UsbRedir;
|
||||||
|
use crate::{Audio, Chardev, Clipboard, Error, Result, VMProxy};
|
||||||
|
|
||||||
struct Inner<'d> {
|
struct Inner<'d> {
|
||||||
proxy: fdo::ObjectManagerProxy<'d>,
|
proxy: fdo::ObjectManagerProxy<'d>,
|
||||||
@ -144,6 +146,7 @@ impl<'d> Display<'d> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
pub async fn usbredir(&self) -> UsbRedir {
|
pub async fn usbredir(&self) -> UsbRedir {
|
||||||
let chardevs = stream::iter(self.chardevs().await)
|
let chardevs = stream::iter(self.chardevs().await)
|
||||||
.filter_map(|c| async move {
|
.filter_map(|c| async move {
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
#![allow(clippy::too_many_arguments)]
|
#![allow(clippy::too_many_arguments)]
|
||||||
|
|
||||||
|
pub mod util;
|
||||||
|
#[cfg(windows)]
|
||||||
|
mod win32;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
|
|
||||||
@ -30,7 +34,9 @@ pub use mouse::*;
|
|||||||
mod display;
|
mod display;
|
||||||
pub use display::*;
|
pub use display::*;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
mod usbredir;
|
mod usbredir;
|
||||||
|
#[cfg(unix)]
|
||||||
pub use usbredir::UsbRedir;
|
pub use usbredir::UsbRedir;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
use async_broadcast::{broadcast, Receiver, Sender};
|
use async_broadcast::{broadcast, Receiver, Sender};
|
||||||
use async_lock::RwLock;
|
use async_lock::RwLock;
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::{
|
||||||
|
io::{AsRawFd, RawFd},
|
||||||
|
net::UnixStream,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
default::Default,
|
default::Default,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
os::unix::{
|
|
||||||
io::{AsRawFd, RawFd},
|
|
||||||
net::UnixStream,
|
|
||||||
},
|
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
thread::JoinHandle,
|
thread::JoinHandle,
|
||||||
};
|
};
|
||||||
|
#[cfg(windows)]
|
||||||
|
use uds_windows::UnixStream;
|
||||||
use usbredirhost::{
|
use usbredirhost::{
|
||||||
rusb::{self, UsbContext},
|
rusb::{self, UsbContext},
|
||||||
Device, DeviceHandler, LogLevel,
|
Device, DeviceHandler, LogLevel,
|
||||||
@ -24,6 +27,7 @@ use crate::{Chardev, Error, Result};
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct InnerHandler {
|
struct InnerHandler {
|
||||||
#[allow(unused)] // keep the device opened, as rusb doesn't take it
|
#[allow(unused)] // keep the device opened, as rusb doesn't take it
|
||||||
|
#[cfg(unix)]
|
||||||
device_fd: Option<zvariant::OwnedFd>,
|
device_fd: Option<zvariant::OwnedFd>,
|
||||||
stream: UnixStream,
|
stream: UnixStream,
|
||||||
ctxt: rusb::Context,
|
ctxt: rusb::Context,
|
||||||
@ -73,6 +77,7 @@ impl DeviceHandler for Handler {
|
|||||||
fn flush_writes(&mut self) {}
|
fn flush_writes(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
#[zbus::dbus_proxy(
|
#[zbus::dbus_proxy(
|
||||||
interface = "org.freedesktop.usbredir1",
|
interface = "org.freedesktop.usbredir1",
|
||||||
default_service = "org.freedesktop.usbredir1",
|
default_service = "org.freedesktop.usbredir1",
|
||||||
@ -88,6 +93,7 @@ impl Handler {
|
|||||||
|
|
||||||
let (dev, device_fd) = match device.open() {
|
let (dev, device_fd) = match device.open() {
|
||||||
Ok(it) => (it, None),
|
Ok(it) => (it, None),
|
||||||
|
#[cfg(unix)]
|
||||||
Err(rusb::Error::Access) => {
|
Err(rusb::Error::Access) => {
|
||||||
let (bus, dev) = (device.bus_number(), device.address());
|
let (bus, dev) = (device.bus_number(), device.address());
|
||||||
let sysbus = zbus::Connection::system().await?;
|
let sysbus = zbus::Connection::system().await?;
|
||||||
@ -120,6 +126,7 @@ impl Handler {
|
|||||||
|
|
||||||
let handler = Self {
|
let handler = Self {
|
||||||
inner: Arc::new(Mutex::new(InnerHandler {
|
inner: Arc::new(Mutex::new(InnerHandler {
|
||||||
|
#[cfg(unix)]
|
||||||
device_fd,
|
device_fd,
|
||||||
stream,
|
stream,
|
||||||
event,
|
event,
|
||||||
@ -302,6 +309,7 @@ impl Stream for NFreeChannelsStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
fn fd_poll_readable(fd: RawFd, wait: Option<RawFd>) -> std::io::Result<bool> {
|
fn fd_poll_readable(fd: RawFd, wait: Option<RawFd>) -> std::io::Result<bool> {
|
||||||
let mut fds = vec![libc::pollfd {
|
let mut fds = vec![libc::pollfd {
|
||||||
fd,
|
fd,
|
||||||
|
45
qemu-display/src/util.rs
Normal file
45
qemu-display/src/util.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use crate::Result;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::{io::AsRawFd, net::UnixStream};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use zbus::zvariant::Fd;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use win32::Fd;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
use crate::win32;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use std::os::windows::io::AsRawSocket;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use uds_windows::UnixStream;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use windows::Win32::Networking::WinSock::{WSADuplicateSocketW, SOCKET, WSAPROTOCOL_INFOW};
|
||||||
|
#[cfg(windows)]
|
||||||
|
use windows::Win32::System::Threading::PROCESS_DUP_HANDLE;
|
||||||
|
|
||||||
|
pub fn prepare_uds_pass(us: &UnixStream) -> Result<Fd> {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
Ok(us.as_raw_fd().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
let pid = win32::unix_stream_get_peer_pid(us)?;
|
||||||
|
let p = win32::ProcessHandle::open(Some(pid), PROCESS_DUP_HANDLE)?;
|
||||||
|
let mut info = unsafe { std::mem::zeroed() };
|
||||||
|
if unsafe { WSADuplicateSocketW(SOCKET(us.as_raw_socket() as _), p.process_id(), &mut info) }
|
||||||
|
!= 0
|
||||||
|
{
|
||||||
|
return Err(crate::Error::Io(win32::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())
|
||||||
|
}
|
||||||
|
}
|
85
qemu-display/src/win32.rs
Normal file
85
qemu-display/src/win32.rs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
use std::io;
|
||||||
|
use uds_windows::UnixStream;
|
||||||
|
use windows::Win32::Foundation::{CloseHandle, HANDLE};
|
||||||
|
use windows::Win32::System::Threading::PROCESS_ACCESS_RIGHTS;
|
||||||
|
|
||||||
|
pub type Fd = Vec<u8>;
|
||||||
|
|
||||||
|
// A process handle
|
||||||
|
pub struct ProcessHandle(HANDLE);
|
||||||
|
|
||||||
|
impl Drop for ProcessHandle {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe { CloseHandle(self.0) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcessHandle {
|
||||||
|
// Open the process associated with the process_id (if None, the current process)
|
||||||
|
pub fn open(
|
||||||
|
process_id: Option<u32>,
|
||||||
|
desired_access: PROCESS_ACCESS_RIGHTS,
|
||||||
|
) -> Result<Self, io::Error> {
|
||||||
|
use windows::Win32::System::Threading::{GetCurrentProcess, OpenProcess};
|
||||||
|
|
||||||
|
let process = if let Some(process_id) = process_id {
|
||||||
|
unsafe { OpenProcess(desired_access, false, process_id)? }
|
||||||
|
} else {
|
||||||
|
unsafe { GetCurrentProcess() }
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self(process))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_id(&self) -> u32 {
|
||||||
|
use windows::Win32::System::Threading::GetProcessId;
|
||||||
|
|
||||||
|
unsafe { GetProcessId(self.0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn wsa_last_err() -> io::Error {
|
||||||
|
use windows::Win32::Networking::WinSock::WSAGetLastError;
|
||||||
|
|
||||||
|
let err = unsafe { WSAGetLastError() };
|
||||||
|
io::Error::from_raw_os_error(err.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the process ID of the connected peer
|
||||||
|
pub fn unix_stream_get_peer_pid(stream: &UnixStream) -> Result<u32, io::Error> {
|
||||||
|
use std::os::windows::io::AsRawSocket;
|
||||||
|
use windows::Win32::Networking::WinSock::{
|
||||||
|
WSAIoctl, IOC_OUT, IOC_VENDOR, SOCKET, 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)
|
||||||
|
}
|
@ -17,3 +17,4 @@ rdw = { package = "rdw4", version = "0.1", features = ["bindings"] }
|
|||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
|
uds_windows = "1.0.2"
|
||||||
|
@ -5,6 +5,7 @@ use keycodemap::KEYMAP_XORGEVDEV2QNUM;
|
|||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use qemu_display::{Console, ConsoleListenerHandler};
|
use qemu_display::{Console, ConsoleListenerHandler};
|
||||||
use rdw::{gtk, DisplayExt};
|
use rdw::{gtk, DisplayExt};
|
||||||
|
#[cfg(unix)]
|
||||||
use std::os::unix::io::IntoRawFd;
|
use std::os::unix::io::IntoRawFd;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
@ -158,6 +159,11 @@ mod imp {
|
|||||||
}
|
}
|
||||||
widget.update_area(u.x as _, u.y as _, u.w as _, u.h as _, u.stride as _, &u.data);
|
widget.update_area(u.x as _, u.y as _, u.w as _, u.h as _, u.stride as _, &u.data);
|
||||||
}
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
ScanoutDMABUF(_) => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
#[cfg(unix)]
|
||||||
ScanoutDMABUF(s) => {
|
ScanoutDMABUF(s) => {
|
||||||
widget.set_display_size(Some((s.width as _, s.height as _)));
|
widget.set_display_size(Some((s.width as _, s.height as _)));
|
||||||
widget.set_dmabuf_scanout(rdw::RdwDmabufScanout {
|
widget.set_dmabuf_scanout(rdw::RdwDmabufScanout {
|
||||||
|
@ -2,17 +2,19 @@ use futures_util::StreamExt;
|
|||||||
use gio::ApplicationFlags;
|
use gio::ApplicationFlags;
|
||||||
use glib::MainContext;
|
use glib::MainContext;
|
||||||
use gtk::{gio, glib, prelude::*};
|
use gtk::{gio, glib, prelude::*};
|
||||||
use qemu_display::{Chardev, Console, Display};
|
use qemu_display::{util, Chardev, Console, Display};
|
||||||
use rdw::gtk;
|
use rdw::gtk;
|
||||||
use std::{cell::RefCell, sync::Arc};
|
use std::{cell::RefCell, sync::Arc};
|
||||||
|
|
||||||
mod audio;
|
mod audio;
|
||||||
mod clipboard;
|
mod clipboard;
|
||||||
mod display;
|
mod display;
|
||||||
|
#[cfg(unix)]
|
||||||
mod usbredir;
|
mod usbredir;
|
||||||
|
|
||||||
struct Inner {
|
struct Inner {
|
||||||
app: gtk::Application,
|
app: gtk::Application,
|
||||||
|
#[cfg(unix)]
|
||||||
usbredir: RefCell<Option<usbredir::Handler>>,
|
usbredir: RefCell<Option<usbredir::Handler>>,
|
||||||
audio: RefCell<Option<audio::Handler>>,
|
audio: RefCell<Option<audio::Handler>>,
|
||||||
clipboard: RefCell<Option<clipboard::Handler>>,
|
clipboard: RefCell<Option<clipboard::Handler>>,
|
||||||
@ -101,6 +103,7 @@ impl App {
|
|||||||
let app = App {
|
let app = App {
|
||||||
inner: Arc::new(Inner {
|
inner: Arc::new(Inner {
|
||||||
app,
|
app,
|
||||||
|
#[cfg(unix)]
|
||||||
usbredir: Default::default(),
|
usbredir: Default::default(),
|
||||||
audio: Default::default(),
|
audio: Default::default(),
|
||||||
clipboard: Default::default(),
|
clipboard: Default::default(),
|
||||||
@ -176,6 +179,7 @@ impl App {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.set_child(Some(&rdw));
|
.set_child(Some(&rdw));
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
app_clone.set_usbredir(usbredir::Handler::new(display.usbredir().await));
|
app_clone.set_usbredir(usbredir::Handler::new(display.usbredir().await));
|
||||||
|
|
||||||
if let Ok(Some(audio)) = display.audio().await {
|
if let Ok(Some(audio)) = display.audio().await {
|
||||||
@ -197,13 +201,15 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(c) = Chardev::new(&conn, "qmp").await {
|
if let Ok(c) = Chardev::new(&conn, "qmp").await {
|
||||||
use std::{
|
use std::io::{prelude::*, BufReader};
|
||||||
io::{prelude::*, BufReader},
|
#[cfg(unix)]
|
||||||
os::unix::{io::AsRawFd, net::UnixStream},
|
use std::os::unix::net::UnixStream;
|
||||||
};
|
#[cfg(windows)]
|
||||||
|
use uds_windows::UnixStream;
|
||||||
|
|
||||||
let (p0, p1) = UnixStream::pair().unwrap();
|
let (p0, p1) = UnixStream::pair().unwrap();
|
||||||
if c.proxy.register(p1.as_raw_fd().into()).await.is_ok() {
|
let fd = util::prepare_uds_pass(&p1).unwrap();
|
||||||
|
if c.proxy.register(fd).await.is_ok() {
|
||||||
let mut reader = BufReader::new(p0.try_clone().unwrap());
|
let mut reader = BufReader::new(p0.try_clone().unwrap());
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
std::thread::spawn(move || loop {
|
std::thread::spawn(move || loop {
|
||||||
@ -218,6 +224,8 @@ impl App {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
let action_usb = gio::SimpleAction::new("usb", None);
|
let action_usb = gio::SimpleAction::new("usb", None);
|
||||||
let app_clone = app.clone();
|
let app_clone = app.clone();
|
||||||
action_usb.connect_activate(move |_, _| {
|
action_usb.connect_activate(move |_, _| {
|
||||||
@ -230,10 +238,12 @@ impl App {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
app.inner.app.add_action(&action_usb);
|
app.inner.app.add_action(&action_usb);
|
||||||
|
}
|
||||||
|
|
||||||
app
|
app
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
fn set_usbredir(&self, usbredir: usbredir::Handler) {
|
fn set_usbredir(&self, usbredir: usbredir::Handler) {
|
||||||
self.inner.usbredir.replace(Some(usbredir));
|
self.inner.usbredir.replace(Some(usbredir));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user