1
0
mirror of https://gitlab.com/marcandre.lureau/qemu-display.git synced 2025-04-14 08:44:46 +00:00
Marc-André Lureau 6ad37b1f61 rdp: quit when dbus service is gone
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2024-08-20 11:16:53 +04:00

100 lines
3.0 KiB
Rust

mod clipboard;
mod display;
mod input;
mod sound;
use anyhow::{anyhow, Context, Error};
use ironrdp::server::{
tokio_rustls::{rustls, TlsAcceptor},
ServerEvent,
};
use qemu_display::{zbus, Display};
use rustls_pemfile::{certs, pkcs8_private_keys};
use std::{fs::File, io::BufReader, sync::Arc};
use tracing::debug;
use ironrdp::server::RdpServer;
use crate::args::ServerArgs;
use clipboard::ClipboardHandler;
use display::DisplayHandler;
use input::InputHandler;
use sound::SoundHandler;
pub struct Server {
dbus: zbus::Connection,
args: ServerArgs,
}
impl Server {
pub fn new(dbus: zbus::Connection, args: ServerArgs) -> Self {
Self { dbus, args }
}
pub async fn run(&mut self) -> Result<(), Error> {
let tls = self
.args
.cert
.as_ref()
.zip(self.args.key.as_ref())
.map(|(cert, key)| acceptor(cert, key).unwrap())
.ok_or_else(|| anyhow!("Failed to setup TLS"))?;
let dbus_display = Display::new::<()>(&self.dbus, None).await?;
let handler = InputHandler::connect(&dbus_display).await?;
let display = DisplayHandler::connect(&dbus_display).await?;
let clipboard = ClipboardHandler::connect(&dbus_display).await?;
let sound = match SoundHandler::connect(&dbus_display).await {
Ok(h) => Some(h),
Err(e) => {
debug!("Can't connect audio: {}", e);
None
}
};
let mut server = RdpServer::builder()
.with_addr((self.args.address, self.args.port))
.with_tls(tls)
.with_input_handler(handler)
.with_display_handler(display)
.with_cliprdr_factory(Some(Box::new(clipboard)))
.with_sound_factory(sound.map(|h| Box::new(h) as _))
.build();
let ev = server.event_sender().clone();
let proxy = dbus_display.inner_proxy().clone();
tokio::spawn(async move {
use futures_util::StreamExt;
let mut owner_changed = proxy.receive_owner_changed().await.unwrap();
let _ = owner_changed.next().await;
ev.send(ServerEvent::Quit("org.qemu is gone".to_owned()))
.unwrap();
});
server.run().await
}
}
fn acceptor(cert_path: &str, key_path: &str) -> Result<TlsAcceptor, Error> {
let cert = certs(&mut BufReader::new(File::open(cert_path)?))
.next()
.context("no certificate")??;
let key = pkcs8_private_keys(&mut BufReader::new(File::open(key_path)?))
.next()
.context("no private key")?
.map(rustls::pki_types::PrivateKeyDer::from)?;
let mut server_config = rustls::ServerConfig::builder()
.with_no_client_auth()
.with_single_cert(vec![cert], key)
.expect("bad certificate/key");
// This adds support for the SSLKEYLOGFILE env variable (https://wiki.wireshark.org/TLS#using-the-pre-master-secret)
server_config.key_log = Arc::new(rustls::KeyLogFile::new());
Ok(TlsAcceptor::from(Arc::new(server_config)))
}