main
1package rfb
2
3import (
4 "encoding/binary"
5 "fmt"
6)
7
8// Session holds the state of an RFB session after handshake.
9type Session struct {
10 // Width of the framebuffer in pixels.
11 Width uint16
12
13 // Height of the framebuffer in pixels.
14 Height uint16
15
16 // Name of the VNC server/desktop.
17 Name string
18
19 // PixelFormat describes the pixel format of the framebuffer.
20 PixelFormat PixelFormat
21
22 // ServerVersion is the RFB version string from the server.
23 ServerVersion string
24}
25
26// PixelFormat describes the format of pixel data.
27type PixelFormat struct {
28 BitsPerPixel uint8
29 Depth uint8
30 BigEndian bool
31 TrueColour bool
32 RedMax uint16
33 GreenMax uint16
34 BlueMax uint16
35 RedShift uint8
36 GreenShift uint8
37 BlueShift uint8
38}
39
40// ParseServerInit parses a ServerInit message and returns a Session.
41// ServerInit format: width(2) + height(2) + pixel_format(16) + name_len(4) + name
42func ParseServerInit(data []byte) (*Session, error) {
43 if len(data) < 24 {
44 return nil, fmt.Errorf("server init too short: %d bytes", len(data))
45 }
46
47 width := binary.BigEndian.Uint16(data[0:2])
48 height := binary.BigEndian.Uint16(data[2:4])
49
50 pf := PixelFormat{
51 BitsPerPixel: data[4],
52 Depth: data[5],
53 BigEndian: data[6] != 0,
54 TrueColour: data[7] != 0,
55 RedMax: binary.BigEndian.Uint16(data[8:10]),
56 GreenMax: binary.BigEndian.Uint16(data[10:12]),
57 BlueMax: binary.BigEndian.Uint16(data[12:14]),
58 RedShift: data[14],
59 GreenShift: data[15],
60 BlueShift: data[16],
61 // data[17:20] is padding
62 }
63
64 nameLen := binary.BigEndian.Uint32(data[20:24])
65 if len(data) < 24+int(nameLen) {
66 return nil, fmt.Errorf("server init name incomplete: need %d, got %d", 24+nameLen, len(data))
67 }
68 name := string(data[24 : 24+nameLen])
69
70 return &Session{
71 Width: width,
72 Height: height,
73 Name: name,
74 PixelFormat: pf,
75 }, nil
76}
77
78// EncodePixelFormat creates a SetPixelFormat message.
79func EncodePixelFormat(pf *PixelFormat) []byte {
80 msg := make([]byte, 20)
81 msg[0] = MsgTypeSetPixelFormat
82 // msg[1:4] padding
83 msg[4] = pf.BitsPerPixel
84 msg[5] = pf.Depth
85 if pf.BigEndian {
86 msg[6] = 1
87 }
88 if pf.TrueColour {
89 msg[7] = 1
90 }
91 binary.BigEndian.PutUint16(msg[8:10], pf.RedMax)
92 binary.BigEndian.PutUint16(msg[10:12], pf.GreenMax)
93 binary.BigEndian.PutUint16(msg[12:14], pf.BlueMax)
94 msg[14] = pf.RedShift
95 msg[15] = pf.GreenShift
96 msg[16] = pf.BlueShift
97 // msg[17:20] padding
98 return msg
99}