From a5ef10c10c0a693a3efd31c165dfd75374f2048d Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 20 May 2026 22:11:28 +0200 Subject: [PATCH] screen: fix framebuffer height parse and stray byte consume Two RFB protocol bugs in the /screen client: 1. ServerInit parsed framebuffer-height from byte offset 1 instead of 2. RFB 3.8 ServerInit is width@0-1, height@2-3; u16be(b,1) mixes the low byte of width with the high byte of height. The wrong height went into the initial non-incremental FramebufferUpdate- Request; neatvnc feeds the client's width/height straight into pixman_region_union_rect un-clipped (src/server.c), so an out-of-range height corrupts the server damage region and pixman reports 'Invalid rectangle passed'. 2. FramebufferUpdate handler had a stray drainTo(1) after the 3-byte padding+nRects header, consuming the first byte of the first rectangle and desyncing every update. Closes #128 --- hive-ag3nt/assets/screen.html | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hive-ag3nt/assets/screen.html b/hive-ag3nt/assets/screen.html index 4899567..338b5dc 100644 --- a/hive-ag3nt/assets/screen.html +++ b/hive-ag3nt/assets/screen.html @@ -467,7 +467,8 @@ canvas { display: block; cursor: default; } case 'server-init': { const b = drainTo(24); if (!b) return false; - fbW = u16be(b, 0); fbH = u16be(b, 1); + // RFB ServerInit: width @ bytes 0-1, height @ bytes 2-3. + fbW = u16be(b, 0); fbH = u16be(b, 2); // pixel format: bpp=b[4], depth=b[5], big-endian=b[6], true-colour=b[7] // red/green/blue max/shift at b[8..17] pixelFormat = { @@ -493,12 +494,10 @@ canvas { display: block; cursor: default; } if (!b) return false; const msgType = b[0]; if (msgType === 0) { - // FramebufferUpdate + // FramebufferUpdate: type(1) + padding(1) + nRects(2). The type + // byte is already consumed above; hdr covers padding + nRects. const hdr = drainTo(3); if (!hdr) { chunks.unshift(b); totalBytes += 1; return false; } - drainTo(1); // padding (already consumed with hdr? no — hdr is 3 bytes after the type) - // Actually: message type (1) + padding (1) + nRects (2) = 4 bytes total after type byte - // Let's re-do: type byte consumed, then 1 pad + 2 nRects = 3 bytes updateRects = u16be(hdr, 1); state = 'rect-header'; } else if (msgType === 2) {