use crate::error::{Result, VncError};
use std::io::Read;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ClientMessage {
SetPixelFormat {
format: [u8; 16],
},
SetEncodings {
encodings: Vec<i32>,
},
FramebufferUpdateRequest {
incremental: bool,
x: u16,
y: u16,
width: u16,
height: u16,
},
KeyEvent {
down: bool,
key: u32,
},
PointerEvent {
buttons: u8,
x: u16,
y: u16,
},
ClientCutText {
text: String,
},
EnableContinuousUpdates {
enable: bool,
x: u16,
y: u16,
width: u16,
height: u16,
},
ClientFence {
flags: u32,
payload: Vec<u8>,
},
}
pub const ENCODING_RAW: i32 = 0;
pub const ENCODING_COPYRECT: i32 = 1;
pub const ENCODING_HEXTILE: i32 = 5;
pub const ENCODING_ZLIB: i32 = 6;
pub const ENCODING_TIGHT: i32 = 7;
pub const ENCODING_ZRLE: i32 = 16;
pub const PSEUDO_TIGHT_QUALITY_BASE: i32 = -32; pub const PSEUDO_TIGHT_COMPRESSION_BASE: i32 = -260; pub const PSEUDO_FENCE: i32 = -312;
pub const PSEUDO_CONTINUOUS_UPDATES: i32 = -313;
const MAX_CUT_TEXT_LEN: usize = 1024 * 1024; const MAX_ENCODINGS_COUNT: usize = 256;
impl ClientMessage {
pub fn read_from<R: Read>(reader: &mut R) -> Result<Self> {
let mut msg_type = [0u8; 1];
reader.read_exact(&mut msg_type)?;
match msg_type[0] {
0 => {
let mut buf = [0u8; 19]; reader.read_exact(&mut buf)?;
let mut format = [0u8; 16];
format.copy_from_slice(&buf[3..19]);
Ok(ClientMessage::SetPixelFormat { format })
}
2 => {
let mut buf = [0u8; 3];
reader.read_exact(&mut buf)?;
let num = u16::from_be_bytes([buf[1], buf[2]]) as usize;
if num > MAX_ENCODINGS_COUNT {
return Err(VncError::MessageTooLarge(num, MAX_ENCODINGS_COUNT));
}
let mut encodings = Vec::with_capacity(num);
for _ in 0..num {
let mut enc = [0u8; 4];
reader.read_exact(&mut enc)?;
encodings.push(i32::from_be_bytes(enc));
}
Ok(ClientMessage::SetEncodings { encodings })
}
3 => {
let mut buf = [0u8; 9];
reader.read_exact(&mut buf)?;
Ok(ClientMessage::FramebufferUpdateRequest {
incremental: buf[0] != 0,
x: u16::from_be_bytes([buf[1], buf[2]]),
y: u16::from_be_bytes([buf[3], buf[4]]),
width: u16::from_be_bytes([buf[5], buf[6]]),
height: u16::from_be_bytes([buf[7], buf[8]]),
})
}
4 => {
let mut buf = [0u8; 7];
reader.read_exact(&mut buf)?;
Ok(ClientMessage::KeyEvent {
down: buf[0] != 0,
key: u32::from_be_bytes([buf[3], buf[4], buf[5], buf[6]]),
})
}
5 => {
let mut buf = [0u8; 5];
reader.read_exact(&mut buf)?;
Ok(ClientMessage::PointerEvent {
buttons: buf[0],
x: u16::from_be_bytes([buf[1], buf[2]]),
y: u16::from_be_bytes([buf[3], buf[4]]),
})
}
6 => {
let mut buf = [0u8; 7];
reader.read_exact(&mut buf)?;
let len = u32::from_be_bytes([buf[3], buf[4], buf[5], buf[6]]) as usize;
if len > MAX_CUT_TEXT_LEN {
return Err(VncError::MessageTooLarge(len, MAX_CUT_TEXT_LEN));
}
let mut text_buf = vec![0u8; len];
reader.read_exact(&mut text_buf)?;
let text = String::from_utf8_lossy(&text_buf).to_string();
Ok(ClientMessage::ClientCutText { text })
}
150 => {
let mut buf = [0u8; 9];
reader.read_exact(&mut buf)?;
Ok(ClientMessage::EnableContinuousUpdates {
enable: buf[0] != 0,
x: u16::from_be_bytes([buf[1], buf[2]]),
y: u16::from_be_bytes([buf[3], buf[4]]),
width: u16::from_be_bytes([buf[5], buf[6]]),
height: u16::from_be_bytes([buf[7], buf[8]]),
})
}
248 => {
let mut buf = [0u8; 8];
reader.read_exact(&mut buf)?;
let flags = u32::from_be_bytes([buf[3], buf[4], buf[5], buf[6]]);
let len = buf[7] as usize;
let mut payload = vec![0u8; len];
if len > 0 {
reader.read_exact(&mut payload)?;
}
Ok(ClientMessage::ClientFence { flags, payload })
}
other => Err(VncError::Protocol(format!(
"Unknown message type: {}",
other
))),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_parse_key_event() {
let data: Vec<u8> = vec![
4, 1, 0, 0, 0x00, 0x00, 0xFF, 0x0D, ];
let mut cursor = Cursor::new(&data[1..]);
let mut buf = [0u8; 7];
cursor.read_exact(&mut buf).unwrap();
let down = buf[0] != 0;
let key = u32::from_be_bytes([buf[3], buf[4], buf[5], buf[6]]);
assert!(down);
assert_eq!(key, 0xFF0D);
}
#[test]
fn test_parse_pointer_event() {
let data: Vec<u8> = vec![
5, 1, 0, 100, 0, 200, ];
let mut cursor = Cursor::new(data);
let msg = ClientMessage::read_from(&mut cursor).unwrap();
match msg {
ClientMessage::PointerEvent { buttons, x, y } => {
assert_eq!(buttons, 1);
assert_eq!(x, 100);
assert_eq!(y, 200);
}
_ => panic!("Expected PointerEvent"),
}
}
#[test]
fn test_parse_framebuffer_update_request() {
let data: Vec<u8> = vec![
3, 1, 0, 0, 0, 0, 0x07, 0x80, 0x04, 0x38, ];
let mut cursor = Cursor::new(data);
let msg = ClientMessage::read_from(&mut cursor).unwrap();
match msg {
ClientMessage::FramebufferUpdateRequest {
incremental,
x,
y,
width,
height,
} => {
assert!(incremental);
assert_eq!(x, 0);
assert_eq!(y, 0);
assert_eq!(width, 1920);
assert_eq!(height, 1080);
}
_ => panic!("Expected FramebufferUpdateRequest"),
}
}
#[test]
fn test_parse_set_encodings() {
let data: Vec<u8> = vec![
2, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, ];
let mut cursor = Cursor::new(data);
let msg = ClientMessage::read_from(&mut cursor).unwrap();
match msg {
ClientMessage::SetEncodings { encodings } => {
assert_eq!(encodings, vec![5, 6, 0]);
}
_ => panic!("Expected SetEncodings"),
}
}
#[test]
fn test_parse_client_cut_text() {
let text = b"Hello VNC!";
let mut data: Vec<u8> = vec![
6, 0, 0, 0, ];
data.extend_from_slice(&(text.len() as u32).to_be_bytes());
data.extend_from_slice(text);
let mut cursor = Cursor::new(data);
let msg = ClientMessage::read_from(&mut cursor).unwrap();
match msg {
ClientMessage::ClientCutText { text: t } => {
assert_eq!(t, "Hello VNC!");
}
_ => panic!("Expected ClientCutText"),
}
}
#[test]
fn test_parse_client_cut_text_too_large() {
let mut data: Vec<u8> = vec![
6, 0, 0, 0, ];
data.extend_from_slice(&(2 * 1024 * 1024u32).to_be_bytes());
let mut cursor = Cursor::new(data);
let res = ClientMessage::read_from(&mut cursor);
assert!(matches!(res, Err(VncError::MessageTooLarge(_, _))));
}
#[test]
fn test_parse_enable_continuous_updates() {
let mut data: Vec<u8> = vec![150, 1]; data.extend_from_slice(&10u16.to_be_bytes()); data.extend_from_slice(&20u16.to_be_bytes()); data.extend_from_slice(&1920u16.to_be_bytes()); data.extend_from_slice(&1080u16.to_be_bytes());
let mut cursor = Cursor::new(data);
let msg = ClientMessage::read_from(&mut cursor).unwrap();
match msg {
ClientMessage::EnableContinuousUpdates {
enable,
x,
y,
width,
height,
} => {
assert!(enable);
assert_eq!(x, 10);
assert_eq!(y, 20);
assert_eq!(width, 1920);
assert_eq!(height, 1080);
}
_ => panic!("Expected EnableContinuousUpdates"),
}
}
#[test]
fn test_parse_client_fence() {
let mut data: Vec<u8> = vec![248, 0, 0, 0]; data.extend_from_slice(&0x12345678u32.to_be_bytes()); data.push(4); data.extend_from_slice(b"SYNC");
let mut cursor = Cursor::new(data);
let msg = ClientMessage::read_from(&mut cursor).unwrap();
match msg {
ClientMessage::ClientFence { flags, payload } => {
assert_eq!(flags, 0x12345678);
assert_eq!(payload, b"SYNC");
}
_ => panic!("Expected ClientFence"),
}
}
}