From b0dd0677a4245e829abd15e9612f29f85bb97d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Fri, 2 Feb 2024 15:33:26 +0400 Subject: [PATCH] refactor(dvc): switch to PduEncode/Decode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau --- crates/ironrdp-dvc/src/client.rs | 8 +- crates/ironrdp-dvc/src/server.rs | 21 +- crates/ironrdp-pdu/src/gcc.rs | 4 +- crates/ironrdp-pdu/src/gcc/monitor_data.rs | 144 +-- .../src/rdp/finalization_messages.rs | 4 +- crates/ironrdp-pdu/src/rdp/vc/dvc.rs | 48 +- .../src/rdp/vc/dvc/capabilities.rs | 4 - crates/ironrdp-pdu/src/rdp/vc/dvc/display.rs | 355 ++++--- crates/ironrdp-pdu/src/rdp/vc/dvc/gfx.rs | 324 +++--- .../src/rdp/vc/dvc/gfx/graphics_messages.rs | 284 ++--- .../dvc/gfx/graphics_messages/avc_messages.rs | 199 ++-- .../vc/dvc/gfx/graphics_messages/client.rs | 147 ++- .../vc/dvc/gfx/graphics_messages/server.rs | 977 +++++++++++------- crates/ironrdp-server/src/server.rs | 8 +- crates/ironrdp-session/src/legacy.rs | 15 +- crates/ironrdp-session/src/x224/display.rs | 6 +- crates/ironrdp-session/src/x224/gfx.rs | 18 +- .../ironrdp-testsuite-core/tests/pdu/gfx.rs | 293 +++--- 18 files changed, 1550 insertions(+), 1309 deletions(-) diff --git a/crates/ironrdp-dvc/src/client.rs b/crates/ironrdp-dvc/src/client.rs index bdeb2548..8bfefbdd 100644 --- a/crates/ironrdp-dvc/src/client.rs +++ b/crates/ironrdp-dvc/src/client.rs @@ -9,7 +9,7 @@ use core::fmt; use ironrdp_pdu as pdu; use ironrdp_svc::{impl_as_any, CompressionCondition, SvcClientProcessor, SvcMessage, SvcProcessor}; -use pdu::cursor::WriteCursor; +use pdu::cursor::{ReadCursor, WriteCursor}; use pdu::gcc::ChannelName; use pdu::rdp::vc; use pdu::{decode, dvc, PduEncode, PduResult}; @@ -239,11 +239,11 @@ fn decode_dvc_message(user_data: &[u8]) -> PduResult> { debug_assert_eq!(user_data_len, channel_header.length as usize); // … | dvc::ServerPdu | … - let dvc_pdu = - vc::dvc::ServerPdu::from_buffer(user_data, user_data_len).map_err(|e| custom_err!("DVC server PDU", e))?; + let mut cursor = ReadCursor::new(user_data); + let dvc_pdu = vc::dvc::ServerPdu::decode(&mut cursor, user_data_len)?; // … | DvcData ] - let dvc_data = user_data; + let dvc_data = cursor.remaining(); Ok(DynamicChannelCtx { dvc_pdu, dvc_data }) } diff --git a/crates/ironrdp-dvc/src/server.rs b/crates/ironrdp-dvc/src/server.rs index 258d1ee9..04eeafd1 100644 --- a/crates/ironrdp-dvc/src/server.rs +++ b/crates/ironrdp-dvc/src/server.rs @@ -5,13 +5,13 @@ use alloc::string::String; use alloc::vec::Vec; use core::any::Any; use core::fmt; -use pdu::dvc::{CreateRequestPdu, DataFirstPdu, DataPdu}; use slab::Slab; use ironrdp_pdu as pdu; use ironrdp_svc::{impl_as_any, ChannelFlags, CompressionCondition, SvcMessage, SvcProcessor, SvcServerProcessor}; -use pdu::cursor::WriteCursor; +use pdu::cursor::{ReadCursor, WriteCursor}; +use pdu::dvc::{CreateRequestPdu, DataFirstPdu, DataPdu}; use pdu::gcc::ChannelName; use pdu::rdp::vc; use pdu::write_buf::WriteBuf; @@ -203,24 +203,18 @@ struct DynamicChannelCtx<'a> { } fn decode_dvc_message(user_data: &[u8]) -> PduResult> { - let mut user_data = user_data; - let user_data_len = user_data.len(); - // … | dvc::ClientPdu | … - let dvc_pdu = - vc::dvc::ClientPdu::from_buffer(&mut user_data, user_data_len).map_err(|e| custom_err!("DVC client PDU", e))?; + let mut cur = ReadCursor::new(user_data); + let dvc_pdu = vc::dvc::ClientPdu::decode(&mut cur, user_data.len())?; // … | DvcData ] - let dvc_data = user_data; + let dvc_data = cur.remaining(); Ok(DynamicChannelCtx { dvc_pdu, dvc_data }) } fn encode_dvc_message(pdu: vc::dvc::ServerPdu) -> PduResult { - // FIXME: use PduEncode instead - let mut buf = Vec::new(); - pdu.to_buffer(&mut buf).map_err(|e| custom_err!("DVC server pdu", e))?; - Ok(SvcMessage::from(buf).with_flags(ChannelFlags::SHOW_PROTOCOL)) + Ok(SvcMessage::from(pdu).with_flags(ChannelFlags::SHOW_PROTOCOL)) } fn encode_dvc_data(channel_id: u32, messages: DvcMessages) -> PduResult> { @@ -245,8 +239,7 @@ fn encode_dvc_data(channel_id: u32, messages: DvcMessages) -> PduResult, } -impl PduParsing for ClientMonitorData { - type Error = MonitorDataError; +impl ClientMonitorData { + const NAME: &'static str = "ClientMonitorData"; - fn from_buffer(mut buffer: impl io::Read) -> Result { - let _flags = buffer.read_u32::()?; // is unused - let monitor_count = buffer.read_u32::()?; + const FIXED_PART_SIZE: usize = 4 /* flags */ + 4 /* count */; +} - if monitor_count > MONITOR_COUNT_MAX as u32 { - return Err(MonitorDataError::InvalidMonitorCount); - } +impl PduEncode for ClientMonitorData { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); - let mut monitors = Vec::with_capacity(monitor_count as usize); - for _ in 0..monitor_count { - monitors.push(Monitor::from_buffer(&mut buffer)?); - } - - Ok(Self { monitors }) - } - fn to_buffer(&self, mut buffer: impl io::Write) -> Result<(), Self::Error> { - buffer.write_u32::(0)?; // flags - buffer.write_u32::(self.monitors.len() as u32)?; + dst.write_u32(0); // flags + dst.write_u32(cast_length!("nMonitors", self.monitors.len())?); for monitor in self.monitors.iter().take(MONITOR_COUNT_MAX) { - monitor.to_buffer(&mut buffer)?; + monitor.encode(dst)?; } Ok(()) } - fn buffer_length(&self) -> usize { - MONITOR_FLAGS_SIZE + MONITOR_COUNT_SIZE + self.monitors.len() * MONITOR_SIZE + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + self.monitors.len() * Monitor::FIXED_PART_SIZE } } +impl<'de> PduDecode<'de> for ClientMonitorData { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let _flags = src.read_u32(); // is unused + let monitor_count = src.read_u32(); + + if monitor_count > MONITOR_COUNT_MAX as u32 { + return Err(invalid_message_err!("nMonitors", "too many monitors")); + } + + let mut monitors = Vec::with_capacity(monitor_count as usize); + for _ in 0..monitor_count { + monitors.push(Monitor::decode(src)?); + } + + Ok(Self { monitors }) + } +} + +impl_pdu_parsing_max!(ClientMonitorData); + #[derive(Debug, Clone, PartialEq, Eq)] pub struct Monitor { pub left: i32, @@ -60,16 +74,44 @@ pub struct Monitor { pub flags: MonitorFlags, } -impl PduParsing for Monitor { - type Error = MonitorDataError; +impl Monitor { + const NAME: &'static str = "Monitor"; - fn from_buffer(mut buffer: impl io::Read) -> Result { - let left = buffer.read_i32::()?; - let top = buffer.read_i32::()?; - let right = buffer.read_i32::()?; - let bottom = buffer.read_i32::()?; - let flags = - MonitorFlags::from_bits(buffer.read_u32::()?).ok_or(MonitorDataError::InvalidMonitorFlags)?; + const FIXED_PART_SIZE: usize = 4 /* left */ + 4 /* top */ + 4 /* right */ + 4 /* bottom */ + 4 /* flags */; +} + +impl PduEncode for Monitor { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + dst.write_i32(self.left); + dst.write_i32(self.top); + dst.write_i32(self.right); + dst.write_i32(self.bottom); + dst.write_u32(self.flags.bits()); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'de> PduDecode<'de> for Monitor { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let left = src.read_i32(); + let top = src.read_i32(); + let right = src.read_i32(); + let bottom = src.read_i32(); + let flags = MonitorFlags::from_bits(src.read_u32()) + .ok_or_else(|| invalid_message_err!("flags", "invalid monitor flags"))?; Ok(Self { left, @@ -79,41 +121,13 @@ impl PduParsing for Monitor { flags, }) } - fn to_buffer(&self, mut buffer: impl io::Write) -> Result<(), Self::Error> { - buffer.write_i32::(self.left)?; - buffer.write_i32::(self.top)?; - buffer.write_i32::(self.right)?; - buffer.write_i32::(self.bottom)?; - buffer.write_u32::(self.flags.bits())?; - - Ok(()) - } - fn buffer_length(&self) -> usize { - MONITOR_SIZE - } } +impl_pdu_parsing!(Monitor); + bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct MonitorFlags: u32 { const PRIMARY = 1; } } - -#[derive(Debug, Error)] -pub enum MonitorDataError { - #[error("IO error")] - IOError(#[from] io::Error), - #[error("invalid monitor count field")] - InvalidMonitorCount, - #[error("invalid monitor flags field")] - InvalidMonitorFlags, - #[error("PDU error")] - Pdu(#[from] PduError), -} - -impl ironrdp_error::legacy::ErrorContext for MonitorDataError { - fn context(&self) -> &'static str { - "monitor data" - } -} diff --git a/crates/ironrdp-pdu/src/rdp/finalization_messages.rs b/crates/ironrdp-pdu/src/rdp/finalization_messages.rs index 7ad84813..d4a1ff40 100644 --- a/crates/ironrdp-pdu/src/rdp/finalization_messages.rs +++ b/crates/ironrdp-pdu/src/rdp/finalization_messages.rs @@ -199,7 +199,7 @@ impl PduEncode for MonitorLayoutPdu { dst.write_u32(cast_length!("nMonitors", self.monitors.len())?); for monitor in self.monitors.iter() { - crate::PduParsing::to_buffer(&monitor, &mut *dst)?; + monitor.encode(dst)?; } Ok(()) @@ -225,7 +225,7 @@ impl<'de> PduDecode<'de> for MonitorLayoutPdu { let mut monitors = Vec::with_capacity(monitor_count as usize); for _ in 0..monitor_count { - monitors.push(::from_buffer(&mut *src)?); + monitors.push(gcc::Monitor::decode(src)?); } Ok(Self { monitors }) diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc.rs index b1e9804c..9a483e7c 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc.rs @@ -3,7 +3,7 @@ use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive}; use crate::cursor::{ReadCursor, WriteCursor}; -use crate::{decode_cursor, PduDecode, PduEncode, PduError, PduResult}; +use crate::{decode_cursor, PduDecode, PduEncode, PduResult}; #[cfg(test)] mod tests; @@ -107,28 +107,6 @@ impl ServerPdu { Ok(res) } - - pub fn from_buffer(mut stream: impl std::io::Read, dvc_data_size: usize) -> Result { - let mut buf = [0; crate::legacy::MAX_PDU_SIZE]; - let len = match stream.read(&mut buf) { - // if not enough data is read, decode will through NotEnoughBytes - Ok(len) => len, - Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => { - return Err(not_enough_bytes_err!(0, crate::legacy::MAX_PDU_SIZE)); - } - Err(e) => return Err(custom_err!(e)), - }; - let mut cur = ReadCursor::new(&buf[0..len]); - Self::decode(&mut cur, dvc_data_size) - } - - pub fn to_buffer(&self, mut stream: impl std::io::Write) -> Result<(), PduError> { - to_buffer!(self, stream, size: self.size()) - } - - pub fn buffer_length(&self) -> usize { - self.size() - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -170,28 +148,6 @@ impl ClientPdu { Ok(res) } - - pub fn from_buffer(mut stream: impl std::io::Read, dvc_data_size: usize) -> Result { - let mut buf = [0; crate::legacy::MAX_PDU_SIZE]; - let len = match stream.read(&mut buf) { - // if not enough data is read, decode will through NotEnoughBytes - Ok(len) => len, - Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => { - return Err(not_enough_bytes_err!(0, crate::legacy::MAX_PDU_SIZE)); - } - Err(e) => return Err(custom_err!(e)), - }; - let mut cur = ReadCursor::new(&buf[0..len]); - Self::decode(&mut cur, dvc_data_size) - } - - pub fn to_buffer(&self, mut stream: impl std::io::Write) -> Result<(), PduError> { - to_buffer!(self, stream, size: self.size()) - } - - pub fn buffer_length(&self) -> usize { - self.size() - } } impl PduEncode for ClientPdu { @@ -316,5 +272,3 @@ impl<'de> PduDecode<'de> for Header { }) } } - -impl_pdu_parsing!(Header); diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/capabilities.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/capabilities.rs index 89c79e07..344751d1 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc/capabilities.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc/capabilities.rs @@ -38,8 +38,6 @@ impl CapabilitiesRequestPdu { const FIXED_PART_SIZE: usize = HEADER_SIZE + DVC_CAPABILITIES_PAD_SIZE + DVC_CAPABILITIES_VERSION_SIZE; } -impl_pdu_parsing!(CapabilitiesRequestPdu); - impl PduEncode for CapabilitiesRequestPdu { fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { ensure_size!(in: dst, size: self.size()); @@ -120,8 +118,6 @@ pub struct CapabilitiesResponsePdu { pub version: CapsVersion, } -impl_pdu_parsing!(CapabilitiesResponsePdu); - impl CapabilitiesResponsePdu { const NAME: &'static str = "CapabilitiesResponsePdu"; diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/display.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/display.rs index c042ba3b..8f9ddb15 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc/display.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc/display.rs @@ -1,12 +1,9 @@ -use std::io; - use bitflags::bitflags; -use byteorder::{LittleEndian, ReadBytesExt as _, WriteBytesExt as _}; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive as _, ToPrimitive as _}; -use thiserror::Error; -use crate::PduParsing; +use crate::cursor::{ReadCursor, WriteCursor}; +use crate::{PduDecode, PduEncode, PduResult}; pub const CHANNEL_NAME: &str = "Microsoft::Windows::RDS::DisplayControl"; @@ -19,13 +16,39 @@ pub struct DisplayControlCapsPdu { pub max_monitor_area_factorb: u32, } -impl PduParsing for DisplayControlCapsPdu { - type Error = io::Error; +impl DisplayControlCapsPdu { + const NAME: &'static str = "DisplayControlCapsPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let max_num_monitors = stream.read_u32::()?; - let max_monitor_area_factora = stream.read_u32::()?; - let max_monitor_area_factorb = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = 4 /* MaxNumMonitors */ + 4 /* MaxFactorA */ + 4 /* MaxFactorB */; +} + +impl PduEncode for DisplayControlCapsPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + dst.write_u32(self.max_num_monitors); + dst.write_u32(self.max_monitor_area_factora); + dst.write_u32(self.max_monitor_area_factorb); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'de> PduDecode<'de> for DisplayControlCapsPdu { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let max_num_monitors = src.read_u32(); + let max_monitor_area_factora = src.read_u32(); + let max_monitor_area_factorb = src.read_u32(); Ok(Self { max_num_monitors, @@ -33,18 +56,6 @@ impl PduParsing for DisplayControlCapsPdu { max_monitor_area_factorb, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u32::(self.max_num_monitors)?; - stream.write_u32::(self.max_monitor_area_factora)?; - stream.write_u32::(self.max_monitor_area_factorb)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 12 - } } bitflags! { @@ -79,22 +90,54 @@ pub struct Monitor { const MONITOR_SIZE: usize = 40; const MONITOR_PDU_HEADER_SIZE: usize = 8; -impl PduParsing for Monitor { - type Error = io::Error; +impl Monitor { + const NAME: &'static str = "DisplayMonitor"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let flags = MonitorFlags::from_bits(stream.read_u32::()?) - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "Invalid monitor flags"))?; - let left = stream.read_u32::()?; - let top = stream.read_u32::()?; - let width = stream.read_u32::()?; - let height = stream.read_u32::()?; - let physical_width = stream.read_u32::()?; - let physical_height = stream.read_u32::()?; - let orientation = Orientation::from_u32(stream.read_u32::()?) - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "Invalid monitor orientation"))?; - let desktop_scale_factor = stream.read_u32::()?; - let device_scale_factor = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = MONITOR_SIZE; +} + +impl PduEncode for Monitor { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + dst.write_u32(self.flags.bits()); + dst.write_u32(self.left); + dst.write_u32(self.top); + dst.write_u32(self.width); + dst.write_u32(self.height); + dst.write_u32(self.physical_width); + dst.write_u32(self.physical_height); + dst.write_u32(self.orientation.to_u32().unwrap()); + dst.write_u32(self.desktop_scale_factor); + dst.write_u32(self.device_scale_factor); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'de> PduDecode<'de> for Monitor { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let flags = MonitorFlags::from_bits_retain(src.read_u32()); + let left = src.read_u32(); + let top = src.read_u32(); + let width = src.read_u32(); + let height = src.read_u32(); + let physical_width = src.read_u32(); + let physical_height = src.read_u32(); + let orientation = Orientation::from_u32(src.read_u32()) + .ok_or_else(|| invalid_message_err!("orientation", "invalid value"))?; + let desktop_scale_factor = src.read_u32(); + let device_scale_factor = src.read_u32(); Ok(Self { flags, @@ -109,25 +152,6 @@ impl PduParsing for Monitor { device_scale_factor, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u32::(self.flags.bits())?; - stream.write_u32::(self.left)?; - stream.write_u32::(self.top)?; - stream.write_u32::(self.width)?; - stream.write_u32::(self.height)?; - stream.write_u32::(self.physical_width)?; - stream.write_u32::(self.physical_height)?; - stream.write_u32::(self.orientation.to_u32().unwrap())?; - stream.write_u32::(self.desktop_scale_factor)?; - stream.write_u32::(self.device_scale_factor)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - MONITOR_SIZE - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -135,82 +159,105 @@ pub struct MonitorLayoutPdu { pub monitors: Vec, } -impl PduParsing for MonitorLayoutPdu { - type Error = io::Error; +impl MonitorLayoutPdu { + const NAME: &'static str = "MonitorLayoutPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let _size = stream.read_u32::()?; - let num_monitors = stream.read_u32::()?; - let mut monitors = Vec::new(); - for _ in 0..num_monitors { - monitors.push(Monitor::from_buffer(&mut stream)?); - } - Ok(Self { monitors }) - } + const FIXED_PART_SIZE: usize = MONITOR_PDU_HEADER_SIZE; +} - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u32::(MONITOR_SIZE as u32)?; - stream.write_u32::(self.monitors.len() as u32)?; +impl PduEncode for MonitorLayoutPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + dst.write_u32(cast_length!("size", MONITOR_SIZE)?); + dst.write_u32(cast_length!("len", self.monitors.len())?); for monitor in &self.monitors { - monitor.to_buffer(stream.by_ref())?; + monitor.encode(dst)?; } Ok(()) } - fn buffer_length(&self) -> usize { + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { MONITOR_PDU_HEADER_SIZE + self.monitors.len() * MONITOR_SIZE } } +impl<'de> PduDecode<'de> for MonitorLayoutPdu { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let _size = src.read_u32(); + let num_monitors = src.read_u32(); + let mut monitors = Vec::new(); + for _ in 0..num_monitors { + monitors.push(Monitor::decode(src)?); + } + Ok(Self { monitors }) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum ServerPdu { DisplayControlCaps(DisplayControlCapsPdu), } -impl PduParsing for ServerPdu { - type Error = DisplayPipelineError; +impl ServerPdu { + const NAME: &'static str = "DisplayServerPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let pdu_type = - ServerPduType::from_u32(stream.read_u32::()?).ok_or(DisplayPipelineError::InvalidCmdId)?; - let pdu_length = stream.read_u32::()? as usize; + const FIXED_PART_SIZE: usize = RDP_DISPLAY_HEADER_SIZE; +} + +impl PduEncode for ServerPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + let size = self.size(); + + ensure_size!(in: dst, size: size); + + dst.write_u32(ServerPduType::from(self).to_u32().unwrap()); + dst.write_u32(cast_length!("len", size)?); + + match self { + ServerPdu::DisplayControlCaps(pdu) => pdu.encode(dst), + } + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + RDP_DISPLAY_HEADER_SIZE + + match self { + ServerPdu::DisplayControlCaps(pdu) => pdu.size(), + } + } +} + +impl<'de> PduDecode<'de> for ServerPdu { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let pdu_type = ServerPduType::from_u32(src.read_u32()) + .ok_or_else(|| invalid_message_err!("pduType", "invalid PDU type"))?; + let pdu_length = src.read_u32() as usize; let server_pdu = match pdu_type { - ServerPduType::DisplayControlCaps => { - ServerPdu::DisplayControlCaps(DisplayControlCapsPdu::from_buffer(&mut stream)?) - } + ServerPduType::DisplayControlCaps => ServerPdu::DisplayControlCaps(DisplayControlCapsPdu::decode(src)?), }; - let buffer_length = server_pdu.buffer_length(); + let actual_size = server_pdu.size(); - if buffer_length != pdu_length { - Err(DisplayPipelineError::InvalidPduLength { - expected: pdu_length, - actual: buffer_length, - }) + if actual_size != pdu_length { + Err(not_enough_bytes_err!(actual_size, pdu_length)) } else { Ok(server_pdu) } } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - let buffer_length = self.buffer_length(); - - stream.write_u32::(ServerPduType::from(self).to_u32().unwrap())?; - stream.write_u32::(buffer_length as u32)?; - - match self { - ServerPdu::DisplayControlCaps(pdu) => pdu.to_buffer(&mut stream).map_err(DisplayPipelineError::from), - } - } - - fn buffer_length(&self) -> usize { - RDP_DISPLAY_HEADER_SIZE - + match self { - ServerPdu::DisplayControlCaps(pdu) => pdu.buffer_length(), - } - } } #[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)] @@ -218,8 +265,8 @@ pub enum ServerPduType { DisplayControlCaps = 0x05, } -impl<'a> From<&'a ServerPdu> for ServerPduType { - fn from(s: &'a ServerPdu) -> Self { +impl From<&ServerPdu> for ServerPduType { + fn from(s: &ServerPdu) -> Self { match s { ServerPdu::DisplayControlCaps(_) => Self::DisplayControlCaps, } @@ -231,78 +278,70 @@ pub enum ClientPdu { DisplayControlMonitorLayout(MonitorLayoutPdu), } -impl PduParsing for ClientPdu { - type Error = DisplayPipelineError; +impl ClientPdu { + const NAME: &'static str = "DisplayClientPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let pdu_type = - ClientPduType::from_u32(stream.read_u32::()?).ok_or(DisplayPipelineError::InvalidCmdId)?; - let pdu_length = stream.read_u32::()? as usize; + const FIXED_PART_SIZE: usize = RDP_DISPLAY_HEADER_SIZE; +} - let server_pdu = match pdu_type { - ClientPduType::DisplayControlMonitorLayout => { - ClientPdu::DisplayControlMonitorLayout(MonitorLayoutPdu::from_buffer(&mut stream)?) - } - }; - let buffer_length = server_pdu.buffer_length(); +impl PduEncode for ClientPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + let size = self.size(); - if buffer_length != pdu_length { - Err(DisplayPipelineError::InvalidPduLength { - expected: pdu_length, - actual: buffer_length, - }) - } else { - Ok(server_pdu) - } - } + ensure_size!(in: dst, size: size); - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - let buffer_length = self.buffer_length(); - - stream.write_u32::(ClientPduType::from(self).to_u32().unwrap())?; - stream.write_u32::(buffer_length as u32)?; + dst.write_u32(ClientPduType::from(self).to_u32().unwrap()); + dst.write_u32(cast_length!("len", size)?); match self { - ClientPdu::DisplayControlMonitorLayout(pdu) => { - pdu.to_buffer(&mut stream).map_err(DisplayPipelineError::from) - } + ClientPdu::DisplayControlMonitorLayout(pdu) => pdu.encode(dst), } } - fn buffer_length(&self) -> usize { + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { RDP_DISPLAY_HEADER_SIZE + match self { - ClientPdu::DisplayControlMonitorLayout(pdu) => pdu.buffer_length(), + ClientPdu::DisplayControlMonitorLayout(pdu) => pdu.size(), } } } +impl<'de> PduDecode<'de> for ClientPdu { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let pdu_type = ClientPduType::from_u32(src.read_u32()) + .ok_or_else(|| invalid_message_err!("pduType", "invalid PDU type"))?; + let pdu_length = src.read_u32() as usize; + + let client_pdu = match pdu_type { + ClientPduType::DisplayControlMonitorLayout => { + ClientPdu::DisplayControlMonitorLayout(MonitorLayoutPdu::decode(src)?) + } + }; + let actual_size = client_pdu.size(); + + if actual_size != pdu_length { + Err(not_enough_bytes_err!(actual_size, pdu_length)) + } else { + Ok(client_pdu) + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)] pub enum ClientPduType { DisplayControlMonitorLayout = 0x02, } -impl<'a> From<&'a ClientPdu> for ClientPduType { - fn from(s: &'a ClientPdu) -> Self { +impl From<&ClientPdu> for ClientPduType { + fn from(s: &ClientPdu) -> Self { match s { ClientPdu::DisplayControlMonitorLayout(_) => Self::DisplayControlMonitorLayout, } } } - -#[derive(Debug, Error)] -pub enum DisplayPipelineError { - #[error("IO error")] - IOError(#[from] io::Error), - #[error("invalid Header cmd ID")] - InvalidCmdId, - #[error("invalid PDU length: expected ({expected}) != actual ({actual})")] - InvalidPduLength { expected: usize, actual: usize }, -} - -#[cfg(feature = "std")] -impl ironrdp_error::legacy::ErrorContext for DisplayPipelineError { - fn context(&self) -> &'static str { - "display pipeline" - } -} diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx.rs index 47e74115..3b7fb8bf 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx.rs @@ -1,9 +1,5 @@ mod graphics_messages; -use std::io; - -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use graphics_messages::RESET_GRAPHICS_PDU_SIZE; pub use graphics_messages::{ Avc420BitmapStream, Avc444BitmapStream, CacheImportReplyPdu, CacheToSurfacePdu, CapabilitiesAdvertisePdu, CapabilitiesConfirmPdu, CapabilitiesV103Flags, CapabilitiesV104Flags, CapabilitiesV107Flags, CapabilitiesV10Flags, @@ -15,11 +11,9 @@ pub use graphics_messages::{ }; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive as _, ToPrimitive as _}; -use thiserror::Error; -use crate::{PduError, PduParsing}; - -const RDP_GFX_HEADER_SIZE: usize = 8; +use crate::cursor::{ReadCursor, WriteCursor}; +use crate::{PduDecode, PduEncode, PduResult}; #[derive(Debug, Clone, PartialEq, Eq)] pub enum ServerPdu { @@ -43,137 +37,125 @@ pub enum ServerPdu { MapSurfaceToScaledWindow(MapSurfaceToScaledWindowPdu), } -impl PduParsing for ServerPdu { - type Error = GraphicsPipelineError; +const RDP_GFX_HEADER_SIZE: usize = 2 /* PduType */ + 2 /* flags */ + 4 /* bufferLen */; - fn from_buffer(mut stream: impl io::Read) -> Result { - let pdu_type = - ServerPduType::from_u16(stream.read_u16::()?).ok_or(GraphicsPipelineError::InvalidCmdId)?; - let _flags = stream.read_u16::()?; - let pdu_length = stream.read_u32::()? as usize; +impl ServerPdu { + const NAME: &'static str = "GfxServerPdu"; - if let ServerPduType::ResetGraphics = pdu_type { - if pdu_length != RESET_GRAPHICS_PDU_SIZE { - return Err(GraphicsPipelineError::InvalidResetGraphicsPduSize { - expected: RESET_GRAPHICS_PDU_SIZE, - actual: pdu_length, - }); - } + const FIXED_PART_SIZE: usize = RDP_GFX_HEADER_SIZE; +} + +impl PduEncode for ServerPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + let buffer_length = self.size(); + + dst.write_u16(ServerPduType::from(self).to_u16().unwrap()); + dst.write_u16(0); // flags + dst.write_u32(cast_length!("bufferLen", buffer_length)?); + + match self { + ServerPdu::WireToSurface1(pdu) => pdu.encode(dst), + ServerPdu::WireToSurface2(pdu) => pdu.encode(dst), + ServerPdu::DeleteEncodingContext(pdu) => pdu.encode(dst), + ServerPdu::SolidFill(pdu) => pdu.encode(dst), + ServerPdu::SurfaceToSurface(pdu) => pdu.encode(dst), + ServerPdu::SurfaceToCache(pdu) => pdu.encode(dst), + ServerPdu::CacheToSurface(pdu) => pdu.encode(dst), + ServerPdu::CreateSurface(pdu) => pdu.encode(dst), + ServerPdu::DeleteSurface(pdu) => pdu.encode(dst), + ServerPdu::ResetGraphics(pdu) => pdu.encode(dst), + ServerPdu::MapSurfaceToOutput(pdu) => pdu.encode(dst), + ServerPdu::MapSurfaceToScaledOutput(pdu) => pdu.encode(dst), + ServerPdu::MapSurfaceToScaledWindow(pdu) => pdu.encode(dst), + ServerPdu::StartFrame(pdu) => pdu.encode(dst), + ServerPdu::EndFrame(pdu) => pdu.encode(dst), + ServerPdu::EvictCacheEntry(pdu) => pdu.encode(dst), + ServerPdu::CapabilitiesConfirm(pdu) => pdu.encode(dst), + ServerPdu::CacheImportReply(pdu) => pdu.encode(dst), } + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + + match self { + ServerPdu::WireToSurface1(pdu) => pdu.size(), + ServerPdu::WireToSurface2(pdu) => pdu.size(), + ServerPdu::DeleteEncodingContext(pdu) => pdu.size(), + ServerPdu::SolidFill(pdu) => pdu.size(), + ServerPdu::SurfaceToSurface(pdu) => pdu.size(), + ServerPdu::SurfaceToCache(pdu) => pdu.size(), + ServerPdu::CacheToSurface(pdu) => pdu.size(), + ServerPdu::CreateSurface(pdu) => pdu.size(), + ServerPdu::DeleteSurface(pdu) => pdu.size(), + ServerPdu::ResetGraphics(pdu) => pdu.size(), + ServerPdu::MapSurfaceToOutput(pdu) => pdu.size(), + ServerPdu::MapSurfaceToScaledOutput(pdu) => pdu.size(), + ServerPdu::MapSurfaceToScaledWindow(pdu) => pdu.size(), + ServerPdu::StartFrame(pdu) => pdu.size(), + ServerPdu::EndFrame(pdu) => pdu.size(), + ServerPdu::EvictCacheEntry(pdu) => pdu.size(), + ServerPdu::CapabilitiesConfirm(pdu) => pdu.size(), + ServerPdu::CacheImportReply(pdu) => pdu.size(), + } + } +} + +impl<'a> PduDecode<'a> for ServerPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let pdu_type = ServerPduType::from_u16(src.read_u16()) + .ok_or_else(|| invalid_message_err!("serverPduType", "invalid pdu type"))?; + let _flags = src.read_u16(); + let pdu_length = cast_length!("pduLen", src.read_u32())?; let (server_pdu, buffer_length) = { let pdu = match pdu_type { ServerPduType::DeleteEncodingContext => { - ServerPdu::DeleteEncodingContext(DeleteEncodingContextPdu::from_buffer(&mut stream)?) - } - ServerPduType::WireToSurface1 => { - ServerPdu::WireToSurface1(WireToSurface1Pdu::from_buffer(&mut stream)?) - } - ServerPduType::WireToSurface2 => { - ServerPdu::WireToSurface2(WireToSurface2Pdu::from_buffer(&mut stream)?) - } - ServerPduType::SolidFill => ServerPdu::SolidFill(SolidFillPdu::from_buffer(&mut stream)?), - ServerPduType::SurfaceToSurface => { - ServerPdu::SurfaceToSurface(SurfaceToSurfacePdu::from_buffer(&mut stream)?) - } - ServerPduType::SurfaceToCache => { - ServerPdu::SurfaceToCache(SurfaceToCachePdu::from_buffer(&mut stream)?) - } - ServerPduType::CacheToSurface => { - ServerPdu::CacheToSurface(CacheToSurfacePdu::from_buffer(&mut stream)?) - } - ServerPduType::EvictCacheEntry => { - ServerPdu::EvictCacheEntry(EvictCacheEntryPdu::from_buffer(&mut stream)?) - } - ServerPduType::CreateSurface => ServerPdu::CreateSurface(CreateSurfacePdu::from_buffer(&mut stream)?), - ServerPduType::DeleteSurface => ServerPdu::DeleteSurface(DeleteSurfacePdu::from_buffer(&mut stream)?), - ServerPduType::StartFrame => ServerPdu::StartFrame(StartFramePdu::from_buffer(&mut stream)?), - ServerPduType::EndFrame => ServerPdu::EndFrame(EndFramePdu::from_buffer(&mut stream)?), - ServerPduType::ResetGraphics => ServerPdu::ResetGraphics(ResetGraphicsPdu::from_buffer(&mut stream)?), - ServerPduType::MapSurfaceToOutput => { - ServerPdu::MapSurfaceToOutput(MapSurfaceToOutputPdu::from_buffer(&mut stream)?) + ServerPdu::DeleteEncodingContext(DeleteEncodingContextPdu::decode(src)?) } + ServerPduType::WireToSurface1 => ServerPdu::WireToSurface1(WireToSurface1Pdu::decode(src)?), + ServerPduType::WireToSurface2 => ServerPdu::WireToSurface2(WireToSurface2Pdu::decode(src)?), + ServerPduType::SolidFill => ServerPdu::SolidFill(SolidFillPdu::decode(src)?), + ServerPduType::SurfaceToSurface => ServerPdu::SurfaceToSurface(SurfaceToSurfacePdu::decode(src)?), + ServerPduType::SurfaceToCache => ServerPdu::SurfaceToCache(SurfaceToCachePdu::decode(src)?), + ServerPduType::CacheToSurface => ServerPdu::CacheToSurface(CacheToSurfacePdu::decode(src)?), + ServerPduType::EvictCacheEntry => ServerPdu::EvictCacheEntry(EvictCacheEntryPdu::decode(src)?), + ServerPduType::CreateSurface => ServerPdu::CreateSurface(CreateSurfacePdu::decode(src)?), + ServerPduType::DeleteSurface => ServerPdu::DeleteSurface(DeleteSurfacePdu::decode(src)?), + ServerPduType::StartFrame => ServerPdu::StartFrame(StartFramePdu::decode(src)?), + ServerPduType::EndFrame => ServerPdu::EndFrame(EndFramePdu::decode(src)?), + ServerPduType::ResetGraphics => ServerPdu::ResetGraphics(ResetGraphicsPdu::decode(src)?), + ServerPduType::MapSurfaceToOutput => ServerPdu::MapSurfaceToOutput(MapSurfaceToOutputPdu::decode(src)?), ServerPduType::CapabilitiesConfirm => { - ServerPdu::CapabilitiesConfirm(CapabilitiesConfirmPdu::from_buffer(&mut stream)?) - } - ServerPduType::CacheImportReply => { - ServerPdu::CacheImportReply(CacheImportReplyPdu::from_buffer(&mut stream)?) + ServerPdu::CapabilitiesConfirm(CapabilitiesConfirmPdu::decode(src)?) } + ServerPduType::CacheImportReply => ServerPdu::CacheImportReply(CacheImportReplyPdu::decode(src)?), ServerPduType::MapSurfaceToScaledOutput => { - ServerPdu::MapSurfaceToScaledOutput(MapSurfaceToScaledOutputPdu::from_buffer(&mut stream)?) + ServerPdu::MapSurfaceToScaledOutput(MapSurfaceToScaledOutputPdu::decode(src)?) } ServerPduType::MapSurfaceToScaledWindow => { - ServerPdu::MapSurfaceToScaledWindow(MapSurfaceToScaledWindowPdu::from_buffer(&mut stream)?) + ServerPdu::MapSurfaceToScaledWindow(MapSurfaceToScaledWindowPdu::decode(src)?) } - _ => return Err(GraphicsPipelineError::UnexpectedServerPduType(pdu_type)), + _ => return Err(invalid_message_err!("pduType", "invalid pdu type")), }; - let buffer_length = pdu.buffer_length(); + let buffer_length = pdu.size(); (pdu, buffer_length) }; if buffer_length != pdu_length { - Err(GraphicsPipelineError::InvalidPduLength { - expected: pdu_length, - actual: buffer_length, - }) + Err(invalid_message_err!("len", "invalid pdu length")) } else { Ok(server_pdu) } } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - let buffer_length = self.buffer_length(); - - stream.write_u16::(ServerPduType::from(self).to_u16().unwrap())?; - stream.write_u16::(0)?; // flags - stream.write_u32::(buffer_length as u32)?; - - match self { - ServerPdu::WireToSurface1(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::WireToSurface2(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::DeleteEncodingContext(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::SolidFill(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::SurfaceToSurface(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::SurfaceToCache(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::CacheToSurface(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::CreateSurface(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::DeleteSurface(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::ResetGraphics(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::MapSurfaceToOutput(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::MapSurfaceToScaledOutput(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::MapSurfaceToScaledWindow(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::StartFrame(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::EndFrame(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::EvictCacheEntry(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::CapabilitiesConfirm(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ServerPdu::CacheImportReply(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - } - } - - fn buffer_length(&self) -> usize { - RDP_GFX_HEADER_SIZE - + match self { - ServerPdu::WireToSurface1(pdu) => pdu.buffer_length(), - ServerPdu::WireToSurface2(pdu) => pdu.buffer_length(), - ServerPdu::DeleteEncodingContext(pdu) => pdu.buffer_length(), - ServerPdu::SolidFill(pdu) => pdu.buffer_length(), - ServerPdu::SurfaceToSurface(pdu) => pdu.buffer_length(), - ServerPdu::SurfaceToCache(pdu) => pdu.buffer_length(), - ServerPdu::CacheToSurface(pdu) => pdu.buffer_length(), - ServerPdu::CreateSurface(pdu) => pdu.buffer_length(), - ServerPdu::DeleteSurface(pdu) => pdu.buffer_length(), - ServerPdu::ResetGraphics(pdu) => pdu.buffer_length(), - ServerPdu::MapSurfaceToOutput(pdu) => pdu.buffer_length(), - ServerPdu::MapSurfaceToScaledOutput(pdu) => pdu.buffer_length(), - ServerPdu::MapSurfaceToScaledWindow(pdu) => pdu.buffer_length(), - ServerPdu::StartFrame(pdu) => pdu.buffer_length(), - ServerPdu::EndFrame(pdu) => pdu.buffer_length(), - ServerPdu::EvictCacheEntry(pdu) => pdu.buffer_length(), - ServerPdu::CapabilitiesConfirm(pdu) => pdu.buffer_length(), - ServerPdu::CacheImportReply(pdu) => pdu.buffer_length(), - } - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -182,53 +164,60 @@ pub enum ClientPdu { CapabilitiesAdvertise(CapabilitiesAdvertisePdu), } -impl PduParsing for ClientPdu { - type Error = GraphicsPipelineError; +impl ClientPdu { + const NAME: &'static str = "GfxClientPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let pdu_type = - ClientPduType::from_u16(stream.read_u16::()?).ok_or(GraphicsPipelineError::InvalidCmdId)?; - let _flags = stream.read_u16::()?; - let pdu_length = stream.read_u32::()? as usize; + const FIXED_PART_SIZE: usize = RDP_GFX_HEADER_SIZE; +} + +impl PduEncode for ClientPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + dst.write_u16(ClientPduType::from(self).to_u16().unwrap()); + dst.write_u16(0); // flags + dst.write_u32(cast_length!("bufferLen", self.size())?); + + match self { + ClientPdu::FrameAcknowledge(pdu) => pdu.encode(dst), + ClientPdu::CapabilitiesAdvertise(pdu) => pdu.encode(dst), + } + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + + match self { + ClientPdu::FrameAcknowledge(pdu) => pdu.size(), + ClientPdu::CapabilitiesAdvertise(pdu) => pdu.size(), + } + } +} + +impl<'a> PduDecode<'a> for ClientPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + let pdu_type = ClientPduType::from_u16(src.read_u16()) + .ok_or_else(|| invalid_message_err!("clientPduType", "invalid pdu type"))?; + let _flags = src.read_u16(); + let pdu_length = cast_length!("bufferLen", src.read_u32())?; let client_pdu = match pdu_type { - ClientPduType::FrameAcknowledge => { - ClientPdu::FrameAcknowledge(FrameAcknowledgePdu::from_buffer(&mut stream)?) - } + ClientPduType::FrameAcknowledge => ClientPdu::FrameAcknowledge(FrameAcknowledgePdu::decode(src)?), ClientPduType::CapabilitiesAdvertise => { - ClientPdu::CapabilitiesAdvertise(CapabilitiesAdvertisePdu::from_buffer(&mut stream)?) + ClientPdu::CapabilitiesAdvertise(CapabilitiesAdvertisePdu::decode(src)?) } - _ => return Err(GraphicsPipelineError::UnexpectedClientPduType(pdu_type)), + _ => return Err(invalid_message_err!("pduType", "invalid pdu type")), }; - if client_pdu.buffer_length() != pdu_length { - Err(GraphicsPipelineError::InvalidPduLength { - expected: pdu_length, - actual: client_pdu.buffer_length(), - }) + if client_pdu.size() != pdu_length { + Err(invalid_message_err!("len", "invalid pdu length")) } else { Ok(client_pdu) } } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(ClientPduType::from(self).to_u16().unwrap())?; - stream.write_u16::(0)?; // flags - stream.write_u32::(self.buffer_length() as u32)?; - - match self { - ClientPdu::FrameAcknowledge(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - ClientPdu::CapabilitiesAdvertise(pdu) => pdu.to_buffer(&mut stream).map_err(GraphicsPipelineError::from), - } - } - - fn buffer_length(&self) -> usize { - RDP_GFX_HEADER_SIZE - + match self { - ClientPdu::FrameAcknowledge(pdu) => pdu.buffer_length(), - ClientPdu::CapabilitiesAdvertise(pdu) => pdu.buffer_length(), - } - } } #[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)] @@ -295,36 +284,3 @@ impl<'a> From<&'a ServerPdu> for ServerPduType { } } } - -#[derive(Debug, Error)] -pub enum GraphicsPipelineError { - #[error("IO error")] - IOError(#[from] io::Error), - #[error("graphics messages error")] - GraphicsMessagesError(#[from] graphics_messages::GraphicsMessagesError), - #[error("invalid Header cmd ID")] - InvalidCmdId, - #[error("unexpected client's PDU type: {0:?}")] - UnexpectedClientPduType(ClientPduType), - #[error("unexpected server's PDU type: {0:?}")] - UnexpectedServerPduType(ServerPduType), - #[error("invalid ResetGraphics PDU size: expected ({expected}) != actual ({actual})")] - InvalidResetGraphicsPduSize { expected: usize, actual: usize }, - #[error("invalid PDU length: expected ({expected}) != actual ({actual})")] - InvalidPduLength { expected: usize, actual: usize }, - #[error("PDU error: {0}")] - Pdu(PduError), -} - -impl From for GraphicsPipelineError { - fn from(e: PduError) -> Self { - Self::Pdu(e) - } -} - -#[cfg(feature = "std")] -impl ironrdp_error::legacy::ErrorContext for GraphicsPipelineError { - fn context(&self) -> &'static str { - "graphics pipeline" - } -} diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages.rs index 85e1577e..b2ae7388 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages.rs @@ -1,18 +1,14 @@ mod client; mod server; -use std::io; mod avc_messages; use bitflags::bitflags; -use byteorder::{LittleEndian, ReadBytesExt as _, WriteBytesExt as _}; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive as _, ToPrimitive as _}; -use thiserror::Error; #[rustfmt::skip] // do not re-order this pub use avc_messages::{Avc420BitmapStream, Avc444BitmapStream, Encoding, QuantQuality}; pub use client::{CacheImportReplyPdu, CapabilitiesAdvertisePdu, FrameAcknowledgePdu, QueueDepth}; -pub(crate) use server::RESET_GRAPHICS_PDU_SIZE; pub use server::{ CacheToSurfacePdu, CapabilitiesConfirmPdu, Codec1Type, Codec2Type, CreateSurfacePdu, DeleteEncodingContextPdu, DeleteSurfacePdu, EndFramePdu, EvictCacheEntryPdu, MapSurfaceToOutputPdu, MapSurfaceToScaledOutputPdu, @@ -21,8 +17,8 @@ pub use server::{ }; use super::RDP_GFX_HEADER_SIZE; -use crate::gcc::MonitorDataError; -use crate::{PduError, PduParsing}; +use crate::cursor::{ReadCursor, WriteCursor}; +use crate::{PduDecode, PduEncode, PduResult}; const CAPABILITY_SET_HEADER_SIZE: usize = 8; @@ -63,79 +59,42 @@ impl CapabilitySet { } } -impl PduParsing for CapabilitySet { - type Error = GraphicsMessagesError; +impl CapabilitySet { + const NAME: &'static str = "GfxCapabilitySet"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let version = CapabilityVersion::from_u32(stream.read_u32::()?) - .ok_or(GraphicsMessagesError::InvalidCapabilitiesVersion)?; - let data_length = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = CAPABILITY_SET_HEADER_SIZE; +} - let mut data = vec![0; data_length as usize]; - stream.read_exact(data.as_mut())?; +impl PduEncode for CapabilitySet { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); - match version { - CapabilityVersion::V8 => Ok(CapabilitySet::V8 { - flags: CapabilitiesV8Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::V8_1 => Ok(CapabilitySet::V8_1 { - flags: CapabilitiesV81Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::V10 => Ok(CapabilitySet::V10 { - flags: CapabilitiesV10Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::V10_1 => { - data.as_slice().read_u128::()?; - - Ok(CapabilitySet::V10_1) - } - CapabilityVersion::V10_2 => Ok(CapabilitySet::V10_2 { - flags: CapabilitiesV10Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::V10_3 => Ok(CapabilitySet::V10_3 { - flags: CapabilitiesV103Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::V10_4 => Ok(CapabilitySet::V10_4 { - flags: CapabilitiesV104Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::V10_5 => Ok(CapabilitySet::V10_5 { - flags: CapabilitiesV104Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::V10_6 => Ok(CapabilitySet::V10_6 { - flags: CapabilitiesV104Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::V10_6Err => Ok(CapabilitySet::V10_6Err { - flags: CapabilitiesV104Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::V10_7 => Ok(CapabilitySet::V10_7 { - flags: CapabilitiesV107Flags::from_bits_truncate(data.as_slice().read_u32::()?), - }), - CapabilityVersion::Unknown => Ok(CapabilitySet::Unknown(data)), - } - } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), GraphicsMessagesError> { - stream.write_u32::(self.version().to_u32().unwrap())?; - stream.write_u32::((self.buffer_length() - CAPABILITY_SET_HEADER_SIZE) as u32)?; + dst.write_u32(self.version().to_u32().unwrap()); + dst.write_u32(cast_length!("dataLength", self.size() - CAPABILITY_SET_HEADER_SIZE)?); match self { - CapabilitySet::V8 { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::V8_1 { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::V10 { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::V10_1 => stream.write_u128::(V10_1_RESERVED)?, - CapabilitySet::V10_2 { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::V10_3 { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::V10_4 { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::V10_5 { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::V10_6 { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::V10_6Err { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::V10_7 { flags } => stream.write_u32::(flags.bits())?, - CapabilitySet::Unknown(data) => stream.write_all(data)?, + CapabilitySet::V8 { flags } => dst.write_u32(flags.bits()), + CapabilitySet::V8_1 { flags } => dst.write_u32(flags.bits()), + CapabilitySet::V10 { flags } => dst.write_u32(flags.bits()), + CapabilitySet::V10_1 => dst.write_u128(V10_1_RESERVED), + CapabilitySet::V10_2 { flags } => dst.write_u32(flags.bits()), + CapabilitySet::V10_3 { flags } => dst.write_u32(flags.bits()), + CapabilitySet::V10_4 { flags } => dst.write_u32(flags.bits()), + CapabilitySet::V10_5 { flags } => dst.write_u32(flags.bits()), + CapabilitySet::V10_6 { flags } => dst.write_u32(flags.bits()), + CapabilitySet::V10_6Err { flags } => dst.write_u32(flags.bits()), + CapabilitySet::V10_7 { flags } => dst.write_u32(flags.bits()), + CapabilitySet::Unknown(data) => dst.write_slice(data), } Ok(()) } - fn buffer_length(&self) -> usize { + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { CAPABILITY_SET_HEADER_SIZE + match self { CapabilitySet::V8 { .. } @@ -154,6 +113,75 @@ impl PduParsing for CapabilitySet { } } +impl<'de> PduDecode<'de> for CapabilitySet { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let version = CapabilityVersion::from_u32(src.read_u32()) + .ok_or_else(|| invalid_message_err!("version", "unhandled version"))?; + let data_length: usize = cast_length!("dataLength", src.read_u32())?; + + ensure_size!(in: src, size: data_length); + let data = src.read_slice(data_length); + let mut cur = ReadCursor::new(data); + + let size = match version { + CapabilityVersion::V8 + | CapabilityVersion::V8_1 + | CapabilityVersion::V10 + | CapabilityVersion::V10_2 + | CapabilityVersion::V10_3 + | CapabilityVersion::V10_4 + | CapabilityVersion::V10_5 + | CapabilityVersion::V10_6 + | CapabilityVersion::V10_6Err + | CapabilityVersion::V10_7 => 4, + CapabilityVersion::V10_1 => 16, + CapabilityVersion::Unknown => 0, + }; + + ensure_size!(in: cur, size: size); + match version { + CapabilityVersion::V8 => Ok(CapabilitySet::V8 { + flags: CapabilitiesV8Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::V8_1 => Ok(CapabilitySet::V8_1 { + flags: CapabilitiesV81Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::V10 => Ok(CapabilitySet::V10 { + flags: CapabilitiesV10Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::V10_1 => { + cur.read_u128(); + + Ok(CapabilitySet::V10_1) + } + CapabilityVersion::V10_2 => Ok(CapabilitySet::V10_2 { + flags: CapabilitiesV10Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::V10_3 => Ok(CapabilitySet::V10_3 { + flags: CapabilitiesV103Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::V10_4 => Ok(CapabilitySet::V10_4 { + flags: CapabilitiesV104Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::V10_5 => Ok(CapabilitySet::V10_5 { + flags: CapabilitiesV104Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::V10_6 => Ok(CapabilitySet::V10_6 { + flags: CapabilitiesV104Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::V10_6Err => Ok(CapabilitySet::V10_6Err { + flags: CapabilitiesV104Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::V10_7 => Ok(CapabilitySet::V10_7 { + flags: CapabilitiesV107Flags::from_bits_truncate(cur.read_u32()), + }), + CapabilityVersion::Unknown => Ok(CapabilitySet::Unknown(data.to_vec())), + } + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct Color { pub b: u8, @@ -162,29 +190,43 @@ pub struct Color { pub xa: u8, } -impl PduParsing for Color { - type Error = GraphicsMessagesError; +impl Color { + const NAME: &'static str = "GfxColor"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let b = stream.read_u8()?; - let g = stream.read_u8()?; - let r = stream.read_u8()?; - let xa = stream.read_u8()?; + const FIXED_PART_SIZE: usize = 4 /* BGRA */; +} - Ok(Self { b, g, r, xa }) - } +impl PduEncode for Color { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u8(self.b)?; - stream.write_u8(self.g)?; - stream.write_u8(self.r)?; - stream.write_u8(self.xa)?; + dst.write_u8(self.b); + dst.write_u8(self.g); + dst.write_u8(self.r); + dst.write_u8(self.xa); Ok(()) } - fn buffer_length(&self) -> usize { - 4 + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'de> PduDecode<'de> for Color { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let b = src.read_u8(); + let g = src.read_u8(); + let r = src.read_u8(); + let xa = src.read_u8(); + + Ok(Self { b, g, r, xa }) } } @@ -194,25 +236,39 @@ pub struct Point { pub y: u16, } -impl PduParsing for Point { - type Error = GraphicsMessagesError; +impl Point { + const NAME: &'static str = "GfxPoint"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let x = stream.read_u16::()?; - let y = stream.read_u16::()?; + const FIXED_PART_SIZE: usize = 2 /* X */ + 2 /* Y */; +} - Ok(Self { x, y }) - } +impl PduEncode for Point { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.x)?; - stream.write_u16::(self.y)?; + dst.write_u16(self.x); + dst.write_u16(self.y); Ok(()) } - fn buffer_length(&self) -> usize { - 4 + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'de> PduDecode<'de> for Point { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let x = src.read_u16(); + let y = src.read_u16(); + + Ok(Self { x, y }) } } @@ -284,35 +340,3 @@ bitflags! { const SCALEDMAP_DISABLE = 0x80; } } - -#[derive(Debug, Error)] -pub enum GraphicsMessagesError { - #[error("IO error")] - IOError(#[from] io::Error), - #[error("invalid codec ID version 1")] - InvalidCodec1Id, - #[error("invalid codec ID version 2")] - InvalidCodec2Id, - #[error("invalid pixel format")] - InvalidPixelFormat, - #[error("monitor error")] - MonitorError(#[from] MonitorDataError), - #[error("invalid ResetGraphics PDU width: {} > MAX ({})", actual, max)] - InvalidResetGraphicsPduWidth { actual: u32, max: u32 }, - #[error("invalid ResetGraphics PDU height: {} > MAX ({})", actual, max)] - InvalidResetGraphicsPduHeight { actual: u32, max: u32 }, - #[error("invalid ResetGraphics PDU monitors count: {} > MAX ({})", actual, max)] - InvalidResetGraphicsPduMonitorsCount { actual: u32, max: u32 }, - #[error("invalid capabilities version")] - InvalidCapabilitiesVersion, - #[error("both luma and chroma packets specified but length is missing")] - InvalidAvcEncoding, - #[error("PDU error: {0}")] - Pdu(PduError), -} - -impl From for GraphicsMessagesError { - fn from(e: PduError) -> Self { - Self::Pdu(e) - } -} diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/avc_messages.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/avc_messages.rs index d371a2dc..0ce966b2 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/avc_messages.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/avc_messages.rs @@ -1,13 +1,11 @@ use std::fmt::Debug; -use std::io::Write as _; use bit_field::BitField; use bitflags::bitflags; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use super::GraphicsMessagesError; +use crate::cursor::{ReadCursor, WriteCursor}; use crate::geometry::InclusiveRectangle; -use crate::{PduBufferParsing, PduParsing}; +use crate::{PduDecode, PduEncode, PduResult}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct QuantQuality { @@ -16,36 +14,47 @@ pub struct QuantQuality { pub quality: u8, } -impl PduParsing for QuantQuality { - type Error = GraphicsMessagesError; +impl QuantQuality { + const NAME: &'static str = "GfxQuantQuality"; - fn from_buffer(mut stream: impl std::io::Read) -> Result - where - Self: Sized, - { - let data = stream.read_u8()?; + const FIXED_PART_SIZE: usize = 1 /* data */ + 1 /* quality */; +} + +impl PduEncode for QuantQuality { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + let mut data = 0u8; + data.set_bits(0..6, self.quantization_parameter); + data.set_bit(7, self.progressive); + dst.write_u8(data); + dst.write_u8(self.quality); + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'de> PduDecode<'de> for QuantQuality { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let data = src.read_u8(); let qp = data.get_bits(0..6); let progressive = data.get_bit(7); - let quality = stream.read_u8()?; + let quality = src.read_u8(); Ok(QuantQuality { quantization_parameter: qp, progressive, quality, }) } - - fn to_buffer(&self, mut stream: impl std::io::Write) -> Result<(), Self::Error> { - let mut data = 0u8; - data.set_bits(0..6, self.quantization_parameter); - data.set_bit(7, self.progressive); - stream.write_u8(data)?; - stream.write_u8(self.quality)?; - Ok(()) - } - - fn buffer_length(&self) -> usize { - 2 - } } #[derive(Clone, PartialEq, Eq)] @@ -65,44 +74,58 @@ impl Debug for Avc420BitmapStream<'_> { } } -impl<'a> PduBufferParsing<'a> for Avc420BitmapStream<'a> { - type Error = GraphicsMessagesError; +impl Avc420BitmapStream<'_> { + const NAME: &'static str = "Avc420BitmapStream"; - fn from_buffer_consume(mut buffer: &mut &'a [u8]) -> Result { - let num_regions = buffer.read_u32::()?; + const FIXED_PART_SIZE: usize = 4 /* nRect */; +} + +impl PduEncode for Avc420BitmapStream<'_> { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + dst.write_u32(cast_length!("len", self.rectangles.len())?); + for rectangle in &self.rectangles { + rectangle.encode(dst)?; + } + for quant_qual_val in &self.quant_qual_vals { + quant_qual_val.encode(dst)?; + } + dst.write_slice(self.data); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + // Each rectangle is 8 bytes and 2 bytes for each quant val + Self::FIXED_PART_SIZE + self.rectangles.len() * 10 + self.data.len() + } +} + +impl<'de> PduDecode<'de> for Avc420BitmapStream<'de> { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let num_regions = src.read_u32(); let mut rectangles = Vec::with_capacity(num_regions as usize); let mut quant_qual_vals = Vec::with_capacity(num_regions as usize); for _ in 0..num_regions { - rectangles.push(InclusiveRectangle::from_buffer(&mut buffer)?); + rectangles.push(InclusiveRectangle::decode(src)?); } for _ in 0..num_regions { - quant_qual_vals.push(QuantQuality::from_buffer(&mut buffer)?); + quant_qual_vals.push(QuantQuality::decode(src)?); } - let data = buffer; + let data = src.remaining(); Ok(Avc420BitmapStream { rectangles, quant_qual_vals, data, }) } - - fn to_buffer_consume(&self, mut buffer: &mut &mut [u8]) -> Result<(), Self::Error> { - buffer.write_u32::(self.rectangles.len() as u32)?; - for rectangle in &self.rectangles { - rectangle.to_buffer(&mut buffer)?; - } - for quant_qual_val in &self.quant_qual_vals { - quant_qual_val.to_buffer(&mut buffer)?; - } - buffer.write_all(self.data)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - // Each rectangle is 8 bytes and 2 bytes for each quant val - 4 + self.rectangles.len() * 10 + self.data.len() - } } bitflags! { @@ -121,30 +144,66 @@ pub struct Avc444BitmapStream<'a> { pub stream2: Option>, } -impl<'a> PduBufferParsing<'a> for Avc444BitmapStream<'a> { - type Error = GraphicsMessagesError; +impl Avc444BitmapStream<'_> { + const NAME: &'static str = "Avc444BitmapStream"; - fn from_buffer_consume(buffer: &mut &'a [u8]) -> Result { - let stream_info = buffer.read_u32::()?; + const FIXED_PART_SIZE: usize = 4 /* streamInfo */; +} + +impl PduEncode for Avc444BitmapStream<'_> { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + let mut stream_info = 0u32; + stream_info.set_bits(0..30, cast_length!("stream1size", self.stream1.size())?); + stream_info.set_bits(30..32, self.encoding.bits() as u32); + dst.write_u32(stream_info); + self.stream1.encode(dst)?; + if let Some(stream) = self.stream2.as_ref() { + stream.encode(dst)?; + } + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + let stream2_size = if let Some(stream) = self.stream2.as_ref() { + stream.size() + } else { + 0 + }; + + Self::FIXED_PART_SIZE + self.stream1.size() + stream2_size + } +} + +impl<'de> PduDecode<'de> for Avc444BitmapStream<'de> { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let stream_info = src.read_u32(); let stream_len = stream_info.get_bits(0..30); let encoding = Encoding::from_bits_truncate(stream_info.get_bits(30..32) as u8); if stream_len == 0 { if encoding == Encoding::LUMA_AND_CHROMA { - return Err(GraphicsMessagesError::InvalidAvcEncoding); + return Err(invalid_message_err!("encoding", "invalid encoding")); } - let stream1 = Avc420BitmapStream::from_buffer_consume(buffer)?; + let stream1 = Avc420BitmapStream::decode(src)?; Ok(Avc444BitmapStream { encoding, stream1, stream2: None, }) } else { - let (mut stream1, mut stream2) = buffer.split_at(stream_len as usize); - let stream1 = Avc420BitmapStream::from_buffer_consume(&mut stream1)?; + let (mut stream1, mut stream2) = src.split_at(stream_len as usize); + let stream1 = Avc420BitmapStream::decode(&mut stream1)?; let stream2 = if encoding == Encoding::LUMA_AND_CHROMA { - Some(Avc420BitmapStream::from_buffer_consume(&mut stream2)?) + Some(Avc420BitmapStream::decode(&mut stream2)?) } else { None }; @@ -155,26 +214,4 @@ impl<'a> PduBufferParsing<'a> for Avc444BitmapStream<'a> { }) } } - - fn to_buffer_consume(&self, buffer: &mut &mut [u8]) -> Result<(), Self::Error> { - let mut stream_info = 0u32; - stream_info.set_bits(0..30, self.stream1.buffer_length() as u32); - stream_info.set_bits(30..32, self.encoding.bits() as u32); - buffer.write_u32::(stream_info)?; - self.stream1.to_buffer_consume(buffer)?; - if let Some(stream) = self.stream2.as_ref() { - stream.to_buffer_consume(buffer)?; - } - Ok(()) - } - - fn buffer_length(&self) -> usize { - let stream2_len = if let Some(stream) = self.stream2.as_ref() { - stream.buffer_length() - } else { - 0 - }; - - 4 + self.stream1.buffer_length() + stream2_len - } } diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/client.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/client.rs index b0330a10..8f1ef5e1 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/client.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/client.rs @@ -1,38 +1,51 @@ -use std::io; - -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -use super::{CapabilitySet, GraphicsMessagesError}; -use crate::PduParsing; +use super::CapabilitySet; +use crate::cursor::{ReadCursor, WriteCursor}; +use crate::{PduDecode, PduEncode, PduResult}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct CapabilitiesAdvertisePdu(pub Vec); -impl PduParsing for CapabilitiesAdvertisePdu { - type Error = GraphicsMessagesError; +impl CapabilitiesAdvertisePdu { + const NAME: &'static str = "CapabilitiesAdvertisePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let capabilities_count = stream.read_u16::()? as usize; + const FIXED_PART_SIZE: usize = 2 /* Count */; +} - let capabilities = (0..capabilities_count) - .map(|_| CapabilitySet::from_buffer(&mut stream)) - .collect::, Self::Error>>()?; +impl PduEncode for CapabilitiesAdvertisePdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); - Ok(Self(capabilities)) - } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.0.len() as u16)?; + dst.write_u16(cast_length!("Count", self.0.len())?); for capability_set in self.0.iter() { - capability_set.to_buffer(&mut stream)?; + capability_set.encode(dst)?; } Ok(()) } - fn buffer_length(&self) -> usize { - 2 + self.0.iter().map(|c| c.buffer_length()).sum::() + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + self.0.iter().map(|c| c.size()).sum::() + } +} + +impl<'a> PduDecode<'a> for CapabilitiesAdvertisePdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let capabilities_count = cast_length!("Count", src.read_u16())?; + + ensure_size!(in: src, size: capabilities_count * CapabilitySet::FIXED_PART_SIZE); + + let capabilities = (0..capabilities_count) + .map(|_| CapabilitySet::decode(src)) + .collect::>()?; + + Ok(Self(capabilities)) } } @@ -43,13 +56,39 @@ pub struct FrameAcknowledgePdu { pub total_frames_decoded: u32, } -impl PduParsing for FrameAcknowledgePdu { - type Error = GraphicsMessagesError; +impl FrameAcknowledgePdu { + const NAME: &'static str = "FrameAcknowledgePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let queue_depth = QueueDepth::from_u32(stream.read_u32::()?); - let frame_id = stream.read_u32::()?; - let total_frames_decoded = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = 4 /* QueueDepth */ + 4 /* FrameId */ + 4 /* TotalFramesDecoded */; +} + +impl PduEncode for FrameAcknowledgePdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + dst.write_u32(self.queue_depth.to_u32()); + dst.write_u32(self.frame_id); + dst.write_u32(self.total_frames_decoded); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for FrameAcknowledgePdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let queue_depth = QueueDepth::from_u32(src.read_u32()); + let frame_id = src.read_u32(); + let total_frames_decoded = src.read_u32(); Ok(Self { queue_depth, @@ -57,18 +96,6 @@ impl PduParsing for FrameAcknowledgePdu { total_frames_decoded, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u32::(self.queue_depth.to_u32())?; - stream.write_u32::(self.frame_id)?; - stream.write_u32::(self.total_frames_decoded)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 12 - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -76,31 +103,43 @@ pub struct CacheImportReplyPdu { pub cache_slots: Vec, } -impl PduParsing for CacheImportReplyPdu { - type Error = GraphicsMessagesError; +impl CacheImportReplyPdu { + const NAME: &'static str = "CacheImportReplyPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let entries_count = stream.read_u16::()? as usize; + const FIXED_PART_SIZE: usize = 2 /* Count */; +} - let cache_slots = (0..entries_count) - .map(|_| stream.read_u16::()) - .collect::>>()?; +impl PduEncode for CacheImportReplyPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); - Ok(Self { cache_slots }) - } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.cache_slots.len() as u16)?; + dst.write_u16(cast_length!("Count", self.cache_slots.len())?); for cache_slot in self.cache_slots.iter() { - stream.write_u16::(*cache_slot)?; + dst.write_u16(*cache_slot); } Ok(()) } - fn buffer_length(&self) -> usize { - 2 + self.cache_slots.iter().map(|_| 2).sum::() + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + self.cache_slots.iter().map(|_| 2).sum::() + } +} + +impl<'a> PduDecode<'a> for CacheImportReplyPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let entries_count = src.read_u16(); + + let cache_slots = (0..entries_count).map(|_| src.read_u16()).collect(); + + Ok(Self { cache_slots }) } } diff --git a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/server.rs b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/server.rs index 2c6209a8..d36b8584 100644 --- a/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/server.rs +++ b/crates/ironrdp-pdu/src/rdp/vc/dvc/gfx/graphics_messages/server.rs @@ -1,14 +1,14 @@ -use std::{fmt, io}; +use std::{fmt, mem}; use bit_field::BitField; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive}; -use super::{CapabilitySet, Color, GraphicsMessagesError, Point, RDP_GFX_HEADER_SIZE}; -use crate::gcc::{Monitor, MonitorDataError}; +use super::{CapabilitySet, Color, Point, RDP_GFX_HEADER_SIZE}; +use crate::cursor::{ReadCursor, WriteCursor}; +use crate::gcc::Monitor; use crate::geometry::InclusiveRectangle; -use crate::PduParsing; +use crate::{decode_cursor, PduDecode, PduEncode, PduResult}; pub(crate) const RESET_GRAPHICS_PDU_SIZE: usize = 340; @@ -36,18 +36,49 @@ impl fmt::Debug for WireToSurface1Pdu { } } -impl PduParsing for WireToSurface1Pdu { - type Error = GraphicsMessagesError; +impl WireToSurface1Pdu { + const NAME: &'static str = "WireToSurface1Pdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; + const FIXED_PART_SIZE: usize = 2 /* SurfaceId */ + 2 /* CodecId */ + 1 /* PixelFormat */ + InclusiveRectangle::FIXED_PART_SIZE /* Dest */ + 4 /* BitmapDataLen */; +} + +impl PduEncode for WireToSurface1Pdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + dst.write_u16(self.surface_id); + dst.write_u16(self.codec_id.to_u16().unwrap()); + dst.write_u8(self.pixel_format.to_u8().unwrap()); + self.destination_rectangle.encode(dst)?; + dst.write_u32(cast_length!("BitmapDataLen", self.bitmap_data.len())?); + dst.write_slice(&self.bitmap_data); + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + self.bitmap_data.len() + } +} + +impl<'a> PduDecode<'a> for WireToSurface1Pdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); let codec_id = - Codec1Type::from_u16(stream.read_u16::()?).ok_or(GraphicsMessagesError::InvalidCodec1Id)?; - let pixel_format = PixelFormat::from_u8(stream.read_u8()?).ok_or(GraphicsMessagesError::InvalidPixelFormat)?; - let destination_rectangle = InclusiveRectangle::from_buffer(&mut stream)?; - let bitmap_data_length = stream.read_u32::()? as usize; - let mut bitmap_data = vec![0; bitmap_data_length]; - stream.read_exact(&mut bitmap_data)?; + Codec1Type::from_u16(src.read_u16()).ok_or_else(|| invalid_message_err!("CodecId", "invalid codec ID"))?; + let pixel_format = PixelFormat::from_u8(src.read_u8()) + .ok_or_else(|| invalid_message_err!("PixelFormat", "invalid pixel format"))?; + let destination_rectangle = InclusiveRectangle::decode(src)?; + let bitmap_data_length = cast_length!("BitmapDataLen", src.read_u32())?; + + ensure_size!(in: src, size: bitmap_data_length); + let bitmap_data = src.read_slice(bitmap_data_length).to_vec(); + Ok(Self { surface_id, codec_id, @@ -56,20 +87,6 @@ impl PduParsing for WireToSurface1Pdu { bitmap_data, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; - stream.write_u16::(self.codec_id.to_u16().unwrap())?; - stream.write_u8(self.pixel_format.to_u8().unwrap())?; - self.destination_rectangle.to_buffer(&mut stream)?; - stream.write_u32::(self.bitmap_data.len() as u32)?; - stream.write_all(&self.bitmap_data)?; - Ok(()) - } - - fn buffer_length(&self) -> usize { - 17 + self.bitmap_data.len() - } } #[derive(Clone, PartialEq, Eq)] @@ -93,18 +110,49 @@ impl fmt::Debug for WireToSurface2Pdu { } } -impl PduParsing for WireToSurface2Pdu { - type Error = GraphicsMessagesError; +impl WireToSurface2Pdu { + const NAME: &'static str = "WireToSurface2Pdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; + const FIXED_PART_SIZE: usize = 2 /* SurfaceId */ + 2 /* CodecId */ + 4 /* ContextId */ + 1 /* PixelFormat */ + 4 /* BitmapDataLen */; +} + +impl PduEncode for WireToSurface2Pdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + dst.write_u16(self.surface_id); + dst.write_u16(self.codec_id.to_u16().unwrap()); + dst.write_u32(self.codec_context_id); + dst.write_u8(self.pixel_format.to_u8().unwrap()); + dst.write_u32(cast_length!("BitmapDataLen", self.bitmap_data.len())?); + dst.write_slice(&self.bitmap_data); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + self.bitmap_data.len() + } +} + +impl<'a> PduDecode<'a> for WireToSurface2Pdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); let codec_id = - Codec2Type::from_u16(stream.read_u16::()?).ok_or(GraphicsMessagesError::InvalidCodec2Id)?; - let codec_context_id = stream.read_u32::()?; - let pixel_format = PixelFormat::from_u8(stream.read_u8()?).ok_or(GraphicsMessagesError::InvalidPixelFormat)?; - let bitmap_data_length = stream.read_u32::()? as usize; - let mut bitmap_data = vec![0; bitmap_data_length]; - stream.read_exact(&mut bitmap_data)?; + Codec2Type::from_u16(src.read_u16()).ok_or_else(|| invalid_message_err!("CodecId", "invalid codec ID"))?; + let codec_context_id = src.read_u32(); + let pixel_format = PixelFormat::from_u8(src.read_u8()) + .ok_or_else(|| invalid_message_err!("PixelFormat", "invalid pixel format"))?; + let bitmap_data_length = cast_length!("BitmapDataLen", src.read_u32())?; + + ensure_size!(in: src, size: bitmap_data_length); + let bitmap_data = src.read_slice(bitmap_data_length).to_vec(); Ok(Self { surface_id, @@ -114,21 +162,6 @@ impl PduParsing for WireToSurface2Pdu { bitmap_data, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; - stream.write_u16::(self.codec_id.to_u16().unwrap())?; - stream.write_u32::(self.codec_context_id)?; - stream.write_u8(self.pixel_format.to_u8().unwrap())?; - stream.write_u32::(self.bitmap_data.len() as u32)?; - stream.write_all(&self.bitmap_data)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 13 + self.bitmap_data.len() - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -137,29 +170,43 @@ pub struct DeleteEncodingContextPdu { pub codec_context_id: u32, } -impl PduParsing for DeleteEncodingContextPdu { - type Error = GraphicsMessagesError; +impl DeleteEncodingContextPdu { + const NAME: &'static str = "DeleteEncodingContextPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; - let codec_context_id = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = 2 /* SurfaceId */ + 4 /* CodecContextId */; +} + +impl PduEncode for DeleteEncodingContextPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + dst.write_u16(self.surface_id); + dst.write_u32(self.codec_context_id); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for DeleteEncodingContextPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); + let codec_context_id = src.read_u32(); Ok(Self { surface_id, codec_context_id, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; - stream.write_u32::(self.codec_context_id)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 6 - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -169,17 +216,48 @@ pub struct SolidFillPdu { pub rectangles: Vec, } -impl PduParsing for SolidFillPdu { - type Error = GraphicsMessagesError; +impl SolidFillPdu { + const NAME: &'static str = "CacheToSurfacePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; - let fill_pixel = Color::from_buffer(&mut stream)?; - let rectangles_count = stream.read_u16::()?; + const FIXED_PART_SIZE: usize = 2 /* SurfaceId */ + Color::FIXED_PART_SIZE /* Color */ + 2 /* RectCount */; +} +impl PduEncode for SolidFillPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + dst.write_u16(self.surface_id); + self.fill_pixel.encode(dst)?; + dst.write_u16(self.rectangles.len() as u16); + + for rectangle in self.rectangles.iter() { + rectangle.encode(dst)?; + } + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + self.rectangles.iter().map(|r| r.size()).sum::() + } +} + +impl<'a> PduDecode<'a> for SolidFillPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); + let fill_pixel = Color::decode(src)?; + let rectangles_count = src.read_u16(); + + ensure_size!(in: src, size: usize::from(rectangles_count) * InclusiveRectangle::FIXED_PART_SIZE); let rectangles = (0..rectangles_count) - .map(|_| InclusiveRectangle::from_buffer(&mut stream).map_err(GraphicsMessagesError::from)) - .collect::, Self::Error>>()?; + .map(|_| InclusiveRectangle::decode(src)) + .collect::>()?; Ok(Self { surface_id, @@ -187,21 +265,6 @@ impl PduParsing for SolidFillPdu { rectangles, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; - self.fill_pixel.to_buffer(&mut stream)?; - stream.write_u16::(self.rectangles.len() as u16)?; - for rectangle in self.rectangles.iter() { - rectangle.to_buffer(&mut stream)?; - } - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 8 + self.rectangles.iter().map(|r| r.buffer_length()).sum::() - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -212,18 +275,49 @@ pub struct SurfaceToSurfacePdu { pub destination_points: Vec, } -impl PduParsing for SurfaceToSurfacePdu { - type Error = GraphicsMessagesError; +impl SurfaceToSurfacePdu { + const NAME: &'static str = "SurfaceToSurfacePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let source_surface_id = stream.read_u16::()?; - let destination_surface_id = stream.read_u16::()?; - let source_rectangle = InclusiveRectangle::from_buffer(&mut stream)?; - let destination_points_count = stream.read_u16::()?; + const FIXED_PART_SIZE: usize = 2 /* SourceId */ + 2 /* DestId */ + InclusiveRectangle::FIXED_PART_SIZE /* SourceRect */ + 2 /* DestPointsCount */; +} + +impl PduEncode for SurfaceToSurfacePdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + dst.write_u16(self.source_surface_id); + dst.write_u16(self.destination_surface_id); + self.source_rectangle.encode(dst)?; + + dst.write_u16(cast_length!("DestinationPoints", self.destination_points.len())?); + for rectangle in self.destination_points.iter() { + rectangle.encode(dst)?; + } + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + self.destination_points.iter().map(|r| r.size()).sum::() + } +} + +impl<'a> PduDecode<'a> for SurfaceToSurfacePdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let source_surface_id = src.read_u16(); + let destination_surface_id = src.read_u16(); + let source_rectangle = InclusiveRectangle::decode(src)?; + let destination_points_count = src.read_u16(); let destination_points = (0..destination_points_count) - .map(|_| Point::from_buffer(&mut stream)) - .collect::, Self::Error>>()?; + .map(|_| Point::decode(src)) + .collect::>()?; Ok(Self { source_surface_id, @@ -232,24 +326,6 @@ impl PduParsing for SurfaceToSurfacePdu { destination_points, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.source_surface_id)?; - stream.write_u16::(self.destination_surface_id)?; - self.source_rectangle.to_buffer(&mut stream)?; - - stream.write_u16::(self.destination_points.len() as u16)?; - for rectangle in self.destination_points.iter() { - rectangle.to_buffer(&mut stream)?; - } - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 6 + self.source_rectangle.buffer_length() - + self.destination_points.iter().map(|r| r.buffer_length()).sum::() - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -260,14 +336,41 @@ pub struct SurfaceToCachePdu { pub source_rectangle: InclusiveRectangle, } -impl PduParsing for SurfaceToCachePdu { - type Error = GraphicsMessagesError; +impl SurfaceToCachePdu { + const NAME: &'static str = "SurfaceToCachePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; - let cache_key = stream.read_u64::()?; - let cache_slot = stream.read_u16::()?; - let source_rectangle = InclusiveRectangle::from_buffer(&mut stream)?; + const FIXED_PART_SIZE: usize = 2 /* SurfaceId */ + 8 /* CacheKey */ + 2 /* CacheSlot */ + InclusiveRectangle::FIXED_PART_SIZE /* SourceRect */; +} + +impl PduEncode for SurfaceToCachePdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + dst.write_u16(self.surface_id); + dst.write_u64(self.cache_key); + dst.write_u16(self.cache_slot); + self.source_rectangle.encode(dst)?; + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for SurfaceToCachePdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); + let cache_key = src.read_u64(); + let cache_slot = src.read_u16(); + let source_rectangle = InclusiveRectangle::decode(src)?; Ok(Self { surface_id, @@ -276,19 +379,6 @@ impl PduParsing for SurfaceToCachePdu { source_rectangle, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; - stream.write_u64::(self.cache_key)?; - stream.write_u16::(self.cache_slot)?; - self.source_rectangle.to_buffer(&mut stream)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 12 + self.source_rectangle.buffer_length() - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -298,17 +388,46 @@ pub struct CacheToSurfacePdu { pub destination_points: Vec, } -impl PduParsing for CacheToSurfacePdu { - type Error = GraphicsMessagesError; +impl CacheToSurfacePdu { + const NAME: &'static str = "CacheToSurfacePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let cache_slot = stream.read_u16::()?; - let surface_id = stream.read_u16::()?; - let destination_points_count = stream.read_u16::()?; + const FIXED_PART_SIZE: usize = mem::size_of::() * 3; +} + +impl PduEncode for CacheToSurfacePdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + dst.write_u16(self.cache_slot); + dst.write_u16(self.surface_id); + dst.write_u16(cast_length!("npoints", self.destination_points.len())?); + for point in self.destination_points.iter() { + point.encode(dst)?; + } + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + self.destination_points.iter().map(|p| p.size()).sum::() + } +} + +impl<'de> PduDecode<'de> for CacheToSurfacePdu { + fn decode(src: &mut ReadCursor<'de>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let cache_slot = src.read_u16(); + let surface_id = src.read_u16(); + let destination_points_count = src.read_u16(); let destination_points = (0..destination_points_count) - .map(|_| Point::from_buffer(&mut stream)) - .collect::, Self::Error>>()?; + .map(|_| decode_cursor(src)) + .collect::>()?; Ok(Self { cache_slot, @@ -316,21 +435,6 @@ impl PduParsing for CacheToSurfacePdu { destination_points, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.cache_slot)?; - stream.write_u16::(self.surface_id)?; - stream.write_u16::(self.destination_points.len() as u16)?; - for point in self.destination_points.iter() { - point.to_buffer(&mut stream)?; - } - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 6 + self.destination_points.iter().map(|p| p.buffer_length()).sum::() - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -341,14 +445,42 @@ pub struct CreateSurfacePdu { pub pixel_format: PixelFormat, } -impl PduParsing for CreateSurfacePdu { - type Error = GraphicsMessagesError; +impl CreateSurfacePdu { + const NAME: &'static str = "CreateSurfacePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; - let width = stream.read_u16::()?; - let height = stream.read_u16::()?; - let pixel_format = PixelFormat::from_u8(stream.read_u8()?).ok_or(GraphicsMessagesError::InvalidPixelFormat)?; + const FIXED_PART_SIZE: usize = 2 /* SurfaceId */ + 2 /* Width */ + 2 /* Height */ + 1 /* PixelFormat */; +} + +impl PduEncode for CreateSurfacePdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + dst.write_u16(self.surface_id); + dst.write_u16(self.width); + dst.write_u16(self.height); + dst.write_u8(self.pixel_format.to_u8().unwrap()); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for CreateSurfacePdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); + let width = src.read_u16(); + let height = src.read_u16(); + let pixel_format = PixelFormat::from_u8(src.read_u8()) + .ok_or_else(|| invalid_message_err!("pixelFormat", "invalid pixel format"))?; Ok(Self { surface_id, @@ -357,19 +489,6 @@ impl PduParsing for CreateSurfacePdu { pixel_format, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; - stream.write_u16::(self.width)?; - stream.write_u16::(self.height)?; - stream.write_u8(self.pixel_format.to_u8().unwrap())?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 7 - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -377,23 +496,37 @@ pub struct DeleteSurfacePdu { pub surface_id: u16, } -impl PduParsing for DeleteSurfacePdu { - type Error = GraphicsMessagesError; +impl DeleteSurfacePdu { + const NAME: &'static str = "DeleteSurfacePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; + const FIXED_PART_SIZE: usize = 2 /* SurfaceId */; +} - Ok(Self { surface_id }) - } +impl PduEncode for DeleteSurfacePdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; + dst.write_u16(self.surface_id); Ok(()) } - fn buffer_length(&self) -> usize { - 2 + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for DeleteSurfacePdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); + + Ok(Self { surface_id }) } } @@ -405,45 +538,59 @@ pub struct ResetGraphicsPdu { } impl ResetGraphicsPdu { - fn padding_size(&self) -> usize { - RESET_GRAPHICS_PDU_SIZE - - RDP_GFX_HEADER_SIZE - - 12 - - self.monitors.iter().map(|m| m.buffer_length()).sum::() + const NAME: &'static str = "ResetGraphicsPdu"; + + const FIXED_PART_SIZE: usize = 4 /* Width */ + 4 /* Height */; +} + +impl PduEncode for ResetGraphicsPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_size!(in: dst, size: self.size()); + + dst.write_u32(self.width); + dst.write_u32(self.height); + dst.write_u32(cast_length!("nMonitors", self.monitors.len())?); + + for monitor in self.monitors.iter() { + monitor.encode(dst)?; + } + + write_padding!(dst, self.padding_size()); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + RESET_GRAPHICS_PDU_SIZE - RDP_GFX_HEADER_SIZE } } -impl PduParsing for ResetGraphicsPdu { - type Error = GraphicsMessagesError; +impl<'a> PduDecode<'a> for ResetGraphicsPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); - fn from_buffer(mut stream: impl io::Read) -> Result { - let width = stream.read_u32::()?; + let width = src.read_u32(); if width > MAX_RESET_GRAPHICS_WIDTH_HEIGHT { - return Err(GraphicsMessagesError::InvalidResetGraphicsPduWidth { - actual: width, - max: MAX_RESET_GRAPHICS_WIDTH_HEIGHT, - }); + return Err(invalid_message_err!("width", "invalid reset graphics width")); } - let height = stream.read_u32::()?; + let height = src.read_u32(); if height > MAX_RESET_GRAPHICS_WIDTH_HEIGHT { - return Err(GraphicsMessagesError::InvalidResetGraphicsPduHeight { - actual: height, - max: MAX_RESET_GRAPHICS_WIDTH_HEIGHT, - }); + return Err(invalid_message_err!("height", "invalid reset graphics height")); } - let monitor_count = stream.read_u32::()?; + let monitor_count = src.read_u32(); if monitor_count > MONITOR_COUNT_MAX { - return Err(GraphicsMessagesError::InvalidResetGraphicsPduMonitorsCount { - actual: monitor_count, - max: MAX_RESET_GRAPHICS_WIDTH_HEIGHT, - }); + return Err(invalid_message_err!("height", "invalid reset graphics monitor count")); } let monitors = (0..monitor_count) - .map(|_| Monitor::from_buffer(&mut stream)) - .collect::, MonitorDataError>>()?; + .map(|_| Monitor::decode(src)) + .collect::, _>>()?; let pdu = Self { width, @@ -451,29 +598,15 @@ impl PduParsing for ResetGraphicsPdu { monitors, }; - let mut padding = vec![0; pdu.padding_size()]; - stream.read_exact(padding.as_mut())?; + read_padding!(src, pdu.padding_size()); Ok(pdu) } +} - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u32::(self.width)?; - stream.write_u32::(self.height)?; - stream.write_u32::(self.monitors.len() as u32)?; - - for monitor in self.monitors.iter() { - monitor.to_buffer(&mut stream)?; - } - - let padding = vec![0; self.padding_size()]; - stream.write_all(padding.as_slice())?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - RESET_GRAPHICS_PDU_SIZE - RDP_GFX_HEADER_SIZE +impl ResetGraphicsPdu { + fn padding_size(&self) -> usize { + RESET_GRAPHICS_PDU_SIZE - RDP_GFX_HEADER_SIZE - 12 - self.monitors.iter().map(|m| m.size()).sum::() } } @@ -484,14 +617,41 @@ pub struct MapSurfaceToOutputPdu { pub output_origin_y: u32, } -impl PduParsing for MapSurfaceToOutputPdu { - type Error = GraphicsMessagesError; +impl MapSurfaceToOutputPdu { + const NAME: &'static str = "MapSurfaceToOutputPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; - let _reserved = stream.read_u16::()?; - let output_origin_x = stream.read_u32::()?; - let output_origin_y = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = 2 /* surfaceId */ + 2 /* reserved */ + 4 /* OutOriginX */ + 4 /* OutOriginY */; +} + +impl PduEncode for MapSurfaceToOutputPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + dst.write_u16(self.surface_id); + dst.write_u16(0); // reserved + dst.write_u32(self.output_origin_x); + dst.write_u32(self.output_origin_y); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for MapSurfaceToOutputPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); + let _reserved = src.read_u16(); + let output_origin_x = src.read_u32(); + let output_origin_y = src.read_u32(); Ok(Self { surface_id, @@ -499,19 +659,6 @@ impl PduParsing for MapSurfaceToOutputPdu { output_origin_y, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; - stream.write_u16::(0)?; // reserved - stream.write_u32::(self.output_origin_x)?; - stream.write_u32::(self.output_origin_y)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 12 - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -523,16 +670,45 @@ pub struct MapSurfaceToScaledOutputPdu { pub target_height: u32, } -impl PduParsing for MapSurfaceToScaledOutputPdu { - type Error = GraphicsMessagesError; +impl MapSurfaceToScaledOutputPdu { + const NAME: &'static str = "MapSurfaceToScaledOutputPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; - let _reserved = stream.read_u16::()?; - let output_origin_x = stream.read_u32::()?; - let output_origin_y = stream.read_u32::()?; - let target_width = stream.read_u32::()?; - let target_height = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = 2 /* SurfaceId */ + 2 /* reserved */ + 4 /* OutOriginX */ + 4 /* OutOriginY */ + 4 /* TargetWidth */ + 4 /* TargetHeight */; +} + +impl PduEncode for MapSurfaceToScaledOutputPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + dst.write_u16(self.surface_id); + dst.write_u16(0); // reserved + dst.write_u32(self.output_origin_x); + dst.write_u32(self.output_origin_y); + dst.write_u32(self.target_width); + dst.write_u32(self.target_height); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for MapSurfaceToScaledOutputPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); + let _reserved = src.read_u16(); + let output_origin_x = src.read_u32(); + let output_origin_y = src.read_u32(); + let target_width = src.read_u32(); + let target_height = src.read_u32(); Ok(Self { surface_id, @@ -542,21 +718,6 @@ impl PduParsing for MapSurfaceToScaledOutputPdu { target_height, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; - stream.write_u16::(0)?; // reserved - stream.write_u32::(self.output_origin_x)?; - stream.write_u32::(self.output_origin_y)?; - stream.write_u32::(self.target_width)?; - stream.write_u32::(self.target_height)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 20 - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -569,16 +730,43 @@ pub struct MapSurfaceToScaledWindowPdu { pub target_height: u32, } -impl PduParsing for MapSurfaceToScaledWindowPdu { - type Error = GraphicsMessagesError; +impl MapSurfaceToScaledWindowPdu { + const NAME: &'static str = "MapSurfaceToScaledWindowPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let surface_id = stream.read_u16::()?; - let window_id = stream.read_u64::()?; - let mapped_width = stream.read_u32::()?; - let mapped_height = stream.read_u32::()?; - let target_width = stream.read_u32::()?; - let target_height = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = 2 /* SurfaceId */ + 8 /* WindowId */ + 4 /* MappedWidth */ + 4 /* MappedHeight */ + 4 /* TargetWidth */ + 4 /* TargetHeight */; +} + +impl PduEncode for MapSurfaceToScaledWindowPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + dst.write_u16(self.surface_id); + dst.write_u64(self.window_id); // reserved + dst.write_u32(self.mapped_width); + dst.write_u32(self.mapped_height); + dst.write_u32(self.target_width); + dst.write_u32(self.target_height); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for MapSurfaceToScaledWindowPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let surface_id = src.read_u16(); + let window_id = src.read_u64(); + let mapped_width = src.read_u32(); + let mapped_height = src.read_u32(); + let target_width = src.read_u32(); + let target_height = src.read_u32(); Ok(Self { surface_id, @@ -589,21 +777,6 @@ impl PduParsing for MapSurfaceToScaledWindowPdu { target_height, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.surface_id)?; - stream.write_u64::(self.window_id)?; // reserved - stream.write_u32::(self.mapped_width)?; - stream.write_u32::(self.mapped_height)?; - stream.write_u32::(self.target_width)?; - stream.write_u32::(self.target_height)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 26 - } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -611,23 +784,37 @@ pub struct EvictCacheEntryPdu { pub cache_slot: u16, } -impl PduParsing for EvictCacheEntryPdu { - type Error = GraphicsMessagesError; +impl EvictCacheEntryPdu { + const NAME: &'static str = "EvictCacheEntryPdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let cache_slot = stream.read_u16::()?; + const FIXED_PART_SIZE: usize = 2; +} - Ok(Self { cache_slot }) - } +impl PduEncode for EvictCacheEntryPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u16::(self.cache_slot)?; + dst.write_u16(self.cache_slot); Ok(()) } - fn buffer_length(&self) -> usize { - 2 + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for EvictCacheEntryPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let cache_slot = src.read_u16(); + + Ok(Self { cache_slot }) } } @@ -637,25 +824,39 @@ pub struct StartFramePdu { pub frame_id: u32, } -impl PduParsing for StartFramePdu { - type Error = GraphicsMessagesError; +impl StartFramePdu { + const NAME: &'static str = "StartFramePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let timestamp = Timestamp::from_buffer(&mut stream)?; - let frame_id = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = Timestamp::FIXED_PART_SIZE + 4 /* FrameId */; +} - Ok(Self { timestamp, frame_id }) - } +impl PduEncode for StartFramePdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - self.timestamp.to_buffer(&mut stream)?; - stream.write_u32::(self.frame_id)?; + self.timestamp.encode(dst)?; + dst.write_u32(self.frame_id); Ok(()) } - fn buffer_length(&self) -> usize { - 8 + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for StartFramePdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let timestamp = Timestamp::decode(src)?; + let frame_id = src.read_u32(); + + Ok(Self { timestamp, frame_id }) } } @@ -664,45 +865,67 @@ pub struct EndFramePdu { pub frame_id: u32, } -impl PduParsing for EndFramePdu { - type Error = GraphicsMessagesError; +impl EndFramePdu { + const NAME: &'static str = "EndFramePdu"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let frame_id = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = 4; +} - Ok(Self { frame_id }) - } +impl PduEncode for EndFramePdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - stream.write_u32::(self.frame_id)?; + dst.write_u32(self.frame_id); Ok(()) } - fn buffer_length(&self) -> usize { - 4 + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for EndFramePdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let frame_id = src.read_u32(); + + Ok(Self { frame_id }) } } #[derive(Debug, Clone, PartialEq, Eq)] pub struct CapabilitiesConfirmPdu(pub CapabilitySet); -impl PduParsing for CapabilitiesConfirmPdu { - type Error = GraphicsMessagesError; +impl CapabilitiesConfirmPdu { + const NAME: &'static str = "CapabilitiesConfirmPdu"; +} - fn from_buffer(mut stream: impl io::Read) -> Result { - let capability_set = CapabilitySet::from_buffer(&mut stream)?; +impl PduEncode for CapabilitiesConfirmPdu { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + self.0.encode(dst) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + self.0.size() + } +} + +impl<'a> PduDecode<'a> for CapabilitiesConfirmPdu { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + let capability_set = CapabilitySet::decode(src)?; Ok(Self(capability_set)) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - self.0.to_buffer(&mut stream) - } - - fn buffer_length(&self) -> usize { - self.0.buffer_length() - } } #[repr(u16)] @@ -739,11 +962,42 @@ pub struct Timestamp { pub hours: u16, } -impl PduParsing for Timestamp { - type Error = GraphicsMessagesError; +impl Timestamp { + const NAME: &'static str = "Timestamp"; - fn from_buffer(mut stream: impl io::Read) -> Result { - let timestamp = stream.read_u32::()?; + const FIXED_PART_SIZE: usize = 4; +} + +impl PduEncode for Timestamp { + fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { + ensure_fixed_part_size!(in: dst); + + let mut timestamp: u32 = 0; + + timestamp.set_bits(..10, u32::from(self.milliseconds)); + timestamp.set_bits(10..16, u32::from(self.seconds)); + timestamp.set_bits(16..22, u32::from(self.minutes)); + timestamp.set_bits(22.., u32::from(self.hours)); + + dst.write_u32(timestamp); + + Ok(()) + } + + fn name(&self) -> &'static str { + Self::NAME + } + + fn size(&self) -> usize { + Self::FIXED_PART_SIZE + } +} + +impl<'a> PduDecode<'a> for Timestamp { + fn decode(src: &mut ReadCursor<'a>) -> PduResult { + ensure_fixed_part_size!(in: src); + + let timestamp = src.read_u32(); let milliseconds = timestamp.get_bits(..10) as u16; let seconds = timestamp.get_bits(10..16) as u8; @@ -757,21 +1011,4 @@ impl PduParsing for Timestamp { hours, }) } - - fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> { - let mut timestamp: u32 = 0; - - timestamp.set_bits(..10, u32::from(self.milliseconds)); - timestamp.set_bits(10..16, u32::from(self.seconds)); - timestamp.set_bits(16..22, u32::from(self.minutes)); - timestamp.set_bits(22.., u32::from(self.hours)); - - stream.write_u32::(timestamp)?; - - Ok(()) - } - - fn buffer_length(&self) -> usize { - 4 - } } diff --git a/crates/ironrdp-server/src/server.rs b/crates/ironrdp-server/src/server.rs index e56f8fe9..2c427b8e 100644 --- a/crates/ironrdp-server/src/server.rs +++ b/crates/ironrdp-server/src/server.rs @@ -11,7 +11,7 @@ use ironrdp_pdu::input::fast_path::{FastPathInput, FastPathInputEvent}; use ironrdp_pdu::input::InputEventPdu; use ironrdp_pdu::mcs::SendDataRequest; use ironrdp_pdu::rdp::capability_sets::{CapabilitySet, CmdFlags, GeneralExtraFlags}; -use ironrdp_pdu::{self, custom_err, decode, mcs, nego, rdp, Action, PduParsing, PduResult}; +use ironrdp_pdu::{self, decode, mcs, nego, rdp, Action, PduParsing, PduResult}; use ironrdp_svc::{server_encode_svc_messages, StaticChannelSet}; use ironrdp_tokio::{Framed, FramedRead, FramedWrite, TokioFramed}; use tokio::net::{TcpListener, TcpStream}; @@ -59,15 +59,13 @@ impl dvc::DvcProcessor for DisplayControlHandler { max_monitor_area_factorb: 2400, }); - let mut buf = vec![]; - pdu.to_buffer(&mut buf).map_err(|e| custom_err!(e))?; - Ok(vec![Box::new(buf)]) + Ok(vec![Box::new(pdu)]) } fn process(&mut self, _channel_id: u32, payload: &[u8]) -> PduResult { use ironrdp_pdu::dvc::display::ClientPdu; - match ClientPdu::from_buffer(payload).map_err(|e| custom_err!(e))? { + match decode(payload)? { ClientPdu::DisplayControlMonitorLayout(layout) => { debug!(?layout); } diff --git a/crates/ironrdp-session/src/legacy.rs b/crates/ironrdp-session/src/legacy.rs index a6abac88..0fd35c13 100644 --- a/crates/ironrdp-session/src/legacy.rs +++ b/crates/ironrdp-session/src/legacy.rs @@ -1,9 +1,9 @@ use ironrdp_connector::encode_send_data_request; use ironrdp_connector::legacy::SendDataIndicationCtx; -use ironrdp_pdu::cursor::WriteCursor; +use ironrdp_pdu::cursor::{ReadCursor, WriteCursor}; use ironrdp_pdu::rdp::vc; use ironrdp_pdu::write_buf::WriteBuf; -use ironrdp_pdu::{decode, ensure_size, PduEncode, PduResult}; +use ironrdp_pdu::{decode, PduEncode, PduResult}; use crate::{SessionError, SessionErrorExt, SessionResult}; @@ -14,7 +14,7 @@ pub fn encode_dvc_message( dvc_data: &[u8], buf: &mut WriteBuf, ) -> SessionResult<()> { - let dvc_length = dvc_pdu.buffer_length() + dvc_data.len(); + let dvc_length = dvc_pdu.size() + dvc_data.len(); let channel_header = vc::ChannelPduHeader { length: u32::try_from(dvc_length).expect("dvc message size"), @@ -47,7 +47,7 @@ impl DvcMessage<'_> { impl PduEncode for DvcMessage<'_> { fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> { - ensure_size!(in: dst, size: self.size()); + ironrdp_pdu::ensure_size!(in: dst, size: self.size()); self.channel_header.encode(dst)?; self.dvc_pdu.encode(dst)?; @@ -70,7 +70,7 @@ pub struct DynamicChannelCtx<'a> { } pub fn decode_dvc_message(ctx: SendDataIndicationCtx<'_>) -> SessionResult> { - let mut user_data = ctx.user_data; + let user_data = ctx.user_data; // [ vc::ChannelPduHeader | … let channel_header: vc::ChannelPduHeader = decode(user_data).map_err(SessionError::pdu)?; @@ -78,10 +78,11 @@ pub fn decode_dvc_message(ctx: SendDataIndicationCtx<'_>) -> SessionResult) -> SessionResult>> { - let gfx_pdu = ServerPdu::from_buffer(&mut complete_data.as_slice())?; + let gfx_pdu: ServerPdu = decode(&complete_data).map_err(SessionError::pdu)?; debug!("Got Display PDU: {:?}", gfx_pdu); Ok(None) } diff --git a/crates/ironrdp-session/src/x224/gfx.rs b/crates/ironrdp-session/src/x224/gfx.rs index 75609e92..8a1115b7 100644 --- a/crates/ironrdp-session/src/x224/gfx.rs +++ b/crates/ironrdp-session/src/x224/gfx.rs @@ -6,10 +6,10 @@ use ironrdp_pdu::dvc::gfx::{ CapabilitiesV10Flags, CapabilitiesV81Flags, CapabilitiesV8Flags, CapabilitySet, ClientPdu, FrameAcknowledgePdu, QueueDepth, ServerPdu, }; -use ironrdp_pdu::PduParsing; +use ironrdp_pdu::{decode, encode_vec}; use crate::x224::DynamicChannelDataHandler; -use crate::SessionResult; +use crate::{SessionError, SessionErrorExt, SessionResult}; pub trait GfxHandler { fn on_message(&self, message: ServerPdu) -> SessionResult>; @@ -39,9 +39,9 @@ impl DynamicChannelDataHandler for Handler { self.decompressed_buffer.clear(); self.decompressor .decompress(complete_data.as_slice(), &mut self.decompressed_buffer)?; - let mut slice = &mut self.decompressed_buffer.as_slice(); + let slice = &mut self.decompressed_buffer.as_slice(); while !slice.is_empty() { - let gfx_pdu = ServerPdu::from_buffer(&mut slice)?; + let gfx_pdu: ServerPdu = decode(slice).map_err(SessionError::pdu)?; debug!("Got GFX PDU: {:?}", gfx_pdu); if let ServerPdu::EndFrame(end_frame_pdu) = &gfx_pdu { @@ -53,8 +53,7 @@ impl DynamicChannelDataHandler for Handler { total_frames_decoded: self.frames_decoded, }); debug!("Sending GFX PDU: {:?}", client_pdu); - client_pdu_buffer.reserve(client_pdu_buffer.len() + client_pdu.buffer_length()); - client_pdu.to_buffer(&mut client_pdu_buffer)?; + client_pdu_buffer.append(&mut encode_vec(&client_pdu).map_err(SessionError::pdu)?); } else { // Handle the normal PDU } @@ -65,8 +64,7 @@ impl DynamicChannelDataHandler for Handler { let client_pdu = handler.on_message(gfx_pdu)?; if let Some(client_pdu) = client_pdu { - client_pdu_buffer.reserve(client_pdu_buffer.len() + client_pdu.buffer_length()); - client_pdu.to_buffer(&mut client_pdu_buffer)?; + client_pdu_buffer.append(&mut encode_vec(&client_pdu).map_err(SessionError::pdu)?); } } } @@ -195,8 +193,6 @@ pub(crate) fn create_capabilities_advertise(graphics_config: &Option