refactor(pdu): convert input module to PduEncode/Decode

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2024-02-08 13:15:45 +04:00 committed by Benoît Cortier
parent 2f955f16c3
commit 9faf1ff08d
14 changed files with 517 additions and 339 deletions

View file

@ -79,8 +79,8 @@ pub fn pdu_decode(data: &[u8]) {
let _ = codecs::rfx::ChannelsPdu::from_buffer(data);
let _ = codecs::rfx::RfxChannel::from_buffer(data);
let _ = input::InputEventPdu::from_buffer(data);
let _ = input::InputEvent::from_buffer(data);
let _ = decode::<input::InputEventPdu>(data);
let _ = decode::<input::InputEvent>(data);
let _ = decode::<bitmap::rdp6::BitmapStream<'_>>(data);

View file

@ -1,14 +1,12 @@
use std::io::{self};
use bit_field::BitField;
use bitflags::bitflags;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive, ToPrimitive};
use crate::cursor::{ReadCursor, WriteCursor};
use crate::fast_path::EncryptionFlags;
use crate::input::{InputEventError, MousePdu, MouseRelPdu, MouseXPdu};
use crate::{per, PduParsing};
use crate::input::{MousePdu, MouseRelPdu, MouseXPdu};
use crate::{per, PduDecode, PduEncode, PduResult};
/// Implements the Fast-Path RDP message header PDU.
#[derive(Debug, Clone, PartialEq, Eq)]
@ -18,21 +16,60 @@ pub struct FastPathInputHeader {
pub num_events: u8,
}
impl PduParsing for FastPathInputHeader {
type Error = InputEventError;
impl FastPathInputHeader {
const NAME: &'static str = "FastPathInputHeader";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let header = stream.read_u8()?;
const FIXED_PART_SIZE: usize = 1 /* header */;
}
impl PduEncode for FastPathInputHeader {
fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> {
ensure_size!(in: dst, size: self.size());
let mut header = 0u8;
header.set_bits(0..2, 0); // fast-path action
if self.num_events < 16 {
header.set_bits(2..7, self.num_events);
}
header.set_bits(6..8, self.flags.bits());
dst.write_u8(header);
per::write_length(dst, cast_length!("len", self.data_length + self.size())?);
if self.num_events > 15 {
dst.write_u8(self.num_events);
}
Ok(())
}
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
let num_events_length = if self.num_events < 16 { 0 } else { 1 };
Self::FIXED_PART_SIZE
+ per::sizeof_length(self.data_length as u16 + num_events_length as u16 + 1)
+ num_events_length
}
}
impl<'de> PduDecode<'de> for FastPathInputHeader {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
let header = src.read_u8();
let flags = EncryptionFlags::from_bits_truncate(header.get_bits(6..8));
let mut num_events = header.get_bits(2..6);
let (length, sizeof_length) = per::legacy::read_length(&mut stream)?;
let (length, sizeof_length) = per::read_length(src).map_err(|e| custom_err!("perLen", e))?;
if !flags.is_empty() {
return Err(InputEventError::EncryptionNotSupported);
return Err(invalid_message_err!("flags", "encryption not supported"));
}
let num_events_length = if num_events == 0 {
num_events = stream.read_u8()?;
ensure_size!(in: src, size: 1);
num_events = src.read_u8();
1
} else {
0
@ -46,28 +83,6 @@ impl PduParsing for FastPathInputHeader {
num_events,
})
}
fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> {
let mut header = 0u8;
header.set_bits(0..2, 0); // fast-path action
if self.num_events < 16 {
header.set_bits(2..7, self.num_events);
}
header.set_bits(6..8, self.flags.bits());
stream.write_u8(header)?;
per::legacy::write_length(&mut stream, (self.data_length + self.buffer_length()) as u16)?;
if self.num_events > 15 {
stream.write_u8(self.num_events)?;
}
Ok(())
}
fn buffer_length(&self) -> usize {
let num_events_length = if self.num_events < 16 { 0 } else { 1 };
1 + per::sizeof_length(self.data_length as u16 + num_events_length as u16 + 1) + num_events_length
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
@ -93,52 +108,16 @@ pub enum FastPathInputEvent {
SyncEvent(SynchronizeFlags),
}
impl PduParsing for FastPathInputEvent {
type Error = InputEventError;
impl FastPathInputEvent {
const NAME: &'static str = "FastPathInputEvent";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let header = stream.read_u8()?;
let flags = header.get_bits(0..5);
let code = header.get_bits(5..8);
let code: FastpathInputEventType =
FastpathInputEventType::from_u8(code).ok_or(InputEventError::EventCodeUnsupported(code))?;
let event = match code {
FastpathInputEventType::ScanCode => {
let code = stream.read_u8()?;
let flags = KeyboardFlags::from_bits(flags).ok_or(InputEventError::KeyboardFlagsUnsupported(flags))?;
FastPathInputEvent::KeyboardEvent(flags, code)
}
FastpathInputEventType::Mouse => {
let mouse_event = MousePdu::from_buffer(stream)?;
FastPathInputEvent::MouseEvent(mouse_event)
}
FastpathInputEventType::MouseX => {
let mouse_event = MouseXPdu::from_buffer(stream)?;
FastPathInputEvent::MouseEventEx(mouse_event)
}
FastpathInputEventType::MouseRel => {
let mouse_event = MouseRelPdu::from_buffer(stream)?;
FastPathInputEvent::MouseEventRel(mouse_event)
}
FastpathInputEventType::Sync => {
let flags =
SynchronizeFlags::from_bits(flags).ok_or(InputEventError::SynchronizeFlagsUnsupported(flags))?;
FastPathInputEvent::SyncEvent(flags)
}
FastpathInputEventType::Unicode => {
let code = stream.read_u16::<LittleEndian>()?;
let flags = KeyboardFlags::from_bits(flags).ok_or(InputEventError::KeyboardFlagsUnsupported(flags))?;
FastPathInputEvent::UnicodeKeyboardEvent(flags, code)
}
FastpathInputEventType::QoeTimestamp => {
let code = stream.read_u32::<LittleEndian>()?;
FastPathInputEvent::QoeEvent(code)
}
};
Ok(event)
}
const FIXED_PART_SIZE: usize = 1 /* header */;
}
impl PduEncode for FastPathInputEvent {
fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> {
ensure_size!(in: dst, size: self.size());
fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> {
let mut header = 0u8;
let (flags, code) = match self {
FastPathInputEvent::KeyboardEvent(flags, _) => (flags.bits(), FastpathInputEventType::ScanCode),
@ -151,41 +130,100 @@ impl PduParsing for FastPathInputEvent {
};
header.set_bits(0..5, flags);
header.set_bits(5..8, code.to_u8().unwrap());
stream.write_u8(header)?;
dst.write_u8(header);
match self {
FastPathInputEvent::KeyboardEvent(_, code) => {
stream.write_u8(*code)?;
dst.write_u8(*code);
}
FastPathInputEvent::UnicodeKeyboardEvent(_, code) => {
stream.write_u16::<LittleEndian>(*code)?;
dst.write_u16(*code);
}
FastPathInputEvent::MouseEvent(pdu) => {
pdu.to_buffer(stream)?;
pdu.encode(dst)?;
}
FastPathInputEvent::MouseEventEx(pdu) => {
pdu.to_buffer(stream)?;
pdu.encode(dst)?;
}
FastPathInputEvent::QoeEvent(stamp) => {
stream.write_u32::<LittleEndian>(*stamp)?;
dst.write_u32(*stamp);
}
_ => {}
};
Ok(())
}
fn buffer_length(&self) -> usize {
1 + match self {
FastPathInputEvent::KeyboardEvent(_, _) => 1,
FastPathInputEvent::UnicodeKeyboardEvent(_, _) => 2,
FastPathInputEvent::MouseEvent(pdu) => pdu.buffer_length(),
FastPathInputEvent::MouseEventEx(pdu) => pdu.buffer_length(),
FastPathInputEvent::MouseEventRel(pdu) => pdu.buffer_length(),
FastPathInputEvent::QoeEvent(_) => 4,
FastPathInputEvent::SyncEvent(_) => 0,
}
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
Self::FIXED_PART_SIZE
+ match self {
FastPathInputEvent::KeyboardEvent(_, _) => 1,
FastPathInputEvent::UnicodeKeyboardEvent(_, _) => 2,
FastPathInputEvent::MouseEvent(pdu) => pdu.size(),
FastPathInputEvent::MouseEventEx(pdu) => pdu.size(),
FastPathInputEvent::MouseEventRel(pdu) => pdu.size(),
FastPathInputEvent::QoeEvent(_) => 4,
FastPathInputEvent::SyncEvent(_) => 0,
}
}
}
impl<'de> PduDecode<'de> for FastPathInputEvent {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
let header = src.read_u8();
let flags = header.get_bits(0..5);
let code = header.get_bits(5..8);
let code: FastpathInputEventType = FastpathInputEventType::from_u8(code)
.ok_or_else(|| invalid_message_err!("code", "input event code unsupported"))?;
let event = match code {
FastpathInputEventType::ScanCode => {
ensure_size!(in: src, size: 1);
let code = src.read_u8();
let flags = KeyboardFlags::from_bits(flags)
.ok_or_else(|| invalid_message_err!("flags", "input keyboard flags unsupported"))?;
FastPathInputEvent::KeyboardEvent(flags, code)
}
FastpathInputEventType::Mouse => {
let mouse_event = MousePdu::decode(src)?;
FastPathInputEvent::MouseEvent(mouse_event)
}
FastpathInputEventType::MouseX => {
let mouse_event = MouseXPdu::decode(src)?;
FastPathInputEvent::MouseEventEx(mouse_event)
}
FastpathInputEventType::MouseRel => {
let mouse_event = MouseRelPdu::decode(src)?;
FastPathInputEvent::MouseEventRel(mouse_event)
}
FastpathInputEventType::Sync => {
let flags = SynchronizeFlags::from_bits(flags)
.ok_or_else(|| invalid_message_err!("flags", "input synchronize flags unsupported"))?;
FastPathInputEvent::SyncEvent(flags)
}
FastpathInputEventType::Unicode => {
ensure_size!(in: src, size: 2);
let code = src.read_u16();
let flags = KeyboardFlags::from_bits(flags)
.ok_or_else(|| invalid_message_err!("flags", "input keyboard flags unsupported"))?;
FastPathInputEvent::UnicodeKeyboardEvent(flags, code)
}
FastpathInputEventType::QoeTimestamp => {
ensure_size!(in: src, size: 4);
let code = src.read_u32();
FastPathInputEvent::QoeEvent(code)
}
};
Ok(event)
}
}
impl_pdu_parsing!(FastPathInputEvent);
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct KeyboardFlags: u8 {
@ -208,45 +246,57 @@ bitflags! {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FastPathInput(pub Vec<FastPathInputEvent>);
impl PduParsing for FastPathInput {
type Error = InputEventError;
impl FastPathInput {
const NAME: &'static str = "FastPathInput";
}
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let header = FastPathInputHeader::from_buffer(&mut stream)?;
let events = (0..header.num_events)
.map(|_| FastPathInputEvent::from_buffer(&mut stream))
.collect::<Result<Vec<_>, _>>()?;
impl PduEncode for FastPathInput {
fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> {
ensure_size!(in: dst, size: self.size());
Ok(Self(events))
}
fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> {
if self.0.is_empty() {
return Err(InputEventError::EmptyFastPathInput);
return Err(other_err!("Empty fast-path input"));
}
let data_length = self.0.iter().map(PduParsing::buffer_length).sum::<usize>();
let data_length = self.0.iter().map(PduEncode::size).sum::<usize>();
let header = FastPathInputHeader {
num_events: self.0.len() as u8,
flags: EncryptionFlags::empty(),
data_length,
};
header.to_buffer(&mut stream)?;
header.encode(dst)?;
for event in self.0.iter() {
event.to_buffer(&mut stream)?;
event.encode(dst)?;
}
Ok(())
}
fn buffer_length(&self) -> usize {
let data_length = self.0.iter().map(PduParsing::buffer_length).sum::<usize>();
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
let data_length = self.0.iter().map(PduEncode::size).sum::<usize>();
let header = FastPathInputHeader {
num_events: self.0.len() as u8,
flags: EncryptionFlags::empty(),
data_length,
};
header.buffer_length() + data_length
header.size() + data_length
}
}
impl<'de> PduDecode<'de> for FastPathInput {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
let header = FastPathInputHeader::decode(src)?;
let events = (0..header.num_events)
.map(|_| FastPathInputEvent::decode(src))
.collect::<Result<Vec<_>, _>>()?;
Ok(Self(events))
}
}
impl_pdu_parsing_max!(FastPathInput);

View file

@ -1,11 +1,11 @@
use std::io;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive, ToPrimitive};
use thiserror::Error;
use crate::PduParsing;
use crate::cursor::{ReadCursor, WriteCursor};
use crate::{PduDecode, PduEncode, PduResult};
pub mod fast_path;
pub mod mouse;
@ -27,36 +27,52 @@ pub use self::unused::UnusedPdu;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InputEventPdu(pub Vec<InputEvent>);
impl PduParsing for InputEventPdu {
type Error = InputEventError;
impl InputEventPdu {
const NAME: &'static str = "InputEventPdu";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let number_of_events = stream.read_u16::<LittleEndian>()?;
let _padding = stream.read_u16::<LittleEndian>()?;
const FIXED_PART_SIZE: usize = 4 /* nEvents */;
}
let events = (0..number_of_events)
.map(|_| InputEvent::from_buffer(&mut stream))
.collect::<Result<Vec<_>, _>>()?;
impl PduEncode for InputEventPdu {
fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> {
ensure_size!(in: dst, size: self.size());
Ok(Self(events))
}
fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> {
stream.write_u16::<LittleEndian>(self.0.len() as u16)?;
stream.write_u16::<LittleEndian>(0)?; // padding
dst.write_u16(self.0.len() as u16);
write_padding!(dst, 2);
for event in self.0.iter() {
event.to_buffer(&mut stream)?;
event.encode(dst)?;
}
Ok(())
}
fn buffer_length(&self) -> usize {
4 + self.0.iter().map(PduParsing::buffer_length).sum::<usize>()
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
4 + self.0.iter().map(PduEncode::size).sum::<usize>()
}
}
impl<'de> PduDecode<'de> for InputEventPdu {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
let number_of_events = src.read_u16();
read_padding!(src, 2);
let events = (0..number_of_events)
.map(|_| InputEvent::decode(src))
.collect::<Result<Vec<_>, _>>()?;
Ok(Self(events))
}
}
impl_pdu_parsing_max!(InputEventPdu);
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InputEvent {
Sync(SyncPdu),
@ -68,54 +84,71 @@ pub enum InputEvent {
MouseRel(MouseRelPdu),
}
impl PduParsing for InputEvent {
type Error = InputEventError;
impl InputEvent {
const NAME: &'static str = "InputEvent";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let _event_time = stream.read_u32::<LittleEndian>()?; // ignored by a server
let event_type = stream.read_u16::<LittleEndian>()?;
let event_type =
InputEventType::from_u16(event_type).ok_or(InputEventError::InvalidInputEventType(event_type))?;
const FIXED_PART_SIZE: usize = 4 /* eventTime */ + 2 /* eventType */;
}
match event_type {
InputEventType::Sync => Ok(Self::Sync(SyncPdu::from_buffer(&mut stream)?)),
InputEventType::Unused => Ok(Self::Unused(UnusedPdu::from_buffer(&mut stream)?)),
InputEventType::ScanCode => Ok(Self::ScanCode(ScanCodePdu::from_buffer(&mut stream)?)),
InputEventType::Unicode => Ok(Self::Unicode(UnicodePdu::from_buffer(&mut stream)?)),
InputEventType::Mouse => Ok(Self::Mouse(MousePdu::from_buffer(&mut stream)?)),
InputEventType::MouseX => Ok(Self::MouseX(MouseXPdu::from_buffer(&mut stream)?)),
InputEventType::MouseRel => Ok(Self::MouseRel(MouseRelPdu::from_buffer(&mut stream)?)),
}
}
impl PduEncode for InputEvent {
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::<LittleEndian>(0)?; // event time is ignored by a server
stream.write_u16::<LittleEndian>(InputEventType::from(self).to_u16().unwrap())?;
dst.write_u32(0); // event time is ignored by a server
dst.write_u16(InputEventType::from(self).to_u16().unwrap());
match self {
Self::Sync(pdu) => pdu.to_buffer(&mut stream),
Self::Unused(pdu) => pdu.to_buffer(&mut stream),
Self::ScanCode(pdu) => pdu.to_buffer(&mut stream),
Self::Unicode(pdu) => pdu.to_buffer(&mut stream),
Self::Mouse(pdu) => pdu.to_buffer(&mut stream),
Self::MouseX(pdu) => pdu.to_buffer(&mut stream),
Self::MouseRel(pdu) => pdu.to_buffer(&mut stream),
Self::Sync(pdu) => pdu.encode(dst),
Self::Unused(pdu) => pdu.encode(dst),
Self::ScanCode(pdu) => pdu.encode(dst),
Self::Unicode(pdu) => pdu.encode(dst),
Self::Mouse(pdu) => pdu.encode(dst),
Self::MouseX(pdu) => pdu.encode(dst),
Self::MouseRel(pdu) => pdu.encode(dst),
}
}
fn buffer_length(&self) -> usize {
6 + match self {
Self::Sync(pdu) => pdu.buffer_length(),
Self::Unused(pdu) => pdu.buffer_length(),
Self::ScanCode(pdu) => pdu.buffer_length(),
Self::Unicode(pdu) => pdu.buffer_length(),
Self::Mouse(pdu) => pdu.buffer_length(),
Self::MouseX(pdu) => pdu.buffer_length(),
Self::MouseRel(pdu) => pdu.buffer_length(),
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
Self::FIXED_PART_SIZE
+ match self {
Self::Sync(pdu) => pdu.size(),
Self::Unused(pdu) => pdu.size(),
Self::ScanCode(pdu) => pdu.size(),
Self::Unicode(pdu) => pdu.size(),
Self::Mouse(pdu) => pdu.size(),
Self::MouseX(pdu) => pdu.size(),
Self::MouseRel(pdu) => pdu.size(),
}
}
}
impl<'de> PduDecode<'de> for InputEvent {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
let _event_time = src.read_u32(); // ignored by a server
let event_type = src.read_u16();
let event_type = InputEventType::from_u16(event_type)
.ok_or_else(|| invalid_message_err!("eventType", "invalid input event type"))?;
match event_type {
InputEventType::Sync => Ok(Self::Sync(SyncPdu::decode(src)?)),
InputEventType::Unused => Ok(Self::Unused(UnusedPdu::decode(src)?)),
InputEventType::ScanCode => Ok(Self::ScanCode(ScanCodePdu::decode(src)?)),
InputEventType::Unicode => Ok(Self::Unicode(UnicodePdu::decode(src)?)),
InputEventType::Mouse => Ok(Self::Mouse(MousePdu::decode(src)?)),
InputEventType::MouseX => Ok(Self::MouseX(MouseXPdu::decode(src)?)),
InputEventType::MouseRel => Ok(Self::MouseRel(MouseRelPdu::decode(src)?)),
}
}
}
impl_pdu_parsing!(InputEvent);
#[derive(Debug, Copy, Clone, PartialEq, FromPrimitive, ToPrimitive)]
#[repr(u16)]
enum InputEventType {

View file

@ -1,10 +1,9 @@
use std::io;
use bitflags::bitflags;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::InputEventError;
use crate::PduParsing;
use crate::{
cursor::{ReadCursor, WriteCursor},
PduDecode, PduEncode, PduResult,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MousePdu {
@ -14,11 +13,47 @@ pub struct MousePdu {
pub y_position: u16,
}
impl PduParsing for MousePdu {
type Error = InputEventError;
impl MousePdu {
const NAME: &'static str = "MousePdu";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let flags_raw = stream.read_u16::<LittleEndian>()?;
const FIXED_PART_SIZE: usize = 2 /* flags */ + 2 /* x */ + 2 /* y */;
}
impl PduEncode for MousePdu {
fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> {
ensure_fixed_part_size!(in: dst);
let wheel_negative_bit = if self.number_of_wheel_rotation_units < 0 {
PointerFlags::WHEEL_NEGATIVE.bits()
} else {
PointerFlags::empty().bits()
};
let wheel_rotations_bits = u16::from(self.number_of_wheel_rotation_units as u8); // truncate
let flags = self.flags.bits() | wheel_negative_bit | wheel_rotations_bits;
dst.write_u16(flags);
dst.write_u16(self.x_position);
dst.write_u16(self.y_position);
Ok(())
}
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
Self::FIXED_PART_SIZE
}
}
impl<'de> PduDecode<'de> for MousePdu {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
let flags_raw = src.read_u16();
let flags = PointerFlags::from_bits_truncate(flags_raw);
@ -30,8 +65,8 @@ impl PduParsing for MousePdu {
i16::from(wheel_rotations_bits)
};
let x_position = stream.read_u16::<LittleEndian>()?;
let y_position = stream.read_u16::<LittleEndian>()?;
let x_position = src.read_u16();
let y_position = src.read_u16();
Ok(Self {
flags,
@ -40,29 +75,8 @@ impl PduParsing for MousePdu {
y_position,
})
}
fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> {
let wheel_negative_bit = if self.number_of_wheel_rotation_units < 0 {
PointerFlags::WHEEL_NEGATIVE.bits()
} else {
PointerFlags::empty().bits()
};
let wheel_rotations_bits = u16::from(self.number_of_wheel_rotation_units as u8); // truncate
let flags = self.flags.bits() | wheel_negative_bit | wheel_rotations_bits;
stream.write_u16::<LittleEndian>(flags)?;
stream.write_u16::<LittleEndian>(self.x_position)?;
stream.write_u16::<LittleEndian>(self.y_position)?;
Ok(())
}
fn buffer_length(&self) -> usize {
6
}
}
impl_pdu_parsing!(MousePdu);
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]

View file

@ -1,10 +1,9 @@
use std::io;
use bitflags::bitflags;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::InputEventError;
use crate::PduParsing;
use crate::{
cursor::{ReadCursor, WriteCursor},
PduDecode, PduEncode, PduResult,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MouseRelPdu {
@ -13,13 +12,39 @@ pub struct MouseRelPdu {
pub y_delta: i16,
}
impl PduParsing for MouseRelPdu {
type Error = InputEventError;
impl MouseRelPdu {
const NAME: &'static str = "MouseRelPdu";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let flags = PointerRelFlags::from_bits_truncate(stream.read_u16::<LittleEndian>()?);
let x_delta = stream.read_i16::<LittleEndian>()?;
let y_delta = stream.read_i16::<LittleEndian>()?;
const FIXED_PART_SIZE: usize = 2 /* flags */ + 2 /* x */ + 2 /* y */;
}
impl PduEncode for MouseRelPdu {
fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> {
ensure_fixed_part_size!(in: dst);
dst.write_u16(self.flags.bits());
dst.write_i16(self.x_delta);
dst.write_i16(self.y_delta);
Ok(())
}
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
Self::FIXED_PART_SIZE
}
}
impl<'de> PduDecode<'de> for MouseRelPdu {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
let flags = PointerRelFlags::from_bits_truncate(src.read_u16());
let x_delta = src.read_i16();
let y_delta = src.read_i16();
Ok(Self {
flags,
@ -27,20 +52,10 @@ impl PduParsing for MouseRelPdu {
y_delta,
})
}
fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> {
stream.write_u16::<LittleEndian>(self.flags.bits())?;
stream.write_i16::<LittleEndian>(self.x_delta)?;
stream.write_i16::<LittleEndian>(self.y_delta)?;
Ok(())
}
fn buffer_length(&self) -> usize {
6
}
}
impl_pdu_parsing!(MouseRelPdu);
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PointerRelFlags: u16 {

View file

@ -1,10 +1,9 @@
use std::io;
use bitflags::bitflags;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::InputEventError;
use crate::PduParsing;
use crate::{
cursor::{ReadCursor, WriteCursor},
PduDecode, PduEncode, PduResult,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MouseXPdu {
@ -13,13 +12,39 @@ pub struct MouseXPdu {
pub y_position: u16,
}
impl PduParsing for MouseXPdu {
type Error = InputEventError;
impl MouseXPdu {
const NAME: &'static str = "MouseXPdu";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let flags = PointerXFlags::from_bits_truncate(stream.read_u16::<LittleEndian>()?);
let x_position = stream.read_u16::<LittleEndian>()?;
let y_position = stream.read_u16::<LittleEndian>()?;
const FIXED_PART_SIZE: usize = 2 /* flags */ + 2 /* x */ + 2 /* y */;
}
impl PduEncode for MouseXPdu {
fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> {
ensure_fixed_part_size!(in: dst);
dst.write_u16(self.flags.bits());
dst.write_u16(self.x_position);
dst.write_u16(self.y_position);
Ok(())
}
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
Self::FIXED_PART_SIZE
}
}
impl<'de> PduDecode<'de> for MouseXPdu {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
let flags = PointerXFlags::from_bits_truncate(src.read_u16());
let x_position = src.read_u16();
let y_position = src.read_u16();
Ok(Self {
flags,
@ -27,20 +52,10 @@ impl PduParsing for MouseXPdu {
y_position,
})
}
fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> {
stream.write_u16::<LittleEndian>(self.flags.bits())?;
stream.write_u16::<LittleEndian>(self.x_position)?;
stream.write_u16::<LittleEndian>(self.y_position)?;
Ok(())
}
fn buffer_length(&self) -> usize {
6
}
}
impl_pdu_parsing!(MouseXPdu);
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PointerXFlags: u16 {

View file

@ -1,10 +1,9 @@
use std::io;
use bitflags::bitflags;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::InputEventError;
use crate::PduParsing;
use crate::{
cursor::{ReadCursor, WriteCursor},
PduDecode, PduEncode, PduResult,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScanCodePdu {
@ -12,30 +11,46 @@ pub struct ScanCodePdu {
pub key_code: u16,
}
impl PduParsing for ScanCodePdu {
type Error = InputEventError;
impl ScanCodePdu {
const NAME: &'static str = "ScanCodePdu";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let flags = KeyboardFlags::from_bits_truncate(stream.read_u16::<LittleEndian>()?);
let key_code = stream.read_u16::<LittleEndian>()?;
let _padding = stream.read_u16::<LittleEndian>()?;
const FIXED_PART_SIZE: usize = 2 /* flags */ + 2 /* keycode */ + 2 /* padding */;
}
Ok(Self { flags, key_code })
}
impl PduEncode for ScanCodePdu {
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::<LittleEndian>(self.flags.bits())?;
stream.write_u16::<LittleEndian>(self.key_code)?;
stream.write_u16::<LittleEndian>(0)?; // padding
dst.write_u16(self.flags.bits());
dst.write_u16(self.key_code);
write_padding!(dst, 2);
Ok(())
}
fn buffer_length(&self) -> usize {
6
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
Self::FIXED_PART_SIZE
}
}
impl<'de> PduDecode<'de> for ScanCodePdu {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
let flags = KeyboardFlags::from_bits_truncate(src.read_u16());
let key_code = src.read_u16();
read_padding!(src, 2);
Ok(Self { flags, key_code })
}
}
impl_pdu_parsing!(ScanCodePdu);
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct KeyboardFlags: u16 {

View file

@ -1,38 +1,53 @@
use std::io;
use bitflags::bitflags;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::InputEventError;
use crate::PduParsing;
use crate::{
cursor::{ReadCursor, WriteCursor},
PduDecode, PduEncode, PduResult,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SyncPdu {
pub flags: SyncToggleFlags,
}
impl PduParsing for SyncPdu {
type Error = InputEventError;
impl SyncPdu {
const NAME: &'static str = "SyncPdu";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let _padding = stream.read_u16::<LittleEndian>()?;
let flags = SyncToggleFlags::from_bits_truncate(stream.read_u32::<LittleEndian>()?);
const FIXED_PART_SIZE: usize = 2 /* padding */ + 4 /* flags */;
}
Ok(Self { flags })
}
impl PduEncode for SyncPdu {
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::<LittleEndian>(0)?; // padding
stream.write_u32::<LittleEndian>(self.flags.bits())?;
write_padding!(dst, 2);
dst.write_u32(self.flags.bits());
Ok(())
}
fn buffer_length(&self) -> usize {
6
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
Self::FIXED_PART_SIZE
}
}
impl<'de> PduDecode<'de> for SyncPdu {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
read_padding!(src, 2);
let flags = SyncToggleFlags::from_bits_truncate(src.read_u32());
Ok(Self { flags })
}
}
impl_pdu_parsing!(SyncPdu);
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SyncToggleFlags: u32 {

View file

@ -1,10 +1,9 @@
use std::io;
use bitflags::bitflags;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::InputEventError;
use crate::PduParsing;
use crate::{
cursor::{ReadCursor, WriteCursor},
PduDecode, PduEncode, PduResult,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnicodePdu {
@ -12,30 +11,46 @@ pub struct UnicodePdu {
pub unicode_code: u16,
}
impl PduParsing for UnicodePdu {
type Error = InputEventError;
impl UnicodePdu {
const NAME: &'static str = "UnicodePdu";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let flags = KeyboardFlags::from_bits_truncate(stream.read_u16::<LittleEndian>()?);
let unicode_code = stream.read_u16::<LittleEndian>()?;
let _padding = stream.read_u16::<LittleEndian>()?;
const FIXED_PART_SIZE: usize = 2 /* flags */ + 2 /* code */ + 2 /* padding */;
}
Ok(Self { flags, unicode_code })
}
impl PduEncode for UnicodePdu {
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::<LittleEndian>(self.flags.bits())?;
stream.write_u16::<LittleEndian>(self.unicode_code)?;
stream.write_u16::<LittleEndian>(0)?; // padding
dst.write_u16(self.flags.bits());
dst.write_u16(self.unicode_code);
write_padding!(dst, 2);
Ok(())
}
fn buffer_length(&self) -> usize {
6
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
Self::FIXED_PART_SIZE
}
}
impl<'de> PduDecode<'de> for UnicodePdu {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
let flags = KeyboardFlags::from_bits_truncate(src.read_u16());
let unicode_code = src.read_u16();
read_padding!(src, 2);
Ok(Self { flags, unicode_code })
}
}
impl_pdu_parsing!(UnicodePdu);
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct KeyboardFlags: u16 {

View file

@ -1,31 +1,41 @@
use std::io;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::InputEventError;
use crate::PduParsing;
use crate::{
cursor::{ReadCursor, WriteCursor},
PduDecode, PduEncode, PduResult,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnusedPdu;
impl PduParsing for UnusedPdu {
type Error = InputEventError;
impl UnusedPdu {
const NAME: &'static str = "UnusedPdu";
fn from_buffer(mut stream: impl io::Read) -> Result<Self, Self::Error> {
let _padding = stream.read_u32::<LittleEndian>()?;
let _padding = stream.read_u16::<LittleEndian>()?;
const FIXED_PART_SIZE: usize = 6 /* padding */;
}
Ok(Self)
}
fn to_buffer(&self, mut stream: impl io::Write) -> Result<(), Self::Error> {
stream.write_u32::<LittleEndian>(0)?; // padding
stream.write_u16::<LittleEndian>(0)?; // padding
impl PduEncode for UnusedPdu {
fn encode(&self, dst: &mut WriteCursor<'_>) -> PduResult<()> {
ensure_fixed_part_size!(in: dst);
write_padding!(dst, 6);
Ok(())
}
fn buffer_length(&self) -> usize {
6
fn name(&self) -> &'static str {
Self::NAME
}
fn size(&self) -> usize {
Self::FIXED_PART_SIZE
}
}
impl<'de> PduDecode<'de> for UnusedPdu {
fn decode(src: &mut ReadCursor<'de>) -> PduResult<Self> {
ensure_fixed_part_size!(in: src);
read_padding!(src, 6);
Ok(Self)
}
}
impl_pdu_parsing!(UnusedPdu);

View file

@ -321,7 +321,7 @@ impl RdpServer {
match action {
Action::FastPath => {
let input = FastPathInput::from_buffer(Cursor::new(&bytes))?;
let input = decode(&bytes)?;
self.handle_fastpath(input).await;
}
@ -378,7 +378,7 @@ impl RdpServer {
for frame in frames {
match Action::from_fp_output_header(frame[0]) {
Ok(Action::FastPath) => {
let input = FastPathInput::from_buffer(Cursor::new(&frame))?;
let input = decode(&frame)?;
self.handle_fastpath(input).await;
}

View file

@ -6,13 +6,13 @@ use ironrdp_pdu::geometry::InclusiveRectangle;
use ironrdp_pdu::input::fast_path::{FastPathInput, FastPathInputEvent};
use ironrdp_pdu::rdp::headers::ShareDataPdu;
use ironrdp_pdu::write_buf::WriteBuf;
use ironrdp_pdu::{mcs, Action, PduParsing};
use ironrdp_pdu::{mcs, Action};
use ironrdp_svc::{SvcProcessor, SvcProcessorMessages};
use crate::fast_path::UpdateKind;
use crate::image::DecodedImage;
use crate::x224::GfxHandler;
use crate::{fast_path, x224, SessionError, SessionResult};
use crate::{fast_path, x224, SessionError, SessionErrorExt, SessionResult};
pub struct ActiveStage {
x224_processor: x224::Processor,
@ -67,10 +67,7 @@ impl ActiveStage {
// Encoding fastpath response frame
// PERF: unnecessary copy
let fastpath_input = FastPathInput(events.to_vec());
let mut frame = Vec::new();
fastpath_input
.to_buffer(&mut frame)
.map_err(|e| custom_err!("FastPathInput encode", e))?;
let frame = ironrdp_pdu::encode_vec(&fastpath_input).map_err(SessionError::pdu)?;
output.push(ActiveStageOutput::ResponseFrame(frame));
// If pointer rendering is disabled - we can skip the rest

View file

@ -1,7 +1,8 @@
use ironrdp_pdu::cursor::ReadCursor;
use ironrdp_pdu::input::fast_path::{FastPathInput, FastPathInputEvent};
use ironrdp_pdu::input::mouse::PointerFlags;
use ironrdp_pdu::input::MousePdu;
use ironrdp_pdu::PduParsing;
use ironrdp_pdu::{decode_cursor, encode_vec};
const FASTPATH_INPUT_MESSAGE: [u8; 44] = [
0x18, 0x2c, 0x20, 0x0, 0x90, 0x1a, 0x0, 0x26, 0x4, 0x20, 0x0, 0x8, 0x1b, 0x0, 0x26, 0x4, 0x20, 0x0, 0x10, 0x1b,
@ -52,16 +53,16 @@ lazy_static::lazy_static! {
#[test]
fn from_buffer_correctly_parses_fastpath_input_message() {
let mut buffer = FASTPATH_INPUT_MESSAGE.as_ref();
let buffer = FASTPATH_INPUT_MESSAGE.as_ref();
assert_eq!(*FASTPATH_INPUT, FastPathInput::from_buffer(&mut buffer).unwrap());
assert!(buffer.is_empty());
let mut cursor = ReadCursor::new(buffer);
assert_eq!(*FASTPATH_INPUT, decode_cursor(&mut cursor).unwrap());
assert!(cursor.is_empty());
}
#[test]
fn to_buffer_correctly_serializes_fastpath_input_message() {
let mut buffer = Vec::with_capacity(1024);
FASTPATH_INPUT.to_buffer(&mut buffer).unwrap();
let buffer = encode_vec(&*FASTPATH_INPUT).unwrap();
assert_eq!(buffer, FASTPATH_INPUT_MESSAGE.as_ref());
}

View file

@ -652,13 +652,11 @@ impl Session {
kana_lock: bool,
) -> Result<(), IronRdpError> {
use ironrdp::pdu::input::fast_path::FastPathInput;
use ironrdp::pdu::PduParsing as _;
let event = ironrdp::input::synchronize_event(scroll_lock, num_lock, caps_lock, kana_lock);
let fastpath_input = FastPathInput(vec![event]);
let mut frame = Vec::new();
fastpath_input.to_buffer(&mut frame).context("FastPathInput encoding")?;
let frame = ironrdp::pdu::encode_vec(&fastpath_input).context("FastPathInput encoding")?;
self.writer_tx
.unbounded_send(frame)