ironrdp_pdu/gcc/
cluster_data.rs

1use std::io;
2
3use bitflags::bitflags;
4use ironrdp_core::{
5    ensure_fixed_part_size, invalid_field_err, Decode, DecodeResult, Encode, EncodeResult, ReadCursor, WriteCursor,
6};
7use num_derive::{FromPrimitive, ToPrimitive};
8use num_traits::{FromPrimitive as _, ToPrimitive as _};
9use thiserror::Error;
10
11const REDIRECTION_VERSION_MASK: u32 = 0x0000_003C;
12
13const FLAGS_SIZE: usize = 4;
14const REDIRECTED_SESSION_ID_SIZE: usize = 4;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ClientClusterData {
18    pub flags: RedirectionFlags,
19    pub redirection_version: RedirectionVersion,
20    pub redirected_session_id: u32,
21}
22
23impl ClientClusterData {
24    const NAME: &'static str = "ClientClusterData";
25
26    const FIXED_PART_SIZE: usize = FLAGS_SIZE + REDIRECTED_SESSION_ID_SIZE;
27}
28
29impl Encode for ClientClusterData {
30    fn encode(&self, dst: &mut WriteCursor<'_>) -> EncodeResult<()> {
31        ensure_fixed_part_size!(in: dst);
32
33        let flags_with_version = self.flags.bits() | (self.redirection_version.to_u32().unwrap() << 2);
34
35        dst.write_u32(flags_with_version);
36        dst.write_u32(self.redirected_session_id);
37
38        Ok(())
39    }
40
41    fn name(&self) -> &'static str {
42        Self::NAME
43    }
44
45    fn size(&self) -> usize {
46        Self::FIXED_PART_SIZE
47    }
48}
49
50impl<'de> Decode<'de> for ClientClusterData {
51    fn decode(src: &mut ReadCursor<'de>) -> DecodeResult<Self> {
52        ensure_fixed_part_size!(in: src);
53
54        let flags_with_version = src.read_u32();
55        let redirected_session_id = src.read_u32();
56
57        let flags = RedirectionFlags::from_bits(flags_with_version & !REDIRECTION_VERSION_MASK)
58            .ok_or_else(|| invalid_field_err!("flags", "invalid redirection flags"))?;
59        let redirection_version =
60            RedirectionVersion::from_u8(((flags_with_version & REDIRECTION_VERSION_MASK) >> 2) as u8)
61                .ok_or_else(|| invalid_field_err!("redirVersion", "invalid redirection version"))?;
62
63        Ok(Self {
64            flags,
65            redirection_version,
66            redirected_session_id,
67        })
68    }
69}
70
71bitflags! {
72    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
73    pub struct RedirectionFlags: u32 {
74        const REDIRECTION_SUPPORTED = 0x0000_0001;
75        const REDIRECTED_SESSION_FIELD_VALID = 0x0000_0002;
76        const REDIRECTED_SMARTCARD = 0x0000_0040;
77    }
78}
79
80#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
81pub enum RedirectionVersion {
82    V1 = 0,
83    V2 = 1,
84    V3 = 2,
85    V4 = 3,
86    V5 = 4,
87    V6 = 5,
88}
89
90#[derive(Debug, Error)]
91pub enum ClusterDataError {
92    #[error("IO error")]
93    IOError(#[from] io::Error),
94    #[error("invalid redirection flags field")]
95    InvalidRedirectionFlags,
96}