mirror of
https://github.com/amitbet/vncproxy.git
synced 2025-04-27 10:50:47 +00:00
285 lines
7.5 KiB
Go
285 lines
7.5 KiB
Go
package client
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
"github.com/amitbet/vncproxy/common"
|
|
"github.com/amitbet/vncproxy/encodings"
|
|
"github.com/amitbet/vncproxy/logger"
|
|
)
|
|
|
|
// MsgFramebufferUpdate consists of a sequence of rectangles of
|
|
// pixel data that the client should put into its framebuffer.
|
|
type MsgFramebufferUpdate struct {
|
|
Rectangles []common.Rectangle
|
|
}
|
|
|
|
func (m *MsgFramebufferUpdate) String() string {
|
|
str := fmt.Sprintf("MsgFramebufferUpdate (type=%d) Rects: ", m.Type())
|
|
for _, rect := range m.Rectangles {
|
|
str += rect.String() + "\n"
|
|
//if this is the last rect, break the loop
|
|
if rect.Enc.Type() == int32(common.EncLastRectPseudo) {
|
|
break
|
|
}
|
|
}
|
|
return str
|
|
}
|
|
|
|
func (*MsgFramebufferUpdate) Type() uint8 {
|
|
return 0
|
|
}
|
|
|
|
func (fbm *MsgFramebufferUpdate) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error {
|
|
reader := common.NewRfbReadHelper(r)
|
|
writeTo := &WriteTo{w, "MsgFramebufferUpdate.CopyTo"}
|
|
reader.Listeners.AddListener(writeTo)
|
|
_, err := fbm.Read(c, reader)
|
|
return err
|
|
}
|
|
|
|
func (fbm *MsgFramebufferUpdate) Read(c common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) {
|
|
|
|
// Read off the padding
|
|
var padding [1]byte
|
|
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var numRects uint16
|
|
if err := binary.Read(r, binary.BigEndian, &numRects); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Build the map of encodings supported
|
|
encMap := make(map[int32]common.IEncoding)
|
|
for _, enc := range c.Encodings() {
|
|
encMap[enc.Type()] = enc
|
|
}
|
|
|
|
// We must always support the raw encoding
|
|
rawEnc := new(encodings.RawEncoding)
|
|
encMap[rawEnc.Type()] = rawEnc
|
|
logger.Debugf("MsgFramebufferUpdate.Read: numrects= %d", numRects)
|
|
|
|
rects := make([]common.Rectangle, numRects)
|
|
for i := uint16(0); i < numRects; i++ {
|
|
logger.Debugf("MsgFramebufferUpdate.Read: ###############rect################: %d", i)
|
|
|
|
var encodingTypeInt int32
|
|
r.SendRectSeparator(-1)
|
|
rect := &rects[i]
|
|
data := []interface{}{
|
|
&rect.X,
|
|
&rect.Y,
|
|
&rect.Width,
|
|
&rect.Height,
|
|
&encodingTypeInt,
|
|
}
|
|
|
|
for _, val := range data {
|
|
if err := binary.Read(r, binary.BigEndian, val); err != nil {
|
|
logger.Errorf("err: %v", err)
|
|
return nil, err
|
|
}
|
|
}
|
|
jBytes, _ := json.Marshal(data)
|
|
|
|
encType := common.EncodingType(encodingTypeInt)
|
|
|
|
logger.Debugf("MsgFramebufferUpdate.Read: rect# %d, rect hdr data: enctype=%s, data: %s", i, encType, string(jBytes))
|
|
enc, supported := encMap[encodingTypeInt]
|
|
if supported {
|
|
var err error
|
|
rect.Enc, err = enc.Read(c.CurrentPixelFormat(), rect, r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
if strings.Contains(encType.String(), "Pseudo") {
|
|
rect.Enc = &encodings.PseudoEncoding{encodingTypeInt}
|
|
|
|
//if this is the last rect, break the for loop
|
|
if rect.Enc.Type() == int32(common.EncLastRectPseudo) {
|
|
break
|
|
}
|
|
} else {
|
|
logger.Errorf("MsgFramebufferUpdate.Read: unsupported encoding type: %d, %s", encodingTypeInt, encType)
|
|
return nil, fmt.Errorf("MsgFramebufferUpdate.Read: unsupported encoding type: %d, %s", encodingTypeInt, encType)
|
|
}
|
|
}
|
|
}
|
|
r.SendMessageEnd(common.ServerMessageType(fbm.Type()))
|
|
|
|
return &MsgFramebufferUpdate{rects}, nil
|
|
}
|
|
|
|
// MsgSetColorMapEntries is sent by the server to set values into
|
|
// the color map. This message will automatically update the color map
|
|
// for the associated connection, but contains the color change data
|
|
// if the consumer wants to read it.
|
|
//
|
|
// See RFC 6143 Section 7.6.2
|
|
type MsgSetColorMapEntries struct {
|
|
FirstColor uint16
|
|
Colors []common.Color
|
|
}
|
|
|
|
func (fbm *MsgSetColorMapEntries) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error {
|
|
reader := common.NewRfbReadHelper(r)
|
|
writeTo := &WriteTo{w, "MsgSetColorMapEntries.CopyTo"}
|
|
reader.Listeners.AddListener(writeTo)
|
|
_, err := fbm.Read(c, reader)
|
|
return err
|
|
}
|
|
func (m *MsgSetColorMapEntries) String() string {
|
|
return fmt.Sprintf("MsgSetColorMapEntries (type=%d) first:%d colors: %v: ", m.Type(), m.FirstColor, m.Colors)
|
|
}
|
|
|
|
func (*MsgSetColorMapEntries) Type() uint8 {
|
|
return 1
|
|
}
|
|
|
|
func (m *MsgSetColorMapEntries) Read(c common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) {
|
|
// Read off the padding
|
|
var padding [1]byte
|
|
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var result MsgSetColorMapEntries
|
|
if err := binary.Read(r, binary.BigEndian, &result.FirstColor); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var numColors uint16
|
|
if err := binary.Read(r, binary.BigEndian, &numColors); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result.Colors = make([]common.Color, numColors)
|
|
for i := uint16(0); i < numColors; i++ {
|
|
|
|
color := &result.Colors[i]
|
|
data := []interface{}{
|
|
&color.R,
|
|
&color.G,
|
|
&color.B,
|
|
}
|
|
|
|
for _, val := range data {
|
|
if err := binary.Read(r, binary.BigEndian, val); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
// cmap := c.CurrentColorMap()
|
|
// // Update the connection's color map
|
|
// cmap[result.FirstColor+i] = *color
|
|
}
|
|
r.SendMessageEnd(common.ServerMessageType(m.Type()))
|
|
return &result, nil
|
|
}
|
|
|
|
// Bell signals that an audible bell should be made on the client.
|
|
//
|
|
// See RFC 6143 Section 7.6.3
|
|
type MsgBell byte
|
|
|
|
func (fbm *MsgBell) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error {
|
|
return nil
|
|
}
|
|
func (m *MsgBell) String() string {
|
|
return fmt.Sprintf("MsgBell (type=%d)", m.Type())
|
|
}
|
|
|
|
func (*MsgBell) Type() uint8 {
|
|
return 2
|
|
}
|
|
|
|
func (m *MsgBell) Read(c common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) {
|
|
r.SendMessageEnd(common.ServerMessageType(m.Type()))
|
|
return new(MsgBell), nil
|
|
}
|
|
|
|
type MsgServerFence byte
|
|
|
|
func (fbm *MsgServerFence) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error {
|
|
return nil
|
|
}
|
|
func (m *MsgServerFence) String() string {
|
|
return fmt.Sprintf("MsgServerFence (type=%d)", m.Type())
|
|
}
|
|
|
|
func (*MsgServerFence) Type() uint8 {
|
|
return uint8(common.ServerFence)
|
|
}
|
|
|
|
func (sf *MsgServerFence) Read(info common.IClientConn, c *common.RfbReadHelper) (common.ServerMessage, error) {
|
|
bytes := make([]byte, 3)
|
|
c.Read(bytes)
|
|
if _, err := c.Read(bytes); err != nil {
|
|
return nil, err
|
|
}
|
|
var flags uint32
|
|
if err := binary.Read(c, binary.BigEndian, &flags); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var length uint8
|
|
if err := binary.Read(c, binary.BigEndian, &length); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bytes = make([]byte, length)
|
|
if _, err := c.Read(bytes); err != nil {
|
|
return nil, err
|
|
}
|
|
c.SendMessageEnd(common.ServerMessageType(sf.Type()))
|
|
return sf, nil
|
|
}
|
|
|
|
// MsgServerCutText indicates the server has new text in the cut buffer.
|
|
//
|
|
// See RFC 6143 Section 7.6.4
|
|
type MsgServerCutText struct {
|
|
Text string
|
|
}
|
|
|
|
func (fbm *MsgServerCutText) CopyTo(r io.Reader, w io.Writer, c common.IClientConn) error {
|
|
reader := &common.RfbReadHelper{Reader: r}
|
|
writeTo := &WriteTo{w, "MsgServerCutText.CopyTo"}
|
|
reader.Listeners.AddListener(writeTo)
|
|
_, err := fbm.Read(c, reader)
|
|
return err
|
|
}
|
|
func (m *MsgServerCutText) String() string {
|
|
return fmt.Sprintf("MsgServerCutText (type=%d)", m.Type())
|
|
}
|
|
|
|
func (*MsgServerCutText) Type() uint8 {
|
|
return 3
|
|
}
|
|
|
|
func (m *MsgServerCutText) Read(conn common.IClientConn, r *common.RfbReadHelper) (common.ServerMessage, error) {
|
|
//reader := common.RfbReadHelper{Reader: r}
|
|
|
|
// Read off the padding
|
|
var padding [3]byte
|
|
if _, err := io.ReadFull(r, padding[:]); err != nil {
|
|
return nil, err
|
|
}
|
|
textLength, err := r.ReadUint32()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
textBytes, err := r.ReadBytes(int(textLength))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r.SendMessageEnd(common.ServerMessageType(m.Type()))
|
|
return &MsgServerCutText{string(textBytes)}, nil
|
|
}
|