Commit 05a6350
Changed files (2)
.gitignore
@@ -1,3 +1,4 @@
.govnc_history
clipboard_in
clipboard_out
+clipboard
main.go
@@ -173,6 +173,10 @@ func run() error {
// drainFrames reads and logs incoming VNC messages
func drainFrames(ctx context.Context, c *websocket.Conn, width, height uint16) error {
+ // Buffer for reassembling fragmented messages
+ var pendingBuf []byte
+ var pendingExpected int
+
for {
_, b, err := c.Read(ctx)
if err != nil {
@@ -184,6 +188,25 @@ func drainFrames(ctx context.Context, c *websocket.Conn, width, height uint16) e
continue
}
+ // If we're waiting for more data on a fragmented message, append it
+ if pendingBuf != nil {
+ pendingBuf = append(pendingBuf, b...)
+ slog.Debug("reassembly", slog.Int("have", len(pendingBuf)), slog.Int("need", pendingExpected))
+
+ if len(pendingBuf) >= pendingExpected {
+ // We have enough data, process the complete message
+ clipboardText := string(pendingBuf[8:pendingExpected])
+ slog.Info("clipboard recv", slog.Int("len", len(clipboardText)))
+ slog.Debug("clipboard", slog.String("text", clipboardText))
+ if err := saveClipboard(clipboardText); err != nil {
+ slog.Warn("failed to save clipboard", slog.String("error", err.Error()))
+ }
+ pendingBuf = nil
+ pendingExpected = 0
+ }
+ continue
+ }
+
msgType := b[0]
switch msgType {
case 0: // FramebufferUpdate
@@ -200,15 +223,32 @@ func drainFrames(ctx context.Context, c *websocket.Conn, width, height uint16) e
case 3: // ServerCutText (clipboard)
if len(b) >= 8 {
textLen := binary.BigEndian.Uint32(b[4:8])
- if len(b) >= 8+int(textLen) {
- clipboardText := string(b[8 : 8+textLen])
+
+ // Check for extended clipboard (high bit set = negative signed int32)
+ if int32(textLen) < 0 {
+ slog.Debug("recv", slog.String("type", "ExtendedClipboard"), slog.Int("flags", int(textLen&0x7FFFFFFF)))
+ // Extended clipboard - for now just log it
+ // TODO: implement extended clipboard request/response
+ continue
+ }
+
+ expectedLen := 8 + int(textLen)
+ if len(b) >= expectedLen {
+ clipboardText := string(b[8:expectedLen])
slog.Info("clipboard recv", slog.Int("len", int(textLen)))
slog.Debug("clipboard", slog.String("text", clipboardText))
if err := saveClipboard(clipboardText); err != nil {
slog.Warn("failed to save clipboard", slog.String("error", err.Error()))
}
} else {
- slog.Info("recv", slog.String("type", "ServerCutText"), slog.Int("textLen", int(textLen)), slog.String("note", "incomplete"))
+ // Start buffering for reassembly
+ slog.Info("recv", slog.String("type", "ServerCutText"),
+ slog.Int("textLen", int(textLen)),
+ slog.Int("have", len(b)),
+ slog.String("note", "fragmented, buffering"))
+ pendingBuf = make([]byte, len(b))
+ copy(pendingBuf, b)
+ pendingExpected = expectedLen
}
}
default: