UltraVNC
UltraVNC copied to clipboard
odd responses to FramebufferUpdateRequest
The following behaviour was observed when communicating with an UltraVNC server 1.3.8.1 x64 on a Windows 10 Pro.
I'm developing a very slim and specialized VNC client, which does not process video data. Still I want to receive DesktopSize changes. As a result the client requests framebuffer updates with an empty area, which should result in only pseudo-encoded rectangles (see rfbproto 7.4.3). Most tested VNC servers do not send framebuffer data, one only a vew very small rectangles (64x64) - not perfect but ok.
Sending a FramebufferUpdateRequest with incremental set to zero (false) to UltraVNC server results in a full framebuffer update ignoring the requested area. It makes no difference if an empty area, a small rectangle (0, 0, 10, 10) or only half the framebuffer is requested. Because my VNC client is very slim it only supports raw encoding und will receive megabytes of not requested framebuffer data. It would be great to have this somehow corrected.
The more critical behaviour results from sending a FramebufferUpdateRequest with incremental set to one (true) and an empty area (0, 0, 0, 0). The UltraVNC server just closes the connection. In Wireshark I can see a packet flagged FIN and ACK as a reply to the FramebufferUpdateRequest (hex 03 01 00 00 00 00 00 00 00 00). Expected behaviour would be a framebuffer update containing only pseudo-encoded rectangles.
This is indeed how it's implemented. if (update_rgn.is_empty()) return false; //disconnect the viewer non incremental is a full update
You can change the behaviour if you change the code like this.
if (!fur.incremental) { if (m_use_ExtDesktopSize && m_firstExtDesktop) { m_NewSWUpdateWaiting = true; } -update.tl.x = (m_ScaledScreen.tl.x + monitor_Offsetx) * m_nScale; -update.tl.y = (m_ScaledScreen.tl.y + monitor_Offsety) * m_nScale; -update.br.x = update.tl.x + (m_ScaledScreen.br.x - m_ScaledScreen.tl.x) * m_nScale; -update.br.y = update.tl.y + (m_ScaledScreen.br.y - m_ScaledScreen.tl.y) * m_nScale; +update.tl.x = (Swap16IfLE(fur.x) + monitor_Offsetx) * m_nScale; +update.tl.y = (Swap16IfLE(fur.y) + monitor_Offsety) * m_nScale; +update.br.x = update.tl.x + Swap16IfLE(fur.w) * m_nScale; +update.br.y = update.tl.y + Swap16IfLE(fur.h) * m_nScale; +// Verify max size, scaled changed on server while not pushed to viewer +if (update.tl.x < (int)((m_ScaledScreen.tl.x + monitor_Offsetx) * m_nScale)) + update.tl.x = (m_ScaledScreen.tl.x + monitor_Offsetx) * m_nScale; +if (update.tl.y < (int)((m_ScaledScreen.tl.y + monitor_Offsety) * m_nScale)) + update.tl.y = (m_ScaledScreen.tl.y + monitor_Offsety) * m_nScale; +if (update.br.x > (int)(update.tl.x + (m_ScaledScreen.br.x - m_ScaledScreen.tl.x) * m_nScale)) + update.br.x = update.tl.x + (m_ScaledScreen.br.x - m_ScaledScreen.tl.x) * m_nScale; +if (update.br.y > (int)(update.tl.y + (m_ScaledScreen.br.y - m_ScaledScreen.tl.y) * m_nScale)) + update.br.y = update.tl.y + (m_ScaledScreen.br.y - m_ScaledScreen.tl.y) * m_nScale; update_rgn = update; if (update_rgn.is_empty()) -return false; +return TRUE; m_update_tracker.add_changed(update_rgn); m_encodemgr.m_buffer->m_desktop->UpdateFullScreen(); } else { if (m_firstExtDesktopIncremental) { //The first full was used for the extDesktopSize, we send it now update.tl.x = (m_ScaledScreen.tl.x + monitor_Offsetx) * m_nScale; update.tl.y = (m_ScaledScreen.tl.y + monitor_Offsety) * m_nScale; update.br.x = update.tl.x + (m_ScaledScreen.br.x - m_ScaledScreen.tl.x) * m_nScale; update.br.y = update.tl.y + (m_ScaledScreen.br.y - m_ScaledScreen.tl.y) * m_nScale; update_rgn = update; if (update_rgn.is_empty()) -return false; +return TRUE; m_update_tracker.add_changed(update_rgn); m_encodemgr.m_buffer->m_desktop->UpdateFullScreen(); m_firstExtDesktopIncremental = false; } else { update.tl.x = (Swap16IfLE(fur.x) + monitor_Offsetx) * m_nScale; update.tl.y = (Swap16IfLE(fur.y) + monitor_Offsety) * m_nScale; update.br.x = update.tl.x + Swap16IfLE(fur.w) * m_nScale; update.br.y = update.tl.y + Swap16IfLE(fur.h) * m_nScale; // Verify max size, scaled changed on server while not pushed to viewer if (update.tl.x < (int)((m_ScaledScreen.tl.x + monitor_Offsetx) * m_nScale)) update.tl.x = (m_ScaledScreen.tl.x + monitor_Offsetx) * m_nScale; if (update.tl.y < (int)((m_ScaledScreen.tl.y + monitor_Offsety) * m_nScale)) update.tl.y = (m_ScaledScreen.tl.y + monitor_Offsety) * m_nScale; if (update.br.x > (int)(update.tl.x + (m_ScaledScreen.br.x - m_ScaledScreen.tl.x) * m_nScale)) update.br.x = update.tl.x + (m_ScaledScreen.br.x - m_ScaledScreen.tl.x) * m_nScale; if (update.br.y > (int)(update.tl.y + (m_ScaledScreen.br.y - m_ScaledScreen.tl.y) * m_nScale)) update.br.y = update.tl.y + (m_ScaledScreen.br.y - m_ScaledScreen.tl.y) * m_nScale; update_rgn = update; if (update_rgn.is_empty()) -return false; +return TRUE; } } #ifdef _DEBUG
@Neustradamus: I have seen it, but have not tried it yet. At the moment, the slim VNC client supports a switch to disable the use of pseudo encodings. This works in the known application scenarios, but not in all theoretically possible configurations. Priority is currently low due to this, would still consider it a bug in the implementation of the RFB protocol.
@mbey-mw: Have you progressed on this ticket?
@mbey-mw: It is possible to have some news from you?
@mbey-mw: Have you progressed on this ticket?
@mbey-mw: It is possible to have a comeback from you?
Thanks in advance.