listen address + port are configurable.

Also, libvncserver log messages now output via Tracing.
This commit is contained in:
Lily Tsuru 2024-08-04 03:47:20 -04:00
parent d4329be132
commit 596839e4ed
7 changed files with 146 additions and 14 deletions

1
Cargo.lock generated
View file

@ -407,6 +407,7 @@ name = "retrovnc"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cc",
"clap", "clap",
"libvnc-sys", "libvnc-sys",
"retro_frontend", "retro_frontend",

View file

@ -0,0 +1,14 @@
//! Libretro VFS
use crate::libretro_sys_new::*;
use std::path;
/// A file handle
struct FileHandle {
/// The path used to open a file on the host
real_path: path::PathBuf,
}
//unsafe extern "C" fn libretro_vfs_get_path(stream: *mut )

View file

@ -11,3 +11,6 @@ libvnc-sys = "0.1.4"
retro_frontend = { path = "../retro_frontend" } retro_frontend = { path = "../retro_frontend" }
tracing = "0.1.40" tracing = "0.1.40"
tracing-subscriber = "0.3.18" tracing-subscriber = "0.3.18"
[build-dependencies]
cc = "1.0.99"

12
crates/retrovnc/build.rs Normal file
View file

@ -0,0 +1,12 @@
use cc;
fn main() {
let mut build = cc::Build::new();
build
.emit_rerun_if_env_changed(true)
.cpp(true)
.std("c++20")
.file("src/rfb_log_helper.cpp")
.compile("rfb_log_helper");
}

View file

@ -1,4 +1,4 @@
use std::path::Path; use std::{net::Ipv4Addr, path::Path};
use anyhow::Result; use anyhow::Result;
@ -21,13 +21,10 @@ struct App {
} }
impl App { impl App {
fn new() -> Result<Box<Self>> { fn new(rfb_config: RfbServerConfig) -> Result<Box<Self>> {
let mut boxed = Box::new(Self { let mut boxed = Box::new(Self {
frontend: None, frontend: None,
rfb_server: RfbServer::new(RfbServerConfig { rfb_server: RfbServer::new(rfb_config)?,
width: 640,
height: 480,
})?,
// nasty, but idk a better way // nasty, but idk a better way
pad: RetroPad::new(), pad: RetroPad::new(),
}); });
@ -146,8 +143,18 @@ fn main() -> Result<()> {
let core_path: &String = matches.get_one("core").unwrap(); let core_path: &String = matches.get_one("core").unwrap();
rfb::init();
let rfb_config = RfbServerConfig {
// default WxH; this is overridden quickly
width: 640,
height: 480,
listen_address: "127.0.0.1".parse::<Ipv4Addr>()?,
listen_port: 6930
};
// Initalize the app // Initalize the app
let mut app = App::new()?; let mut app = App::new(rfb_config)?;
app.load_core(core_path)?; app.load_core(core_path)?;

View file

@ -8,8 +8,8 @@ use anyhow::{anyhow, Result};
pub struct RfbServerConfig { pub struct RfbServerConfig {
pub width: u16, pub width: u16,
pub height: u16, pub height: u16,
// TODO: Listen address pub listen_address: std::net::Ipv4Addr,
// TODO: listen port pub listen_port: u16,
} }
pub struct RfbServer { pub struct RfbServer {
@ -20,16 +20,18 @@ pub struct RfbServer {
buttons: [bool; 32], buttons: [bool; 32],
} }
impl RfbServer { impl RfbServer {
pub fn new(config: RfbServerConfig) -> Result<Box<Self>> { pub fn new(config: RfbServerConfig) -> Result<Box<Self>> {
unsafe { unsafe {
// Feed a fake argv in (TODO: Make this better.) // Feed a fake argv in (TODO: Make this better.)
let ip_string = std::ffi::CString::new(config.listen_address.to_string())?;
let argc = 3; let argc = 3;
let argv: [*const std::ffi::c_char; 3] = [ let argv: [*const std::ffi::c_char; 3] = [
b"RfbServer".as_ptr() as *const i8, b"RfbServer".as_ptr() as *const i8,
b"-listen".as_ptr() as *const i8, b"-listen".as_ptr() as *const i8,
b"127.0.0.1".as_ptr() as *const i8, ip_string.as_ptr(),
]; ];
let screen = rfb::bindings::rfbGetScreen( let screen = rfb::bindings::rfbGetScreen(
@ -42,7 +44,6 @@ impl RfbServer {
4, 4,
); );
// result
if screen.is_null() { if screen.is_null() {
return Err(anyhow!("rfbGetScreen() failed")); return Err(anyhow!("rfbGetScreen() failed"));
} }
@ -64,7 +65,7 @@ impl RfbServer {
(*screen).kbdAddEvent = Some(Self::on_key_callback); (*screen).kbdAddEvent = Some(Self::on_key_callback);
// testing // testing
(*screen).port = 6930; (*screen).port = config.listen_port as i32;
(*screen).ipv6port = 0; (*screen).ipv6port = 0;
ret.resize(config.width, config.height); ret.resize(config.width, config.height);
@ -76,7 +77,6 @@ impl RfbServer {
pub fn resize(&mut self, w: u16, h: u16) { pub fn resize(&mut self, w: u16, h: u16) {
let len = (w as usize) * (h as usize); let len = (w as usize) * (h as usize);
//self.framebuffer = Vec::with_capacity(len);
self.framebuffer.resize(len, 0); self.framebuffer.resize(len, 0);
unsafe { unsafe {
@ -239,3 +239,55 @@ impl RfbServer {
} }
} }
} }
// Logging support
use std::ffi;
use tracing::*;
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn rfb_log(buf: *const ffi::c_char) {
// Safety: This pointer is never null, and always comes from the stack;
// we really only should get UTF-8 errors here, probably.
unsafe {
match ffi::CStr::from_ptr(buf).to_str() {
Ok(message) => {
info!("{}", message);
}
Err(err) => {
error!("Broken rfb log: {:?}", err);
}
}
}
}
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn rfb_log_error(buf: *const ffi::c_char) {
// Safety: This pointer is never null, and always comes from the stack;
// we really only should get UTF-8 errors here, probably.
unsafe {
match ffi::CStr::from_ptr(buf).to_str() {
Ok(message) => {
error!("{}", message);
}
Err(err) => {
error!("Broken rfb log: {:?}", err);
}
}
}
}
extern "C" {
/// Provided by a C++ helper to do vararg formatting for us.
/// Calls back to the above functions to output messages to Tracing
fn rfb_log_init();
}
/// Call at program startup.
pub fn init() {
unsafe {
rfb_log_init();
}
}

View file

@ -0,0 +1,43 @@
#include <cstdarg>
#include <cstdio>
using rfbLogProc = void(*)(const char*, ...);
extern "C" {
// defined in Rust; these pipe to Tracing
void rfb_log(const char* buf);
void rfb_log_error(const char* buf);
// libvncserver provides these for customizing where logging goes
extern rfbLogProc rfbLog;
extern rfbLogProc rfbErr;
}
template<auto* reciever>
void rfb_log_impl(const char* format, ...) {
char buf[512]{};
va_list val;
va_start(val, format);
auto n = std::vsnprintf(&buf[0], sizeof(buf)-1, format, val);
va_end(val);
// Failed to format for some reason, just give up.
if(n == -1)
return;
// Remove the last newline and replace it with a null terminator.
if(buf[n-1] == '\n')
buf[n-1] = '\0';
// Call the Rust-side reciever.
reciever(&buf[0]);
}
extern "C" {
void rfb_log_init() {
// Pretty simple.
rfbLog = &rfb_log_impl<&rfb_log>;
rfbErr = &rfb_log_impl<&rfb_log_error>;
}
}