From 3116eaa74b45c21ee925e0c9e39ac58303ef58e0 Mon Sep 17 00:00:00 2001 From: ache Date: Fri, 15 Nov 2024 04:05:33 +0100 Subject: Init commit --- Cargo.toml | 22 ++++++++++ screen-rfp.png | Bin 0 -> 81160 bytes src/main.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 Cargo.toml create mode 100644 screen-rfp.png create mode 100644 src/main.rs diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f56955b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "vncstrost" +version = "0.1.0" +description = "Simple trolling VNC server" +authors = ["ache "] +license = "MPL-2.0" +edition = "2021" + +[dependencies] +ascii = { version = "1.1", default-features = false } +async-trait = "0.1.80" +bitflags = "2.4" +env_logger = "0.11" +futures = "0.3.30" +log = "0.4.17" +thiserror = "1.0" +tokio = { version = "1", features = ["full"] } +anyhow = "1.0" +clap = { version = "4.5", features = ["derive"] } +image = "0.25.1" +rfb = { path = 'deps/rfb' } + diff --git a/screen-rfp.png b/screen-rfp.png new file mode 100644 index 0000000..a279a96 Binary files /dev/null and b/screen-rfp.png differ diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..96455ac --- /dev/null +++ b/src/main.rs @@ -0,0 +1,129 @@ +use anyhow::Result; +use async_trait::async_trait; +// use clap::{Parser, ValueEnum}; +use env_logger; +use image::GenericImageView; +use image::ImageReader; +use log::info; +use rfb::encodings; +use rfb::pixel_formats::rgb_888; +use rfb::rfb::{ + FramebufferUpdate, KeyEvent, PixelFormat, ProtoVersion, Rectangle, SecurityType, SecurityTypes, +}; +use rfb::server::{Server, VncServer, VncServerConfig, VncServerData}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + +const WIDTH: usize = 1053; +const HEIGHT: usize = 1053; + +#[derive(Clone)] +struct AcheServer { + rgb_order: (u8, u8, u8), + big_endian: bool, +} + +#[tokio::main] +async fn main() -> Result<()> { + env_logger::init(); + /* + TODO: Should add a CLI option to configure the port to listen to. + + TODO: Should add a CLI option to configure the image to display. + */ + + let pf = PixelFormat::new_colorformat( + rgb_888::BITS_PER_PIXEL, + rgb_888::DEPTH, + false, // endianness = little-endian + order_to_shift(0), + rgb_888::MAX_VALUE, + order_to_shift(1), + rgb_888::MAX_VALUE, + order_to_shift(2), + rgb_888::MAX_VALUE, + ); + info!("Starting server: pixel format; {:#?}", pf); + + let config = VncServerConfig { + addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 5901), + version: ProtoVersion::Rfb38, + sec_types: SecurityTypes(vec![SecurityType::None, SecurityType::VncAuthentication]), + name: "rfb-ache-server".to_string(), + }; + let data = VncServerData { + width: WIDTH as u16, + height: HEIGHT as u16, + input_pixel_format: pf.clone(), + }; + let server = AcheServer { + rgb_order: (0, 1, 2), + big_endian: false, + }; + let s = VncServer::new(server, config, data); + s.start().await?; + + Ok(()) +} + +fn order_to_shift(order: u8) -> u8 { + assert!(order <= 3); + (3 - order) * rgb_888::BITS_PER_COLOR +} + +fn order_to_index(order: u8, big_endian: bool) -> u8 { + assert!(order <= 3); + + if big_endian { + order + } else { + 4 - order - 1 + } +} + +fn generate_image(name: &str, big_endian: bool, rgb_order: (u8, u8, u8)) -> Vec { + const LEN: usize = WIDTH * HEIGHT * rgb_888::BYTES_PER_PIXEL; + let mut pixels = vec![0xffu8; LEN]; + + let img = ImageReader::open(name).unwrap().decode().unwrap(); + + let (r, g, b) = rgb_order; + let r_idx = order_to_index(r, big_endian) as usize; + let g_idx = order_to_index(g, big_endian) as usize; + let b_idx = order_to_index(b, big_endian) as usize; + let x_idx = rgb_888::unused_index(r_idx, g_idx, b_idx); + + // Convert the input image pixels to the requested pixel format. + for (x, y, pixel) in img.pixels() { + let ux = x as usize; + let uy = y as usize; + + let y_offset = WIDTH * rgb_888::BYTES_PER_PIXEL; + let x_offset = ux * rgb_888::BYTES_PER_PIXEL; + + pixels[uy * y_offset + x_offset + r_idx] = pixel[0]; + pixels[uy * y_offset + x_offset + g_idx] = pixel[1]; + pixels[uy * y_offset + x_offset + b_idx] = pixel[2]; + pixels[uy * y_offset + x_offset + x_idx] = pixel[3]; + } + + pixels +} + +#[async_trait] +impl Server for AcheServer { + async fn get_framebuffer_update(&self) -> FramebufferUpdate { + let pixels_width = 1053; + let pixels_height = 1053; + let pixels = generate_image("screen-rfp.png", self.big_endian, self.rgb_order); + let r = Rectangle::new( + 0, + 0, + pixels_width, + pixels_height, + Box::new(encodings::RawEncoding::new(pixels)), + ); + FramebufferUpdate::new(vec![r]) + } + + async fn key_event(&self, _ke: KeyEvent) {} +} -- cgit v1.3-2-g11bf