Skip to content

Commit 1e53669

Browse files
author
Isaiah Becker-Mayer
authored
feat: add support for dydynvc (#419)
1 parent a1d8bb2 commit 1e53669

File tree

60 files changed

+1741
-2806
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1741
-2806
lines changed

Cargo.lock

+7-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+9-2
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,22 @@ ironrdp-tls = { version = "0.1", path = "crates/ironrdp-tls" }
5151
ironrdp-tokio = { version = "0.1", path = "crates/ironrdp-tokio" }
5252
ironrdp = { version = "0.5", path = "crates/ironrdp" }
5353

54+
bitflags = "2.4"
5455
expect-test = "1"
56+
png = "0.17"
5557
proptest = "1.4"
5658
rstest = "0.18"
5759
sspi = "0.11"
5860
tracing = { version = "0.1", features = ["log"] }
5961
thiserror = "1.0"
60-
png = "0.17"
61-
bitflags = "2.4"
62+
63+
# Note: we are trying to move away from using these crates.
64+
# They are being kept around for now for legacy compatibility,
65+
# but new usage should be avoided.
6266
byteorder = "1.5"
67+
lazy_static = "1.4" # prefer https://doc.rust-lang.org/std/sync/struct.OnceLock.html
68+
num-derive = "0.4"
69+
num-traits = "0.2"
6370

6471
[profile.dev]
6572
opt-level = 1

crates/ironrdp-ainput/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ doctest = false
1616
test = false
1717

1818
[dependencies]
19+
ironrdp-dvc.workspace = true
1920
ironrdp-pdu.workspace = true
2021
bitflags.workspace = true
2122

22-
num-derive = "0.4"
23-
num-traits = "0.2"
23+
num-derive.workspace = true # TODO: remove
24+
num-traits.workspace = true # TODO: remove

crates/ironrdp-ainput/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use bitflags::bitflags;
2+
use ironrdp_dvc::DvcPduEncode;
23
use num_derive::{FromPrimitive, ToPrimitive};
34
use num_traits::{FromPrimitive as _, ToPrimitive as _};
45

@@ -136,6 +137,8 @@ impl PduEncode for ServerPdu {
136137
}
137138
}
138139

140+
impl DvcPduEncode for ServerPdu {}
141+
139142
impl<'de> PduDecode<'de> for ServerPdu {
140143
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
141144
ensure_fixed_part_size!(in: src);

crates/ironrdp-client/src/rdp.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ async fn connect(
104104

105105
let mut connector = connector::ClientConnector::new(config.connector.clone())
106106
.with_server_addr(server_addr)
107-
// .with_static_channel(ironrdp::dvc::DrdynvcClient::new()) // FIXME(#61): drdynvc is not working
107+
.with_static_channel(ironrdp::dvc::DrdynvcClient::new())
108108
.with_static_channel(rdpsnd::Rdpsnd::new())
109109
.with_static_channel(rdpdr::Rdpdr::new(Box::new(NoopRdpdrBackend {}), "IronRDP".to_owned()).with_smartcard(0));
110110

@@ -160,7 +160,7 @@ async fn active_session(
160160
connection_result.desktop_size.height,
161161
);
162162

163-
let mut active_stage = ActiveStage::new(connection_result, None);
163+
let mut active_stage = ActiveStage::new(connection_result);
164164

165165
let disconnect_reason = 'outer: loop {
166166
let outputs = tokio::select! {

crates/ironrdp-cliprdr/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl<R: Role> Cliprdr<R> {
222222
/// implementation when user performs OS-specific copy command (e.g. `Ctrl+C` shortcut on
223223
/// keyboard)
224224
pub fn initiate_copy(&self, available_formats: &[ClipboardFormat]) -> PduResult<CliprdrSvcMessages<R>> {
225-
let mut pdus = vec![];
225+
let mut pdus = Vec::new();
226226

227227
match (self.state, R::is_server()) {
228228
// When user initiates copy, we should send format list to server.
@@ -275,7 +275,7 @@ impl<R: Role> SvcProcessor for Cliprdr<R> {
275275
if R::is_server() {
276276
Ok(vec![self.capabilities()?, self.monitor_ready()?])
277277
} else {
278-
Ok(vec![])
278+
Ok(Vec::new())
279279
}
280280
}
281281

crates/ironrdp-cliprdr/src/pdu/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub use self::lock::*;
1919
use bitflags::bitflags;
2020
use ironrdp_pdu::cursor::{ReadCursor, WriteCursor};
2121
use ironrdp_pdu::{ensure_fixed_part_size, invalid_message_err, PduDecode, PduEncode, PduResult};
22+
use ironrdp_svc::SvcPduEncode;
2223

2324
const MSG_TYPE_MONITOR_READY: u16 = 0x0001;
2425
const MSG_TYPE_FORMAT_LIST: u16 = 0x0002;
@@ -215,6 +216,8 @@ impl PduEncode for ClipboardPdu<'_> {
215216
}
216217
}
217218

219+
impl SvcPduEncode for ClipboardPdu<'_> {}
220+
218221
impl<'de> PduDecode<'de> for ClipboardPdu<'de> {
219222
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
220223
ensure_fixed_part_size!(in: src);

crates/ironrdp-displaycontrol/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ keywords.workspace = true
1212
categories.workspace = true
1313

1414
[dependencies]
15-
ironrdp-pdu.workspace = true
15+
ironrdp-dvc.workspace = true
16+
ironrdp-pdu.workspace = true
17+
ironrdp-svc.workspace = true
18+
tracing.workspace = true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use crate::{
2+
pdu::{DisplayControlMonitorLayout, DisplayControlPdu, MonitorLayoutEntry},
3+
CHANNEL_NAME,
4+
};
5+
use ironrdp_dvc::{encode_dvc_messages, DvcClientProcessor, DvcMessage, DvcProcessor};
6+
use ironrdp_pdu::PduResult;
7+
use ironrdp_svc::{impl_as_any, ChannelFlags, SvcMessage};
8+
use tracing::debug;
9+
10+
/// A client for the Display Control Virtual Channel.
11+
pub struct DisplayControlClient {}
12+
13+
impl_as_any!(DisplayControlClient);
14+
15+
impl DvcProcessor for DisplayControlClient {
16+
fn channel_name(&self) -> &str {
17+
CHANNEL_NAME
18+
}
19+
20+
fn start(&mut self, _channel_id: u32) -> PduResult<Vec<DvcMessage>> {
21+
Ok(Vec::new())
22+
}
23+
24+
fn process(&mut self, _channel_id: u32, payload: &[u8]) -> PduResult<Vec<DvcMessage>> {
25+
// TODO: We can parse the payload here for completeness sake,
26+
// in practice we don't need to do anything with the payload.
27+
debug!("Got Display PDU of length: {}", payload.len());
28+
Ok(Vec::new())
29+
}
30+
}
31+
32+
impl DvcClientProcessor for DisplayControlClient {}
33+
34+
impl DisplayControlClient {
35+
pub fn new() -> Self {
36+
Self {}
37+
}
38+
39+
/// Fully encodes a [`MonitorLayoutPdu`] with the given monitors.
40+
pub fn encode_monitors(&self, channel_id: u32, monitors: Vec<MonitorLayoutEntry>) -> PduResult<Vec<SvcMessage>> {
41+
let pdu: DisplayControlPdu = DisplayControlMonitorLayout::new(&monitors)?.into();
42+
encode_dvc_messages(channel_id, vec![Box::new(pdu)], ChannelFlags::empty())
43+
}
44+
}
45+
46+
impl Default for DisplayControlClient {
47+
fn default() -> Self {
48+
Self::new()
49+
}
50+
}
+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
#![doc = include_str!("../README.md")]
22

3+
pub const CHANNEL_NAME: &str = "Microsoft::Windows::RDS::DisplayControl";
4+
5+
pub mod client;
36
pub mod pdu;
7+
pub mod server;

crates/ironrdp-displaycontrol/src/pdu/mod.rs

+26
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//!
33
//! [1]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedisp/d2954508-f487-48bc-8731-39743e0854a9
44
5+
use ironrdp_dvc::DvcPduEncode;
56
use ironrdp_pdu::cursor::{ReadCursor, WriteCursor};
67
use ironrdp_pdu::{ensure_fixed_part_size, invalid_message_err, PduDecode, PduEncode, PduResult};
78

@@ -73,6 +74,8 @@ impl PduEncode for DisplayControlPdu {
7374
}
7475
}
7576

77+
impl DvcPduEncode for DisplayControlPdu {}
78+
7679
impl<'de> PduDecode<'de> for DisplayControlPdu {
7780
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
7881
ensure_fixed_part_size!(in: src);
@@ -99,12 +102,28 @@ impl<'de> PduDecode<'de> for DisplayControlPdu {
99102
}
100103
}
101104

105+
impl From<DisplayControlCapabilities> for DisplayControlPdu {
106+
fn from(caps: DisplayControlCapabilities) -> Self {
107+
Self::Caps(caps)
108+
}
109+
}
110+
111+
impl From<DisplayControlMonitorLayout> for DisplayControlPdu {
112+
fn from(layout: DisplayControlMonitorLayout) -> Self {
113+
Self::MonitorLayout(layout)
114+
}
115+
}
116+
117+
/// 2.2.2.1 DISPLAYCONTROL_CAPS_PDU
118+
///
102119
/// Display control channel capabilities PDU.
103120
///
104121
/// INVARIANTS:
105122
/// 0 <= max_num_monitors <= MAX_SUPPORTED_MONITORS
106123
/// 0 <= max_monitor_area_factor_a <= MAX_MONITOR_AREA_FACTOR
107124
/// 0 <= max_monitor_area_factor_b <= MAX_MONITOR_AREA_FACTOR
125+
///
126+
/// [2.2.2.1]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedisp/8989a211-984e-4ecc-80f3-60694fc4b476
108127
#[derive(Debug, Clone, PartialEq, Eq)]
109128
pub struct DisplayControlCapabilities {
110129
max_num_monitors: u32,
@@ -179,10 +198,14 @@ impl<'de> PduDecode<'de> for DisplayControlCapabilities {
179198
}
180199
}
181200

201+
/// [2.2.2.2] DISPLAYCONTROL_MONITOR_LAYOUT_PDU
202+
///
182203
/// Sent from client to server to notify about new monitor layout (e.g screen resize).
183204
///
184205
/// INVARIANTS:
185206
/// 0 <= monitors.length() <= MAX_SUPPORTED_MONITORS
207+
///
208+
/// [2.2.2.2]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedisp/22741217-12a0-4fb8-b5a0-df43905aaf06
186209
#[derive(Debug, Clone, PartialEq, Eq)]
187210
pub struct DisplayControlMonitorLayout {
188211
monitors: Vec<MonitorLayoutEntry>,
@@ -280,6 +303,9 @@ impl<'de> PduDecode<'de> for DisplayControlMonitorLayout {
280303
}
281304
}
282305

306+
/// [2.2.2.2.1] DISPLAYCONTROL_MONITOR_LAYOUT_PDU
307+
///
308+
/// [2.2.2.2.2]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpedisp/ea2de591-9203-42cd-9908-be7a55237d1c
283309
#[derive(Debug, Clone, PartialEq, Eq)]
284310
pub struct MonitorLayoutEntry {
285311
is_primary: bool,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use ironrdp_dvc::{DvcMessage, DvcProcessor, DvcServerProcessor};
2+
use ironrdp_pdu::{decode, PduResult};
3+
use ironrdp_svc::impl_as_any;
4+
use tracing::debug;
5+
6+
use crate::{
7+
pdu::{DisplayControlCapabilities, DisplayControlPdu},
8+
CHANNEL_NAME,
9+
};
10+
11+
/// A server for the Display Control Virtual Channel.
12+
pub struct DisplayControlServer {}
13+
14+
impl_as_any!(DisplayControlServer);
15+
16+
impl DvcProcessor for DisplayControlServer {
17+
fn channel_name(&self) -> &str {
18+
CHANNEL_NAME
19+
}
20+
21+
fn start(&mut self, _channel_id: u32) -> PduResult<Vec<DvcMessage>> {
22+
let pdu: DisplayControlPdu = DisplayControlCapabilities::new(1, 3840, 2400)?.into();
23+
24+
Ok(vec![Box::new(pdu)])
25+
}
26+
27+
fn process(&mut self, _channel_id: u32, payload: &[u8]) -> PduResult<Vec<DvcMessage>> {
28+
match decode(payload)? {
29+
DisplayControlPdu::MonitorLayout(layout) => {
30+
debug!(?layout);
31+
}
32+
DisplayControlPdu::Caps(caps) => {
33+
debug!(?caps);
34+
}
35+
}
36+
Ok(Vec::new())
37+
}
38+
}
39+
40+
impl DvcServerProcessor for DisplayControlServer {}

0 commit comments

Comments
 (0)