1#![cfg_attr(doc, doc = include_str!("../README.md"))]
2#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5extern crate alloc;
6
7use alloc::boxed::Box;
8use alloc::collections::BTreeMap;
9use alloc::string::String;
10use alloc::vec::Vec;
11use core::any::TypeId;
12
13use pdu::DrdynvcDataPdu;
14
15use crate::alloc::borrow::ToOwned as _;
16#[rustfmt::skip] pub use ironrdp_pdu;
19use ironrdp_core::{assert_obj_safe, cast_length, encode_vec, other_err, AsAny, Encode, EncodeResult};
20use ironrdp_pdu::{decode_err, pdu_other_err, PduResult};
21use ironrdp_svc::SvcMessage;
22
23mod complete_data;
24use complete_data::CompleteData;
25
26mod client;
27pub use client::*;
28
29mod server;
30pub use server::*;
31
32pub mod pdu;
33
34pub trait DvcEncode: Encode + Send {}
38pub type DvcMessage = Box<dyn DvcEncode>;
39
40pub trait DvcProcessor: AsAny + Send {
47 fn channel_name(&self) -> &str;
49
50 fn start(&mut self, channel_id: u32) -> PduResult<Vec<DvcMessage>>;
53
54 fn process(&mut self, channel_id: u32, payload: &[u8]) -> PduResult<Vec<DvcMessage>>;
55
56 fn close(&mut self, _channel_id: u32) {}
57}
58
59assert_obj_safe!(DvcProcessor);
60
61pub fn encode_dvc_messages(
62 channel_id: u32,
63 messages: Vec<DvcMessage>,
64 flags: ironrdp_svc::ChannelFlags,
65) -> EncodeResult<Vec<SvcMessage>> {
66 let mut res = Vec::new();
67 for msg in messages {
68 let total_length = msg.size();
69 let needs_splitting = total_length >= DrdynvcDataPdu::MAX_DATA_SIZE;
70
71 let msg = encode_vec(msg.as_ref())?;
72 let mut off = 0;
73
74 while off < total_length {
75 let first = off == 0;
76
77 #[expect(clippy::missing_panics_doc, reason = "unreachable panic (checked underflow)")]
78 let remaining_length = total_length.checked_sub(off).expect("never overflow");
79 let size = core::cmp::min(remaining_length, DrdynvcDataPdu::MAX_DATA_SIZE);
80 let end = off
81 .checked_add(size)
82 .ok_or_else(|| other_err!("encode_dvc_messages", "overflow occurred"))?;
83
84 let pdu = if needs_splitting && first {
85 DrdynvcDataPdu::DataFirst(pdu::DataFirstPdu::new(
86 channel_id,
87 cast_length!("total_length", total_length)?,
88 msg[off..end].to_vec(),
89 ))
90 } else {
91 DrdynvcDataPdu::Data(pdu::DataPdu::new(channel_id, msg[off..end].to_vec()))
92 };
93
94 let svc = SvcMessage::from(pdu).with_flags(flags);
95
96 res.push(svc);
97 off = end;
98 }
99 }
100
101 Ok(res)
102}
103
104pub struct DynamicVirtualChannel {
105 channel_processor: Box<dyn DvcProcessor + Send>,
106 complete_data: CompleteData,
107 channel_id: Option<DynamicChannelId>,
111}
112
113impl DynamicVirtualChannel {
114 fn new<T: DvcProcessor + 'static>(handler: T) -> Self {
115 Self {
116 channel_processor: Box::new(handler),
117 complete_data: CompleteData::new(),
118 channel_id: None,
119 }
120 }
121
122 pub fn is_open(&self) -> bool {
123 self.channel_id.is_some()
124 }
125
126 pub fn channel_id(&self) -> Option<DynamicChannelId> {
127 self.channel_id
128 }
129
130 pub fn channel_processor_downcast_ref<T: DvcProcessor>(&self) -> Option<&T> {
131 self.channel_processor.as_any().downcast_ref()
132 }
133
134 fn start(&mut self) -> PduResult<Vec<DvcMessage>> {
135 if let Some(channel_id) = self.channel_id {
136 self.channel_processor.start(channel_id)
137 } else {
138 Err(pdu_other_err!("DynamicVirtualChannel::start", "channel ID not set"))
139 }
140 }
141
142 fn process(&mut self, pdu: DrdynvcDataPdu) -> PduResult<Vec<DvcMessage>> {
143 let channel_id = pdu.channel_id();
144 let complete_data = self.complete_data.process_data(pdu).map_err(|e| decode_err!(e))?;
145 if let Some(complete_data) = complete_data {
146 self.channel_processor.process(channel_id, &complete_data)
147 } else {
148 Ok(Vec::new())
149 }
150 }
151
152 fn channel_name(&self) -> &str {
153 self.channel_processor.channel_name()
154 }
155}
156
157struct DynamicChannelSet {
158 channels: BTreeMap<DynamicChannelName, DynamicVirtualChannel>,
159 name_to_channel_id: BTreeMap<DynamicChannelName, DynamicChannelId>,
160 channel_id_to_name: BTreeMap<DynamicChannelId, DynamicChannelName>,
161 type_id_to_name: BTreeMap<TypeId, DynamicChannelName>,
162}
163
164impl DynamicChannelSet {
165 #[inline]
166 fn new() -> Self {
167 Self {
168 channels: BTreeMap::new(),
169 name_to_channel_id: BTreeMap::new(),
170 channel_id_to_name: BTreeMap::new(),
171 type_id_to_name: BTreeMap::new(),
172 }
173 }
174
175 fn insert<T: DvcProcessor + 'static>(&mut self, channel: T) -> Option<DynamicVirtualChannel> {
176 let name = channel.channel_name().to_owned();
177 self.type_id_to_name.insert(TypeId::of::<T>(), name.clone());
178 self.channels.insert(name, DynamicVirtualChannel::new(channel))
179 }
180
181 fn attach_channel_id(&mut self, name: DynamicChannelName, id: DynamicChannelId) -> Option<DynamicChannelId> {
182 self.channel_id_to_name.insert(id, name.clone());
183 self.name_to_channel_id.insert(name.clone(), id);
184 let dvc = self.get_by_channel_name_mut(&name)?;
185 let old_id = dvc.channel_id;
186 dvc.channel_id = Some(id);
187 old_id
188 }
189
190 fn get_by_type_id(&self, type_id: TypeId) -> Option<&DynamicVirtualChannel> {
191 self.type_id_to_name
192 .get(&type_id)
193 .and_then(|name| self.channels.get(name))
194 }
195
196 fn get_by_channel_name(&self, name: &DynamicChannelName) -> Option<&DynamicVirtualChannel> {
197 self.channels.get(name)
198 }
199
200 fn get_by_channel_name_mut(&mut self, name: &DynamicChannelName) -> Option<&mut DynamicVirtualChannel> {
201 self.channels.get_mut(name)
202 }
203
204 fn get_by_channel_id(&self, id: DynamicChannelId) -> Option<&DynamicVirtualChannel> {
205 self.channel_id_to_name
206 .get(&id)
207 .and_then(|name| self.channels.get(name))
208 }
209
210 fn get_by_channel_id_mut(&mut self, id: DynamicChannelId) -> Option<&mut DynamicVirtualChannel> {
211 self.channel_id_to_name
212 .get(&id)
213 .and_then(|name| self.channels.get_mut(name))
214 }
215
216 fn remove_by_channel_id(&mut self, id: DynamicChannelId) -> Option<DynamicChannelId> {
217 if let Some(name) = self.channel_id_to_name.remove(&id) {
218 return self.name_to_channel_id.remove(&name);
219 }
222 None
223 }
224
225 #[inline]
226 fn values(&self) -> impl Iterator<Item = &DynamicVirtualChannel> {
227 self.channels.values()
228 }
229}
230
231pub type DynamicChannelName = String;
232pub type DynamicChannelId = u32;