ironrdp_pdu/gcc/core_data/
server.rs1use bitflags::bitflags;
2use ironrdp_core::{
3 ensure_fixed_part_size, ensure_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor,
4 WriteCursor,
5};
6use tap::Pipe as _;
7
8use super::RdpVersion;
9use crate::nego::SecurityProtocol;
10
11const CLIENT_REQUESTED_PROTOCOL_SIZE: usize = 4;
12const EARLY_CAPABILITY_FLAGS_SIZE: usize = 4;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct ServerCoreData {
16 pub version: RdpVersion,
17 pub optional_data: ServerCoreOptionalData,
18}
19
20impl ServerCoreData {
21 const NAME: &'static str = "ServerCoreData";
22
23 const FIXED_PART_SIZE: usize = 4 ;
24}
25
26impl Encode for ServerCoreData {
27 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
28 ensure_size!(in: dst, size: self.size());
29
30 dst.write_u32(self.version.0);
31 self.optional_data.encode(dst)
32 }
33
34 fn name(&self) -> &'static str {
35 Self::NAME
36 }
37
38 fn size(&self) -> usize {
39 Self::FIXED_PART_SIZE + self.optional_data.size()
40 }
41}
42
43impl<'de> Decode<'de> for ServerCoreData {
44 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
45 ensure_fixed_part_size!(in: src);
46
47 let version = src.read_u32().pipe(RdpVersion);
48 let optional_data = ServerCoreOptionalData::decode(src)?;
49
50 Ok(Self { version, optional_data })
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Default)]
55pub struct ServerCoreOptionalData {
56 pub client_requested_protocols: Option<SecurityProtocol>,
57 pub early_capability_flags: Option<ServerEarlyCapabilityFlags>,
58}
59
60impl ServerCoreOptionalData {
61 const NAME: &'static str = "ServerCoreOptionalData";
62}
63
64impl Encode for ServerCoreOptionalData {
65 fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
66 ensure_size!(in: dst, size: self.size());
67
68 if let Some(value) = self.client_requested_protocols {
69 dst.write_u32(value.bits());
70 };
71
72 if let Some(value) = self.early_capability_flags {
73 dst.write_u32(value.bits());
74 }
75
76 Ok(())
77 }
78
79 fn name(&self) -> &'static str {
80 Self::NAME
81 }
82
83 fn size(&self) -> usize {
84 let mut size = 0;
85
86 if self.client_requested_protocols.is_some() {
87 size += CLIENT_REQUESTED_PROTOCOL_SIZE;
88 }
89 if self.early_capability_flags.is_some() {
90 size += EARLY_CAPABILITY_FLAGS_SIZE;
91 }
92
93 size
94 }
95}
96
97macro_rules! try_or_return {
98 ($expr:expr, $ret:expr) => {
99 match $expr {
100 Ok(v) => v,
101 Err(_) => return Ok($ret),
102 }
103 };
104}
105
106impl<'de> Decode<'de> for ServerCoreOptionalData {
107 fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
108 let mut optional_data = Self::default();
109
110 optional_data.client_requested_protocols = Some(
111 SecurityProtocol::from_bits(try_or_return!(src.try_read_u32(), optional_data))
112 .ok_or_else(|| invalid_field_err!("clientReqProtocols", "invalid server security protocol"))?,
113 );
114
115 optional_data.early_capability_flags = Some(
116 ServerEarlyCapabilityFlags::from_bits(try_or_return!(src.try_read_u32(), optional_data))
117 .ok_or_else(|| invalid_field_err!("earlyCapFlags", "invalid early capability flags"))?,
118 );
119
120 Ok(optional_data)
121 }
122}
123
124bitflags! {
125 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
126 pub struct ServerEarlyCapabilityFlags: u32 {
127 const EDGE_ACTIONS_SUPPORTED_V1 = 0x0000_0001;
128 const DYNAMIC_DST_SUPPORTED = 0x0000_0002;
129 const EDGE_ACTIONS_SUPPORTED_V2 = 0x0000_0004;
130 const SKIP_CHANNELJOIN_SUPPORTED = 0x0000_0008;
131 const _ = !0;
133 }
134}