vnc raw encoding
This commit is contained in:
parent
6ee1cd8d32
commit
918878b0c5
@ -15,8 +15,8 @@ struct TcpCodec;
|
|||||||
impl Encoder<Bytes> for TcpCodec {
|
impl Encoder<Bytes> for TcpCodec {
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
|
||||||
fn encode(&mut self, item: Bytes, _dst: &mut BytesMut) -> Result<(), Self::Error> {
|
fn encode(&mut self, _item: Bytes, _dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||||
info!("encoding: {:?}", item);
|
// info!("encoding: {:?}", item);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,7 +26,7 @@ impl Decoder for TcpCodec {
|
|||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
|
|
||||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||||
info!("recv from server: {:?}", src);
|
// info!("recv from server: {:?}", src);
|
||||||
if 0 == src.len() {
|
if 0 == src.len() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@ impl StreamHandler<Result<Bytes, io::Error>> for Agent {
|
|||||||
fn handle(&mut self, msg: Result<Bytes, io::Error>, ctx: &mut Context<Self>) {
|
fn handle(&mut self, msg: Result<Bytes, io::Error>, ctx: &mut Context<Self>) {
|
||||||
match msg {
|
match msg {
|
||||||
Ok(data) => {
|
Ok(data) => {
|
||||||
info!("recv from server: {:?}", data);
|
// info!("recv from server: {:?}", data);
|
||||||
if self.ws_addr.is_some() {
|
if self.ws_addr.is_some() {
|
||||||
ctx.address().do_send(AgentMsg::SendToClient(data));
|
ctx.address().do_send(AgentMsg::SendToClient(data));
|
||||||
} else {
|
} else {
|
||||||
|
@ -51,7 +51,7 @@ impl Handler<AuthMsg> for Authenticator {
|
|||||||
|
|
||||||
fn handle(&mut self, msg: AuthMsg, _ctx: &mut Context<Self>) -> Self::Result {
|
fn handle(&mut self, msg: AuthMsg, _ctx: &mut Context<Self>) -> Self::Result {
|
||||||
match msg {
|
match msg {
|
||||||
AuthMsg::DoAuth(auth_info) => {
|
AuthMsg::DoAuth(_auth_info) => {
|
||||||
// if auth_info.username == "admin" && auth_info.password == "admin" {
|
// if auth_info.username == "admin" && auth_info.password == "admin" {
|
||||||
// AuthResult::AuthSuccess
|
// AuthResult::AuthSuccess
|
||||||
// } else {
|
// } else {
|
||||||
|
@ -20,7 +20,8 @@ crate-type = ["cdylib", "rlib"]
|
|||||||
wasm-bindgen = "^0.2"
|
wasm-bindgen = "^0.2"
|
||||||
yew = "0.18"
|
yew = "0.18"
|
||||||
js-sys = "0.3.55"
|
js-sys = "0.3.55"
|
||||||
web-sys = "0.3.55"
|
web-sys = {version="0.3.55", features=["HtmlCanvasElement", "CanvasRenderingContext2d", "ImageData"]}
|
||||||
|
gloo = "0.4.0"
|
||||||
yew-router = "0.15"
|
yew-router = "0.15"
|
||||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
# The `console_error_panic_hook` crate provides better debugging of panics by
|
||||||
# logging them with `console.error`. This is great for development, but requires
|
# logging them with `console.error`. This is great for development, but requires
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
use wasm_bindgen::{Clamped, JsValue};
|
||||||
|
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, ImageData};
|
||||||
use yew::{
|
use yew::{
|
||||||
format::Json,
|
format::Json,
|
||||||
html,
|
html,
|
||||||
@ -9,6 +11,8 @@ use yew::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use gloo::timers::callback::Interval;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
components::{self, input::Input, ws::WebsocketMsg},
|
components::{self, input::Input, ws::WebsocketMsg},
|
||||||
protocal::{common::*, vnc::VncHandler},
|
protocal::{common::*, vnc::VncHandler},
|
||||||
@ -27,6 +31,9 @@ pub struct PageRemote {
|
|||||||
request_password: bool,
|
request_password: bool,
|
||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: String,
|
||||||
|
canvas: NodeRef,
|
||||||
|
canvas_ctx: Option<CanvasRenderingContext2d>,
|
||||||
|
interval: Option<Interval>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Properties)]
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
@ -41,6 +48,7 @@ pub enum RemoteMsg {
|
|||||||
UpdateUsername(String),
|
UpdateUsername(String),
|
||||||
UpdatePassword(String),
|
UpdatePassword(String),
|
||||||
SendCredential,
|
SendCredential,
|
||||||
|
RequireFrame(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for PageRemote {
|
impl Component for PageRemote {
|
||||||
@ -60,6 +68,9 @@ impl Component for PageRemote {
|
|||||||
request_password: false,
|
request_password: false,
|
||||||
username: String::from(""),
|
username: String::from(""),
|
||||||
password: String::from(""),
|
password: String::from(""),
|
||||||
|
canvas: NodeRef::default(),
|
||||||
|
canvas_ctx: None,
|
||||||
|
interval: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,6 +151,16 @@ impl Component for PageRemote {
|
|||||||
let _ = self.protocal_out_handler(out);
|
let _ = self.protocal_out_handler(out);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
RemoteMsg::RequireFrame(incremental) => {
|
||||||
|
let out = self.handler.require_frame(incremental);
|
||||||
|
if self.interval.is_none() {
|
||||||
|
let link = self.link.clone();
|
||||||
|
let tick =
|
||||||
|
Interval::new(250, move || link.send_message(RemoteMsg::RequireFrame(1)));
|
||||||
|
self.interval = Some(tick);
|
||||||
|
}
|
||||||
|
self.protocal_out_handler(out)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +188,7 @@ impl Component for PageRemote {
|
|||||||
{self.button_connect_view()}
|
{self.button_connect_view()}
|
||||||
<components::ws::WebsocketCtx
|
<components::ws::WebsocketCtx
|
||||||
weak_link=ws_link onrecv=recv_msg/>
|
weak_link=ws_link onrecv=recv_msg/>
|
||||||
|
<canvas id="remote-canvas" ref=self.canvas.clone() ></canvas>
|
||||||
{self.error_msg.clone()}
|
{self.error_msg.clone()}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -197,7 +219,42 @@ impl PageRemote {
|
|||||||
self.request_password = true;
|
self.request_password = true;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
ProtocalHandlerOutput::RenderCanvas(crs) => {
|
||||||
|
let canvas = self.canvas.cast::<HtmlCanvasElement>().unwrap();
|
||||||
|
let ctx = match &self.canvas_ctx {
|
||||||
|
Some(ctx) => ctx,
|
||||||
|
None => {
|
||||||
|
let ctx = CanvasRenderingContext2d::from(JsValue::from(
|
||||||
|
canvas.get_context("2d").unwrap().unwrap(),
|
||||||
|
));
|
||||||
|
self.canvas_ctx = Some(ctx);
|
||||||
|
self.canvas_ctx.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for cr in crs {
|
||||||
|
let data = ImageData::new_with_u8_clamped_array_and_sh(
|
||||||
|
Clamped(&cr.data),
|
||||||
|
cr.width as u32,
|
||||||
|
cr.height as u32,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
ConsoleService::log(&format!(
|
||||||
|
"renderring at ({}, {}), width {}, height {}",
|
||||||
|
cr.x, cr.y, cr.width, cr.height
|
||||||
|
));
|
||||||
|
let _ = ctx.put_image_data(&data, cr.x as f64, cr.y as f64);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
ProtocalHandlerOutput::SetCanvas(width, height) => {
|
||||||
|
let canvas = self.canvas.cast::<HtmlCanvasElement>().unwrap();
|
||||||
|
canvas.set_width(width as u32);
|
||||||
|
canvas.set_height(height as u32);
|
||||||
|
self.link.send_message(RemoteMsg::RequireFrame(0));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,21 @@
|
|||||||
use std::slice::Iter;
|
use std::slice::Iter;
|
||||||
|
|
||||||
|
pub struct CanvasData {
|
||||||
|
pub x: u16,
|
||||||
|
pub y: u16,
|
||||||
|
pub width: u16,
|
||||||
|
pub height: u16,
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum ProtocalHandlerOutput {
|
pub enum ProtocalHandlerOutput {
|
||||||
Ok,
|
Ok,
|
||||||
WsBuf(Vec<u8>),
|
WsBuf(Vec<u8>),
|
||||||
Err(String),
|
Err(String),
|
||||||
RequireUsername,
|
RequireUsername,
|
||||||
RequirePassword,
|
RequirePassword,
|
||||||
|
SetCanvas(u16, u16),
|
||||||
|
RenderCanvas(Vec<CanvasData>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ProtocalHandler<T>
|
pub struct ProtocalHandler<T>
|
||||||
@ -29,12 +40,17 @@ where
|
|||||||
pub fn set_credential(&mut self, username: &str, password: &str) -> ProtocalHandlerOutput {
|
pub fn set_credential(&mut self, username: &str, password: &str) -> ProtocalHandlerOutput {
|
||||||
self.inner.set_credential(username, password)
|
self.inner.set_credential(username, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn require_frame(&mut self, incremental: u8) -> ProtocalHandlerOutput {
|
||||||
|
self.inner.require_frame(incremental)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ProtocalImpl {
|
pub trait ProtocalImpl {
|
||||||
fn new() -> Self;
|
fn new() -> Self;
|
||||||
fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput;
|
fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput;
|
||||||
fn set_credential(&mut self, username: &str, password: &str) -> ProtocalHandlerOutput;
|
fn set_credential(&mut self, username: &str, password: &str) -> ProtocalHandlerOutput;
|
||||||
|
fn require_frame(&mut self, incremental: u8) -> ProtocalHandlerOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct StreamReader<'a> {
|
pub struct StreamReader<'a> {
|
||||||
@ -112,3 +128,55 @@ impl<'a> StreamReader<'a> {
|
|||||||
self.inner.next().is_none()
|
self.inner.next().is_none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct StreamWriter<'a> {
|
||||||
|
inner: &'a mut Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> StreamWriter<'a> {
|
||||||
|
pub fn new(buf: &'a mut Vec<u8>) -> Self {
|
||||||
|
Self { inner: buf }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_u8(&mut self, b: u8) {
|
||||||
|
self.inner.push(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_u16(&mut self, b: u16) {
|
||||||
|
self.inner.extend_from_slice(&b.to_be_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_u32(&mut self, b: u32) {
|
||||||
|
self.inner.extend_from_slice(&b.to_be_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_s8(&mut self, b: i8) {
|
||||||
|
self.write_u8(b as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_s16(&mut self, b: i16) {
|
||||||
|
self.write_u16(b as u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_s32(&mut self, b: i32) {
|
||||||
|
self.write_u32(b as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_string_with_len(&mut self, s: &str) {
|
||||||
|
self.inner.extend_from_slice(s.as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_string_l16(&mut self, s: &str) {
|
||||||
|
self.write_u16(s.len() as u16);
|
||||||
|
self.write_string_with_len(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_string_l32(&mut self, s: &str) {
|
||||||
|
self.write_u32(s.len() as u32);
|
||||||
|
self.write_string_with_len(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_slice(&mut self, s: &[u8]) {
|
||||||
|
self.inner.extend_from_slice(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,20 +8,6 @@ const VNC_RFB38: &[u8; 12] = b"RFB 003.008\n";
|
|||||||
const VNC_VER_UNSUPPORTED: &str = "unsupported version";
|
const VNC_VER_UNSUPPORTED: &str = "unsupported version";
|
||||||
const VNC_FAILED: &str = "Connection failed with unknow reason";
|
const VNC_FAILED: &str = "Connection failed with unknow reason";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum VncState {
|
|
||||||
Handshake,
|
|
||||||
Authentication,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum VncVersion {
|
|
||||||
NONE,
|
|
||||||
VNC33,
|
|
||||||
VNC37,
|
|
||||||
VNC38,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum SecurityType {
|
pub enum SecurityType {
|
||||||
@ -37,7 +23,7 @@ pub enum SecurityType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct VncHandler {
|
pub struct VncHandler {
|
||||||
inner: Box<dyn VncStateMachine>,
|
inner: Box<dyn VncState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProtocalImpl for VncHandler {
|
impl ProtocalImpl for VncHandler {
|
||||||
@ -75,12 +61,19 @@ impl ProtocalImpl for VncHandler {
|
|||||||
}
|
}
|
||||||
self.inner.handle(&pass_bytes)
|
self.inner.handle(&pass_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn require_frame(&mut self, incremental: u8) -> ProtocalHandlerOutput {
|
||||||
|
self.inner.frame_require(incremental)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait VncStateMachine {
|
trait VncState {
|
||||||
fn handle(&mut self, _input: &[u8]) -> ProtocalHandlerOutput;
|
fn handle(&mut self, _input: &[u8]) -> ProtocalHandlerOutput;
|
||||||
|
fn frame_require(&self, _incremental: u8) -> ProtocalHandlerOutput {
|
||||||
|
ProtocalHandlerOutput::Err(VNC_FAILED.to_string())
|
||||||
|
}
|
||||||
fn done(&self) -> bool;
|
fn done(&self) -> bool;
|
||||||
fn next(&self) -> Box<dyn VncStateMachine>;
|
fn next(&self) -> Box<dyn VncState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VncHandShake {
|
struct VncHandShake {
|
||||||
@ -93,7 +86,7 @@ impl Default for VncHandShake {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VncStateMachine for VncHandShake {
|
impl VncState for VncHandShake {
|
||||||
fn handle(&mut self, rfbversion: &[u8]) -> ProtocalHandlerOutput {
|
fn handle(&mut self, rfbversion: &[u8]) -> ProtocalHandlerOutput {
|
||||||
let support_version = match rfbversion {
|
let support_version = match rfbversion {
|
||||||
b"RFB 003.003\n" => Ok(VNC_RFB33),
|
b"RFB 003.003\n" => Ok(VNC_RFB33),
|
||||||
@ -113,7 +106,7 @@ impl VncStateMachine for VncHandShake {
|
|||||||
self.done
|
self.done
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self) -> Box<dyn VncStateMachine> {
|
fn next(&self) -> Box<dyn VncState> {
|
||||||
Box::new(VncAuthentiacator::default())
|
Box::new(VncAuthentiacator::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,7 +129,7 @@ impl Default for VncAuthentiacator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VncStateMachine for VncAuthentiacator {
|
impl VncState for VncAuthentiacator {
|
||||||
fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput {
|
fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput {
|
||||||
if self.security_type == SecurityType::VncAuth {
|
if self.security_type == SecurityType::VncAuth {
|
||||||
if self.wait_password {
|
if self.wait_password {
|
||||||
@ -153,7 +146,7 @@ impl VncStateMachine for VncAuthentiacator {
|
|||||||
self.done
|
self.done
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self) -> Box<dyn VncStateMachine> {
|
fn next(&self) -> Box<dyn VncState> {
|
||||||
Box::new(VncDrawing::default())
|
Box::new(VncDrawing::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,6 +206,9 @@ struct VncDrawing {
|
|||||||
pf: PixelFormat,
|
pf: PixelFormat,
|
||||||
name: String,
|
name: String,
|
||||||
server_init: bool,
|
server_init: bool,
|
||||||
|
buffer: Vec<u8>,
|
||||||
|
rects: Vec<VncRect>,
|
||||||
|
num_rects_left: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VncDrawing {
|
impl Default for VncDrawing {
|
||||||
@ -223,25 +219,50 @@ impl Default for VncDrawing {
|
|||||||
pf: PixelFormat::default(),
|
pf: PixelFormat::default(),
|
||||||
name: "".to_string(),
|
name: "".to_string(),
|
||||||
server_init: false,
|
server_init: false,
|
||||||
|
buffer: Vec::with_capacity(50),
|
||||||
|
rects: Vec::new(),
|
||||||
|
num_rects_left: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VncStateMachine for VncDrawing {
|
impl VncState for VncDrawing {
|
||||||
fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput {
|
fn handle(&mut self, input: &[u8]) -> ProtocalHandlerOutput {
|
||||||
if self.server_init {
|
if self.server_init {
|
||||||
// ProtocalHandlerOutput::WsBuf(self.get_framebuffer_update_request())
|
let mut sr = StreamReader::new(input);
|
||||||
self.handle_server_init(input)
|
if self.num_rects_left > 0 {
|
||||||
|
// still in the previous update frame request
|
||||||
|
self.extract_rects(&mut sr);
|
||||||
|
self.render_rects()
|
||||||
|
} else {
|
||||||
|
let msg_type = sr.read_u8().unwrap();
|
||||||
|
|
||||||
|
match msg_type {
|
||||||
|
0 => self.handle_framebuffer_update(&mut sr),
|
||||||
|
1 => self.handle_set_colour_map(&mut sr),
|
||||||
|
2 => self.handle_bell(&mut sr),
|
||||||
|
3 => self.handle_server_cut_text(&mut sr),
|
||||||
|
_ => ProtocalHandlerOutput::Err(VNC_FAILED.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.handle_server_init(input)
|
self.handle_server_init(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn frame_require(&self, incremental: u8) -> ProtocalHandlerOutput {
|
||||||
|
if self.num_rects_left > 0 {
|
||||||
|
ProtocalHandlerOutput::Ok
|
||||||
|
} else {
|
||||||
|
self.framebuffer_update_request(incremental)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn done(&self) -> bool {
|
fn done(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self) -> Box<dyn VncStateMachine> {
|
fn next(&self) -> Box<dyn VncState> {
|
||||||
Box::new(VncEnds)
|
Box::new(VncEnds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -256,6 +277,8 @@ impl VncDrawing {
|
|||||||
// 4 CARD32 name-length
|
// 4 CARD32 name-length
|
||||||
// name-length CARD8 array name-string
|
// name-length CARD8 array name-string
|
||||||
fn handle_server_init(&mut self, init: &[u8]) -> ProtocalHandlerOutput {
|
fn handle_server_init(&mut self, init: &[u8]) -> ProtocalHandlerOutput {
|
||||||
|
self.buffer.extend_from_slice(init);
|
||||||
|
if self.buffer.len() > 24 {
|
||||||
let mut sr = StreamReader::new(init);
|
let mut sr = StreamReader::new(init);
|
||||||
self.width = sr.read_u16().unwrap();
|
self.width = sr.read_u16().unwrap();
|
||||||
self.height = sr.read_u16().unwrap();
|
self.height = sr.read_u16().unwrap();
|
||||||
@ -265,13 +288,185 @@ impl VncDrawing {
|
|||||||
self.pf = (&pfb).into();
|
self.pf = (&pfb).into();
|
||||||
self.name = sr.read_string_l32().unwrap();
|
self.name = sr.read_string_l32().unwrap();
|
||||||
ConsoleService::log(&format!("VNC: {}x{}", self.width, self.height));
|
ConsoleService::log(&format!("VNC: {}x{}", self.width, self.height));
|
||||||
|
self.server_init = true;
|
||||||
|
ProtocalHandlerOutput::SetCanvas(self.width, self.height)
|
||||||
|
} else {
|
||||||
ProtocalHandlerOutput::Ok
|
ProtocalHandlerOutput::Ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No. of bytes Type [Value] Description
|
||||||
|
// 1 CARD8 3 message-type
|
||||||
|
// 1 CARD8 incremental
|
||||||
|
// 2 CARD16 x-position
|
||||||
|
// 2 CARD16 y-position
|
||||||
|
// 2 CARD16 width
|
||||||
|
// 2 CARD16 height
|
||||||
|
fn framebuffer_update_request(&self, incremental: u8) -> ProtocalHandlerOutput {
|
||||||
|
// ConsoleService::log(&format!("VNC: framebuffer_update_request {}", incremental));
|
||||||
|
let mut out: Vec<u8> = Vec::new();
|
||||||
|
let mut sw = StreamWriter::new(&mut out);
|
||||||
|
sw.write_u8(3);
|
||||||
|
sw.write_u8(incremental);
|
||||||
|
sw.write_u16(0);
|
||||||
|
sw.write_u16(0);
|
||||||
|
sw.write_u16(self.width);
|
||||||
|
sw.write_u16(self.height);
|
||||||
|
ProtocalHandlerOutput::WsBuf(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// No. of bytes Type [Value] Description
|
||||||
|
// 1 CARD8 0 message-type
|
||||||
|
// 1 padding
|
||||||
|
// 2 CARD16 number-of-rectangles
|
||||||
|
// This is followed by number-of-rectanglesrectangles of pixel data.
|
||||||
|
fn handle_framebuffer_update(&mut self, sr: &mut StreamReader) -> ProtocalHandlerOutput {
|
||||||
|
let _padding = sr.read_u8().unwrap();
|
||||||
|
self.num_rects_left = sr.read_u16().unwrap();
|
||||||
|
self.rects = Vec::with_capacity(self.num_rects_left as usize);
|
||||||
|
self.extract_rects(sr);
|
||||||
|
self.render_rects()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_set_colour_map(&mut self, _sr: &mut StreamReader) -> ProtocalHandlerOutput {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_bell(&mut self, _sr: &mut StreamReader) -> ProtocalHandlerOutput {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_server_cut_text(&mut self, _sr: &mut StreamReader) -> ProtocalHandlerOutput {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_rects(&mut self, sr: &mut StreamReader) {
|
||||||
|
while self.num_rects_left > 0 {
|
||||||
|
// we always keep the last rect in the vec
|
||||||
|
// and all the rects that has already been re-assembly should already been rendered
|
||||||
|
if self.rects.len() > 0 && self.rects.last().unwrap().left_data > 0 {
|
||||||
|
// which means that there is one rects that has not been re-assembly
|
||||||
|
let last_rect = self.rects.last_mut().unwrap();
|
||||||
|
while let Some(v) = sr.read_u8() {
|
||||||
|
last_rect.encoding_data.push(v);
|
||||||
|
last_rect.left_data -= 1;
|
||||||
|
if last_rect.left_data == 0 {
|
||||||
|
// at the end of the rect
|
||||||
|
self.num_rects_left -= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConsoleService::log(&format!(
|
||||||
|
"VNC read: {}, pending {}",
|
||||||
|
last_rect.encoding_data.len(),
|
||||||
|
last_rect.left_data
|
||||||
|
));
|
||||||
|
if last_rect.left_data == 0 {
|
||||||
|
// there is still some data left
|
||||||
|
// start a new rect
|
||||||
|
// it must be handled in the else branch
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// break the while loop
|
||||||
|
// render as much as we can
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// a brand new rects
|
||||||
|
let x = sr.read_u16().unwrap();
|
||||||
|
let y = sr.read_u16().unwrap();
|
||||||
|
let width = sr.read_u16().unwrap();
|
||||||
|
let height = sr.read_u16().unwrap();
|
||||||
|
let encoding_type = sr.read_u32().unwrap();
|
||||||
|
match encoding_type {
|
||||||
|
0 => {
|
||||||
|
let mut left_data = width as u32 * height as u32 * 4;
|
||||||
|
let mut encoding_data: Vec<u8> = Vec::with_capacity(left_data as usize);
|
||||||
|
while let Some(v) = sr.read_u8() {
|
||||||
|
// read as much as we can
|
||||||
|
encoding_data.push(v);
|
||||||
|
if encoding_data.len() == left_data as usize {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
left_data -= encoding_data.len() as u32;
|
||||||
|
if left_data == 0 {
|
||||||
|
self.num_rects_left -= 1;
|
||||||
|
}
|
||||||
|
// ConsoleService::log(&format!("VNC read new: {}", encoding_data.len()));
|
||||||
|
self.rects.push(VncRect {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
encoding_data,
|
||||||
|
encoding_type,
|
||||||
|
left_data,
|
||||||
|
});
|
||||||
|
// break the while loop
|
||||||
|
// render as much as we can
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
ConsoleService::log(&format!(
|
||||||
|
"VNC: unknown encoding type {}",
|
||||||
|
encoding_type
|
||||||
|
));
|
||||||
|
ConsoleService::log(&format!(
|
||||||
|
"VNC: x:{}, y:{}, w:{}, h:{}",
|
||||||
|
x, y, width, height
|
||||||
|
));
|
||||||
|
ConsoleService::log(&format!("VNC: left_data:{:x?}", sr.read_u32()));
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_rects(&mut self) -> ProtocalHandlerOutput {
|
||||||
|
let mut out: Vec<CanvasData> = Vec::new();
|
||||||
|
if self.rects.len() > 1 || self.num_rects_left == 0 {
|
||||||
|
let drain_len = {
|
||||||
|
if self.num_rects_left != 0 {
|
||||||
|
self.rects.len() - 1
|
||||||
|
} else {
|
||||||
|
self.rects.len()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ConsoleService::log(&format!("VNC render {} rects", drain_len));
|
||||||
|
for x in self.rects.drain(0..drain_len) {
|
||||||
|
let mut data: Vec<u8> = Vec::with_capacity(x.encoding_data.len());
|
||||||
|
for i in 0..x.width {
|
||||||
|
for j in 0..x.height {
|
||||||
|
let idx = (i as usize + j as usize * x.width as usize) * 4;
|
||||||
|
|
||||||
|
let b = x.encoding_data[idx + 0];
|
||||||
|
let g = x.encoding_data[idx + 1];
|
||||||
|
let r = x.encoding_data[idx + 2];
|
||||||
|
let a = x.encoding_data[idx + 3];
|
||||||
|
|
||||||
|
data.extend_from_slice(&[r, g, b, a]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.push(CanvasData {
|
||||||
|
x: x.x,
|
||||||
|
y: x.y,
|
||||||
|
width: x.width,
|
||||||
|
height: x.height,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocalHandlerOutput::RenderCanvas(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct VncEnds;
|
struct VncEnds;
|
||||||
|
|
||||||
impl VncStateMachine for VncEnds {
|
impl VncState for VncEnds {
|
||||||
fn handle(&mut self, _input: &[u8]) -> ProtocalHandlerOutput {
|
fn handle(&mut self, _input: &[u8]) -> ProtocalHandlerOutput {
|
||||||
ProtocalHandlerOutput::Err(VNC_FAILED.to_string())
|
ProtocalHandlerOutput::Err(VNC_FAILED.to_string())
|
||||||
}
|
}
|
||||||
@ -280,7 +475,7 @@ impl VncStateMachine for VncEnds {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&self) -> Box<dyn VncStateMachine> {
|
fn next(&self) -> Box<dyn VncState> {
|
||||||
Box::new(VncEnds)
|
Box::new(VncEnds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -397,3 +592,24 @@ impl Default for PixelFormat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Each rectangle consists of:
|
||||||
|
// 2 CARD16 x-position
|
||||||
|
// 2 CARD16 y-position
|
||||||
|
// 2 CARD16 width
|
||||||
|
// 2 CARD16 height
|
||||||
|
// 4 CARD32 encoding-type:
|
||||||
|
// 0 raw encoding
|
||||||
|
// 1 copy rectangle encoding
|
||||||
|
// 2 RRE encoding
|
||||||
|
// 4 CoRRE encoding
|
||||||
|
// 5 Hextile encoding
|
||||||
|
struct VncRect {
|
||||||
|
x: u16,
|
||||||
|
y: u16,
|
||||||
|
width: u16,
|
||||||
|
height: u16,
|
||||||
|
encoding_type: u32,
|
||||||
|
encoding_data: Vec<u8>,
|
||||||
|
left_data: u32,
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user