1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#[cfg(test)]
mod test;

use std::io;

use bitflags::bitflags;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use crate::{rdp::CapabilitySetsError, try_read_optional, try_write_optional, PduParsing};

const FLAGS_FIELD_SIZE: usize = 4;
const CHUNK_SIZE_FIELD_SIZE: usize = 4;

bitflags! {
    pub struct VirtualChannelFlags: u32 {
        const NO_COMPRESSION = 0;
        const COMPRESSION_SERVER_TO_CLIENT = 1;
        const COMPRESSION_CLIENT_TO_SERVER_8K = 2;
    }
}

/// The VirtualChannel structure is used to advertise virtual channel support characteristics. This capability is sent by both client and server.
///
/// # Fields
///
/// * `flags` - virtual channel compression flags
/// * `chunk_size` - when sent from server to client, this field contains the maximum allowed size of a virtual channel chunk and MUST be greater than or equal to 1600 and less than or equal to 16256.
/// When sent from client to server, the value in this field is ignored by the server. This value is not verified in IronRDP and MUST be verified on the caller's side
///
/// # MSDN
///
/// * [Virtual Channel Capability Set](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a8593178-80c0-4b80-876c-cb77e62cecfc)
#[derive(Debug, PartialEq, Clone)]
pub struct VirtualChannel {
    pub flags: VirtualChannelFlags,
    pub chunk_size: Option<u32>,
}

impl PduParsing for VirtualChannel {
    type Error = CapabilitySetsError;

    fn from_buffer(mut buffer: impl io::Read) -> Result<Self, Self::Error> {
        let flags = VirtualChannelFlags::from_bits_truncate(buffer.read_u32::<LittleEndian>()?);

        let mut virtual_channel_pdu = Self {
            flags,
            chunk_size: None,
        };

        virtual_channel_pdu.chunk_size = Some(try_read_optional!(
            buffer.read_u32::<LittleEndian>(),
            virtual_channel_pdu
        ));

        Ok(virtual_channel_pdu)
    }

    fn to_buffer(&self, mut buffer: impl io::Write) -> Result<(), Self::Error> {
        buffer.write_u32::<LittleEndian>(self.flags.bits())?;

        try_write_optional!(self.chunk_size, |value: &u32| {
            buffer.write_u32::<LittleEndian>(*value)
        });

        Ok(())
    }

    fn buffer_length(&self) -> usize {
        FLAGS_FIELD_SIZE + self.chunk_size.map(|_| CHUNK_SIZE_FIELD_SIZE).unwrap_or(0)
    }
}