vnc

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2025 License: MIT Imports: 18 Imported by: 0

README

A Go library for the VNC client protocol, compliant with RFC 6143.

go-vnc

A Go library for the VNC client protocol, compliant with RFC 6143.

[!TIP] This library maintains API compatibility with archived github.com/mitchellh/go-vnc and can be used as a drop-in replacement.

Go Reference

Refer to package reference and the examples/ folder for more usage scenarios.

Sponsor

Sponsor   Buy me a Coffee

License

Copyright © Ryan Johnson

Licensed under the MIT License.

Documentation

Overview

Example
// Create a VNC error with context
err := NewVNCError("handshake", ErrNetwork, "connection timeout", fmt.Errorf("dial tcp: timeout"))

fmt.Println("Error:", err)
fmt.Println("Is network error:", IsVNCError(err, ErrNetwork))
fmt.Println("Error code:", GetErrorCode(err))
Output:
Error: vnc network: handshake: connection timeout: dial tcp: timeout
Is network error: true
Error code: network

Index

Examples

Constants

View Source
const (
	ColorMapSize             = 256
	MaxClipboardLength       = 1024 * 1024
	Latin1MaxCodePoint       = 255
	MaxRectanglesPerUpdate   = 10000
	MaxServerClipboardLength = 10 * 1024 * 1024
)

VNC protocol constants.

View Source
const (
	HextileRaw                 = 1
	HextileBackgroundSpecified = 2
	HextileForegroundSpecified = 4
	HextileAnySubrects         = 8
	HextileSubrectsColoured    = 16

	HextileTileSize    = 16
	MaxSubrectsPerTile = 255
)

Hextile encoding constants as defined in RFC 6143.

View Source
const (
	VNCChallengeSize     = 16
	DESKeySize           = 8
	VNCMaxPasswordLength = 8
)

VNC security constants.

Variables

View Source
var (
	// ColorBlack represents pure black (0, 0, 0).
	ColorBlack = Color{R: 0, G: 0, B: 0}

	// ColorWhite represents pure white (65535, 65535, 65535).
	ColorWhite = Color{R: 65535, G: 65535, B: 65535}

	// ColorRed represents pure red (65535, 0, 0).
	ColorRed = Color{R: 65535, G: 0, B: 0}

	// ColorGreen represents pure green (0, 65535, 0).
	ColorGreen = Color{R: 0, G: 65535, B: 0}

	// ColorBlue represents pure blue (0, 0, 65535).
	ColorBlue = Color{R: 0, G: 0, B: 65535}

	// ColorYellow represents pure yellow (65535, 65535, 0).
	ColorYellow = Color{R: 65535, G: 65535, B: 0}

	// ColorMagenta represents pure magenta (65535, 0, 65535).
	ColorMagenta = Color{R: 65535, G: 0, B: 65535}

	// ColorCyan represents pure cyan (0, 65535, 65535).
	ColorCyan = Color{R: 0, G: 65535, B: 65535}
)

Common color constants for convenience.

View Source
var (
	// PixelFormat32BitRGBA represents high-quality 32-bit RGBA true color format.
	// This format provides the best color fidelity but uses the most bandwidth.
	PixelFormat32BitRGBA = &PixelFormat{
		BPP:        32,
		Depth:      24,
		BigEndian:  false,
		TrueColor:  true,
		RedMax:     255,
		GreenMax:   255,
		BlueMax:    255,
		RedShift:   16,
		GreenShift: 8,
		BlueShift:  0,
	}

	// PixelFormat16BitRGB565 represents balanced 16-bit RGB565 true color format.
	// This format provides good color quality with moderate bandwidth usage.
	PixelFormat16BitRGB565 = &PixelFormat{
		BPP:        16,
		Depth:      16,
		BigEndian:  false,
		TrueColor:  true,
		RedMax:     31,
		GreenMax:   63,
		BlueMax:    31,
		RedShift:   11,
		GreenShift: 5,
		BlueShift:  0,
	}

	// PixelFormat16BitRGB555 represents 16-bit RGB555 true color format.
	// This format provides balanced color with equal bits per color component.
	PixelFormat16BitRGB555 = &PixelFormat{
		BPP:        16,
		Depth:      15,
		BigEndian:  false,
		TrueColor:  true,
		RedMax:     31,
		GreenMax:   31,
		BlueMax:    31,
		RedShift:   10,
		GreenShift: 5,
		BlueShift:  0,
	}

	// PixelFormat8BitIndexed represents bandwidth-efficient 8-bit indexed color format.
	// This format uses the least bandwidth but is limited to 256 simultaneous colors.
	PixelFormat8BitIndexed = &PixelFormat{
		BPP:       8,
		Depth:     8,
		BigEndian: false,
		TrueColor: false,
	}
)

Common pixel format presets for easy configuration.

Functions

func ConvertPixelFormat

func ConvertPixelFormat(ctx context.Context, srcData []byte, srcFormat, dstFormat *PixelFormat) ([]byte, error)

ConvertPixelFormat converts pixel data from one format to another. This is useful for format conversion during encoding/decoding operations.

func IsVNCError

func IsVNCError(err error, code ...ErrorCode) bool

IsVNCError checks if an error is a VNCError and optionally matches specific error codes. If no codes are provided, returns true for any VNCError. If codes are provided, returns true only if the error matches one of the specified codes.

func WrapError

func WrapError(op string, code ErrorCode, message string, err error) error

WrapError wraps an existing error with VNC-specific context. Returns nil if the input error is nil, otherwise creates a new VNCError.

Types

type AuthFactory

type AuthFactory func() ClientAuth

AuthFactory is a function type that creates new instances of authentication methods.

type AuthRegistry

type AuthRegistry struct {
	// contains filtered or unexported fields
}

AuthRegistry manages available authentication methods.

func NewAuthRegistry

func NewAuthRegistry() *AuthRegistry

NewAuthRegistry creates a new authentication registry with default authentication methods.

func (*AuthRegistry) CreateAuth

func (r *AuthRegistry) CreateAuth(securityType uint8) (ClientAuth, error)

CreateAuth creates a new instance of the authentication method for the given security type.

func (*AuthRegistry) GetSupportedTypes

func (r *AuthRegistry) GetSupportedTypes() []uint8

GetSupportedTypes returns a list of all supported security types.

func (*AuthRegistry) IsSupported

func (r *AuthRegistry) IsSupported(securityType uint8) bool

IsSupported checks if a security type is supported by the registry.

func (*AuthRegistry) NegotiateAuth

func (r *AuthRegistry) NegotiateAuth(ctx context.Context, serverTypes []uint8, preferredOrder []uint8) (ClientAuth, uint8, error)

NegotiateAuth performs authentication method negotiation between client and server.

func (*AuthRegistry) Register

func (r *AuthRegistry) Register(securityType uint8, factory AuthFactory)

Register adds an authentication method factory to the registry.

func (*AuthRegistry) SetLogger

func (r *AuthRegistry) SetLogger(logger Logger)

SetLogger sets the logger for the authentication registry.

func (*AuthRegistry) Unregister

func (r *AuthRegistry) Unregister(securityType uint8) bool

Unregister removes an authentication method from the registry.

func (*AuthRegistry) ValidateAuthMethod

func (r *AuthRegistry) ValidateAuthMethod(auth ClientAuth) error

ValidateAuthMethod performs validation on an authentication method instance.

type BellMessage

type BellMessage byte

BellMessage represents an audible bell notification from the server (message type 2). This message indicates that the server wants the client to produce an audible alert, typically corresponding to a system bell or notification sound on the remote desktop.

As defined in RFC 6143 Section 7.6.3, this is a simple notification message with no additional data. The client should respond by producing an appropriate audible alert using the local system's notification mechanisms.

The message contains no payload data beyond the message type identifier. Applications can handle this message to provide audio feedback, visual notifications, or other appropriate user alerts.

Example usage:

switch msg := serverMsg.(type) {
case *BellMessage:
	// Play system bell sound or show notification
	fmt.Println("Bell notification received")
	// Could trigger: system beep, notification popup, etc.
}

func (*BellMessage) Read

Read processes a bell message from the server.

func (*BellMessage) Type

func (*BellMessage) Type() uint8

Type returns the message type identifier for bell messages.

type ButtonMask

type ButtonMask uint8

ButtonMask represents the state of pointer buttons in a VNC pointer event.

const (
	ButtonLeft ButtonMask = 1 << iota
	ButtonMiddle
	ButtonRight
	Button4
	Button5
	Button6
	Button7
	Button8
)

Button mask constants for standard mouse buttons and scroll wheel events.

type ClientAuth

type ClientAuth interface {
	SecurityType() uint8
	Handshake(ctx context.Context, conn net.Conn) error
	String() string
}

ClientAuth defines the interface for VNC authentication methods.

type ClientAuthNone

type ClientAuthNone struct {
	// contains filtered or unexported fields
}

ClientAuthNone implements the "None" authentication method (security type 1).

func (*ClientAuthNone) Handshake

func (c *ClientAuthNone) Handshake(ctx context.Context, conn net.Conn) error

Handshake performs the None authentication handshake.

func (*ClientAuthNone) SecurityType

func (c *ClientAuthNone) SecurityType() uint8

SecurityType returns the security type identifier for None authentication.

func (*ClientAuthNone) SetLogger

func (c *ClientAuthNone) SetLogger(logger Logger)

SetLogger sets the logger for the authentication method.

func (*ClientAuthNone) String

func (c *ClientAuthNone) String() string

String returns a human-readable description of the authentication method.

type ClientConfig

type ClientConfig struct {
	// Auth specifies the authentication methods supported by the client.
	Auth []ClientAuth

	// Exclusive determines whether this client requests exclusive access.
	Exclusive bool

	// ServerMessageCh is the channel where server messages will be delivered.
	ServerMessageCh chan<- ServerMessage

	// ServerMessages specifies additional custom server message types.
	ServerMessages []ServerMessage

	// Logger specifies the logger instance to use for connection logging.
	Logger Logger

	// AuthRegistry specifies the authentication registry to use.
	AuthRegistry *AuthRegistry

	// ConnectTimeout specifies the timeout for the initial connection handshake.
	ConnectTimeout time.Duration

	// ReadTimeout specifies the timeout for individual read operations.
	ReadTimeout time.Duration

	// WriteTimeout specifies the timeout for individual write operations.
	WriteTimeout time.Duration

	// Metrics specifies the metrics collector to use for connection monitoring.
	Metrics MetricsCollector
}

ClientConfig configures VNC client connection behavior.

type ClientConn

type ClientConn struct {

	// ColorMap contains the color map for indexed color modes.
	ColorMap [ColorMapSize]Color

	// Encs contains the list of encodings supported by this client.
	Encs []Encoding

	// FrameBufferWidth is the width of the remote framebuffer in pixels.
	FrameBufferWidth uint16

	// FrameBufferHeight is the height of the remote framebuffer in pixels.
	FrameBufferHeight uint16

	// DesktopName is the human-readable name of the desktop.
	DesktopName string

	// PixelFormat describes the format of pixel data used in this connection.
	PixelFormat PixelFormat
	// contains filtered or unexported fields
}

ClientConn represents an active VNC client connection. Safe for concurrent use for sending client messages.

func Client deprecated

func Client(c net.Conn, cfg *ClientConfig) (*ClientConn, error)

Client establishes a VNC client connection with the provided configuration. Performs complete handshake and starts background message processing.

Deprecated: Use ClientWithContext for better cancellation support.

func ClientWithContext

func ClientWithContext(ctx context.Context, c net.Conn, cfg *ClientConfig) (*ClientConn, error)

ClientWithContext establishes a VNC client connection with context support. Performs complete handshake including protocol negotiation, security, and initialization.

func ClientWithOptions

func ClientWithOptions(ctx context.Context, c net.Conn, options ...ClientOption) (*ClientConn, error)

ClientWithOptions establishes a VNC client connection using functional options for configuration. This provides a modern, flexible way to configure client connections while maintaining backward compatibility. Options are applied in the order they are provided.

Parameters:

  • ctx: Context for cancellation and timeout control
  • c: An established network connection to a VNC server (typically TCP)
  • options: Functional options for configuring the client behavior

Returns:

  • *ClientConn: A configured VNC client connection ready for use
  • error: Any error that occurred during the handshake process

Example usage:

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

conn, err := net.Dial("tcp", "localhost:5900")
if err != nil {
	log.Fatal(err)
}
defer conn.Close()

client, err := ClientWithOptions(ctx, conn,
	WithAuth(&PasswordAuth{Password: "secret"}),
	WithExclusive(true),
	WithLogger(&StandardLogger{}),
	WithTimeout(10*time.Second),
)
if err != nil {
	log.Fatal(err)
}
defer client.Close()

Advanced configuration example:

msgCh := make(chan ServerMessage, 100)
registry := NewAuthRegistry()
registry.Register(16, func() ClientAuth { return &CustomAuth{} })

client, err := ClientWithOptions(ctx, conn,
	WithAuthRegistry(registry),
	WithServerMessageChannel(msgCh),
	WithConnectTimeout(30*time.Second),
	WithReadTimeout(5*time.Second),
	WithWriteTimeout(5*time.Second),
	WithMetrics(&PrometheusMetrics{}),
)

The functional options approach provides several benefits: - Type-safe configuration with compile-time validation - Extensible without breaking existing code - Self-documenting through option names - Composable and reusable option sets - Optional parameters with sensible defaults.

func (*ClientConn) Close

func (c *ClientConn) Close() error

Close terminates the VNC connection and releases associated resources. This method closes the underlying network connection, cancels the connection context, and will cause the message processing goroutine to exit and close the server message channel.

It is safe to call Close multiple times; subsequent calls will have no effect. After calling Close, the ClientConn should not be used for any other operations.

Returns:

  • error: Any error that occurred while closing the network connection

Example usage:

client, err := Client(conn, config)
if err != nil {
	log.Fatal(err)
}
defer client.Close() // Ensure cleanup

// Use the client...

// Explicit close when done
if err := client.Close(); err != nil {
	log.Printf("Error closing VNC connection: %v", err)
}

func (*ClientConn) CutText

func (c *ClientConn) CutText(text string) error

CutText sends clipboard text from the client to the VNC server. This method implements the ClientCutText message as defined in RFC 6143 Section 7.5.6, allowing the client to share clipboard content with the remote desktop.

The text must contain only Latin-1 characters (Unicode code points 0-255). Characters outside this range will cause a validation error. This restriction is imposed by the VNC protocol specification for compatibility across different systems and character encodings.

Parameters:

  • text: The clipboard text to send to the server (Latin-1 characters only)

Returns:

  • error: ValidationError if text contains invalid characters, NetworkError for transmission issues

Example usage:

// Send simple ASCII text
err := client.CutText("Hello, World!")
if err != nil {
	log.Printf("Failed to send clipboard text: %v", err)
}

// Handle clipboard synchronization
clipboardText := getLocalClipboard()
if isValidLatin1(clipboardText) {
	client.CutText(clipboardText)
}

Character validation: The method validates each character to ensure it falls within the Latin-1 character set (0-255). Characters beyond this range will result in an error:

// This will fail - contains Unicode characters outside Latin-1
err := client.CutText("Hello 世界") // Contains Chinese characters
if err != nil {
	// Handle validation error
}

Security considerations: Clipboard sharing can potentially expose sensitive information. Applications should consider whether clipboard synchronization is appropriate for their security requirements and may want to filter or sanitize clipboard content.

func (*ClientConn) FramebufferUpdateRequest

func (c *ClientConn) FramebufferUpdateRequest(incremental bool, x, y, width, height uint16) error

FramebufferUpdateRequest requests a framebuffer update from the VNC server. This method implements the FramebufferUpdateRequest message as defined in RFC 6143 Section 7.5.3, asking the server to send pixel data for a specified rectangular region of the desktop.

The server will respond asynchronously with a FramebufferUpdateMessage containing the requested pixel data. There is no guarantee about response timing, and the server may combine multiple requests or send partial updates.

Parameters:

  • incremental: If true, only send pixels that have changed since the last update. If false, send all pixels in the specified rectangle regardless of changes.
  • x, y: The top-left corner coordinates of the requested rectangle (0-based)
  • width, height: The dimensions of the requested rectangle in pixels

Returns:

  • error: NetworkError if the request cannot be sent to the server

Example usage:

// Request full screen update (non-incremental)
err := client.FramebufferUpdateRequest(false, 0, 0,
	client.FrameBufferWidth, client.FrameBufferHeight)
if err != nil {
	log.Printf("Failed to request framebuffer update: %v", err)
}

// Request incremental update for a specific region
err = client.FramebufferUpdateRequest(true, 100, 100, 200, 150)
if err != nil {
	log.Printf("Failed to request incremental update: %v", err)
}

Update strategies:

// Initial full screen capture
client.FramebufferUpdateRequest(false, 0, 0, width, height)

// Continuous incremental updates for live viewing
ticker := time.NewTicker(33 * time.Millisecond) // ~30 FPS
go func() {
	for range ticker.C {
		client.FramebufferUpdateRequest(true, 0, 0, width, height)
	}
}()

Performance considerations: - Incremental updates are more bandwidth-efficient for live viewing - Non-incremental updates ensure complete accuracy but use more bandwidth - Request frequency should balance responsiveness with network/CPU usage - Large rectangles may be split by the server into multiple smaller updates.

func (*ClientConn) GetDesktopName

func (c *ClientConn) GetDesktopName() string

GetDesktopName returns the desktop name in a thread-safe manner.

func (*ClientConn) GetFrameBufferSize

func (c *ClientConn) GetFrameBufferSize() (width, height uint16)

GetFrameBufferSize returns the current framebuffer dimensions in a thread-safe manner.

func (*ClientConn) GetPixelFormat

func (c *ClientConn) GetPixelFormat() PixelFormat

GetPixelFormat returns a copy of the current pixel format in a thread-safe manner.

func (*ClientConn) KeyEvent

func (c *ClientConn) KeyEvent(keysym uint32, down bool) error

KeyEvent sends a keyboard key press or release event to the VNC server. This method implements the KeyEvent message as defined in RFC 6143 Section 7.5.4, allowing the client to send keyboard input to the remote desktop.

Keys are identified using X Window System keysym values, which provide a standardized way to represent keyboard keys across different platforms and keyboard layouts. To simulate a complete key press, you must send both a key down event (down=true) followed by a key up event (down=false).

Parameters:

  • keysym: The X11 keysym value identifying the key (see X11/keysymdef.h)
  • down: true for key press, false for key release

Returns:

  • error: NetworkError if the event cannot be sent to the server

Example usage:

// Send the letter 'A' (complete key press and release)
const XK_A = 0x0041
client.KeyEvent(XK_A, true)  // Key down
client.KeyEvent(XK_A, false) // Key up

// Send Enter key
const XK_Return = 0xff0d
client.KeyEvent(XK_Return, true)
client.KeyEvent(XK_Return, false)

// Send Ctrl+C (hold Ctrl, press C, release C, release Ctrl)
const XK_Control_L = 0xffe3
const XK_c = 0x0063
client.KeyEvent(XK_Control_L, true)  // Ctrl down
client.KeyEvent(XK_c, true)          // C down
client.KeyEvent(XK_c, false)         // C up
client.KeyEvent(XK_Control_L, false) // Ctrl up

Common keysym values:

// Letters (uppercase when Shift is held)
XK_a = 0x0061, XK_b = 0x0062, ..., XK_z = 0x007a
XK_A = 0x0041, XK_B = 0x0042, ..., XK_Z = 0x005a

// Numbers
XK_0 = 0x0030, XK_1 = 0x0031, ..., XK_9 = 0x0039

// Special keys
XK_Return = 0xff0d     // Enter
XK_Escape = 0xff1b     // Escape
XK_BackSpace = 0xff08  // Backspace
XK_Tab = 0xff09        // Tab
XK_space = 0x0020      // Space

// Modifier keys
XK_Shift_L = 0xffe1    // Left Shift
XK_Control_L = 0xffe3  // Left Ctrl
XK_Alt_L = 0xffe9      // Left Alt

Key sequence helper:

func (c *ClientConn) SendKey(keysym uint32) error {
	if err := c.KeyEvent(keysym, true); err != nil {
		return err
	}
	return c.KeyEvent(keysym, false)
}

For a complete reference of keysym values, consult the X11 keysym definitions or online keysym references. The values are standardized and consistent across VNC implementations.

func (*ClientConn) PointerEvent

func (c *ClientConn) PointerEvent(mask ButtonMask, x, y uint16) error

PointerEvent sends mouse movement and button state to the VNC server. This method implements the PointerEvent message as defined in RFC 6143 Section 7.5.5, allowing the client to send mouse input including movement, clicks, and scroll events to the remote desktop.

The button mask represents the current state of all mouse buttons simultaneously. When a bit is set (1), the corresponding button is pressed; when clear (0), the button is released. This allows for complex interactions like drag operations where multiple buttons may be held simultaneously.

Parameters:

  • mask: Bitmask indicating which buttons are currently pressed (see ButtonMask constants)
  • x, y: Mouse cursor coordinates in pixels (0-based, relative to framebuffer)

Returns:

  • error: NetworkError if the event cannot be sent to the server

Example usage:

// Simple mouse movement (no buttons pressed)
err := client.PointerEvent(0, 100, 200)

// Left mouse button click at coordinates (150, 300)
client.PointerEvent(ButtonLeft, 150, 300)      // Button down
client.PointerEvent(0, 150, 300)               // Button up

// Right mouse button click
client.PointerEvent(ButtonRight, 200, 100)     // Right button down
client.PointerEvent(0, 200, 100)               // Button up

// Drag operation (left button held while moving)
client.PointerEvent(ButtonLeft, 100, 100)      // Start drag
client.PointerEvent(ButtonLeft, 120, 120)      // Drag to new position
client.PointerEvent(ButtonLeft, 140, 140)      // Continue dragging
client.PointerEvent(0, 140, 140)               // End drag (release button)

Scroll wheel events:

// Scroll up (wheel away from user)
client.PointerEvent(Button4, x, y)
client.PointerEvent(0, x, y)

// Scroll down (wheel toward user)
client.PointerEvent(Button5, x, y)
client.PointerEvent(0, x, y)

Multiple buttons simultaneously:

// Left and right buttons pressed together
mask := ButtonLeft | ButtonRight
client.PointerEvent(mask, x, y)
client.PointerEvent(0, x, y) // Release both buttons

Helper functions for common operations:

func (c *ClientConn) MouseMove(x, y uint16) error {
	return c.PointerEvent(0, x, y)
}

func (c *ClientConn) LeftClick(x, y uint16) error {
	if err := c.PointerEvent(ButtonLeft, x, y); err != nil {
		return err
	}
	return c.PointerEvent(0, x, y)
}

func (c *ClientConn) ScrollUp(x, y uint16) error {
	if err := c.PointerEvent(Button4, x, y); err != nil {
		return err
	}
	return c.PointerEvent(0, x, y)
}

Coordinate system: Mouse coordinates are relative to the framebuffer origin (0,0) at the top-left corner. Valid coordinates range from (0,0) to (FrameBufferWidth-1, FrameBufferHeight-1). Coordinates outside this range may be clamped or ignored by the server.

func (*ClientConn) SetEncodings

func (c *ClientConn) SetEncodings(encs []Encoding) error

SetEncodings configures which encoding types the client supports for framebuffer updates. This method implements the SetEncodings message as defined in RFC 6143 Section 7.5.2, informing the server about the client's encoding capabilities and preferences.

The server will use this information to select appropriate encodings when sending framebuffer updates, potentially choosing different encodings for different rectangles based on content characteristics and bandwidth considerations.

The encodings are specified in preference order - the server will prefer encodings that appear earlier in the slice when multiple options are suitable. The Raw encoding is always supported as a fallback and does not need to be explicitly included.

Parameters:

  • encs: Slice of supported encodings in preference order (most preferred first)

Returns:

  • error: NetworkError if the encoding list cannot be sent to the server

Example usage:

// Basic encoding support (Raw is always supported)
encodings := []Encoding{
	&RawEncoding{},
}
err := client.SetEncodings(encodings)

// Multiple encodings in preference order
encodings := []Encoding{
	&HextileEncoding{},    // Preferred for mixed content
	&CopyRectEncoding{},   // Efficient for window movement
	&RREEncoding{},        // Good for simple graphics
	&RawEncoding{},        // Fallback for complex content
}
err := client.SetEncodings(encodings)

Encoding selection strategy:

// Optimize for bandwidth (slower connections)
encodings := []Encoding{
	&ZRLEEncoding{},       // Best compression
	&HextileEncoding{},    // Good compression
	&RREEncoding{},        // Moderate compression
	&RawEncoding{},        // No compression (fallback)
}

// Optimize for speed (fast connections)
encodings := []Encoding{
	&CopyRectEncoding{},   // Fastest for window operations
	&RawEncoding{},        // Fast for complex content
	&HextileEncoding{},    // Moderate speed/compression balance
}

Pseudo-encodings for additional features:

encodings := []Encoding{
	&HextileEncoding{},
	&RawEncoding{},
	&CursorPseudoEncoding{},     // Client-side cursor rendering
	&DesktopSizePseudoEncoding{}, // Dynamic desktop resizing
}

Important considerations: - The provided slice should not be modified after calling this method - Raw encoding support is mandatory and always available as fallback - Pseudo-encodings provide additional features beyond pixel data - Encoding preferences affect bandwidth usage and rendering performance - Some servers may not support all encoding types

The method updates the connection's Encs field to reflect the configured encodings, which can be inspected to verify the current encoding configuration.

func (*ClientConn) SetPixelFormat

func (c *ClientConn) SetPixelFormat(format *PixelFormat) error

SetPixelFormat configures the pixel format used for framebuffer updates from the server. This method implements the SetPixelFormat message as defined in RFC 6143 Section 7.5.1, allowing the client to specify how pixel color data should be encoded in subsequent framebuffer updates.

Changing the pixel format affects all future framebuffer updates and can be used to optimize for different display characteristics, color depths, or bandwidth requirements. The server will convert its internal pixel representation to match the requested format.

When the pixel format is changed to indexed color mode (TrueColor=false), the connection's color map is automatically reset, and the server may send SetColorMapEntries messages to populate the new color map.

Parameters:

  • format: The desired pixel format specification

Returns:

  • error: EncodingError if the format cannot be encoded, NetworkError for transmission issues

Example usage:

// 32-bit true color RGBA (high quality, more bandwidth)
format := &PixelFormat{
	BPP: 32, Depth: 24, BigEndian: false, TrueColor: true,
	RedMax: 255, GreenMax: 255, BlueMax: 255,
	RedShift: 16, GreenShift: 8, BlueShift: 0,
}
err := client.SetPixelFormat(format)

// 16-bit true color RGB565 (balanced quality/bandwidth)
format := &PixelFormat{
	BPP: 16, Depth: 16, BigEndian: false, TrueColor: true,
	RedMax: 31, GreenMax: 63, BlueMax: 31,
	RedShift: 11, GreenShift: 5, BlueShift: 0,
}
err := client.SetPixelFormat(format)

// 8-bit indexed color (low bandwidth, limited colors)
format := &PixelFormat{
	BPP: 8, Depth: 8, BigEndian: false, TrueColor: false,
}
err := client.SetPixelFormat(format)

Bandwidth optimization:

// For slow connections - use 8-bit indexed color
lowBandwidthFormat := &PixelFormat{
	BPP: 8, Depth: 8, TrueColor: false,
}

// For fast connections - use 32-bit true color
highQualityFormat := &PixelFormat{
	BPP: 32, Depth: 24, TrueColor: true,
	RedMax: 255, GreenMax: 255, BlueMax: 255,
	RedShift: 16, GreenShift: 8, BlueShift: 0,
}

Color depth considerations: - 32-bit: Best quality, highest bandwidth usage - 16-bit: Good quality, moderate bandwidth usage - 8-bit: Limited colors (256), lowest bandwidth usage - True color: Direct RGB values, more colors available - Indexed color: Uses color map, limited to 256 simultaneous colors

Performance impact: - Higher bit depths provide better color accuracy but use more bandwidth - Indexed color modes require color map synchronization - Format changes may cause temporary visual artifacts during transition - Some servers may perform better with specific pixel formats

The method automatically resets the color map when switching to indexed color mode, as the previous color map may not be compatible with the new pixel format.

type ClientOption

type ClientOption func(*ClientConfig)

ClientOption represents a functional option for configuring a VNC client connection.

func WithAuth

func WithAuth(auth ...ClientAuth) ClientOption

WithAuth sets the authentication methods for the client connection. The methods are tried in the order provided during server negotiation.

func WithAuthRegistry

func WithAuthRegistry(registry *AuthRegistry) ClientOption

WithAuthRegistry sets a custom authentication registry for the client. This allows registration of custom authentication methods beyond the defaults.

func WithConnectTimeout

func WithConnectTimeout(timeout time.Duration) ClientOption

WithConnectTimeout sets the timeout for the initial connection handshake. This includes protocol negotiation, security handshake, and initialization.

func WithExclusive

func WithExclusive(exclusive bool) ClientOption

WithExclusive sets whether the client should request exclusive access to the server. When true, other clients will be disconnected when this client connects.

func WithLogger

func WithLogger(logger Logger) ClientOption

WithLogger sets the logger for the client connection. Use NoOpLogger to disable logging or provide a custom implementation.

func WithMetrics

func WithMetrics(metrics MetricsCollector) ClientOption

WithMetrics sets the metrics collector for connection monitoring. Use NoOpMetrics to disable metrics collection or provide a custom implementation.

func WithReadTimeout

func WithReadTimeout(timeout time.Duration) ClientOption

WithReadTimeout sets the timeout for individual read operations. This applies to reading server messages and framebuffer data.

func WithServerMessageChannel

func WithServerMessageChannel(ch chan<- ServerMessage) ClientOption

WithServerMessageChannel sets the channel where server messages will be delivered. The channel should be buffered to prevent blocking the message processing loop.

func WithServerMessages

func WithServerMessages(messages ...ServerMessage) ClientOption

WithServerMessages sets additional custom server message types. These will be registered alongside the standard VNC message types.

func WithTimeout

func WithTimeout(timeout time.Duration) ClientOption

WithTimeout sets both read and write timeouts to the same value. This is a convenience function for setting both timeouts at once.

func WithWriteTimeout

func WithWriteTimeout(timeout time.Duration) ClientOption

WithWriteTimeout sets the timeout for individual write operations. This applies to sending client messages like key events and pointer events.

type Color

type Color struct {
	// R is the red color component value (0-65535).
	R uint16

	// G is the green color component value (0-65535).
	G uint16

	// B is the blue color component value (0-65535).
	B uint16
}

Color represents an RGB color value used in VNC color maps and pixel data.

type ColorFormatConverter

type ColorFormatConverter struct{}

ColorFormatConverter provides utilities for converting between different color formats and performing color space transformations.

func NewColorFormatConverter

func NewColorFormatConverter() *ColorFormatConverter

NewColorFormatConverter creates a new color format converter. Used for converting between different color formats and performing color space transformations.

func (*ColorFormatConverter) ColorToHSV

func (c *ColorFormatConverter) ColorToHSV(color Color) (h, s, v float64)

ColorToHSV converts RGB Color to HSV (Hue, Saturation, Value). Returns H in degrees (0-360), S and V as percentages (0-100).

func (*ColorFormatConverter) ColorToRGB8

func (c *ColorFormatConverter) ColorToRGB8(color Color) (r, g, b uint8)

ColorToRGB8 converts a 16-bit Color to 8-bit RGB values.

func (*ColorFormatConverter) ColorToRGB16

func (c *ColorFormatConverter) ColorToRGB16(color Color) (r, g, b uint16)

ColorToRGB16 extracts 16-bit RGB values from a Color.

func (*ColorFormatConverter) HSVToColor

func (c *ColorFormatConverter) HSVToColor(h, s, v float64) Color

HSVToColor converts HSV (Hue, Saturation, Value) to RGB Color. H is in degrees (0-360), S and V are percentages (0-100).

func (*ColorFormatConverter) RGB8ToColor

func (c *ColorFormatConverter) RGB8ToColor(r, g, b uint8) Color

RGB8ToColor converts 8-bit RGB values to a 16-bit Color.

func (*ColorFormatConverter) RGB16ToColor

func (c *ColorFormatConverter) RGB16ToColor(r, g, b uint16) Color

RGB16ToColor converts 16-bit RGB values to a Color.

type ColorMap

type ColorMap struct {
	// contains filtered or unexported fields
}

ColorMap represents a thread-safe color map for indexed color modes. It provides efficient access and updates with proper synchronization for concurrent operations.

func NewColorMap

func NewColorMap() *ColorMap

NewColorMap creates a new color map initialized with default grayscale colors. The default color map provides a reasonable fallback for indexed color modes.

func (*ColorMap) Copy

func (cm *ColorMap) Copy() *ColorMap

Copy creates a deep copy of the color map.

func (*ColorMap) FromArray

func (cm *ColorMap) FromArray(colors [ColorMapSize]Color)

FromArray updates the color map from a fixed-size array.

func (*ColorMap) Get

func (cm *ColorMap) Get(index uint8) Color

Get retrieves the color at the specified index from the color map.

func (*ColorMap) GetRange

func (cm *ColorMap) GetRange(startIndex uint16, count uint16) ([]Color, error)

GetRange retrieves multiple consecutive color map entries starting at the specified index. This method is thread-safe and provides efficient bulk access.

func (*ColorMap) Set

func (cm *ColorMap) Set(index uint8, color Color)

Set updates the color at the specified index in the color map.

func (*ColorMap) SetRange

func (cm *ColorMap) SetRange(startIndex uint16, colors []Color) error

SetRange updates multiple consecutive color map entries starting at the specified index. This method is thread-safe and provides efficient bulk updates.

func (*ColorMap) ToArray

func (cm *ColorMap) ToArray() [ColorMapSize]Color

ToArray returns the color map as a fixed-size array.

type ColorMapValidationError

type ColorMapValidationError struct {
	Index   uint16
	Value   interface{}
	Rule    string
	Message string
}

ColorMapValidationError represents a color map validation error with detailed context.

func (*ColorMapValidationError) Error

func (e *ColorMapValidationError) Error() string

Error returns the formatted error message for color map validation errors.

type CopyRectEncoding

type CopyRectEncoding struct {
	// SrcX is the X coordinate of the source rectangle's top-left corner.
	// This specifies the horizontal position within the framebuffer from
	// which pixels should be copied to the destination rectangle.
	SrcX uint16

	// SrcY is the Y coordinate of the source rectangle's top-left corner.
	// This specifies the vertical position within the framebuffer from
	// which pixels should be copied to the destination rectangle.
	SrcY uint16
}

CopyRectEncoding represents the CopyRect encoding as defined in RFC 6143 Section 7.7.2. This encoding is used to efficiently update screen regions by copying pixel data from another location within the same framebuffer, rather than transmitting new pixel data.

CopyRect is particularly efficient for operations like window movement, scrolling, or any scenario where screen content is moved from one location to another without modification. Instead of sending the actual pixel data, the server only needs to send the source coordinates from which to copy the pixels.

The encoding provides significant bandwidth savings when large areas of the screen are moved, as only 4 bytes of coordinate data are transmitted regardless of the rectangle size, compared to width × height × bytes-per-pixel for raw encoding.

Example usage scenarios: - Moving windows across the desktop - Scrolling content within applications - Drag and drop operations - Any operation that relocates existing screen content

Wire format: The CopyRect encoding data consists of exactly 4 bytes:

[2 bytes] - Source X coordinate (big-endian uint16)
[2 bytes] - Source Y coordinate (big-endian uint16)

The source coordinates specify the top-left corner of the source rectangle from which pixels should be copied. The dimensions of the source rectangle are identical to the destination rectangle specified in the Rectangle header.

func (*CopyRectEncoding) Read

func (*CopyRectEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error)

Read decodes CopyRect encoding data from the server for the specified rectangle. This method implements the Encoding interface and processes CopyRect encoding as defined in RFC 6143 Section 7.7.2. It reads the source coordinates from which pixels should be copied within the framebuffer.

The CopyRect encoding is unique among VNC encodings because it doesn't contain actual pixel data. Instead, it specifies coordinates within the existing framebuffer from which to copy pixels to the destination rectangle.

Parameters:

  • c: The client connection (unused for CopyRect but required by interface)
  • rect: The destination rectangle specifying where the copied pixels should be placed
  • r: Reader containing the CopyRect encoding data (4 bytes: source X and Y coordinates)

Returns:

  • Encoding: A new CopyRectEncoding instance containing the source coordinates
  • error: EncodingError if the coordinate data cannot be read

Example usage:

// This method is typically called by the VNC client's message processing loop
enc := &CopyRectEncoding{}
decodedEnc, err := enc.Read(clientConn, rectangle, dataReader)
if err != nil {
	log.Printf("Failed to decode CopyRect encoding: %v", err)
	return
}

// Process the CopyRect operation
copyRectEnc := decodedEnc.(*CopyRectEncoding)
fmt.Printf("Copy from (%d,%d) to (%d,%d) size %dx%d\n",
	copyRectEnc.SrcX, copyRectEnc.SrcY,
	rectangle.X, rectangle.Y,
	rectangle.Width, rectangle.Height)

// Perform the copy operation on the local framebuffer
copyFramebufferRegion(
	copyRectEnc.SrcX, copyRectEnc.SrcY,    // Source
	rectangle.X, rectangle.Y,              // Destination
	rectangle.Width, rectangle.Height)     // Dimensions

Implementation considerations:

// The copy operation should handle overlapping regions correctly:
func copyFramebufferRegion(srcX, srcY, dstX, dstY, width, height uint16) {
	// For overlapping regions, copy direction matters to avoid corruption
	if srcY < dstY || (srcY == dstY && srcX < dstX) {
		// Copy from bottom-right to top-left to avoid overwriting source data
		copyBackward(srcX, srcY, dstX, dstY, width, height)
	} else {
		// Copy from top-left to bottom-right (normal case)
		copyForward(srcX, srcY, dstX, dstY, width, height)
	}
}

Validation considerations:

// Ensure source rectangle is within framebuffer bounds:
if copyRectEnc.SrcX + rectangle.Width > framebufferWidth ||
   copyRectEnc.SrcY + rectangle.Height > framebufferHeight {
	// Handle out-of-bounds source rectangle
	return fmt.Errorf("source rectangle extends beyond framebuffer")
}

Performance characteristics: - Extremely efficient: only 4 bytes transmitted regardless of rectangle size - Copy operation performance depends on local framebuffer implementation - No network bandwidth used for pixel data transmission - Ideal for large rectangle moves (windows, scrolling)

Error conditions: The method returns an EncodingError if: - Insufficient data is available in the reader (less than 4 bytes) - I/O errors occur while reading coordinate data - Network connection issues during data reading

Wire format details:

// Byte layout in network stream:
// Offset 0-1: Source X coordinate (big-endian uint16)
// Offset 2-3: Source Y coordinate (big-endian uint16)
// Total size: 4 bytes

// Example: Copy from (100, 200) to destination rectangle
// Wire bytes: [0x00, 0x64, 0x00, 0xC8]
//             |  100   |  200   |

func (*CopyRectEncoding) Type

func (*CopyRectEncoding) Type() int32

Type returns the encoding type identifier for CopyRect encoding.

type CursorPseudoEncoding

type CursorPseudoEncoding struct {
	// Width is the width of the cursor in pixels.
	// A width of 0 indicates that the cursor should be hidden.
	Width uint16

	// Height is the height of the cursor in pixels.
	// A height of 0 indicates that the cursor should be hidden.
	Height uint16

	// HotspotX is the horizontal offset from the cursor's left edge to the hotspot.
	// This represents the active point of the cursor (e.g., the tip of an arrow).
	HotspotX uint16

	// HotspotY is the vertical offset from the cursor's top edge to the hotspot.
	// This represents the active point of the cursor (e.g., the tip of an arrow).
	HotspotY uint16

	// PixelData contains the cursor image data in the current pixel format.
	// The data is organized in row-major order (left-to-right, top-to-bottom).
	// The length is width × height × bytes-per-pixel.
	PixelData []uint8

	// MaskData contains the transparency mask for the cursor.
	// Each bit represents one pixel: 1 = opaque, 0 = transparent.
	// The data is organized in row-major order with bits packed into bytes.
	// The length is ceil(width/8) × height bytes.
	MaskData []uint8
}

CursorPseudoEncoding represents the Cursor pseudo-encoding as defined in RFC 6143. Allows the server to send cursor shape and hotspot information to the client.

func (*CursorPseudoEncoding) Handle

func (cursor *CursorPseudoEncoding) Handle(c *ClientConn, rect *Rectangle) error

Handle processes the cursor pseudo-encoding by updating the client's cursor state. This method implements the PseudoEncoding interface and provides a way to handle cursor updates without requiring the application to manually process the encoding data.

The method updates the client connection's cursor state and can trigger cursor visibility changes or cursor shape updates based on the encoding data.

Parameters:

  • c: The client connection to update
  • rect: The rectangle containing cursor position and dimensions (unused for cursor)

Returns:

  • error: Always returns nil for cursor pseudo-encoding (no processing errors expected)

Example usage:

// This method is typically called automatically by the VNC client
cursorEnc := &CursorPseudoEncoding{...}
err := cursorEnc.Handle(clientConn, rectangle)
if err != nil {
	log.Printf("Failed to handle cursor update: %v", err)
}

Note: This is a basic implementation that logs the cursor update. Applications should extend this to integrate with their cursor management system.

func (*CursorPseudoEncoding) IsPseudo

func (*CursorPseudoEncoding) IsPseudo() bool

IsPseudo returns true indicating this is a pseudo-encoding.

func (*CursorPseudoEncoding) Read

Read decodes Cursor pseudo-encoding data from the server for the specified rectangle. This method implements the Encoding interface and processes cursor shape data including pixel data, transparency mask, and hotspot coordinates.

The rectangle's X and Y coordinates represent the cursor hotspot offset, while Width and Height represent the cursor dimensions. A cursor with width=0 and height=0 indicates that the cursor should be hidden.

Parameters:

  • c: The client connection providing pixel format information
  • rect: The rectangle containing cursor dimensions and hotspot coordinates
  • r: Reader containing the cursor pixel data and mask

Returns:

  • Encoding: A new CursorPseudoEncoding instance containing the cursor data
  • error: EncodingError if the cursor data cannot be read or is invalid

Example usage:

// This method is typically called by the VNC client's message processing loop
enc := &CursorPseudoEncoding{}
decodedEnc, err := enc.Read(clientConn, rectangle, dataReader)
if err != nil {
	log.Printf("Failed to decode cursor pseudo-encoding: %v", err)
	return
}

// Process the cursor update
cursorEnc := decodedEnc.(*CursorPseudoEncoding)
if cursorEnc.Width == 0 && cursorEnc.Height == 0 {
	// Hide cursor
	hideCursor()
} else {
	// Update cursor shape
	updateCursor(cursorEnc.PixelData, cursorEnc.MaskData,
		cursorEnc.Width, cursorEnc.Height,
		cursorEnc.HotspotX, cursorEnc.HotspotY)
}

Cursor rendering example:

func updateCursor(pixelData, maskData []uint8, width, height, hotspotX, hotspotY uint16) {
	// Create cursor bitmap from pixel data and mask
	cursor := createCursorBitmap(pixelData, maskData, width, height)

	// Set cursor hotspot
	cursor.SetHotspot(int(hotspotX), int(hotspotY))

	// Apply cursor to window/display
	window.SetCursor(cursor)
}

Mask processing example:

func processCursorMask(maskData []uint8, width, height uint16) []bool {
	mask := make([]bool, width*height)
	bytesPerRow := (width + 7) / 8

	for y := uint16(0); y < height; y++ {
		for x := uint16(0); x < width; x++ {
			byteIndex := y*bytesPerRow + x/8
			bitIndex := 7 - (x % 8)
			mask[y*width+x] = (maskData[byteIndex] & (1 << bitIndex)) != 0
		}
	}
	return mask
}

Error conditions: The method returns an EncodingError if: - Insufficient pixel data is available (less than width × height × bytes-per-pixel) - Insufficient mask data is available (less than ceil(width/8) × height) - I/O errors occur while reading cursor data - Invalid cursor dimensions (width or height too large).

func (*CursorPseudoEncoding) Type

func (*CursorPseudoEncoding) Type() int32

Type returns the encoding type identifier for Cursor pseudo-encoding.

type DesktopSizePseudoEncoding

type DesktopSizePseudoEncoding struct {
	// Width is the new framebuffer width in pixels.
	Width uint16

	// Height is the new framebuffer height in pixels.
	Height uint16
}

DesktopSizePseudoEncoding represents the DesktopSize pseudo-encoding. Allows the server to notify the client when the framebuffer size changes dynamically.

func (*DesktopSizePseudoEncoding) Handle

func (desktop *DesktopSizePseudoEncoding) Handle(c *ClientConn, rect *Rectangle) error

Handle processes the desktop size pseudo-encoding by updating the client's framebuffer dimensions. This method implements the PseudoEncoding interface and automatically updates the client connection's framebuffer size when a desktop resize occurs.

The method updates the client connection's FrameBufferWidth and FrameBufferHeight fields to reflect the new desktop dimensions. Applications can then respond to the size change by resizing their display windows, updating viewports, or requesting new framebuffer data.

Parameters:

  • c: The client connection to update with new framebuffer dimensions
  • rect: The rectangle containing position information (unused for desktop size)

Returns:

  • error: Always returns nil for desktop size pseudo-encoding (no processing errors expected)

Example usage:

// This method is typically called automatically by the VNC client
desktopSizeEnc := &DesktopSizePseudoEncoding{Width: 1920, Height: 1080}
err := desktopSizeEnc.Handle(clientConn, rectangle)
if err != nil {
	log.Printf("Failed to handle desktop size update: %v", err)
}

// After handling, the client connection will have updated dimensions:
fmt.Printf("New framebuffer size: %dx%d\n",
	clientConn.FrameBufferWidth, clientConn.FrameBufferHeight)

Integration with application:

// Applications can monitor for desktop size changes:
func monitorDesktopSize(client *ClientConn) {
	oldWidth, oldHeight := client.FrameBufferWidth, client.FrameBufferHeight

	// Check periodically or in message handler
	if client.FrameBufferWidth != oldWidth || client.FrameBufferHeight != oldHeight {
		// Handle desktop size change
		handleDesktopResize(client.FrameBufferWidth, client.FrameBufferHeight)
		oldWidth, oldHeight = client.FrameBufferWidth, client.FrameBufferHeight
	}
}

Note: Applications should typically request a full framebuffer update after a desktop size change to refresh the display content for the new dimensions.

func (*DesktopSizePseudoEncoding) IsPseudo

func (*DesktopSizePseudoEncoding) IsPseudo() bool

IsPseudo returns true indicating this is a pseudo-encoding.

func (*DesktopSizePseudoEncoding) Read

Read decodes DesktopSize pseudo-encoding data from the server.

func (*DesktopSizePseudoEncoding) Type

Type returns the encoding type identifier for DesktopSize pseudo-encoding.

type Encoding

type Encoding interface {
	Type() int32
	Read(*ClientConn, *Rectangle, io.Reader) (Encoding, error)
}

Encoding defines the interface for VNC framebuffer encoding methods.

type ErrorCode

type ErrorCode int

ErrorCode represents specific error categories for VNC operations.

const (
	// ErrProtocol indicates a protocol-level error.
	ErrProtocol ErrorCode = iota
	// ErrAuthentication indicates an authentication failure.
	ErrAuthentication
	// ErrEncoding indicates an encoding/decoding error.
	ErrEncoding
	// ErrNetwork indicates a network-related error.
	ErrNetwork
	// ErrConfiguration indicates a configuration error.
	ErrConfiguration
	// ErrTimeout indicates a timeout error.
	ErrTimeout
	// ErrValidation indicates input validation failure.
	ErrValidation
	// ErrUnsupported indicates an unsupported feature or operation.
	ErrUnsupported
)

func GetErrorCode

func GetErrorCode(err error) ErrorCode

GetErrorCode extracts the error code from a VNCError. Returns the error code if the error is a VNCError, otherwise returns -1.

func (ErrorCode) String

func (e ErrorCode) String() string

String returns the string representation of the error code.

type Field

type Field struct {
	Key   string
	Value interface{}
}

Field represents a structured logging field with a key-value pair.

type FramebufferUpdateMessage

type FramebufferUpdateMessage struct {
	// Rectangles contains the list of screen rectangles being updated.
	Rectangles []Rectangle
}

FramebufferUpdateMessage represents a framebuffer update from the server (message type 0).

func (*FramebufferUpdateMessage) Read

Read parses a FramebufferUpdate message from the server. This method implements the ServerMessage interface and processes framebuffer update data as defined in RFC 6143 Section 7.6.1. It reads one or more rectangles of pixel data, each potentially using different encoding methods.

The method handles the complete message parsing including:

  1. Reading the message padding and rectangle count
  2. For each rectangle: position, dimensions, and encoding type
  3. Delegating encoding-specific decoding to the appropriate Encoding implementation
  4. Building a complete FramebufferUpdateMessage with all decoded rectangles

Parameters:

  • c: The client connection providing encoding support and state information
  • r: Reader containing the message data (excluding the message type byte)

Returns:

  • ServerMessage: A new FramebufferUpdateMessage containing all decoded rectangles
  • error: NetworkError for I/O issues, UnsupportedError for unknown encodings, EncodingError for decoding failures

Example usage:

// This method is typically called by the VNC client's message processing loop
msg := &FramebufferUpdateMessage{}
parsedMsg, err := msg.Read(clientConn, messageReader)
if err != nil {
	log.Printf("Failed to parse framebuffer update: %v", err)
	return
}

// Process the parsed message
fbUpdate := parsedMsg.(*FramebufferUpdateMessage)
for _, rect := range fbUpdate.Rectangles {
	fmt.Printf("Rectangle at (%d,%d) size %dx%d using encoding %d\n",
		rect.X, rect.Y, rect.Width, rect.Height, rect.Enc.Type())

	// Apply rectangle to local framebuffer
	switch enc := rect.Enc.(type) {
	case *RawEncoding:
		// Handle raw pixel data
		applyRawPixels(rect, enc.Colors)
	case *CopyRectEncoding:
		// Handle copy rectangle operation
		applyCopyRect(rect, enc)
	}
}

Encoding support:

// The method uses the client's configured encodings plus mandatory Raw encoding
// Supported encodings are determined by previous SetEncodings calls:
clientConn.SetEncodings([]Encoding{
	&HextileEncoding{},
	&CopyRectEncoding{},
	&RawEncoding{}, // Always supported as fallback
})

Message structure:

// Wire format (after message type byte):
// [1 byte]  - Padding (ignored)
// [2 bytes] - Number of rectangles (big-endian uint16)
// For each rectangle:
//   [2 bytes] - X position (big-endian uint16)
//   [2 bytes] - Y position (big-endian uint16)
//   [2 bytes] - Width (big-endian uint16)
//   [2 bytes] - Height (big-endian uint16)
//   [4 bytes] - Encoding type (big-endian int32)
//   [variable] - Encoding-specific pixel data

Error handling: The method may return various error types:

  • NetworkError: I/O failures reading message data
  • UnsupportedError: Unknown or unsupported encoding type encountered
  • EncodingError: Failure decoding rectangle pixel data
  • All errors include context about which rectangle or operation failed

Performance considerations: - Large updates with many rectangles may consume significant memory - Different encodings have varying decode performance characteristics - Rectangle processing is sequential and may benefit from parallel decoding - Memory usage scales with total pixel count across all rectangles.

func (*FramebufferUpdateMessage) Type

Type returns the message type identifier for framebuffer update messages.

type HextileEncoding

type HextileEncoding struct {
	Tiles []HextileTile
}

HextileEncoding represents the Hextile encoding as defined in RFC 6143 Section 7.7.4. Hextile divides rectangles into 16x16 pixel tiles and applies different compression techniques to each tile based on its content.

func (*HextileEncoding) Read

func (*HextileEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error)

Read decodes Hextile encoding data from the server.

  • error: EncodingError if the data cannot be read or is invalid

Example usage:

// This method is typically called by the VNC client's message processing loop
enc := &HextileEncoding{}
decodedEnc, err := enc.Read(clientConn, rectangle, dataReader)
if err != nil {
	log.Printf("Failed to decode Hextile encoding: %v", err)
	return
}

// Process the Hextile encoding
hextileEnc := decodedEnc.(*HextileEncoding)

// Render each tile to the framebuffer
tileIndex := 0
for tileY := uint16(0); tileY < rectangle.Height; tileY += 16 {
	for tileX := uint16(0); tileX < rectangle.Width; tileX += 16 {
		tile := hextileEnc.Tiles[tileIndex]
		renderTile(rectangle.X + tileX, rectangle.Y + tileY, tile)
		tileIndex++
	}
}

func (*HextileEncoding) Type

func (*HextileEncoding) Type() int32

Type returns the encoding type identifier for Hextile encoding.

type HextileSubrectangle

type HextileSubrectangle struct {
	// Color is the color of this subrectangle.
	Color Color

	// X is the horizontal position within the tile (0-15).
	X uint8

	// Y is the vertical position within the tile (0-15).
	Y uint8

	// Width is the width of the subrectangle (1-16).
	Width uint8

	// Height is the height of the subrectangle (1-16).
	Height uint8
}

HextileSubrectangle represents a colored subrectangle within a Hextile tile.

type HextileTile

type HextileTile struct {
	Width      uint16
	Height     uint16
	Background Color

	// Foreground color for this tile.
	Foreground Color

	// Colors contains decoded pixel data for raw tiles.
	Colors []Color

	// Subrectangles contains colored subrectangles for this tile.
	Subrectangles []HextileSubrectangle
}

HextileTile represents a single 16x16 (or smaller) tile within a Hextile encoding.

type InputValidator

type InputValidator struct{}

InputValidator validates network input data and prevents protocol vulnerabilities.

func (*InputValidator) SanitizeText

func (iv *InputValidator) SanitizeText(text string) string

SanitizeText sanitizes text data by removing or replacing potentially dangerous characters.

func (*InputValidator) ValidateBinaryData

func (iv *InputValidator) ValidateBinaryData(data []byte, expectedLength, maxLength int) error

ValidateBinaryData validates binary data for protocol messages.

func (*InputValidator) ValidateColorMapEntries

func (iv *InputValidator) ValidateColorMapEntries(firstColor, numColors, maxColors uint16) error

ValidateColorMapEntries validates color map entry data.

func (*InputValidator) ValidateEncodingType

func (iv *InputValidator) ValidateEncodingType(encodingType int32) error

ValidateEncodingType validates encoding type values.

func (*InputValidator) ValidateFramebufferDimensions

func (iv *InputValidator) ValidateFramebufferDimensions(width, height uint16) error

ValidateFramebufferDimensions validates framebuffer dimensions.

func (*InputValidator) ValidateKeySymbol

func (iv *InputValidator) ValidateKeySymbol(keysym uint32) error

ValidateKeySymbol validates X11 keysym values for key events.

func (*InputValidator) ValidateMessageLength

func (iv *InputValidator) ValidateMessageLength(length uint32, maxLength uint32) error

ValidateMessageLength validates message length fields to prevent overflow.

func (*InputValidator) ValidatePixelFormat

func (iv *InputValidator) ValidatePixelFormat(pf *PixelFormat) error

ValidatePixelFormat validates a VNC pixel format structure.

func (*InputValidator) ValidatePointerPosition

func (iv *InputValidator) ValidatePointerPosition(x, y, fbWidth, fbHeight uint16) error

ValidatePointerPosition validates pointer coordinates against framebuffer bounds.

func (*InputValidator) ValidateProtocolVersion

func (iv *InputValidator) ValidateProtocolVersion(version string) error

ValidateProtocolVersion validates VNC protocol version strings.

func (*InputValidator) ValidateRectangle

func (iv *InputValidator) ValidateRectangle(x, y, width, height, fbWidth, fbHeight uint16) error

ValidateRectangle validates rectangle bounds against framebuffer dimensions.

func (*InputValidator) ValidateSecurityType

func (iv *InputValidator) ValidateSecurityType(securityType uint8) error

ValidateSecurityType validates a VNC security type identifier.

func (*InputValidator) ValidateSecurityTypes

func (iv *InputValidator) ValidateSecurityTypes(securityTypes []uint8) error

ValidateSecurityTypes validates an array of VNC security types.

func (*InputValidator) ValidateTextData

func (iv *InputValidator) ValidateTextData(text string, maxLength int) error

ValidateTextData validates text data for clipboard operations.

type Logger

type Logger interface {
	// Debug logs debug-level messages with optional structured fields.
	Debug(msg string, fields ...Field)

	// Info logs info-level messages with optional structured fields.
	Info(msg string, fields ...Field)

	// Warn logs warning-level messages with optional structured fields.
	Warn(msg string, fields ...Field)

	// Error logs error-level messages with optional structured fields.
	Error(msg string, fields ...Field)

	// With creates a new logger instance with the provided fields pre-populated.
	With(fields ...Field) Logger
}

Logger defines the interface for structured logging throughout the VNC library.

type MemoryProtection

type MemoryProtection struct {
	// contains filtered or unexported fields
}

MemoryProtection provides utilities for protecting sensitive data in memory.

func (*MemoryProtection) NewProtectedBytes

func (mp *MemoryProtection) NewProtectedBytes(size int) *ProtectedBytes

NewProtectedBytes creates a new protected byte slice.

Parameters:

  • size: The size of the protected byte slice

Returns:

  • *ProtectedBytes: The protected byte slice

Security considerations: - Automatically clears data when no longer needed - Use defer Clear() to ensure cleanup - Suitable for storing sensitive cryptographic data.

type MetricsCollector

type MetricsCollector interface {
	Counter(name string, tags ...interface{}) interface{}
	Gauge(name string, tags ...interface{}) interface{}
	Histogram(name string, tags ...interface{}) interface{}
}

MetricsCollector defines the interface for collecting metrics and observability data.

type NoOpLogger

type NoOpLogger struct{}

NoOpLogger is a Logger implementation that discards all log messages.

func (*NoOpLogger) Debug

func (l *NoOpLogger) Debug(msg string, fields ...Field)

Debug discards debug-level log messages.

func (*NoOpLogger) Error

func (l *NoOpLogger) Error(msg string, fields ...Field)

Error discards error-level log messages.

func (*NoOpLogger) Info

func (l *NoOpLogger) Info(msg string, fields ...Field)

Info discards info-level log messages.

func (*NoOpLogger) Warn

func (l *NoOpLogger) Warn(msg string, fields ...Field)

Warn discards warning-level log messages.

func (*NoOpLogger) With

func (l *NoOpLogger) With(fields ...Field) Logger

With returns a new NoOpLogger instance (ignores fields).

type NoOpMetrics

type NoOpMetrics struct{}

NoOpMetrics is a MetricsCollector implementation that discards all metrics.

func (*NoOpMetrics) Counter

func (m *NoOpMetrics) Counter(name string, tags ...interface{}) interface{}

Counter returns a no-op counter metric.

func (*NoOpMetrics) Gauge

func (m *NoOpMetrics) Gauge(name string, tags ...interface{}) interface{}

Gauge returns a no-op gauge metric.

func (*NoOpMetrics) Histogram

func (m *NoOpMetrics) Histogram(name string, tags ...interface{}) interface{}

Histogram returns a no-op histogram metric.

type PasswordAuth

type PasswordAuth struct {
	Password string
	// contains filtered or unexported fields
}

PasswordAuth implements VNC Authentication (security type 2).

func NewPasswordAuth

func NewPasswordAuth(password string) *PasswordAuth

NewPasswordAuth creates a new PasswordAuth instance with enhanced security features.

func (*PasswordAuth) ClearPassword

func (p *PasswordAuth) ClearPassword()

ClearPassword securely clears the password from memory.

func (*PasswordAuth) Handshake

func (p *PasswordAuth) Handshake(ctx context.Context, c net.Conn) error

Handshake performs the VNC Authentication handshake with the server.

func (*PasswordAuth) SecurityType

func (p *PasswordAuth) SecurityType() uint8

SecurityType returns the security type identifier for VNC Password authentication.

func (*PasswordAuth) SetLogger

func (p *PasswordAuth) SetLogger(logger Logger)

SetLogger sets the logger for the authentication method.

func (*PasswordAuth) String

func (p *PasswordAuth) String() string

String returns a human-readable description of the authentication method.

type PixelFormat

type PixelFormat struct {
	// BPP (bits-per-pixel) specifies how many bits are used to represent each pixel.
	BPP uint8

	// Depth specifies the number of useful bits within each pixel value.
	Depth uint8

	// BigEndian determines the byte order for multi-byte pixel values.
	BigEndian bool

	// TrueColor determines whether pixels represent direct RGB values (true)
	// or indices into a color map (false).
	TrueColor bool

	// RedMax specifies the maximum value for the red color component.
	RedMax uint16

	// GreenMax specifies the maximum value for the green color component.
	GreenMax uint16

	// BlueMax specifies the maximum value for the blue color component.
	BlueMax uint16

	// RedShift specifies how many bits to right-shift a pixel value
	// to position the red color component at the least significant bits.
	RedShift uint8

	// GreenShift specifies how many bits to right-shift a pixel value
	// to position the green color component at the least significant bits.
	GreenShift uint8

	// BlueShift specifies how many bits to right-shift a pixel value
	// to position the blue color component at the least significant bits.
	BlueShift uint8
}

PixelFormat describes how pixel color data is encoded and interpreted in a VNC connection.

func (*PixelFormat) Validate

func (pf *PixelFormat) Validate() error

Validate performs comprehensive validation of a pixel format according to RFC 6143. It checks all fields for consistency and validity, returning detailed error information if any validation rules are violated.

type PixelFormatConverter

type PixelFormatConverter struct {
	// contains filtered or unexported fields
}

PixelFormatConverter provides utilities for converting between different pixel formats and extracting color components from pixel data.

func NewPixelFormatConverter

func NewPixelFormatConverter(format *PixelFormat) (*PixelFormatConverter, error)

NewPixelFormatConverter creates a new pixel format converter for the given format.

func (*PixelFormatConverter) BytesPerPixel

func (c *PixelFormatConverter) BytesPerPixel() int

BytesPerPixel returns the number of bytes per pixel for this format.

func (*PixelFormatConverter) CreatePixel

func (c *PixelFormatConverter) CreatePixel(r, g, b uint8) uint32

CreatePixel creates a pixel value from 8-bit RGB components according to the pixel format. The RGB values are scaled to match the pixel format's color depth.

func (*PixelFormatConverter) ExtractRGB

func (c *PixelFormatConverter) ExtractRGB(pixel uint32) (r, g, b uint8)

ExtractRGB extracts RGB color components from a pixel value according to the pixel format. Returns 8-bit RGB values (0-255) regardless of the source pixel format.

func (*PixelFormatConverter) ReadPixel

func (c *PixelFormatConverter) ReadPixel(r io.Reader) (uint32, error)

ReadPixel reads a single pixel from the reader according to the pixel format's byte order.

func (*PixelFormatConverter) WritePixel

func (c *PixelFormatConverter) WritePixel(w io.Writer, pixel uint32) error

WritePixel writes a single pixel to the writer according to the pixel format's byte order.

type PixelFormatValidationError

type PixelFormatValidationError struct {
	Field   string
	Value   interface{}
	Rule    string
	Message string
}

PixelFormatValidationError represents a pixel format validation error with detailed context.

func (*PixelFormatValidationError) Error

Error returns the formatted error message for pixel format validation errors.

type PixelReader

type PixelReader struct {
	// contains filtered or unexported fields
}

PixelReader provides utilities for reading pixel data from VNC streams.

func NewPixelReader

func NewPixelReader(pixelFormat PixelFormat, colorMap [ColorMapSize]Color) *PixelReader

NewPixelReader creates a new pixel reader for the given pixel format and color map.

func (*PixelReader) BytesPerPixel

func (pr *PixelReader) BytesPerPixel() int

BytesPerPixel returns the number of bytes per pixel for the current pixel format.

func (*PixelReader) ReadPixelColor

func (pr *PixelReader) ReadPixelColor(r io.Reader) (Color, error)

ReadPixelColor reads a single pixel from the reader and converts it to a Color. This consolidates the pixel reading logic that was duplicated across encoding files.

func (*PixelReader) ReadPixelData

func (pr *PixelReader) ReadPixelData(r io.Reader, size int) ([]uint8, error)

ReadPixelData reads raw pixel data without color conversion. Used by encodings that need the raw pixel bytes (like cursor encoding).

type ProtectedBytes

type ProtectedBytes struct {
	// contains filtered or unexported fields
}

ProtectedBytes represents a byte slice with automatic secure clearing.

func (*ProtectedBytes) Clear

func (pb *ProtectedBytes) Clear()

Clear securely clears the protected bytes from memory.

func (*ProtectedBytes) Copy

func (pb *ProtectedBytes) Copy(src []byte) error

Copy copies data into the protected byte slice.

Parameters:

  • src: The source data to copy

Returns:

  • error: Any error that occurred during copying

func (*ProtectedBytes) Data

func (pb *ProtectedBytes) Data() []byte

Data returns the protected byte slice.

func (*ProtectedBytes) IsCleared

func (pb *ProtectedBytes) IsCleared() bool

IsCleared returns true if the protected bytes have been cleared.

func (*ProtectedBytes) Size

func (pb *ProtectedBytes) Size() int

Size returns the size of the protected byte slice.

func (*ProtectedBytes) Zero

func (pb *ProtectedBytes) Zero()

Zero fills the protected bytes with zeros.

type PseudoEncoding

type PseudoEncoding interface {
	Encoding

	IsPseudo() bool
	Handle(*ClientConn, *Rectangle) error
}

PseudoEncoding defines the interface for VNC pseudo-encodings. Pseudo-encodings provide metadata or control information rather than pixel data.

type RREEncoding

type RREEncoding struct {
	BackgroundColor Color
	Subrectangles   []RRESubrectangle
}

RREEncoding represents the RRE (Rise-and-Run-length Encoding) as defined in RFC 6143 Section 7.7.3. RRE works by defining a background color and overlaying solid-color subrectangles.

func (*RREEncoding) Read

func (*RREEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error)

Read decodes RRE encoding data from the server.

	return
}

// Process the RRE encoding
rreEnc := decodedEnc.(*RREEncoding)

// Fill rectangle with background color
fillRectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height,
	rreEnc.BackgroundColor)

// Apply each subrectangle
for _, subrect := range rreEnc.Subrectangles {
	fillRectangle(rectangle.X + subrect.X, rectangle.Y + subrect.Y,
		subrect.Width, subrect.Height, subrect.Color)
}

Pixel format handling:

// The method handles different pixel formats automatically:
func readPixelColor(r io.Reader, pixelFormat PixelFormat) (Color, error) {
	bytesPerPixel := pixelFormat.BPP / 8
	pixelBytes := make([]byte, bytesPerPixel)

	if _, err := io.ReadFull(r, pixelBytes); err != nil {
		return Color{}, err
	}

	// Convert pixel bytes to Color based on pixel format
	return convertPixelToColor(pixelBytes, pixelFormat), nil
}

Validation and error handling:

// The method validates subrectangle bounds:
if subrect.X + subrect.Width > rectangle.Width ||
   subrect.Y + subrect.Height > rectangle.Height {
	return encodingError("invalid subrectangle bounds")
}

Performance considerations: - Decoding performance scales with the number of subrectangles - Memory usage depends on subrectangle count (typically small) - Rendering performance depends on the graphics system's rectangle fill efficiency - Best suited for images with few distinct color regions

Error conditions: The method returns an EncodingError if: - Insufficient data is available for the subrectangle count - Background color data cannot be read - Any subrectangle data is incomplete or invalid - Subrectangle bounds extend outside the parent rectangle - I/O errors occur during data reading.

func (*RREEncoding) Type

func (*RREEncoding) Type() int32

Type returns the encoding type identifier for RRE encoding.

type RRESubrectangle

type RRESubrectangle struct {
	// Color is the solid color that fills this subrectangle.
	// All pixels within the subrectangle bounds will be set to this color.
	Color Color

	// X is the horizontal position of the subrectangle's left edge,
	// relative to the parent rectangle's top-left corner (0-based).
	X uint16

	// Y is the vertical position of the subrectangle's top edge,
	// relative to the parent rectangle's top-left corner (0-based).
	Y uint16

	// Width is the width of the subrectangle in pixels.
	// Must be greater than 0 for valid subrectangles.
	Width uint16

	// Height is the height of the subrectangle in pixels.
	// Must be greater than 0 for valid subrectangles.
	Height uint16
}

RRESubrectangle represents a single solid-color rectangle within an RRE encoding. Each subrectangle defines a rectangular area that should be filled with a specific color, overlaying the background color in that region.

type RawEncoding

type RawEncoding struct {
	// Colors contains the decoded pixel data for the rectangle.
	Colors []Color
}

RawEncoding represents uncompressed pixel data as defined in RFC 6143 Section 7.7.1.

func (*RawEncoding) Read

func (*RawEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error)

Read decodes raw pixel data from the server for the specified rectangle. This method implements the Encoding interface and processes uncompressed pixel data as defined in RFC 6143 Section 7.7.1. Each pixel is transmitted in the format specified by the connection's PixelFormat without any compression or transformation.

The method reads pixel data in left-to-right, top-to-bottom order and converts each pixel from the wire format to the standard Color representation. For true color formats, it extracts RGB components using the pixel format's shift and mask values. For indexed color formats, it looks up colors in the connection's color map.

Parameters:

  • c: The client connection providing pixel format and color map information
  • rect: The rectangle being decoded, specifying dimensions and position
  • r: Reader containing the raw pixel data from the server

Returns:

  • Encoding: A new RawEncoding instance containing the decoded pixel colors
  • error: EncodingError if pixel data cannot be read or decoded

Example usage:

// This method is typically called by the VNC client's message processing loop
enc := &RawEncoding{}
decodedEnc, err := enc.Read(clientConn, rectangle, dataReader)
if err != nil {
	log.Printf("Failed to decode raw encoding: %v", err)
	return
}

// Access the decoded pixel data
rawEnc := decodedEnc.(*RawEncoding)
for i, color := range rawEnc.Colors {
	// Process each pixel color
	x := uint16(i % int(rectangle.Width))
	y := uint16(i / int(rectangle.Width))
	// Apply color to framebuffer at (rect.X + x, rect.Y + y)
}

Pixel format handling:

// The method automatically handles different pixel formats:
// - 8-bit: Single byte per pixel (indexed or true color)
// - 16-bit: Two bytes per pixel (typically RGB565 true color)
// - 32-bit: Four bytes per pixel (typically RGBA true color)

// For true color formats, RGB components are extracted:
// red = (pixel >> RedShift) & RedMax
// green = (pixel >> GreenShift) & GreenMax
// blue = (pixel >> BlueShift) & BlueMax

// For indexed color formats, the pixel value is used as a color map index:
// color = colorMap[pixelValue]

Performance characteristics: - No compression overhead (fastest decoding) - Highest bandwidth usage (largest data size) - Predictable memory usage (width × height × bytes-per-pixel) - Suitable for complex images with high color variation

Error conditions: The method returns an EncodingError if: - Insufficient pixel data is available in the reader - I/O errors occur while reading pixel data - Invalid pixel format parameters are encountered.

func (*RawEncoding) Type

func (*RawEncoding) Type() int32

Type returns the encoding type identifier for Raw encoding.

type Rectangle

type Rectangle struct {
	// X is the horizontal position of the rectangle's left edge in pixels,
	// measured from the left edge of the framebuffer (0-based coordinate system).
	X uint16

	// Y is the vertical position of the rectangle's top edge in pixels,
	// measured from the top edge of the framebuffer (0-based coordinate system).
	Y uint16

	// Width is the width of the rectangle in pixels.
	// Must be greater than 0 for valid rectangles.
	Width uint16

	// Height is the height of the rectangle in pixels.
	// Must be greater than 0 for valid rectangles.
	Height uint16

	// Enc contains the encoding implementation and decoded pixel data for this rectangle.
	// The encoding type determines how the pixel data was compressed and transmitted,
	// and the encoding instance contains the actual decoded pixel information.
	Enc Encoding
}

Rectangle represents a rectangular region of the framebuffer with associated pixel data. Rectangles are the fundamental unit of framebuffer updates in the VNC protocol, defining both the screen coordinates and the encoded pixel data for a specific area.

Each rectangle specifies: - The position and dimensions of the screen area being updated - The encoding method used for the pixel data - The actual encoded pixel data (contained within the Encoding)

Rectangles are processed sequentially, and some encoding types (like CopyRect) may reference pixel data from previously processed rectangles or other areas of the framebuffer.

type SecureDESCipher

type SecureDESCipher struct {
	// contains filtered or unexported fields
}

SecureDESCipher provides enhanced DES encryption with secure memory handling and timing attack protection for VNC authentication.

func (*SecureDESCipher) EncryptVNCChallenge

func (sdc *SecureDESCipher) EncryptVNCChallenge(password string, challenge []byte) ([]byte, error)

EncryptVNCChallenge encrypts a VNC authentication challenge using DES encryption with enhanced security measures including secure memory handling and timing attack protection.

This method implements the VNC authentication encryption as specified in RFC 6143, but with additional security enhancements: - Secure memory clearing of sensitive data - Timing attack protection - Enhanced input validation - Proper error handling

Parameters:

  • password: The VNC password (limited to 8 characters)
  • challenge: The 16-byte challenge from the server

Returns:

  • []byte: The encrypted response (16 bytes)
  • error: Any error that occurred during encryption

Security enhancements: - Clears password key material from memory after use - Uses constant-time operations where possible - Validates input parameters thoroughly - Protects against timing attacks during key preparation.

type SecureMemory

type SecureMemory struct{}

SecureMemory provides utilities for secure handling of sensitive data in memory.

func (*SecureMemory) ClearBytes

func (sm *SecureMemory) ClearBytes(data []byte)

ClearBytes securely clears a byte slice by overwriting it with random data.

func (*SecureMemory) ClearString

func (sm *SecureMemory) ClearString(s string) string

ClearString securely clears a string by converting it to a byte slice and clearing the underlying memory. Note that Go strings are immutable, so this only clears the copy, not the original string data.

Parameters:

  • s: The string to clear (creates a mutable copy for clearing)

Returns:

  • The cleared string (empty string)

Security considerations: - Go strings are immutable, so original string data may persist - This method clears a mutable copy to prevent accidental reuse - For maximum security, avoid storing sensitive data in strings.

func (*SecureMemory) ConstantTimeCompare

func (sm *SecureMemory) ConstantTimeCompare(a, b []byte) bool

ConstantTimeCompare performs a constant-time comparison of two byte slices to prevent timing attacks. This is crucial for comparing cryptographic values like authentication tokens or encrypted data.

Parameters:

  • a, b: The byte slices to compare

Returns:

  • bool: true if the slices are equal, false otherwise

Security considerations: - Uses crypto/subtle.ConstantTimeCompare for timing attack protection - Always takes the same amount of time regardless of input differences - Essential for secure authentication and cryptographic operations.

type SecureRandom

type SecureRandom struct{}

SecureRandom provides cryptographically secure random number generation for security-critical operations.

func (*SecureRandom) GenerateBytes

func (sr *SecureRandom) GenerateBytes(length int) ([]byte, error)

GenerateBytes generates cryptographically secure random bytes.

Parameters:

  • length: The number of random bytes to generate

Returns:

  • []byte: The generated random bytes
  • error: Any error that occurred during generation

Security considerations: - Uses crypto/rand for cryptographically secure randomness - Suitable for cryptographic keys, nonces, and challenges - Returns error if insufficient entropy is available.

func (*SecureRandom) GenerateChallenge

func (sr *SecureRandom) GenerateChallenge(length int) ([]byte, error)

GenerateChallenge generates a cryptographically secure challenge for authentication.

Parameters:

  • length: The length of the challenge in bytes

Returns:

  • []byte: The generated challenge
  • error: Any error that occurred during generation

Security considerations: - Uses cryptographically secure random generation - Suitable for authentication challenges and nonces - Each challenge should be unique and unpredictable.

type ServerCutTextMessage

type ServerCutTextMessage struct {
	// Text contains the clipboard text from the server.
	// The text is encoded using Latin-1 character encoding, which includes
	// all ASCII characters plus additional characters in the 128-255 range.
	// Applications should handle character encoding conversion if needed
	// for integration with local clipboard systems that use different encodings.
	Text string
}

ServerCutTextMessage represents clipboard data from the server (message type 3). This message is sent when the server's clipboard (cut buffer) contents change and should be synchronized with the client's clipboard.

As defined in RFC 6143 Section 7.6.4, this message enables clipboard sharing between the client and server systems. When the server's clipboard is updated (typically by a user copying text on the remote desktop), this message communicates the new clipboard contents to the client.

The text data is transmitted as Latin-1 encoded bytes, which is compatible with ASCII and the first 256 Unicode code points. Applications should handle character encoding appropriately when integrating with local clipboard systems.

Example usage:

switch msg := serverMsg.(type) {
case *ServerCutTextMessage:
	// Update local clipboard with server's clipboard content
	clipboard.WriteAll(msg.Text)
	fmt.Printf("Clipboard updated: %q\n", msg.Text)
}

func (*ServerCutTextMessage) Read

Read parses a ServerCutText message from the server. This method implements the ServerMessage interface and processes clipboard data as defined in RFC 6143 Section 7.6.4. It reads text content from the server's clipboard and makes it available for integration with the client's clipboard system.

The method handles the complete message parsing including:

  1. Reading message padding
  2. Reading the text length field
  3. Reading the clipboard text data
  4. Converting the text to a Go string

Parameters:

  • c: The client connection (unused for ServerCutText messages)
  • r: Reader containing the message data (excluding the message type byte)

Returns:

  • ServerMessage: A new ServerCutTextMessage containing the clipboard text
  • error: NetworkError for I/O issues during message parsing

Example usage:

// This method is typically called by the VNC client's message processing loop
msg := &ServerCutTextMessage{}
parsedMsg, err := msg.Read(clientConn, messageReader)
if err != nil {
	log.Printf("Failed to parse server cut text: %v", err)
	return
}

// Process the parsed message
cutTextMsg := parsedMsg.(*ServerCutTextMessage)
fmt.Printf("Server clipboard updated: %q\n", cutTextMsg.Text)

// Update local clipboard
updateLocalClipboard(cutTextMsg.Text)

Clipboard integration examples:

func updateLocalClipboard(text string) {
	// Cross-platform clipboard integration
	switch runtime.GOOS {
	case "windows":
		// Use Windows clipboard API
		clipboard.WriteAll(text)
	case "darwin":
		// Use macOS pasteboard
		clipboard.WriteAll(text)
	case "linux":
		// Use X11 clipboard
		clipboard.WriteAll(text)
	default:
		// Log or store for manual handling
		log.Printf("Clipboard text: %s", text)
	}
}

Message structure:

// Wire format (after message type byte):
// [3 bytes] - Padding (ignored)
// [4 bytes] - Text length (big-endian uint32)
// [N bytes] - Text data (Latin-1 encoded)

Character encoding:

// The text is transmitted as Latin-1 encoded bytes
// Latin-1 includes ASCII (0-127) plus extended characters (128-255)
// Go strings handle this encoding naturally for most use cases

// For applications requiring specific encoding handling:
func convertFromLatin1(text string) string {
	// Convert Latin-1 to UTF-8 if needed
	bytes := []byte(text)
	runes := make([]rune, len(bytes))
	for i, b := range bytes {
		runes[i] = rune(b) // Latin-1 maps directly to Unicode
	}
	return string(runes)
}

Bidirectional clipboard synchronization:

// Handle server clipboard updates
func handleServerCutText(msg *ServerCutTextMessage) {
	// Update local clipboard
	clipboard.WriteAll(msg.Text)

	// Prevent feedback loops by tracking clipboard source
	lastServerClipboard = msg.Text
}

// Monitor local clipboard changes
func monitorLocalClipboard(client *ClientConn) {
	for {
		text, _ := clipboard.ReadAll()
		if text != lastServerClipboard && text != "" {
			client.CutText(text) // Send to server
		}
		time.Sleep(100 * time.Millisecond)
	}
}

Error handling: The method may return NetworkError for:

  • I/O failures reading message padding or text length
  • I/O failures reading text data
  • Incomplete text data (fewer bytes than specified length)
  • Network connection issues during message parsing

Security considerations: - Clipboard data may contain sensitive information - Applications should consider whether automatic clipboard sync is appropriate - Large clipboard content may consume significant memory - Consider sanitizing or filtering clipboard content based on security requirements

Performance considerations: - Text length is limited by uint32 maximum (4GB theoretical limit) - Large clipboard content is rare but possible - Memory usage scales linearly with text length - Consider implementing size limits for clipboard content in security-sensitive applications.

func (*ServerCutTextMessage) Type

func (*ServerCutTextMessage) Type() uint8

Type returns the message type identifier for server cut text messages.

type ServerMessage

type ServerMessage interface {
	Type() uint8
	Read(conn *ClientConn, r io.Reader) (ServerMessage, error)
}

ServerMessage defines the interface for messages sent from a VNC server to the client.

type SetColorMapEntriesMessage

type SetColorMapEntriesMessage struct {
	// FirstColor is the index of the first color map entry being updated.
	// Color map indices range from 0 to 255, and this value indicates
	// where in the color map the new color values should be placed.
	FirstColor uint16

	// Colors contains the new color values to be installed in the color map.
	// These colors will be placed in the color map starting at the FirstColor
	// index. The length of this slice determines how many consecutive color
	// map entries will be updated.
	Colors []Color
}

SetColorMapEntriesMessage represents a color map update from the server (message type 1). This message is sent when the server needs to update entries in the client's color map, which is used when the pixel format uses indexed color mode rather than true color.

As defined in RFC 6143 Section 7.6.2, this message allows the server to dynamically change the color palette used for interpreting pixel values. This is particularly important for 8-bit color modes where pixel values are indices into a 256-entry color table rather than direct RGB values.

The message automatically updates the connection's ColorMap field when processed, ensuring that subsequent framebuffer updates use the correct color interpretations. Applications can also access the color change data directly for custom processing.

Example usage:

switch msg := serverMsg.(type) {
case *SetColorMapEntriesMessage:
	fmt.Printf("Color map updated: %d colors starting at index %d\n",
		len(msg.Colors), msg.FirstColor)
	// The connection's ColorMap is automatically updated
}

func (*SetColorMapEntriesMessage) Read

Read parses a SetColorMapEntries message from the server. This method implements the ServerMessage interface and processes color map updates as defined in RFC 6143 Section 7.6.2. It reads new color values and automatically updates the connection's color map for use with indexed color pixel formats.

The method handles the complete message parsing including:

  1. Reading message padding and the starting color index
  2. Reading the number of colors being updated
  3. Reading RGB values for each color entry
  4. Automatically updating the connection's ColorMap field

Parameters:

  • c: The client connection whose color map will be updated
  • r: Reader containing the message data (excluding the message type byte)

Returns:

  • ServerMessage: A new SetColorMapEntriesMessage containing the color update data
  • error: NetworkError for I/O issues during message parsing

Example usage:

// This method is typically called by the VNC client's message processing loop
msg := &SetColorMapEntriesMessage{}
parsedMsg, err := msg.Read(clientConn, messageReader)
if err != nil {
	log.Printf("Failed to parse color map update: %v", err)
	return
}

// Process the parsed message
colorUpdate := parsedMsg.(*SetColorMapEntriesMessage)
fmt.Printf("Updated %d colors starting at index %d\n",
	len(colorUpdate.Colors), colorUpdate.FirstColor)

// The connection's ColorMap is automatically updated
// Access updated colors if needed:
for i, color := range colorUpdate.Colors {
	index := colorUpdate.FirstColor + uint16(i)
	fmt.Printf("Color[%d] = RGB(%d, %d, %d)\n",
		index, color.R, color.G, color.B)
}

Color map usage:

// After this message is processed, indexed pixel values will use the new colors:
// For 8-bit indexed pixel format:
pixelValue := uint8(42) // Example pixel value from framebuffer update
actualColor := clientConn.ColorMap[pixelValue] // Uses updated color map

Message structure:

// Wire format (after message type byte):
// [1 byte]  - Padding (ignored)
// [2 bytes] - First color index (big-endian uint16)
// [2 bytes] - Number of colors (big-endian uint16)
// For each color:
//   [2 bytes] - Red component (big-endian uint16)
//   [2 bytes] - Green component (big-endian uint16)
//   [2 bytes] - Blue component (big-endian uint16)

Automatic color map update:

// The method automatically updates the connection's color map:
for i, color := range newColors {
	clientConn.ColorMap[firstColor + i] = color
}

// This ensures that subsequent framebuffer updates with indexed pixels
// will use the correct color interpretations

Color value format: Color components are 16-bit values (0-65535) providing high precision color representation. When displaying on 8-bit systems, applications should scale appropriately (e.g., divide by 257 to convert to 8-bit values).

Error handling: The method may return NetworkError for:

  • I/O failures reading message padding, indices, or color data
  • Incomplete color data (fewer bytes than expected)
  • Network connection issues during message parsing

Performance considerations: - Color map updates are typically small (few colors changed at once) - The automatic color map update is performed synchronously - Large color map changes (updating many colors) are rare but possible - Color map updates may trigger visual changes in subsequent framebuffer updates.

func (*SetColorMapEntriesMessage) Type

Type returns the message type identifier for color map update messages.

type StandardLogger

type StandardLogger struct {
	// Logger is the underlying standard library logger.
	Logger *log.Logger
	// contains filtered or unexported fields
}

StandardLogger wraps Go's standard log package to implement the Logger interface.

func (*StandardLogger) Debug

func (l *StandardLogger) Debug(msg string, fields ...Field)

Debug logs a debug-level message with structured fields.

func (*StandardLogger) Error

func (l *StandardLogger) Error(msg string, fields ...Field)

Error logs an error-level message with structured fields.

func (*StandardLogger) Info

func (l *StandardLogger) Info(msg string, fields ...Field)

Info logs an info-level message with structured fields.

func (*StandardLogger) Warn

func (l *StandardLogger) Warn(msg string, fields ...Field)

Warn logs a warning-level message with structured fields.

func (*StandardLogger) With

func (l *StandardLogger) With(fields ...Field) Logger

With creates a new StandardLogger instance with additional context fields. The returned logger will include the provided fields in all subsequent log messages.

type TimingProtection

type TimingProtection struct{}

TimingProtection provides utilities for protecting against timing attacks during authentication and cryptographic operations.

func (*TimingProtection) ConstantTimeAuthentication

func (tp *TimingProtection) ConstantTimeAuthentication(authFunc func() error, baseDelay time.Duration) error

ConstantTimeAuthentication performs authentication with timing attack protection. This ensures that both successful and failed authentication attempts take approximately the same amount of time.

Parameters:

  • authFunc: The authentication function to execute
  • baseDelay: The minimum time the operation should take

Returns:

  • error: Any error from the authentication function

Security considerations: - Normalizes timing between success and failure cases - Prevents timing-based username/password enumeration - Should be used for all authentication operations.

func (*TimingProtection) ConstantTimeDelay

func (tp *TimingProtection) ConstantTimeDelay(baseDelay time.Duration)

ConstantTimeDelay introduces a constant delay to normalize operation timing. This helps prevent timing attacks by ensuring operations take a consistent amount of time regardless of the input or success/failure status.

Parameters:

  • baseDelay: The base delay duration to apply

Security considerations: - Helps prevent timing analysis of authentication operations - Should be used consistently across success and failure paths - Delay should be long enough to mask timing variations.

type VNCError

type VNCError struct {
	Op      string
	Code    ErrorCode
	Message string
	Err     error
}

VNCError provides structured error information with operation context, error codes, and message wrapping for comprehensive error handling.

func NewVNCError

func NewVNCError(op string, code ErrorCode, message string, err error) *VNCError

NewVNCError creates a new VNCError with the specified parameters. This is the primary constructor for structured VNC errors.

func (*VNCError) Error

func (e *VNCError) Error() string

Error returns the formatted error message.

func (*VNCError) Is

func (e *VNCError) Is(target error) bool

Is reports whether this error matches the target error.

func (*VNCError) Unwrap

func (e *VNCError) Unwrap() error

Unwrap returns the underlying error for error chain unwrapping.

Directories

Path Synopsis
examples
advanced command
basic command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL