Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 104 additions & 18 deletions crates/ironrdp-dvc/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use core::any::TypeId;
use core::fmt;

use crate::alloc::borrow::ToOwned as _;
use crate::complete_data::CompleteData;
use ironrdp_core::{Decode as _, DecodeResult, ReadCursor, impl_as_any};
use ironrdp_pdu::{self as pdu, decode_err, encode_err, pdu_other_err};
use ironrdp_svc::{ChannelFlags, CompressionCondition, SvcClientProcessor, SvcMessage, SvcProcessor};
Expand All @@ -14,9 +15,12 @@ use tracing::debug;

use crate::pdu::{
CapabilitiesResponsePdu, CapsVersion, ClosePdu, CreateResponsePdu, CreationStatus, DrdynvcClientPdu,
DrdynvcServerPdu,
DrdynvcDataPdu, DrdynvcServerPdu,
};
use crate::{
DvcMessage, DvcProcessor, DynamicChannelId, DynamicChannelMut, DynamicChannelName, DynamicChannelRef,
encode_dvc_messages,
};
use crate::{DvcProcessor, DynamicChannelId, DynamicChannelName, DynamicVirtualChannel, encode_dvc_messages};

pub trait DvcClientProcessor: DvcProcessor {}

Expand All @@ -25,18 +29,18 @@ pub trait DvcChannelListener: Send {

/// Called for each incoming DYNVC_CREATE_REQ matching this name.
/// Return `None` to reject (NO_LISTENER).
fn create(&mut self, channel_id: DynamicChannelId) -> Option<Box<dyn DvcProcessor>>;
fn create(&mut self, channel_id: DynamicChannelId) -> Option<Box<dyn DvcClientProcessor>>;
}

pub type DynamicChannelListener = Box<dyn DvcChannelListener>;

/// For pre-registered DVC
struct OnceListener {
inner: Option<Box<dyn DvcProcessor>>,
inner: Option<Box<dyn DvcClientProcessor>>,
}

impl OnceListener {
fn new(dvc_processor: impl DvcProcessor + 'static) -> Self {
fn new(dvc_processor: impl DvcClientProcessor + 'static) -> Self {
Self {
inner: Some(Box::new(dvc_processor)),
}
Expand All @@ -51,11 +55,62 @@ impl DvcChannelListener for OnceListener {
.channel_name()
}

fn create(&mut self, _channel_id: DynamicChannelId) -> Option<Box<dyn DvcProcessor>> {
fn create(&mut self, _channel_id: DynamicChannelId) -> Option<Box<dyn DvcClientProcessor>> {
self.inner.take()
}
}

struct DynamicVirtualChannel {
channel_processor: Box<dyn DvcClientProcessor + Send>,
complete_data: CompleteData,
/// The channel ID assigned by the server.
///
/// `Some` only after [`DynamicVirtualChannel::start`] has succeeded. This invariant
channel_id: Option<DynamicChannelId>,
Comment on lines +66 to +69
}

impl Drop for DynamicVirtualChannel {
fn drop(&mut self) {
if let Some(id) = self.channel_id {
self.channel_processor.close(id);
}
}
}

impl DynamicVirtualChannel {
fn from_boxed(processor: Box<dyn DvcClientProcessor + Send>) -> Self {
Self {
channel_processor: processor,
complete_data: CompleteData::new(),
channel_id: None,
}
}

fn processor_type_id(&self) -> TypeId {
self.channel_processor.as_any().type_id()
}

fn start(&mut self, channel_id: DynamicChannelId) -> PduResult<Vec<DvcMessage>> {
let messages = self.channel_processor.start(channel_id)?;
self.channel_id = Some(channel_id);
Ok(messages)
}

fn process(&mut self, pdu: DrdynvcDataPdu) -> PduResult<Vec<DvcMessage>> {
let channel_id = pdu.channel_id();
let complete_data = self.complete_data.process_data(pdu).map_err(|e| decode_err!(e))?;
if let Some(complete_data) = complete_data {
self.channel_processor.process(channel_id, &complete_data)
} else {
Ok(Vec::new())
}
}

fn channel_name(&self) -> &str {
self.channel_processor.channel_name()
}
}

/// DRDYNVC Static Virtual Channel (the Remote Desktop Protocol: Dynamic Virtual Channel Extension)
///
/// It adds support for dynamic virtual channels (DVC).
Expand Down Expand Up @@ -100,7 +155,7 @@ impl DrdynvcClient {
#[must_use]
pub fn with_dynamic_channel<T>(mut self, channel: T) -> Self
where
T: DvcProcessor + 'static,
T: DvcClientProcessor + 'static,
{
self.dynamic_channels.register_once(channel);
self
Expand All @@ -115,7 +170,7 @@ impl DrdynvcClient {
/// it will be silently overwritten.
pub fn attach_dynamic_channel<T>(&mut self, channel: T)
where
T: DvcProcessor + 'static,
T: DvcClientProcessor + 'static,
{
self.dynamic_channels.register_once(channel);
}
Expand All @@ -124,7 +179,7 @@ impl DrdynvcClient {
///
/// # Note
///
/// * Doesn't support [TypeId] lookup via [DrdynvcClient::get_dvc_by_type_id].
/// * Doesn't support [TypeId] lookup via [DrdynvcClient::get_dvc].
/// * If a listener or a pre-registered channel with the same name already exists,
/// it will be silently overwritten.
#[must_use]
Expand All @@ -140,7 +195,7 @@ impl DrdynvcClient {
///
/// # Note
///
/// * Doesn't support [TypeId] lookup via [DrdynvcClient::get_dvc_by_type_id].
/// * Doesn't support [TypeId] lookup via [DrdynvcClient::get_dvc].
/// * If a listener or a pre-registered channel with the same name already exists,
/// it will be silently overwritten.
pub fn attach_listener<T>(&mut self, listener: T)
Expand All @@ -150,19 +205,50 @@ impl DrdynvcClient {
self.dynamic_channels.register_listener(listener);
}

pub fn get_dvc_by_type_id<T>(&self) -> Option<&DynamicVirtualChannel>
/// Returns a typed accessor for a pre-registered client DVC.
///
/// Type lookup is available only for channels registered with
/// [`DrdynvcClient::with_dynamic_channel`] or [`DrdynvcClient::attach_dynamic_channel`].
/// Listener-created channels can be retrieved with [`DrdynvcClient::get_dvc_by_channel_id`].
///
/// Returns `None` until the server has created the channel and the processor has started.
pub fn get_dvc<T>(&self) -> Option<DynamicChannelRef<'_, T>>
where
T: DvcProcessor,
T: DvcClientProcessor,
{
self.dynamic_channels.get_by_type_id(TypeId::of::<T>())
let dvc_channel = self.dynamic_channels.get_by_type_id(TypeId::of::<T>())?;
let channel_id = dvc_channel.channel_id?;
dvc_channel
.channel_processor
.as_any()
.downcast_ref()
.map(|p| DynamicChannelRef::new(channel_id, p))
}

pub fn get_dvc_by_channel_id(&self, channel_id: u32) -> Option<&DynamicVirtualChannel> {
self.dynamic_channels.get_by_channel_id(channel_id)
/// Returns a typed accessor for an active client DVC by channel ID.
///
/// Returns `None` when the channel ID is unknown or the processor has a different type.
pub fn get_dvc_by_channel_id<T>(&self, channel_id: u32) -> Option<DynamicChannelRef<'_, T>>
where
T: DvcClientProcessor,
{
self.dynamic_channels
.get_by_channel_id(channel_id)
.and_then(|dvc| dvc.channel_processor.as_any().downcast_ref())
.map(|p| DynamicChannelRef::new(channel_id, p))
}

pub fn get_dvc_by_channel_id_mut(&mut self, channel_id: u32) -> Option<&mut DynamicVirtualChannel> {
self.dynamic_channels.get_by_channel_id_mut(channel_id)
/// Returns a mutable typed accessor for an active client DVC by channel ID.
///
/// Returns `None` when the channel ID is unknown or the processor has a different type.
pub fn get_dvc_by_channel_id_mut<T>(&mut self, channel_id: u32) -> Option<DynamicChannelMut<'_, T>>
where
T: DvcClientProcessor,
{
self.dynamic_channels
.get_by_channel_id_mut(channel_id)
.and_then(|dvc| dvc.channel_processor.as_any_mut().downcast_mut())
.map(|p| DynamicChannelMut::new(channel_id, p))
}

fn create_capabilities_response(&mut self, server_version: CapsVersion) -> SvcMessage {
Expand Down Expand Up @@ -307,7 +393,7 @@ impl DynamicChannelSet {
);
}

fn register_once<T: DvcProcessor + 'static>(&mut self, channel: T) {
fn register_once<T: DvcClientProcessor + 'static>(&mut self, channel: T) {
let name = channel.channel_name().to_owned();
self.listeners.insert(
name,
Expand Down
69 changes: 3 additions & 66 deletions crates/ironrdp-dvc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

extern crate alloc;

use core::any::TypeId;

use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
Expand All @@ -16,7 +14,7 @@ use pdu::DrdynvcDataPdu;
#[rustfmt::skip] // do not re-order this pub use
pub use ironrdp_pdu;
use ironrdp_core::{AsAny, Encode, EncodeResult, assert_obj_safe, cast_length, encode_vec, other_err};
use ironrdp_pdu::{PduResult, decode_err};
use ironrdp_pdu::PduResult;
use ironrdp_svc::SvcMessage;

mod complete_data;
Expand Down Expand Up @@ -100,69 +98,7 @@ pub fn encode_dvc_messages(
Ok(res)
}

pub struct DynamicVirtualChannel {
channel_processor: Box<dyn DvcProcessor + Send>,
complete_data: CompleteData,
/// The channel ID assigned by the server.
///
/// `Some` only after [`DynamicVirtualChannel::start`] has succeeded. This invariant
channel_id: Option<DynamicChannelId>,
}

impl Drop for DynamicVirtualChannel {
fn drop(&mut self) {
if let Some(id) = self.channel_id {
self.channel_processor.close(id);
}
}
}

impl DynamicVirtualChannel {
fn from_boxed(processor: Box<dyn DvcProcessor + Send>) -> Self {
Self {
channel_processor: processor,
complete_data: CompleteData::new(),
channel_id: None,
}
}

fn processor_type_id(&self) -> TypeId {
self.channel_processor.as_any().type_id()
}

pub fn is_open(&self) -> bool {
self.channel_id.is_some()
}

pub fn channel_id(&self) -> Option<DynamicChannelId> {
self.channel_id
}

pub fn channel_processor_downcast_ref<T: DvcProcessor>(&self) -> Option<&T> {
self.channel_processor.as_any().downcast_ref()
}

fn start(&mut self, channel_id: DynamicChannelId) -> PduResult<Vec<DvcMessage>> {
let messages = self.channel_processor.start(channel_id)?;
self.channel_id = Some(channel_id);
Ok(messages)
}

fn process(&mut self, pdu: DrdynvcDataPdu) -> PduResult<Vec<DvcMessage>> {
let channel_id = pdu.channel_id();
let complete_data = self.complete_data.process_data(pdu).map_err(|e| decode_err!(e))?;
if let Some(complete_data) = complete_data {
self.channel_processor.process(channel_id, &complete_data)
} else {
Ok(Vec::new())
}
}

fn channel_name(&self) -> &str {
self.channel_processor.channel_name()
}
}

/// Borrowed typed view of a dynamic virtual channel.
#[derive(Debug, Clone, Copy)]
pub struct DynamicChannelRef<'a, T> {
channel_id: DynamicChannelId,
Expand All @@ -185,6 +121,7 @@ impl<'a, T: DvcProcessor> DynamicChannelRef<'a, T> {
}
}

/// Mutable borrowed typed view of a dynamic virtual channel.
#[derive(Debug)]
pub struct DynamicChannelMut<'a, T> {
channel_id: DynamicChannelId,
Expand Down
4 changes: 3 additions & 1 deletion crates/ironrdp-dvc/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ enum ChannelState {

struct DynamicChannel {
state: ChannelState,
processor: Box<dyn DvcProcessor>,
processor: Box<dyn DvcServerProcessor>,
complete_data: CompleteData,
channel_id: u32,
}
Expand Down Expand Up @@ -186,6 +186,7 @@ impl DrdynvcServer {
.ok_or_else(|| invalid_field_err!("DRDYNVC", "", "invalid channel id"))
}

/// Returns a typed accessor for an active server DVC by channel ID.
pub fn dvc_by_id<T: DvcServerProcessor>(&self, id: u32) -> Option<DynamicChannelRef<'_, T>> {
let channel = self.dynamic_channels.get(id)?;
if channel.state != ChannelState::Opened {
Expand All @@ -198,6 +199,7 @@ impl DrdynvcServer {
.map(|p| DynamicChannelRef::new(id, p))
}

/// Returns a mutable typed accessor for an active server DVC by channel ID.
pub fn dvc_by_id_mut<T: DvcServerProcessor>(&mut self, id: u32) -> Option<DynamicChannelMut<'_, T>> {
let channel = self.dynamic_channels.get_mut(id)?;
if channel.state != ChannelState::Opened {
Expand Down
42 changes: 20 additions & 22 deletions crates/ironrdp-session/src/active_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use ironrdp_connector::ConnectionResult;
use ironrdp_connector::connection_activation::ConnectionActivationSequence;
use ironrdp_core::{ReadCursor, WriteBuf};
use ironrdp_displaycontrol::client::DisplayControlClient;
use ironrdp_dvc::{DrdynvcClient, DvcProcessor, DynamicVirtualChannel};
use ironrdp_dvc::{DrdynvcClient, DvcClientProcessor, DynamicChannelRef};
use ironrdp_graphics::pointer::DecodedPointer;
use ironrdp_pdu::geometry::InclusiveRectangle;
use ironrdp_pdu::input::fast_path::{FastPathInput, FastPathInputEvent};
Expand Down Expand Up @@ -237,11 +237,14 @@ impl ActiveStage {
self.x224_processor.get_svc_processor_mut()
}

pub fn get_dvc<T: DvcProcessor + 'static>(&mut self) -> Option<&DynamicVirtualChannel> {
pub fn get_dvc<T: DvcClientProcessor + 'static>(&mut self) -> Option<DynamicChannelRef<'_, T>> {
self.x224_processor.get_dvc::<T>()
}

pub fn get_dvc_by_channel_id(&mut self, channel_id: u32) -> Option<&DynamicVirtualChannel> {
pub fn get_dvc_by_channel_id<T: DvcClientProcessor + 'static>(
&mut self,
channel_id: u32,
) -> Option<DynamicChannelRef<'_, T>> {
self.x224_processor.get_dvc_by_channel_id(channel_id)
}

Expand Down Expand Up @@ -277,25 +280,20 @@ impl ActiveStage {
physical_dims: Option<(u32, u32)>,
) -> Option<SessionResult<Vec<u8>>> {
if let Some(dvc) = self.get_dvc::<DisplayControlClient>() {
if let Some(channel_id) = dvc.channel_id() {
let display_control = dvc.channel_processor_downcast_ref::<DisplayControlClient>()?;
let svc_messages = match display_control.encode_single_primary_monitor(
channel_id,
width,
height,
scale_factor,
physical_dims,
) {
Ok(messages) => messages,
Err(e) => return Some(Err(SessionError::encode(e))),
};

return Some(
self.process_svc_processor_messages(SvcProcessorMessages::<DrdynvcClient>::new(svc_messages)),
);
} else {
debug!("Could not encode a resize: Display Control Virtual Channel is not yet connected");
}
let channel_id = dvc.channel_id();
let display_control = dvc.processor();
let svc_messages = match display_control.encode_single_primary_monitor(
channel_id,
width,
height,
scale_factor,
physical_dims,
) {
Ok(messages) => messages,
Err(e) => return Some(Err(SessionError::encode(e))),
};

return Some(self.process_svc_processor_messages(SvcProcessorMessages::<DrdynvcClient>::new(svc_messages)));
} else {
debug!("Could not encode a resize: Display Control Virtual Channel is not available");
}
Expand Down
Loading
Loading