Add skeleton support for VNC server.#113
Conversation
pfmooney
left a comment
There was a problem hiding this comment.
I have a few comments, but am also inclined to land it sooner rather than later, and iterate after that.
| } | ||
|
|
||
| #[derive(Clone)] | ||
| pub struct PropolisVncServer { |
There was a problem hiding this comment.
style nit: probably don't need 'propolis' in the name
There was a problem hiding this comment.
I just called it that because there's another type called rfb::VncServer and I found it confusing. I would prefer to name it not just VncServer but am down to rename it otherwise.
| // Show a white screen if the guest isn't ready yet. | ||
| const LEN: usize = 1024 * 768 * 4; | ||
| let mut pixels = vec![0u8; LEN]; | ||
| for i in 0..LEN { | ||
| pixels[i] = 0xff; | ||
| } | ||
| let r = Rectangle::new( | ||
| 0, | ||
| 0, | ||
| 1024, | ||
| 768, | ||
| Box::new(RawEncoding::new(pixels)), | ||
| ); | ||
| FramebufferUpdate::new(vec![r]) |
There was a problem hiding this comment.
It seems like the framebuffer-not-yet-initialized behavior, complete with white screen (or whatever Please Stand By graphics we want) should probably be centralized?
There was a problem hiding this comment.
Ooops, I missed one place where the width/height was hardcoded. Let me fix in a follow up.
|
|
||
| #[async_trait] | ||
| impl Server for PropolisVncServer { | ||
| async fn get_framebuffer_update(&self) -> FramebufferUpdate { |
There was a problem hiding this comment.
Long-term structure question: It looks like this is mostly a 'pull' model from the RFB crate? Seems like we might want at least some 'push' portions of it, like when the ramfb config is updated from inside the guest (potentially requiring an explicit change-of-res message in the proto).
There was a problem hiding this comment.
Yes, that's right. I structured it that way because the RFC describes the protocol as client-driven, so the server isn't supposed to send messages that aren't requested (like framebuffer updates) after the initial handshake. That said, I think where we've landed is that we're going to want to control the client for product quality purposes, so that's definitely something we can do. (It also seems to be something that the clients I've tested with might handle already -- even before I wrote code to process client messages they seemed to accept unprompted framebuffer updates, but I would need to do more testing to be sure.)
| // XXX: vncviewer won't work without offering VncAuth, even though it doesn't ask to use | ||
| // it. |
There was a problem hiding this comment.
Can probably be a "durable" (sans XXX) comment, considering the value
There was a problem hiding this comment.
Fair. I don't think I care too much about vncviewer as a client (it seems to be buggy, or at least behaves differently from others when processing framebuffer updates), but it has the nice quality of very verbose error messages, which has helped me debug protocol errors on my end. VNCAuth isn't implemented yet (and maybe never will be) so it probably should be removed in that case.
dbb4f6a to
a57c3ca
Compare
Summary
This PR implements prototype-level support in
propolis-serverfor connecting to a propolis VM over VNC. Specifically:See the "Examples" section below for what this looks like in noVNC.
There's a lot left to implement. Broadly, this includes:
propolis-standaloneStill, I am making this PR now in the interest of merging often and making review easier as this project is ongoing and has a lot of moving parts.
Overview of Changes
rfb::server::Servertrait, which for now only requires a method to provide framebuffer data.PropolisVncServerstruct implementsrfb::server::Server, which calls into the guest memory if the guest has been initialized (otherwise, it provides a white screen). A handle to this server is hung off the server Context that each dropshot endpoint gets. The propolisRamFbdevice notifiesPropolisVncServerof updates when it's updated viafwcfg_rw.RamFbentity ID through the intializer code so that its notifier function could be updated when an instance is created (instance_ensure).server/src/main.rs.Examples
Example Uninitialized Framebuffer (guest not started)
Here's an example of connecting without a guest running. I chose to make the screen white instead of black to differentiate between the framebuffer not being sent at all (which renders as black on some clients).

Example Initialized Framebuffer (guest started)
Here's a low-ish quality gif demonstrating what it looks like to connect to propolis-server over VNC, then create a VM and run it. (It looks better on a real client, I promise).
A couple of things to note here:
serialcommand on the CLI. I'm not sure why this is, or if we should expect to see the serial console here by default (I would think so).