not working example

Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
This commit is contained in:
Василий Толстов 2017-06-12 14:11:23 +03:00
parent 5139d1dd82
commit a45bca15e3
19 changed files with 2078 additions and 0 deletions

2
.gitignore vendored
View File

@ -12,3 +12,5 @@
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/ .glide/
example/client/client
example/server/server

View File

@ -1,5 +1,7 @@
MIT License MIT License
Copyright (c) 2013 Mitchell Hashimoto
Copyright (c) 2016-2017 Kate Ward
Copyright (c) 2017 Vasiliy Tolstov Copyright (c) 2017 Vasiliy Tolstov
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy

46
button_string.go Normal file
View 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
View 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
View 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
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}

View 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]]
}