Skip to content

Commit 66ceda2

Browse files
author
Isaiah Becker-Mayer
committed
Removes the explicit state machine from DecodingContext. State comes to us from the server via the BlockType in the BlockHeader, so it needn't be rigidly tracked explicitly in DecodingContext. This makes the RFX pipeline more flexible, which in turn allows us to seamlessly use it when we get another sync sequence mid-stream due to having fielded a Server Deactivate PDU.
1 parent 074f47d commit 66ceda2

File tree

5 files changed

+62
-35
lines changed

5 files changed

+62
-35
lines changed

crates/ironrdp-pdu/src/codecs/rfx.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ pub struct BlockHeader {
7676
}
7777

7878
impl BlockHeader {
79+
pub fn from_buffer_consume(buffer: &mut &[u8]) -> Result<Self, RfxError> {
80+
let ty = BlockType::from_buffer(buffer)?;
81+
Self::from_buffer_consume_with_type(buffer, ty)
82+
}
83+
7984
fn from_buffer_consume_with_type(buffer: &mut &[u8], ty: BlockType) -> Result<Self, RfxError> {
8085
let block_length = buffer.read_u32::<LittleEndian>()? as usize;
8186

@@ -98,8 +103,7 @@ impl BlockHeader {
98103
}
99104

100105
fn from_buffer_consume_with_expected_type(buffer: &mut &[u8], expected_type: BlockType) -> Result<Self, RfxError> {
101-
let ty = buffer.read_u16::<LittleEndian>()?;
102-
let ty = BlockType::from_u16(ty).ok_or(RfxError::InvalidBlockType(ty))?;
106+
let ty = BlockType::from_buffer(buffer)?;
103107
if ty != expected_type {
104108
return Err(RfxError::UnexpectedBlockType {
105109
expected: expected_type,
@@ -220,6 +224,14 @@ pub enum BlockType {
220224
Extension = 0xCCC7,
221225
}
222226

227+
impl BlockType {
228+
fn from_buffer(buffer: &mut &[u8]) -> Result<Self, RfxError> {
229+
let ty = buffer.read_u16::<LittleEndian>()?;
230+
let ty = BlockType::from_u16(ty).ok_or(RfxError::InvalidBlockType(ty))?;
231+
Ok(ty)
232+
}
233+
}
234+
223235
#[derive(Debug, Error)]
224236
pub enum RfxError {
225237
#[error("IO error")]

crates/ironrdp-pdu/src/codecs/rfx/data_messages.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,8 @@ pub struct FrameBeginPdu {
120120
pub number_of_regions: i16,
121121
}
122122

123-
impl PduBufferParsing<'_> for FrameBeginPdu {
124-
type Error = RfxError;
125-
126-
fn from_buffer_consume(buffer: &mut &[u8]) -> Result<Self, Self::Error> {
127-
let header = BlockHeader::from_buffer_consume_with_expected_type(buffer, BlockType::FrameBegin)?;
123+
impl FrameBeginPdu {
124+
pub fn from_buffer_consume_with_header(buffer: &mut &[u8], header: BlockHeader) -> Result<Self, RfxError> {
128125
CodecChannelHeader::from_buffer_consume_with_type(buffer, BlockType::FrameBegin)?;
129126
let mut buffer = buffer.split_to(header.data_length);
130127

@@ -136,6 +133,15 @@ impl PduBufferParsing<'_> for FrameBeginPdu {
136133
number_of_regions,
137134
})
138135
}
136+
}
137+
138+
impl PduBufferParsing<'_> for FrameBeginPdu {
139+
type Error = RfxError;
140+
141+
fn from_buffer_consume(buffer: &mut &[u8]) -> Result<Self, Self::Error> {
142+
let header = BlockHeader::from_buffer_consume_with_expected_type(buffer, BlockType::FrameBegin)?;
143+
Self::from_buffer_consume_with_header(buffer, header)
144+
}
139145

140146
fn to_buffer_consume(&self, buffer: &mut &mut [u8]) -> Result<(), Self::Error> {
141147
let header = BlockHeader {

crates/ironrdp-pdu/src/codecs/rfx/header_messages.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,8 @@ const CHANNEL_SIZE: usize = 5;
1616
#[derive(Debug, Clone, PartialEq, Eq)]
1717
pub struct SyncPdu;
1818

19-
impl PduBufferParsing<'_> for SyncPdu {
20-
type Error = RfxError;
21-
22-
fn from_buffer_consume(buffer: &mut &[u8]) -> Result<Self, Self::Error> {
23-
let header = BlockHeader::from_buffer_consume_with_expected_type(buffer, BlockType::Sync)?;
19+
impl SyncPdu {
20+
pub fn from_buffer_consume_with_header(buffer: &mut &[u8], header: BlockHeader) -> Result<Self, RfxError> {
2421
let mut buffer = buffer.split_to(header.data_length);
2522

2623
let magic = buffer.read_u32::<LittleEndian>()?;
@@ -34,6 +31,15 @@ impl PduBufferParsing<'_> for SyncPdu {
3431
Ok(Self)
3532
}
3633
}
34+
}
35+
36+
impl PduBufferParsing<'_> for SyncPdu {
37+
type Error = RfxError;
38+
39+
fn from_buffer_consume(buffer: &mut &[u8]) -> Result<Self, Self::Error> {
40+
let header = BlockHeader::from_buffer_consume_with_expected_type(buffer, BlockType::Sync)?;
41+
Self::from_buffer_consume_with_header(buffer, header)
42+
}
3743

3844
fn to_buffer_consume(&self, buffer: &mut &mut [u8]) -> Result<(), Self::Error> {
3945
let header = BlockHeader {

crates/ironrdp-session/src/rfx.rs

+22-22
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const TILE_SIZE: u16 = 64;
1515
pub type FrameId = u32;
1616

1717
pub struct DecodingContext {
18-
state: SequenceState,
1918
context: rfx::ContextPdu,
2019
channels: rfx::ChannelsPdu,
2120
decoding_tiles: DecodingTileContext,
@@ -24,7 +23,6 @@ pub struct DecodingContext {
2423
impl Default for DecodingContext {
2524
fn default() -> Self {
2625
Self {
27-
state: SequenceState::HeaderMessages,
2826
context: rfx::ContextPdu {
2927
flags: rfx::OperatingMode::empty(),
3028
entropy_algorithm: rfx::EntropyAlgorithm::Rlgr1,
@@ -47,20 +45,31 @@ impl DecodingContext {
4745
input: &mut &[u8],
4846
) -> SessionResult<(FrameId, InclusiveRectangle)> {
4947
loop {
50-
match self.state {
51-
SequenceState::HeaderMessages => {
52-
self.process_headers(input)?;
48+
let block_header = rfx::BlockHeader::from_buffer_consume(input)?;
49+
match block_header.ty {
50+
rfx::BlockType::Sync => {
51+
self.process_sync(input, block_header)?;
5352
}
54-
SequenceState::DataMessages => {
55-
return self.process_data_messages(image, destination, input);
53+
rfx::BlockType::FrameBegin => {
54+
return self.process_frame(input, block_header, image, destination);
55+
}
56+
_ => {
57+
return Err(reason_err!(
58+
"rfx::DecodingContext",
59+
"unexpected RFX block type: {:?}",
60+
block_header.ty
61+
));
5662
}
5763
}
5864
}
5965
}
6066

61-
fn process_headers(&mut self, input: &mut &[u8]) -> SessionResult<()> {
62-
let _sync = rfx::SyncPdu::from_buffer_consume(input)?;
67+
fn process_sync(&mut self, input: &mut &[u8], header: rfx::BlockHeader) -> SessionResult<()> {
68+
let _sync = rfx::SyncPdu::from_buffer_consume_with_header(input, header)?;
69+
self.process_headers(input)
70+
}
6371

72+
fn process_headers(&mut self, input: &mut &[u8]) -> SessionResult<()> {
6473
let mut context = None;
6574
let mut channels = None;
6675

@@ -81,24 +90,24 @@ impl DecodingContext {
8190

8291
self.context = context;
8392
self.channels = channels;
84-
self.state = SequenceState::DataMessages;
8593

8694
Ok(())
8795
}
8896

8997
#[instrument(skip_all)]
90-
fn process_data_messages(
98+
fn process_frame(
9199
&mut self,
100+
input: &mut &[u8],
101+
header: rfx::BlockHeader,
92102
image: &mut DecodedImage,
93103
destination: &InclusiveRectangle,
94-
input: &mut &[u8],
95104
) -> SessionResult<(FrameId, InclusiveRectangle)> {
96105
let channel = self.channels.0.first().unwrap();
97106
let width = channel.width.as_u16();
98107
let height = channel.height.as_u16();
99108
let entropy_algorithm = self.context.entropy_algorithm;
100109

101-
let frame_begin = rfx::FrameBeginPdu::from_buffer_consume(input)?;
110+
let frame_begin = rfx::FrameBeginPdu::from_buffer_consume_with_header(input, header)?;
102111
let mut region = rfx::RegionPdu::from_buffer_consume(input)?;
103112
let tile_set = rfx::TileSetPdu::from_buffer_consume(input)?;
104113
let _frame_end = rfx::FrameEndPdu::from_buffer_consume(input)?;
@@ -145,10 +154,6 @@ impl DecodingContext {
145154
final_update_rectangle = final_update_rectangle.union(&current_update_rectangle);
146155
}
147156

148-
if self.context.flags.contains(rfx::OperatingMode::IMAGE_MODE) {
149-
self.state = SequenceState::HeaderMessages;
150-
}
151-
152157
Ok((frame_begin.index, final_update_rectangle))
153158
}
154159
}
@@ -258,8 +263,3 @@ struct TileData<'a> {
258263
quants: [Quant; 3],
259264
data: [&'a [u8]; 3],
260265
}
261-
262-
enum SequenceState {
263-
HeaderMessages,
264-
DataMessages,
265-
}

crates/ironrdp-session/src/x224/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ pub enum ProcessorOutput {
3030
ResponseFrame(Vec<u8>),
3131
/// A graceful disconnect notification. Client should close the connection upon receiving this.
3232
Disconnect(DisconnectReason),
33-
/// Received a [`ironrdp_pdu::rdp::headers::ServerDeactivateAll`] PDU.
33+
/// Received a [`ironrdp_pdu::rdp::headers::ServerDeactivateAll`] PDU. Client should execute the
34+
/// [Deactivation-Reactivation Sequence].
35+
///
36+
/// [Deactivation-Reactivation Sequence]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/dfc234ce-481a-4674-9a5d-2a7bafb14432
3437
DeactivateAll(ConnectionActivationSequence),
3538
}
3639

0 commit comments

Comments
 (0)