not working example
Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
This commit is contained in:
parent
5139d1dd82
commit
a45bca15e3
2
.gitignore
vendored
2
.gitignore
vendored
@ -12,3 +12,5 @@
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
example/client/client
|
||||
example/server/server
|
||||
|
2
LICENSE
2
LICENSE
@ -1,5 +1,7 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 Mitchell Hashimoto
|
||||
Copyright (c) 2016-2017 Kate Ward
|
||||
Copyright (c) 2017 Vasiliy Tolstov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
46
button_string.go
Normal file
46
button_string.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Code generated by "stringer -type=Button"; DO NOT EDIT.
|
||||
|
||||
package vnc
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_Button_name_0 = "BtnNoneBtnLeftBtnMiddle"
|
||||
_Button_name_1 = "BtnRight"
|
||||
_Button_name_2 = "BtnFour"
|
||||
_Button_name_3 = "BtnFive"
|
||||
_Button_name_4 = "BtnSix"
|
||||
_Button_name_5 = "BtnSeven"
|
||||
_Button_name_6 = "BtnEight"
|
||||
)
|
||||
|
||||
var (
|
||||
_Button_index_0 = [...]uint8{0, 7, 14, 23}
|
||||
_Button_index_1 = [...]uint8{0, 8}
|
||||
_Button_index_2 = [...]uint8{0, 7}
|
||||
_Button_index_3 = [...]uint8{0, 7}
|
||||
_Button_index_4 = [...]uint8{0, 6}
|
||||
_Button_index_5 = [...]uint8{0, 8}
|
||||
_Button_index_6 = [...]uint8{0, 8}
|
||||
)
|
||||
|
||||
func (i Button) String() string {
|
||||
switch {
|
||||
case 0 <= i && i <= 2:
|
||||
return _Button_name_0[_Button_index_0[i]:_Button_index_0[i+1]]
|
||||
case i == 4:
|
||||
return _Button_name_1
|
||||
case i == 8:
|
||||
return _Button_name_2
|
||||
case i == 16:
|
||||
return _Button_name_3
|
||||
case i == 32:
|
||||
return _Button_name_4
|
||||
case i == 64:
|
||||
return _Button_name_5
|
||||
case i == 128:
|
||||
return _Button_name_6
|
||||
default:
|
||||
return fmt.Sprintf("Button(%d)", i)
|
||||
}
|
||||
}
|
23
buttons.go
Normal file
23
buttons.go
Normal file
@ -0,0 +1,23 @@
|
||||
package vnc
|
||||
|
||||
// Button represents a mask of pointer presses/releases.
|
||||
type Button uint8
|
||||
|
||||
//go:generate stringer -type=Button
|
||||
|
||||
// All available button mask components.
|
||||
const (
|
||||
BtnLeft Button = 1 << iota
|
||||
BtnMiddle
|
||||
BtnRight
|
||||
BtnFour
|
||||
BtnFive
|
||||
BtnSix
|
||||
BtnSeven
|
||||
BtnEight
|
||||
BtnNone Button = 0
|
||||
)
|
||||
|
||||
func Mask(button Button) uint8 {
|
||||
return uint8(button)
|
||||
}
|
453
client.go
Normal file
453
client.go
Normal file
@ -0,0 +1,453 @@
|
||||
package vnc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
var DefaultServerMessages = []ServerMessage{
|
||||
&FramebufferUpdate{},
|
||||
&SetColorMapEntries{},
|
||||
&Bell{},
|
||||
&ServerCutText{},
|
||||
}
|
||||
|
||||
func Connect(ctx context.Context, c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
||||
conn, err := NewClientConn(c, cfg)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := cfg.VersionHandler(cfg, conn); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := cfg.SecurityHandler(cfg, conn); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := cfg.ClientInitHandler(cfg, conn); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
if err := cfg.ServerInitHandler(cfg, conn); err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
/*
|
||||
// Send client-to-server messages.
|
||||
encs := conn.encodings
|
||||
if err := conn.SetEncodings(encs); err != nil {
|
||||
conn.Close()
|
||||
return nil, Errorf("failure calling SetEncodings; %s", err)
|
||||
}
|
||||
pf := conn.pixelFormat
|
||||
if err := conn.SetPixelFormat(pf); err != nil {
|
||||
conn.Close()
|
||||
return nil, Errorf("failure calling SetPixelFormat; %s", err)
|
||||
}
|
||||
*/
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
var _ Conn = (*ClientConn)(nil)
|
||||
|
||||
func (c *ClientConn) Flush() error {
|
||||
return c.bw.Flush()
|
||||
}
|
||||
|
||||
func (c *ClientConn) Close() error {
|
||||
return c.c.Close()
|
||||
}
|
||||
|
||||
func (c *ClientConn) Read(buf []byte) (int, error) {
|
||||
return c.br.Read(buf)
|
||||
}
|
||||
|
||||
func (c *ClientConn) Write(buf []byte) (int, error) {
|
||||
return c.bw.Write(buf)
|
||||
}
|
||||
|
||||
func (c *ClientConn) ColorMap() *ColorMap {
|
||||
return c.colorMap
|
||||
}
|
||||
|
||||
func (c *ClientConn) SetColorMap(cm *ColorMap) {
|
||||
c.colorMap = cm
|
||||
}
|
||||
func (c *ClientConn) DesktopName() string {
|
||||
return c.desktopName
|
||||
}
|
||||
func (c *ClientConn) PixelFormat() *PixelFormat {
|
||||
return c.pixelFormat
|
||||
}
|
||||
func (c *ClientConn) Encodings() []Encoding {
|
||||
return c.encodings
|
||||
}
|
||||
func (c *ClientConn) Width() uint16 {
|
||||
return c.fbWidth
|
||||
}
|
||||
func (c *ClientConn) Height() uint16 {
|
||||
return c.fbHeight
|
||||
}
|
||||
func (c *ClientConn) Protocol() string {
|
||||
return c.protocol
|
||||
}
|
||||
func (c *ClientConn) SetWidth(w uint16) {
|
||||
c.fbWidth = w
|
||||
}
|
||||
func (c *ClientConn) SetHeight(h uint16) {
|
||||
c.fbHeight = h
|
||||
}
|
||||
|
||||
// The ClientConn type holds client connection information.
|
||||
type ClientConn struct {
|
||||
c net.Conn
|
||||
br *bufio.Reader
|
||||
bw *bufio.Writer
|
||||
cfg *ClientConfig
|
||||
protocol string
|
||||
|
||||
// If the pixel format uses a color map, then this is the color
|
||||
// map that is used. This should not be modified directly, since
|
||||
// the data comes from the server.
|
||||
// Definition in §5 - Representation of Pixel Data.
|
||||
colorMap *ColorMap
|
||||
|
||||
// Name associated with the desktop, sent from the server.
|
||||
desktopName string
|
||||
|
||||
// Encodings supported by the client. This should not be modified
|
||||
// directly. Instead, SetEncodings() should be used.
|
||||
encodings []Encoding
|
||||
|
||||
// Height of the frame buffer in pixels, sent from the server.
|
||||
fbHeight uint16
|
||||
|
||||
// Width of the frame buffer in pixels, sent from the server.
|
||||
fbWidth uint16
|
||||
|
||||
// The pixel format associated with the connection. This shouldn't
|
||||
// be modified. If you wish to set a new pixel format, use the
|
||||
// SetPixelFormat method.
|
||||
pixelFormat *PixelFormat
|
||||
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
func NewClientConn(c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
||||
if cfg.ServerMessages == nil {
|
||||
return nil, fmt.Errorf("ServerMessages cannel is nil")
|
||||
}
|
||||
if len(cfg.Encodings) == 0 {
|
||||
return nil, fmt.Errorf("client can't handle encodings")
|
||||
}
|
||||
return &ClientConn{
|
||||
c: c,
|
||||
cfg: cfg,
|
||||
br: bufio.NewReader(c),
|
||||
bw: bufio.NewWriter(c),
|
||||
encodings: cfg.Encodings,
|
||||
pixelFormat: cfg.PixelFormat,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ClientMessage represents a Client-to-Server RFB message type.
|
||||
type ClientMessageType uint8
|
||||
|
||||
//go:generate stringer -type=ClientMessageType
|
||||
|
||||
// Client-to-Server message types.
|
||||
const (
|
||||
SetPixelFormatMsgType ClientMessageType = iota
|
||||
_
|
||||
SetEncodingsMsgType
|
||||
FramebufferUpdateRequestMsgType
|
||||
KeyEventMsgType
|
||||
PointerEventMsgType
|
||||
ClientCutTextMsgType
|
||||
)
|
||||
|
||||
// SetPixelFormat holds the wire format message.
|
||||
type SetPixelFormat struct {
|
||||
MsgType ClientMessageType
|
||||
_ [3]byte // padding
|
||||
PF PixelFormat // pixel-format
|
||||
}
|
||||
|
||||
func (msg *SetPixelFormat) Type() ClientMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *SetPixelFormat) Write(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pf := c.PixelFormat()
|
||||
// Invalidate the color map.
|
||||
if pf.TrueColor != 1 {
|
||||
c.SetColorMap(&ColorMap{})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg *SetPixelFormat) Read(c Conn) error {
|
||||
return binary.Read(c, binary.BigEndian, msg)
|
||||
}
|
||||
|
||||
// SetEncodings holds the wire format message, sans encoding-type field.
|
||||
type SetEncodings struct {
|
||||
MsgType ClientMessageType
|
||||
_ [1]byte // padding
|
||||
EncNum uint16 // number-of-encodings
|
||||
Encodings []Encoding
|
||||
}
|
||||
|
||||
func (msg *SetEncodings) Type() ClientMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *SetEncodings) Read(c Conn) error {
|
||||
if err := binary.Read(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pad [1]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, msg.EncNum); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var enc Encoding
|
||||
for i := uint16(0); i < msg.EncNum; i++ {
|
||||
if err := binary.Read(c, binary.BigEndian, &enc); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Encodings = append(msg.Encodings, enc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg *SetEncodings) Write(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pad [1]byte
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if uint16(len(msg.Encodings)) > msg.EncNum {
|
||||
msg.EncNum = uint16(len(msg.Encodings))
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, msg.EncNum); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, enc := range msg.Encodings {
|
||||
if err := binary.Write(c, binary.BigEndian, enc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// FramebufferUpdateRequest holds the wire format message.
|
||||
type FramebufferUpdateRequest struct {
|
||||
MsgType ClientMessageType
|
||||
Inc uint8 // incremental
|
||||
X, Y uint16 // x-, y-position
|
||||
Width, Height uint16 // width, height
|
||||
}
|
||||
|
||||
func (msg *FramebufferUpdateRequest) Type() ClientMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *FramebufferUpdateRequest) Read(c Conn) error {
|
||||
return binary.Read(c, binary.BigEndian, msg)
|
||||
}
|
||||
|
||||
func (msg *FramebufferUpdateRequest) Write(c Conn) error {
|
||||
return binary.Write(c, binary.BigEndian, msg)
|
||||
}
|
||||
|
||||
// KeyEvent holds the wire format message.
|
||||
type KeyEvent struct {
|
||||
MsgType ClientMessageType // message-type
|
||||
Down uint8 // down-flag
|
||||
_ [2]byte // padding
|
||||
Key Key // key
|
||||
}
|
||||
|
||||
func (msg *KeyEvent) Type() ClientMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *KeyEvent) Read(c Conn) error {
|
||||
return binary.Read(c, binary.BigEndian, msg)
|
||||
}
|
||||
|
||||
func (msg *KeyEvent) Write(c Conn) error {
|
||||
return binary.Write(c, binary.BigEndian, msg)
|
||||
}
|
||||
|
||||
// PointerEventMessage holds the wire format message.
|
||||
type PointerEvent struct {
|
||||
MsgType ClientMessageType // message-type
|
||||
Mask uint8 // button-mask
|
||||
X, Y uint16 // x-, y-position
|
||||
}
|
||||
|
||||
func (msg *PointerEvent) Type() ClientMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *PointerEvent) Read(c Conn) error {
|
||||
return binary.Read(c, binary.BigEndian, msg)
|
||||
}
|
||||
|
||||
func (msg *PointerEvent) Write(c Conn) error {
|
||||
return binary.Write(c, binary.BigEndian, msg)
|
||||
}
|
||||
|
||||
// ClientCutText holds the wire format message, sans the text field.
|
||||
type ClientCutText struct {
|
||||
MsgType ClientMessageType // message-type
|
||||
_ [3]byte // padding
|
||||
Length uint32 // length
|
||||
Text []byte
|
||||
}
|
||||
|
||||
func (msg *ClientCutText) Type() ClientMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *ClientCutText) Read(c Conn) error {
|
||||
if err := binary.Read(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pad [3]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, msg.Length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
text := make([]uint8, msg.Length)
|
||||
if err := binary.Read(c, binary.BigEndian, &text); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Text = text
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg *ClientCutText) Write(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pad [3]byte
|
||||
if err := binary.Write(c, binary.BigEndian, &pad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if uint32(len(msg.Text)) > msg.Length {
|
||||
msg.Length = uint32(len(msg.Text))
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Text); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
// ListenAndHandle listens to a VNC server and handles server messages.
|
||||
func (c *ClientConn) Handle() error {
|
||||
var err error
|
||||
|
||||
defer c.Close()
|
||||
|
||||
serverMessages := make(map[ServerMessageType]ServerMessage)
|
||||
for _, m := range c.cfg.ServerMessages {
|
||||
serverMessages[m.Type()] = m
|
||||
}
|
||||
|
||||
clientLoop:
|
||||
for {
|
||||
select {
|
||||
case msg := <-c.cfg.ServerMessageCh:
|
||||
if err = msg.Write(c); err != nil {
|
||||
return err
|
||||
}
|
||||
case <-c.quit:
|
||||
break clientLoop
|
||||
}
|
||||
}
|
||||
|
||||
serverLoop:
|
||||
for {
|
||||
select {
|
||||
case <-c.quit:
|
||||
break serverLoop
|
||||
default:
|
||||
var messageType ServerMessageType
|
||||
if err = binary.Read(c, binary.BigEndian, &messageType); err != nil {
|
||||
break serverLoop
|
||||
}
|
||||
msg, ok := serverMessages[messageType]
|
||||
if !ok {
|
||||
break serverLoop
|
||||
}
|
||||
if err = msg.Read(c); err != nil {
|
||||
break serverLoop
|
||||
}
|
||||
if c.cfg.ServerMessageCh == nil {
|
||||
continue
|
||||
}
|
||||
c.cfg.ServerMessageCh <- msg
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type ClientHandler func(*ClientConfig, Conn) error
|
||||
|
||||
// A ClientConfig structure is used to configure a ClientConn. After
|
||||
// one has been passed to initialize a connection, it must not be modified.
|
||||
type ClientConfig struct {
|
||||
VersionHandler ClientHandler
|
||||
SecurityHandler ClientHandler
|
||||
SecurityHandlers []ClientHandler
|
||||
ClientInitHandler ClientHandler
|
||||
ServerInitHandler ClientHandler
|
||||
Encodings []Encoding
|
||||
PixelFormat *PixelFormat
|
||||
ColorMap *ColorMap
|
||||
ClientMessageCh chan ClientMessage
|
||||
ServerMessageCh chan ServerMessage
|
||||
Exclusive bool
|
||||
ServerMessages []ServerMessage
|
||||
}
|
27
clientmessagetype_string.go
Normal file
27
clientmessagetype_string.go
Normal file
@ -0,0 +1,27 @@
|
||||
// Code generated by "stringer -type=ClientMessageType"; DO NOT EDIT.
|
||||
|
||||
package vnc
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_ClientMessageType_name_0 = "SetPixelFormatMsgType"
|
||||
_ClientMessageType_name_1 = "SetEncodingsMsgTypeFramebufferUpdateRequestMsgTypeKeyEventMsgTypePointerEventMsgTypeClientCutTextMsgType"
|
||||
)
|
||||
|
||||
var (
|
||||
_ClientMessageType_index_0 = [...]uint8{0, 21}
|
||||
_ClientMessageType_index_1 = [...]uint8{0, 19, 50, 65, 84, 104}
|
||||
)
|
||||
|
||||
func (i ClientMessageType) String() string {
|
||||
switch {
|
||||
case i == 0:
|
||||
return _ClientMessageType_name_0
|
||||
case 2 <= i && i <= 6:
|
||||
i -= 2
|
||||
return _ClientMessageType_name_1[_ClientMessageType_index_1[i]:_ClientMessageType_index_1[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("ClientMessageType(%d)", i)
|
||||
}
|
||||
}
|
18
conn.go
Normal file
18
conn.go
Normal file
@ -0,0 +1,18 @@
|
||||
package vnc
|
||||
|
||||
import "io"
|
||||
|
||||
type Conn interface {
|
||||
io.ReadWriteCloser
|
||||
Protocol() string
|
||||
PixelFormat() *PixelFormat
|
||||
ColorMap() *ColorMap
|
||||
SetColorMap(*ColorMap)
|
||||
Encodings() []Encoding
|
||||
Width() uint16
|
||||
Height() uint16
|
||||
SetWidth(uint16)
|
||||
SetHeight(uint16)
|
||||
DesktopName() string
|
||||
Flush() error
|
||||
}
|
88
encoding.go
Normal file
88
encoding.go
Normal file
@ -0,0 +1,88 @@
|
||||
package vnc
|
||||
|
||||
// EncodingType represents a known VNC encoding type.
|
||||
type EncodingType int32
|
||||
|
||||
//go:generate stringer -type=EncodingType
|
||||
|
||||
const (
|
||||
EncRaw EncodingType = 0
|
||||
EncCopyRect EncodingType = 1
|
||||
EncRRE EncodingType = 2
|
||||
EncHextile EncodingType = 5
|
||||
EncTRLE EncodingType = 15
|
||||
EncZRLE EncodingType = 16
|
||||
EncColorPseudo EncodingType = -239
|
||||
EncDesktopSizePseudo EncodingType = -223
|
||||
)
|
||||
|
||||
type Encoding interface {
|
||||
Type() EncodingType
|
||||
Read(Conn, *Rectangle) error
|
||||
Write(Conn, *Rectangle) error
|
||||
}
|
||||
|
||||
type RawEncoding struct {
|
||||
Colors []Color
|
||||
}
|
||||
|
||||
func (enc *RawEncoding) Write(c Conn, rect *Rectangle) error {
|
||||
/*
|
||||
for _, cl := range enc.Colors {
|
||||
bytes, err := cl.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, bytes); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*/
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (enc *RawEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
/*
|
||||
var buf bytes.Buffer
|
||||
pf := c.PixelFormat()
|
||||
cm := c.ColorMap()
|
||||
bytesPerPixel := int(pf.BPP / 8)
|
||||
n := rect.Area() * bytesPerPixel
|
||||
if err := c.receiveN(&buf, n); err != nil {
|
||||
return fmt.Errorf("unable to read rectangle with raw encoding: %s", err)
|
||||
}
|
||||
|
||||
colors := make([]Color, rect.Area())
|
||||
for y := uint16(0); y < rect.Height; y++ {
|
||||
for x := uint16(0); x < rect.Width; x++ {
|
||||
color := NewColor(pf, cm)
|
||||
if err := color.Unmarshal(buf.Next(bytesPerPixel)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
colors[int(y)*int(rect.Width)+int(x)] = *color
|
||||
}
|
||||
}
|
||||
|
||||
return &RawEncoding{colors}, nil
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*RawEncoding) Type() EncodingType { return EncRaw }
|
||||
|
||||
// DesktopSizePseudoEncoding represents a desktop size message from the server.
|
||||
type DesktopSizePseudoEncoding struct{}
|
||||
|
||||
// Read implements the Encoding interface.
|
||||
func (*DesktopSizePseudoEncoding) Read(c Conn, rect *Rectangle) error {
|
||||
c.SetWidth(rect.Width)
|
||||
c.SetHeight(rect.Height)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *DesktopSizePseudoEncoding) Write(c *ServerConn, rect *Rectangle) error {
|
||||
return nil
|
||||
}
|
39
encodingtype_string.go
Normal file
39
encodingtype_string.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Code generated by "stringer -type=EncodingType"; DO NOT EDIT.
|
||||
|
||||
package vnc
|
||||
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
_EncodingType_name_0 = "EncColorPseudo"
|
||||
_EncodingType_name_1 = "EncDesktopSizePseudo"
|
||||
_EncodingType_name_2 = "EncRawEncCopyRectEncRRE"
|
||||
_EncodingType_name_3 = "EncHextile"
|
||||
_EncodingType_name_4 = "EncTRLEEncZRLE"
|
||||
)
|
||||
|
||||
var (
|
||||
_EncodingType_index_0 = [...]uint8{0, 14}
|
||||
_EncodingType_index_1 = [...]uint8{0, 20}
|
||||
_EncodingType_index_2 = [...]uint8{0, 6, 17, 23}
|
||||
_EncodingType_index_3 = [...]uint8{0, 10}
|
||||
_EncodingType_index_4 = [...]uint8{0, 7, 14}
|
||||
)
|
||||
|
||||
func (i EncodingType) String() string {
|
||||
switch {
|
||||
case i == -239:
|
||||
return _EncodingType_name_0
|
||||
case i == -223:
|
||||
return _EncodingType_name_1
|
||||
case 0 <= i && i <= 2:
|
||||
return _EncodingType_name_2[_EncodingType_index_2[i]:_EncodingType_index_2[i+1]]
|
||||
case i == 5:
|
||||
return _EncodingType_name_3
|
||||
case 15 <= i && i <= 16:
|
||||
i -= 15
|
||||
return _EncodingType_name_4[_EncodingType_index_4[i]:_EncodingType_index_4[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("EncodingType(%d)", i)
|
||||
}
|
||||
}
|
60
example/client/main.go
Normal file
60
example/client/main.go
Normal file
@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
vnc "github.com/kward/go-vnc"
|
||||
"github.com/kward/go-vnc/logging"
|
||||
"github.com/kward/go-vnc/messages"
|
||||
"github.com/kward/go-vnc/rfbflags"
|
||||
)
|
||||
|
||||
func main() {
|
||||
logging.V(logging.FnDeclLevel)
|
||||
// Establish TCP connection to VNC server.
|
||||
nc, err := net.Dial("tcp", "127.0.0.1:5923")
|
||||
if err != nil {
|
||||
log.Fatalf("Error connecting to VNC host. %v", err)
|
||||
}
|
||||
|
||||
// Negotiate connection with the server.
|
||||
ch := make(chan vnc.ServerMessage)
|
||||
vc, err := vnc.Connect(context.Background(), nc,
|
||||
&vnc.ClientConfig{
|
||||
Auth: []vnc.ClientAuth{&vnc.ClientAuthNone{}},
|
||||
ServerMessageCh: ch,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error negotiating connection to VNC host. %v", err)
|
||||
}
|
||||
|
||||
// Periodically request framebuffer updates.
|
||||
go func() {
|
||||
w, h := vc.FramebufferWidth(), vc.FramebufferHeight()
|
||||
for {
|
||||
if err := vc.FramebufferUpdateRequest(rfbflags.RFBTrue, 0, 0, w, h); err != nil {
|
||||
log.Printf("error requesting framebuffer update: %v", err)
|
||||
return
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
// Listen and handle server messages.
|
||||
go vc.ListenAndHandle()
|
||||
|
||||
// Process messages coming in on the ServerMessage channel.
|
||||
for {
|
||||
msg := <-ch
|
||||
switch msg.Type() {
|
||||
case messages.FramebufferUpdate:
|
||||
log.Println("Received FramebufferUpdate message.")
|
||||
default:
|
||||
log.Printf("Received message type:%v msg:%v\n", msg.Type(), msg)
|
||||
}
|
||||
}
|
||||
}
|
70
example/proxy/main.go
Normal file
70
example/proxy/main.go
Normal file
@ -0,0 +1,70 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
vnc "github.com/kward/go-vnc"
|
||||
"github.com/kward/go-vnc/logging"
|
||||
"github.com/kward/go-vnc/messages"
|
||||
"github.com/kward/go-vnc/rfbflags"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
logging.V(logging.FnDeclLevel)
|
||||
ln, err := net.Listen("tcp", os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatalf("Error listen. %v", err)
|
||||
}
|
||||
|
||||
// Negotiate connection with the server.
|
||||
sch := make(chan vnc.ClientMessage)
|
||||
|
||||
// handle client messages.
|
||||
vcc := vnc.NewServerConfig()
|
||||
vcc.Auth = []vnc.ServerAuth{&vnc.ServerAuthNone{}}
|
||||
vcc.ClientMessageCh = sch
|
||||
go vnc.Serve(context.Background(), ln, vcc)
|
||||
|
||||
nc, err := net.Dial("tcp", os.Args[1])
|
||||
if err != nil {
|
||||
log.Fatalf("Error connecting to VNC host. %v", err)
|
||||
}
|
||||
|
||||
// Negotiate connection with the server.
|
||||
cch := make(chan vnc.ServerMessage)
|
||||
vc, err := vnc.Connect(context.Background(), nc,
|
||||
&vnc.ClientConfig{
|
||||
Auth: []vnc.ClientAuth{&vnc.ClientAuthNone{}},
|
||||
ServerMessageCh: cch,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error negotiating connection to VNC host. %v", err)
|
||||
}
|
||||
|
||||
// Listen and handle server messages.
|
||||
go vc.ListenAndHandle()
|
||||
|
||||
// Process messages coming in on the ServerMessage channel.
|
||||
for {
|
||||
msg := <-ch
|
||||
switch msg.Type() {
|
||||
case messages.FramebufferUpdate:
|
||||
log.Println("Received FramebufferUpdate message.")
|
||||
default:
|
||||
log.Printf("Received message type:%v msg:%v\n", msg.Type(), msg)
|
||||
}
|
||||
}
|
||||
|
||||
// Process messages coming in on the ClientMessage channel.
|
||||
for {
|
||||
msg := <-ch
|
||||
msg.Write(
|
||||
}
|
||||
}
|
42
example/server/main.go
Normal file
42
example/server/main.go
Normal file
@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"net"
|
||||
|
||||
vnc "github.com/vtolstov/go-vnc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ln, err := net.Listen("tcp", ":5900")
|
||||
if err != nil {
|
||||
log.Fatalf("Error listen. %v", err)
|
||||
}
|
||||
|
||||
chServer := make(chan vnc.ClientMessage)
|
||||
chClient := make(chan vnc.ServerMessage)
|
||||
|
||||
cfg := &vnc.ServerConfig{
|
||||
VersionHandler: vnc.ServerVersionHandler,
|
||||
SecurityHandler: vnc.ServerSecurityHandler,
|
||||
SecurityHandlers: []vnc.ServerHandler{vnc.ServerSecurityNoneHandler},
|
||||
ClientInitHandler: vnc.ServerClientInitHandler,
|
||||
ServerInitHandler: vnc.ServerServerInitHandler,
|
||||
Encodings: []vnc.Encoding{&vnc.RawEncoding{}},
|
||||
PixelFormat: vnc.PixelFormat32bit,
|
||||
ClientMessageCh: chServer,
|
||||
ServerMessageCh: chClient,
|
||||
ClientMessages: vnc.DefaultClientMessages,
|
||||
}
|
||||
go vnc.Serve(context.Background(), ln, cfg)
|
||||
|
||||
// Process messages coming in on the ClientMessage channel.
|
||||
for {
|
||||
msg := <-chClient
|
||||
switch msg.Type() {
|
||||
default:
|
||||
log.Printf("Received message type:%v msg:%v\n", msg.Type(), msg)
|
||||
}
|
||||
}
|
||||
}
|
35
handlers.go
Normal file
35
handlers.go
Normal file
@ -0,0 +1,35 @@
|
||||
package vnc
|
||||
|
||||
// ClientMessage is the interface
|
||||
type ClientMessage interface {
|
||||
Type() ClientMessageType
|
||||
Read(Conn) error
|
||||
Write(Conn) error
|
||||
}
|
||||
|
||||
// ServerMessage is the interface
|
||||
type ServerMessage interface {
|
||||
Type() ServerMessageType
|
||||
Read(Conn) error
|
||||
Write(Conn) error
|
||||
}
|
||||
|
||||
func ServerVersionHandler(cfg *ServerConfig, c Conn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ServerSecurityHandler(cfg *ServerConfig, c Conn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ServerSecurityNoneHandler(cfg *ServerConfig, c Conn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ServerServerInitHandler(cfg *ServerConfig, c Conn) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ServerClientInitHandler(cfg *ServerConfig, c Conn) error {
|
||||
return nil
|
||||
}
|
156
image.go
Normal file
156
image.go
Normal file
@ -0,0 +1,156 @@
|
||||
package vnc
|
||||
|
||||
import (
|
||||
"image"
|
||||
)
|
||||
|
||||
//var _ draw.Drawer = (*ServerConn)(nil)
|
||||
//var _ draw.Image = (*ServerConn)(nil)
|
||||
|
||||
// Color represents a single color in a color map.
|
||||
type Color struct {
|
||||
pf *PixelFormat
|
||||
cm *ColorMap
|
||||
cmIndex uint32 // Only valid if pf.TrueColor is false.
|
||||
R, G, B uint16
|
||||
}
|
||||
|
||||
type ColorMap [256]Color
|
||||
|
||||
// NewColor returns a new Color object.
|
||||
func NewColor(pf *PixelFormat, cm *ColorMap) *Color {
|
||||
return &Color{
|
||||
pf: pf,
|
||||
cm: cm,
|
||||
}
|
||||
}
|
||||
|
||||
// Rectangle represents a rectangle of pixel data.
|
||||
type Rectangle struct {
|
||||
X, Y uint16
|
||||
Width, Height uint16
|
||||
Enc Encoding
|
||||
}
|
||||
|
||||
// Marshal implements the Marshaler interface.
|
||||
func (c *Color) Marshal() ([]byte, error) {
|
||||
order := c.pf.order()
|
||||
pixel := c.cmIndex
|
||||
if c.pf.TrueColor == 1 {
|
||||
pixel = uint32(c.R) << c.pf.RedShift
|
||||
pixel |= uint32(c.G) << c.pf.GreenShift
|
||||
pixel |= uint32(c.B) << c.pf.BlueShift
|
||||
}
|
||||
|
||||
var bytes []byte
|
||||
switch c.pf.BPP {
|
||||
case 8:
|
||||
bytes = make([]byte, 1)
|
||||
bytes[0] = byte(pixel)
|
||||
case 16:
|
||||
bytes = make([]byte, 2)
|
||||
order.PutUint16(bytes, uint16(pixel))
|
||||
case 32:
|
||||
bytes = make([]byte, 4)
|
||||
order.PutUint32(bytes, pixel)
|
||||
}
|
||||
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
// Unmarshal implements the Unmarshaler interface.
|
||||
func (c *Color) Unmarshal(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
order := c.pf.order()
|
||||
|
||||
var pixel uint32
|
||||
switch c.pf.BPP {
|
||||
case 8:
|
||||
pixel = uint32(data[0])
|
||||
case 16:
|
||||
pixel = uint32(order.Uint16(data))
|
||||
case 32:
|
||||
pixel = order.Uint32(data)
|
||||
}
|
||||
|
||||
if c.pf.TrueColor == 1 {
|
||||
c.R = uint16((pixel >> c.pf.RedShift) & uint32(c.pf.RedMax))
|
||||
c.G = uint16((pixel >> c.pf.GreenShift) & uint32(c.pf.GreenMax))
|
||||
c.B = uint16((pixel >> c.pf.BlueShift) & uint32(c.pf.BlueMax))
|
||||
} else {
|
||||
*c = c.cm[pixel]
|
||||
c.cmIndex = pixel
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func colorsToImage(x, y, width, height uint16, colors []Color) *image.RGBA64 {
|
||||
rect := image.Rect(int(x), int(y), int(x+width), int(y+height))
|
||||
rgba := image.NewRGBA64(rect)
|
||||
a := uint16(1)
|
||||
for i, color := range colors {
|
||||
rgba.Pix[4*i+0] = uint8(color.R >> 8)
|
||||
rgba.Pix[4*i+1] = uint8(color.R)
|
||||
rgba.Pix[4*i+2] = uint8(color.G >> 8)
|
||||
rgba.Pix[4*i+3] = uint8(color.G)
|
||||
rgba.Pix[4*i+4] = uint8(color.B >> 8)
|
||||
rgba.Pix[4*i+5] = uint8(color.B)
|
||||
rgba.Pix[4*i+6] = uint8(a >> 8)
|
||||
rgba.Pix[4*i+7] = uint8(a)
|
||||
}
|
||||
return rgba
|
||||
}
|
||||
|
||||
// Marshal implements the Marshaler interface.
|
||||
func (r *Rectangle) Marshal() ([]byte, error) {
|
||||
/*
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
var msg Rectangle
|
||||
msg.X, msg.Y, msg.W, msg.H = r.X, r.Y, r.Width, r.Height
|
||||
msg.E = r.Enc.Type()
|
||||
if err := binary.Write(buf, binary.BigEndian, msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bytes, err := r.Enc.Marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := binary.Write(buf, binary.BigEndian, bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
*/
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Unmarshal implements the Unmarshaler interface.
|
||||
func (r *Rectangle) Unmarshal(data []byte) error {
|
||||
/*
|
||||
buf := bytes.NewBuffer(data)
|
||||
|
||||
var msg Rectangle
|
||||
if err := binary.Read(buf, binary.BigEndian, &msg); err != nil {
|
||||
return err
|
||||
}
|
||||
r.X, r.Y, r.Width, r.Height = msg.X, msg.Y, msg.W, msg.H
|
||||
|
||||
switch msg.E {
|
||||
case encodings.Raw:
|
||||
r.Enc = &RawEncoding{}
|
||||
default:
|
||||
return fmt.Errorf("unable to unmarshal encoding %v", msg.E)
|
||||
}
|
||||
return nil
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
||||
// Area returns the total area in pixels of the Rectangle.
|
||||
func (r *Rectangle) Area() int { return int(r.Width) * int(r.Height) }
|
197
key_string.go
Normal file
197
key_string.go
Normal file
@ -0,0 +1,197 @@
|
||||
// Code generated by "stringer -type=Key"; DO NOT EDIT.
|
||||
|
||||
package vnc
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _Key_name = "SpaceExclaimQuoteDblNumberSignDollarPercentAmpersandApostropheParenLeftParenRightAsteriskPlusCommaMinusPeriodSlashDigit0Digit1Digit2Digit3Digit4Digit5Digit6Digit7Digit8Digit9ColonSemicolonLessEqualGreaterQuestionAtABCDEFGHIJKLMNOPQRSTUVWXYZBracketLeftBackslashBracketRightAsciiCircumUnderscoreGraveSmallASmallBSmallCSmallDSmallESmallFSmallGSmallHSmallISmallJSmallKSmallLSmallMSmallNSmallOSmallPSmallQSmallRSmallSSmallTSmallUSmallVSmallWSmallXSmallYSmallZBraceLeftBarBraceRightAsciiTildeBackSpaceTabLinefeedClearReturnPauseScrollLockSysReqEscapeHomeLeftUpRightDownPageUpPageDownEndBeginSelectModeSwitchNumLockKeypadSpaceKeypadTabKeypadEnterKeypadF1KeypadF2KeypadF3KeypadF4KeypadHomeKeypadLeftKeypadUpKeypadRightKeypadDownKeypadPriorKeypadPageUpKeypadNextKeypadPageDownKeypadEndKeypadBeginKeypadInsertKeypadDeleteKeypadMultiplyKeypadAddKeypadSeparatorKeypadSubtractKeypadDecimalKeypadDivideKeypad0Keypad1Keypad2Keypad3Keypad4Keypad5Keypad6Keypad7Keypad8Keypad9KeypadEqualF1F2F3F4F5F6F7F8F9F10F11F12ShiftLeftShiftRightControlLeftControlRightCapsLockShiftLockMetaLeftMetaRightAltLeftAltRightSuperLeftSuperRightHyperLeftHyperRightDelete"
|
||||
|
||||
var _Key_map = map[Key]string{
|
||||
32: _Key_name[0:5],
|
||||
33: _Key_name[5:12],
|
||||
34: _Key_name[12:20],
|
||||
35: _Key_name[20:30],
|
||||
36: _Key_name[30:36],
|
||||
37: _Key_name[36:43],
|
||||
38: _Key_name[43:52],
|
||||
39: _Key_name[52:62],
|
||||
40: _Key_name[62:71],
|
||||
41: _Key_name[71:81],
|
||||
42: _Key_name[81:89],
|
||||
43: _Key_name[89:93],
|
||||
44: _Key_name[93:98],
|
||||
45: _Key_name[98:103],
|
||||
46: _Key_name[103:109],
|
||||
47: _Key_name[109:114],
|
||||
48: _Key_name[114:120],
|
||||
49: _Key_name[120:126],
|
||||
50: _Key_name[126:132],
|
||||
51: _Key_name[132:138],
|
||||
52: _Key_name[138:144],
|
||||
53: _Key_name[144:150],
|
||||
54: _Key_name[150:156],
|
||||
55: _Key_name[156:162],
|
||||
56: _Key_name[162:168],
|
||||
57: _Key_name[168:174],
|
||||
58: _Key_name[174:179],
|
||||
59: _Key_name[179:188],
|
||||
60: _Key_name[188:192],
|
||||
61: _Key_name[192:197],
|
||||
62: _Key_name[197:204],
|
||||
63: _Key_name[204:212],
|
||||
64: _Key_name[212:214],
|
||||
65: _Key_name[214:215],
|
||||
66: _Key_name[215:216],
|
||||
67: _Key_name[216:217],
|
||||
68: _Key_name[217:218],
|
||||
69: _Key_name[218:219],
|
||||
70: _Key_name[219:220],
|
||||
71: _Key_name[220:221],
|
||||
72: _Key_name[221:222],
|
||||
73: _Key_name[222:223],
|
||||
74: _Key_name[223:224],
|
||||
75: _Key_name[224:225],
|
||||
76: _Key_name[225:226],
|
||||
77: _Key_name[226:227],
|
||||
78: _Key_name[227:228],
|
||||
79: _Key_name[228:229],
|
||||
80: _Key_name[229:230],
|
||||
81: _Key_name[230:231],
|
||||
82: _Key_name[231:232],
|
||||
83: _Key_name[232:233],
|
||||
84: _Key_name[233:234],
|
||||
85: _Key_name[234:235],
|
||||
86: _Key_name[235:236],
|
||||
87: _Key_name[236:237],
|
||||
88: _Key_name[237:238],
|
||||
89: _Key_name[238:239],
|
||||
90: _Key_name[239:240],
|
||||
91: _Key_name[240:251],
|
||||
92: _Key_name[251:260],
|
||||
93: _Key_name[260:272],
|
||||
94: _Key_name[272:283],
|
||||
95: _Key_name[283:293],
|
||||
96: _Key_name[293:298],
|
||||
97: _Key_name[298:304],
|
||||
98: _Key_name[304:310],
|
||||
99: _Key_name[310:316],
|
||||
100: _Key_name[316:322],
|
||||
101: _Key_name[322:328],
|
||||
102: _Key_name[328:334],
|
||||
103: _Key_name[334:340],
|
||||
104: _Key_name[340:346],
|
||||
105: _Key_name[346:352],
|
||||
106: _Key_name[352:358],
|
||||
107: _Key_name[358:364],
|
||||
108: _Key_name[364:370],
|
||||
109: _Key_name[370:376],
|
||||
110: _Key_name[376:382],
|
||||
111: _Key_name[382:388],
|
||||
112: _Key_name[388:394],
|
||||
113: _Key_name[394:400],
|
||||
114: _Key_name[400:406],
|
||||
115: _Key_name[406:412],
|
||||
116: _Key_name[412:418],
|
||||
117: _Key_name[418:424],
|
||||
118: _Key_name[424:430],
|
||||
119: _Key_name[430:436],
|
||||
120: _Key_name[436:442],
|
||||
121: _Key_name[442:448],
|
||||
122: _Key_name[448:454],
|
||||
123: _Key_name[454:463],
|
||||
124: _Key_name[463:466],
|
||||
125: _Key_name[466:476],
|
||||
126: _Key_name[476:486],
|
||||
65288: _Key_name[486:495],
|
||||
65289: _Key_name[495:498],
|
||||
65290: _Key_name[498:506],
|
||||
65291: _Key_name[506:511],
|
||||
65293: _Key_name[511:517],
|
||||
65299: _Key_name[517:522],
|
||||
65300: _Key_name[522:532],
|
||||
65301: _Key_name[532:538],
|
||||
65307: _Key_name[538:544],
|
||||
65360: _Key_name[544:548],
|
||||
65361: _Key_name[548:552],
|
||||
65362: _Key_name[552:554],
|
||||
65363: _Key_name[554:559],
|
||||
65364: _Key_name[559:563],
|
||||
65365: _Key_name[563:569],
|
||||
65366: _Key_name[569:577],
|
||||
65367: _Key_name[577:580],
|
||||
65368: _Key_name[580:585],
|
||||
65376: _Key_name[585:591],
|
||||
65406: _Key_name[591:601],
|
||||
65407: _Key_name[601:608],
|
||||
65408: _Key_name[608:619],
|
||||
65417: _Key_name[619:628],
|
||||
65421: _Key_name[628:639],
|
||||
65425: _Key_name[639:647],
|
||||
65426: _Key_name[647:655],
|
||||
65427: _Key_name[655:663],
|
||||
65428: _Key_name[663:671],
|
||||
65429: _Key_name[671:681],
|
||||
65430: _Key_name[681:691],
|
||||
65431: _Key_name[691:699],
|
||||
65432: _Key_name[699:710],
|
||||
65433: _Key_name[710:720],
|
||||
65434: _Key_name[720:731],
|
||||
65435: _Key_name[731:743],
|
||||
65436: _Key_name[743:753],
|
||||
65437: _Key_name[753:767],
|
||||
65438: _Key_name[767:776],
|
||||
65439: _Key_name[776:787],
|
||||
65440: _Key_name[787:799],
|
||||
65441: _Key_name[799:811],
|
||||
65442: _Key_name[811:825],
|
||||
65443: _Key_name[825:834],
|
||||
65444: _Key_name[834:849],
|
||||
65445: _Key_name[849:863],
|
||||
65446: _Key_name[863:876],
|
||||
65447: _Key_name[876:888],
|
||||
65448: _Key_name[888:895],
|
||||
65449: _Key_name[895:902],
|
||||
65450: _Key_name[902:909],
|
||||
65451: _Key_name[909:916],
|
||||
65452: _Key_name[916:923],
|
||||
65453: _Key_name[923:930],
|
||||
65454: _Key_name[930:937],
|
||||
65455: _Key_name[937:944],
|
||||
65456: _Key_name[944:951],
|
||||
65457: _Key_name[951:958],
|
||||
65469: _Key_name[958:969],
|
||||
65470: _Key_name[969:971],
|
||||
65471: _Key_name[971:973],
|
||||
65472: _Key_name[973:975],
|
||||
65473: _Key_name[975:977],
|
||||
65474: _Key_name[977:979],
|
||||
65475: _Key_name[979:981],
|
||||
65476: _Key_name[981:983],
|
||||
65477: _Key_name[983:985],
|
||||
65478: _Key_name[985:987],
|
||||
65479: _Key_name[987:990],
|
||||
65480: _Key_name[990:993],
|
||||
65481: _Key_name[993:996],
|
||||
65505: _Key_name[996:1005],
|
||||
65506: _Key_name[1005:1015],
|
||||
65507: _Key_name[1015:1026],
|
||||
65508: _Key_name[1026:1038],
|
||||
65509: _Key_name[1038:1046],
|
||||
65510: _Key_name[1046:1055],
|
||||
65511: _Key_name[1055:1063],
|
||||
65512: _Key_name[1063:1072],
|
||||
65513: _Key_name[1072:1079],
|
||||
65514: _Key_name[1079:1087],
|
||||
65515: _Key_name[1087:1096],
|
||||
65516: _Key_name[1096:1106],
|
||||
65517: _Key_name[1106:1115],
|
||||
65518: _Key_name[1115:1125],
|
||||
65535: _Key_name[1125:1131],
|
||||
}
|
||||
|
||||
func (i Key) String() string {
|
||||
if str, ok := _Key_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return fmt.Sprintf("Key(%d)", i)
|
||||
}
|
254
keys.go
Normal file
254
keys.go
Normal file
@ -0,0 +1,254 @@
|
||||
package vnc
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Key represents a VNC key press.
|
||||
type Key uint32
|
||||
|
||||
//go:generate stringer -type=Key
|
||||
|
||||
// Keys is a slice of Key values.
|
||||
type Keys []Key
|
||||
|
||||
var keymap = map[rune]Key{
|
||||
'-': Minus,
|
||||
'0': Digit0,
|
||||
'1': Digit1,
|
||||
'2': Digit2,
|
||||
'3': Digit3,
|
||||
'4': Digit4,
|
||||
'5': Digit5,
|
||||
'6': Digit6,
|
||||
'7': Digit7,
|
||||
'8': Digit8,
|
||||
'9': Digit9,
|
||||
}
|
||||
|
||||
// IntToKeys returns Keys that represent the key presses required to type an int.
|
||||
func IntToKeys(v int) Keys {
|
||||
k := Keys{}
|
||||
for _, c := range fmt.Sprintf("%d", v) {
|
||||
k = append(k, keymap[c])
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
// Latin 1 (byte 3 = 0)
|
||||
// ISO/IEC 8859-1 = Unicode U+0020..U+00FF
|
||||
const (
|
||||
Space Key = iota + 0x0020
|
||||
Exclaim // exclamation mark
|
||||
QuoteDbl
|
||||
NumberSign
|
||||
Dollar
|
||||
Percent
|
||||
Ampersand
|
||||
Apostrophe
|
||||
ParenLeft
|
||||
ParenRight
|
||||
Asterisk
|
||||
Plus
|
||||
Comma
|
||||
Minus
|
||||
Period
|
||||
Slash
|
||||
Digit0
|
||||
Digit1
|
||||
Digit2
|
||||
Digit3
|
||||
Digit4
|
||||
Digit5
|
||||
Digit6
|
||||
Digit7
|
||||
Digit8
|
||||
Digit9
|
||||
Colon
|
||||
Semicolon
|
||||
Less
|
||||
Equal
|
||||
Greater
|
||||
Question
|
||||
At
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
BracketLeft
|
||||
Backslash
|
||||
BracketRight
|
||||
AsciiCircum
|
||||
Underscore
|
||||
Grave
|
||||
SmallA
|
||||
SmallB
|
||||
SmallC
|
||||
SmallD
|
||||
SmallE
|
||||
SmallF
|
||||
SmallG
|
||||
SmallH
|
||||
SmallI
|
||||
SmallJ
|
||||
SmallK
|
||||
SmallL
|
||||
SmallM
|
||||
SmallN
|
||||
SmallO
|
||||
SmallP
|
||||
SmallQ
|
||||
SmallR
|
||||
SmallS
|
||||
SmallT
|
||||
SmallU
|
||||
SmallV
|
||||
SmallW
|
||||
SmallX
|
||||
SmallY
|
||||
SmallZ
|
||||
BraceLeft
|
||||
Bar
|
||||
BraceRight
|
||||
AsciiTilde
|
||||
)
|
||||
|
||||
const (
|
||||
BackSpace Key = iota + 0xff08
|
||||
Tab
|
||||
Linefeed
|
||||
Clear
|
||||
_
|
||||
Return
|
||||
)
|
||||
|
||||
const (
|
||||
Pause Key = iota + 0xff13
|
||||
ScrollLock
|
||||
SysReq
|
||||
Escape Key = 0xff1b
|
||||
Delete Key = 0xffff
|
||||
)
|
||||
|
||||
const ( // Cursor control & motion.
|
||||
Home Key = iota + 0xff50
|
||||
Left
|
||||
Up
|
||||
Right
|
||||
Down
|
||||
PageUp
|
||||
PageDown
|
||||
End
|
||||
Begin
|
||||
)
|
||||
|
||||
const ( // Misc functions.
|
||||
Select Key = 0xff60
|
||||
Print
|
||||
Execute
|
||||
Insert
|
||||
Undo
|
||||
Redo
|
||||
Menu
|
||||
Find
|
||||
Cancel
|
||||
Help
|
||||
Break
|
||||
ModeSwitch Key = 0xff7e
|
||||
NumLock Key = 0xff7f
|
||||
)
|
||||
|
||||
const ( // Keypad functions.
|
||||
KeypadSpace Key = 0xff80
|
||||
KeypadTab Key = 0xff89
|
||||
KeypadEnter Key = 0xff8d
|
||||
)
|
||||
|
||||
const ( // Keypad functions cont.
|
||||
KeypadF1 Key = iota + 0xff91
|
||||
KeypadF2
|
||||
KeypadF3
|
||||
KeypadF4
|
||||
KeypadHome
|
||||
KeypadLeft
|
||||
KeypadUp
|
||||
KeypadRight
|
||||
KeypadDown
|
||||
KeypadPrior
|
||||
KeypadPageUp
|
||||
KeypadNext
|
||||
KeypadPageDown
|
||||
KeypadEnd
|
||||
KeypadBegin
|
||||
KeypadInsert
|
||||
KeypadDelete
|
||||
KeypadMultiply
|
||||
KeypadAdd
|
||||
KeypadSeparator
|
||||
KeypadSubtract
|
||||
KeypadDecimal
|
||||
KeypadDivide
|
||||
Keypad0
|
||||
Keypad1
|
||||
Keypad2
|
||||
Keypad3
|
||||
Keypad4
|
||||
Keypad5
|
||||
Keypad6
|
||||
Keypad7
|
||||
Keypad8
|
||||
Keypad9
|
||||
KeypadEqual Key = 0xffbd
|
||||
)
|
||||
|
||||
const (
|
||||
F1 Key = iota + 0xffbe
|
||||
F2
|
||||
F3
|
||||
F4
|
||||
F5
|
||||
F6
|
||||
F7
|
||||
F8
|
||||
F9
|
||||
F10
|
||||
F11
|
||||
F12
|
||||
)
|
||||
|
||||
const (
|
||||
ShiftLeft Key = iota + 0xffe1
|
||||
ShiftRight
|
||||
ControlLeft
|
||||
ControlRight
|
||||
CapsLock
|
||||
ShiftLock
|
||||
MetaLeft
|
||||
MetaRight
|
||||
AltLeft
|
||||
AltRight
|
||||
SuperLeft
|
||||
SuperRight
|
||||
HyperLeft
|
||||
HyperRight
|
||||
)
|
112
pixel_format.go
Normal file
112
pixel_format.go
Normal file
@ -0,0 +1,112 @@
|
||||
// Implementation of RFC 6143 §7.4 Pixel Format Data Structure.
|
||||
|
||||
package vnc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
)
|
||||
|
||||
var (
|
||||
PixelFormat8bit *PixelFormat = NewPixelFormat(8)
|
||||
PixelFormat16bit *PixelFormat = NewPixelFormat(16)
|
||||
PixelFormat32bit *PixelFormat = NewPixelFormat(32)
|
||||
)
|
||||
|
||||
// PixelFormat describes the way a pixel is formatted for a VNC connection.
|
||||
type PixelFormat struct {
|
||||
BPP uint8 // bits-per-pixel
|
||||
Depth uint8 // depth
|
||||
BigEndian uint8 // big-endian-flag
|
||||
TrueColor uint8 // true-color-flag
|
||||
RedMax, GreenMax, BlueMax uint16 // red-, green-, blue-max (2^BPP-1)
|
||||
RedShift, GreenShift, BlueShift uint8 // red-, green-, blue-shift
|
||||
_ [3]byte // padding
|
||||
}
|
||||
|
||||
const pixelFormatLen = 16
|
||||
|
||||
// NewPixelFormat returns a populated PixelFormat structure.
|
||||
func NewPixelFormat(bpp uint8) *PixelFormat {
|
||||
bigEndian := uint8(1)
|
||||
rgbMax := uint16(math.Exp2(float64(bpp))) - 1
|
||||
var (
|
||||
tc = uint8(1)
|
||||
rs, gs, bs uint8
|
||||
)
|
||||
switch bpp {
|
||||
case 8:
|
||||
tc = 0
|
||||
rs, gs, bs = 0, 0, 0
|
||||
case 16:
|
||||
rs, gs, bs = 0, 4, 8
|
||||
case 32:
|
||||
rs, gs, bs = 0, 8, 16
|
||||
}
|
||||
return &PixelFormat{bpp, bpp, bigEndian, tc, rgbMax, rgbMax, rgbMax, rs, gs, bs, [3]byte{}}
|
||||
}
|
||||
|
||||
// Marshal implements the Marshaler interface.
|
||||
func (pf *PixelFormat) Marshal() ([]byte, error) {
|
||||
// Validation checks.
|
||||
switch pf.BPP {
|
||||
case 8, 16, 32:
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid BPP value %v; must be 8, 16, or 32.", pf.BPP)
|
||||
}
|
||||
|
||||
if pf.Depth < pf.BPP {
|
||||
return nil, fmt.Errorf("Invalid Depth value %v; cannot be < BPP", pf.Depth)
|
||||
}
|
||||
switch pf.Depth {
|
||||
case 8, 16, 32:
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid Depth value %v; must be 8, 16, or 32.", pf.Depth)
|
||||
}
|
||||
|
||||
// Create the slice of bytes
|
||||
buf := bytes.NewBuffer(nil)
|
||||
if err := binary.Write(buf, binary.BigEndian, &pf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Read reads from an io.Reader, and populates the PixelFormat.
|
||||
func (pf *PixelFormat) Read(r io.Reader) error {
|
||||
buf := make([]byte, pixelFormatLen)
|
||||
if _, err := io.ReadAtLeast(r, buf, pixelFormatLen); err != nil {
|
||||
return err
|
||||
}
|
||||
return pf.Unmarshal(buf)
|
||||
}
|
||||
|
||||
// Unmarshal implements the Unmarshaler interface.
|
||||
func (pf *PixelFormat) Unmarshal(data []byte) error {
|
||||
buf := bytes.NewBuffer(data)
|
||||
|
||||
var msg PixelFormat
|
||||
if err := binary.Read(buf, binary.BigEndian, &msg); err != nil {
|
||||
return err
|
||||
}
|
||||
*pf = msg
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer interface.
|
||||
func (pf *PixelFormat) String() string {
|
||||
return fmt.Sprintf("{ bpp: %d depth: %d big-endian: %s true-color: %s red-max: %d green-max: %d blue-max: %d red-shift: %d green-shift: %d blue-shift: %d }",
|
||||
pf.BPP, pf.Depth, pf.BigEndian, pf.TrueColor, pf.RedMax, pf.GreenMax, pf.BlueMax, pf.RedShift, pf.GreenShift, pf.BlueShift)
|
||||
}
|
||||
|
||||
func (pf *PixelFormat) order() binary.ByteOrder {
|
||||
if pf.BigEndian == 1 {
|
||||
return binary.BigEndian
|
||||
}
|
||||
return binary.LittleEndian
|
||||
}
|
438
server.go
Normal file
438
server.go
Normal file
@ -0,0 +1,438 @@
|
||||
package vnc
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
var DefaultClientMessages = []ClientMessage{
|
||||
&SetPixelFormat{},
|
||||
&SetEncodings{},
|
||||
&FramebufferUpdateRequest{},
|
||||
&KeyEvent{},
|
||||
&PointerEvent{},
|
||||
&ClientCutText{},
|
||||
}
|
||||
|
||||
var _ Conn = (*ServerConn)(nil)
|
||||
|
||||
func (c *ServerConn) Flush() error {
|
||||
return c.bw.Flush()
|
||||
}
|
||||
|
||||
func (c *ServerConn) Close() error {
|
||||
return c.c.Close()
|
||||
}
|
||||
|
||||
/*
|
||||
func (c *ServerConn) Input() chan *ServerMessage {
|
||||
return c.cfg.ServerMessageCh
|
||||
}
|
||||
|
||||
func (c *ServerConn) Output() chan *ClientMessage {
|
||||
return c.cfg.ClientMessageCh
|
||||
}
|
||||
*/
|
||||
func (c *ServerConn) Read(buf []byte) (int, error) {
|
||||
return c.br.Read(buf)
|
||||
}
|
||||
|
||||
func (c *ServerConn) Write(buf []byte) (int, error) {
|
||||
return c.bw.Write(buf)
|
||||
}
|
||||
|
||||
func (c *ServerConn) ColorMap() *ColorMap {
|
||||
return c.colorMap
|
||||
}
|
||||
|
||||
func (c *ServerConn) SetColorMap(cm *ColorMap) {
|
||||
c.colorMap = cm
|
||||
}
|
||||
func (c *ServerConn) DesktopName() string {
|
||||
return c.desktopName
|
||||
}
|
||||
func (c *ServerConn) PixelFormat() *PixelFormat {
|
||||
return c.pixelFormat
|
||||
}
|
||||
func (c *ServerConn) Encodings() []Encoding {
|
||||
return c.encodings
|
||||
}
|
||||
func (c *ServerConn) Width() uint16 {
|
||||
return c.fbWidth
|
||||
}
|
||||
func (c *ServerConn) Height() uint16 {
|
||||
return c.fbHeight
|
||||
}
|
||||
func (c *ServerConn) Protocol() string {
|
||||
return c.protocol
|
||||
}
|
||||
|
||||
// TODO send desktopsize pseudo encoding
|
||||
func (c *ServerConn) SetWidth(w uint16) {
|
||||
c.fbWidth = w
|
||||
}
|
||||
func (c *ServerConn) SetHeight(h uint16) {
|
||||
c.fbHeight = h
|
||||
}
|
||||
|
||||
// ServerMessage represents a Client-to-Server RFB message type.
|
||||
type ServerMessageType uint8
|
||||
|
||||
//go:generate stringer -type=ServerMessageType
|
||||
|
||||
// Client-to-Server message types.
|
||||
const (
|
||||
FramebufferUpdateMsgType ServerMessageType = iota
|
||||
SetColorMapEntriesMsgType
|
||||
BellMsgType
|
||||
ServerCutTextMsgType
|
||||
)
|
||||
|
||||
// FramebufferUpdate holds a FramebufferUpdate wire format message.
|
||||
type FramebufferUpdate struct {
|
||||
MsgType ServerMessageType
|
||||
NumRect uint16 // number-of-rectangles
|
||||
_ [1]byte // pad
|
||||
Rects []Rectangle // rectangles
|
||||
}
|
||||
|
||||
func (msg *FramebufferUpdate) Type() ServerMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *FramebufferUpdate) Read(c Conn) error {
|
||||
if err := binary.Read(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pad [1]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, msg.NumRect); err != nil {
|
||||
return err
|
||||
}
|
||||
/*
|
||||
// Extract rectangles.
|
||||
rects := make([]Rectangle, msg.NumRect)
|
||||
for i := uint16(0); i < msg.NumRect; i++ {
|
||||
rect := NewRectangle(c)
|
||||
if err := rect.Read(c); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Rects = append(msg.Rects, *rect)
|
||||
}
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg *FramebufferUpdate) Write(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
var pad [1]byte
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg.NumRect); err != nil {
|
||||
return err
|
||||
}
|
||||
/*
|
||||
for _, rect := range msg.Rects {
|
||||
if err := rect.Write(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*/
|
||||
return c.Flush()
|
||||
}
|
||||
|
||||
type ServerConn struct {
|
||||
c net.Conn
|
||||
cfg *ServerConfig
|
||||
br *bufio.Reader
|
||||
bw *bufio.Writer
|
||||
protocol string
|
||||
|
||||
// If the pixel format uses a color map, then this is the color
|
||||
// map that is used. This should not be modified directly, since
|
||||
// the data comes from the server.
|
||||
// Definition in §5 - Representation of Pixel Data.
|
||||
colorMap *ColorMap
|
||||
|
||||
// Name associated with the desktop, sent from the server.
|
||||
desktopName string
|
||||
|
||||
// Encodings supported by the client. This should not be modified
|
||||
// directly. Instead, SetEncodings() should be used.
|
||||
encodings []Encoding
|
||||
|
||||
// Height of the frame buffer in pixels, sent to the client.
|
||||
fbHeight uint16
|
||||
|
||||
// Width of the frame buffer in pixels, sent to the client.
|
||||
fbWidth uint16
|
||||
|
||||
// The pixel format associated with the connection. This shouldn't
|
||||
// be modified. If you wish to set a new pixel format, use the
|
||||
// SetPixelFormat method.
|
||||
pixelFormat *PixelFormat
|
||||
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
type ServerHandler func(*ServerConfig, Conn) error
|
||||
|
||||
type ServerConfig struct {
|
||||
VersionHandler ServerHandler
|
||||
SecurityHandler ServerHandler
|
||||
SecurityHandlers []ServerHandler
|
||||
ClientInitHandler ServerHandler
|
||||
ServerInitHandler ServerHandler
|
||||
Encodings []Encoding
|
||||
PixelFormat *PixelFormat
|
||||
ColorMap *ColorMap
|
||||
ClientMessageCh chan ClientMessage
|
||||
ServerMessageCh chan ServerMessage
|
||||
ClientMessages []ClientMessage
|
||||
}
|
||||
|
||||
func NewServerConn(c net.Conn, cfg *ServerConfig) (*ServerConn, error) {
|
||||
if cfg.ClientMessageCh == nil {
|
||||
return nil, fmt.Errorf("ClientMessageCh nil")
|
||||
}
|
||||
if len(cfg.ClientMessages) == 0 {
|
||||
return nil, fmt.Errorf("ClientMessage 0")
|
||||
}
|
||||
return &ServerConn{
|
||||
c: c,
|
||||
br: bufio.NewReader(c),
|
||||
bw: bufio.NewWriter(c),
|
||||
cfg: cfg,
|
||||
encodings: cfg.Encodings,
|
||||
pixelFormat: cfg.PixelFormat,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func Serve(ctx context.Context, ln net.Listener, cfg *ServerConfig) error {
|
||||
for {
|
||||
c, err := ln.Accept()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
conn, err := NewServerConn(c, cfg)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if err := cfg.VersionHandler(cfg, conn); err != nil {
|
||||
conn.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
if err := cfg.SecurityHandler(cfg, conn); err != nil {
|
||||
conn.Close()
|
||||
continue
|
||||
}
|
||||
if err := cfg.ClientInitHandler(cfg, conn); err != nil {
|
||||
conn.Close()
|
||||
continue
|
||||
}
|
||||
if err := cfg.ServerInitHandler(cfg, conn); err != nil {
|
||||
conn.Close()
|
||||
continue
|
||||
}
|
||||
go conn.Handle()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ServerConn) Handle() error {
|
||||
var err error
|
||||
defer c.Close()
|
||||
clientMessages := make(map[ClientMessageType]ClientMessage)
|
||||
for _, m := range c.cfg.ClientMessages {
|
||||
clientMessages[m.Type()] = m
|
||||
}
|
||||
|
||||
serverLoop:
|
||||
for {
|
||||
select {
|
||||
case msg := <-c.cfg.ServerMessageCh:
|
||||
if err = msg.Write(c); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Flush()
|
||||
case <-c.quit:
|
||||
break serverLoop
|
||||
}
|
||||
}
|
||||
|
||||
clientLoop:
|
||||
for {
|
||||
select {
|
||||
case <-c.quit:
|
||||
break clientLoop
|
||||
default:
|
||||
var messageType ClientMessageType
|
||||
if err := binary.Read(c, binary.BigEndian, &messageType); err != nil {
|
||||
break clientLoop
|
||||
}
|
||||
|
||||
msg, ok := clientMessages[messageType]
|
||||
if !ok {
|
||||
err = fmt.Errorf("unsupported message-type: %v", messageType)
|
||||
break clientLoop
|
||||
}
|
||||
if err := msg.Read(c); err != nil {
|
||||
break clientLoop
|
||||
}
|
||||
|
||||
c.cfg.ClientMessageCh <- msg
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ServerCutText struct {
|
||||
MsgType ServerMessageType
|
||||
_ [1]byte
|
||||
Length uint32
|
||||
Text []byte
|
||||
}
|
||||
|
||||
func (msg *ServerCutText) Type() ServerMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *ServerCutText) Read(c Conn) error {
|
||||
if err := binary.Read(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
var pad [1]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var length uint32
|
||||
if err := binary.Read(c, binary.BigEndian, &length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
text := make([]byte, length)
|
||||
if err := binary.Read(c, binary.BigEndian, &text); err != nil {
|
||||
return err
|
||||
}
|
||||
msg.Text = text
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg *ServerCutText) Write(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
var pad [1]byte
|
||||
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Length); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, msg.Text); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Bell struct {
|
||||
MsgType ServerMessageType
|
||||
}
|
||||
|
||||
func (msg *Bell) Type() ServerMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *Bell) Read(c Conn) error {
|
||||
return binary.Read(c, binary.BigEndian, msg.MsgType)
|
||||
}
|
||||
|
||||
func (msg *Bell) Write(c Conn) error {
|
||||
return binary.Write(c, binary.BigEndian, msg.MsgType)
|
||||
}
|
||||
|
||||
type SetColorMapEntries struct {
|
||||
MsgType ServerMessageType
|
||||
_ [1]byte
|
||||
FirstColor uint16
|
||||
ColorsNum uint16
|
||||
Colors []Color
|
||||
}
|
||||
|
||||
func (msg *SetColorMapEntries) Type() ServerMessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *SetColorMapEntries) Read(c Conn) error {
|
||||
if err := binary.Read(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
var pad [1]byte
|
||||
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, msg.FirstColor); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Read(c, binary.BigEndian, msg.ColorsNum); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg.Colors = make([]Color, msg.ColorsNum)
|
||||
colorMap := c.ColorMap()
|
||||
|
||||
for i := uint16(0); i < msg.ColorsNum; i++ {
|
||||
color := &msg.Colors[i]
|
||||
if err := binary.Read(c, binary.BigEndian, &color); err != nil {
|
||||
return err
|
||||
}
|
||||
colorMap[msg.FirstColor+i] = *color
|
||||
}
|
||||
c.SetColorMap(colorMap)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg *SetColorMapEntries) Write(c Conn) error {
|
||||
if err := binary.Write(c, binary.BigEndian, msg.MsgType); err != nil {
|
||||
return err
|
||||
}
|
||||
var pad [1]byte
|
||||
if err := binary.Write(c, binary.BigEndian, &pad); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := binary.Write(c, binary.BigEndian, msg.FirstColor); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if msg.ColorsNum < uint16(len(msg.Colors)) {
|
||||
msg.ColorsNum = uint16(len(msg.Colors))
|
||||
}
|
||||
if err := binary.Write(c, binary.BigEndian, msg.ColorsNum); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := 0; i < len(msg.Colors); i++ {
|
||||
color := msg.Colors[i]
|
||||
if err := binary.Write(c, binary.BigEndian, color); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
16
servermessagetype_string.go
Normal file
16
servermessagetype_string.go
Normal file
@ -0,0 +1,16 @@
|
||||
// Code generated by "stringer -type=ServerMessageType"; DO NOT EDIT.
|
||||
|
||||
package vnc
|
||||
|
||||
import "fmt"
|
||||
|
||||
const _ServerMessageType_name = "FramebufferUpdateMsgTypeSetColorMapEntriesMsgTypeBellMsgTypeServerCutTextMsgType"
|
||||
|
||||
var _ServerMessageType_index = [...]uint8{0, 24, 49, 60, 80}
|
||||
|
||||
func (i ServerMessageType) String() string {
|
||||
if i >= ServerMessageType(len(_ServerMessageType_index)-1) {
|
||||
return fmt.Sprintf("ServerMessageType(%d)", i)
|
||||
}
|
||||
return _ServerMessageType_name[_ServerMessageType_index[i]:_ServerMessageType_index[i+1]]
|
||||
}
|
Loading…
Reference in New Issue
Block a user