2017-06-12 14:11:23 +03:00
|
|
|
package vnc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"context"
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
2017-06-13 01:52:07 +03:00
|
|
|
"sync"
|
2017-06-12 14:11:23 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
var DefaultServerMessages = []ServerMessage{
|
|
|
|
&FramebufferUpdate{},
|
|
|
|
&SetColorMapEntries{},
|
|
|
|
&Bell{},
|
|
|
|
&ServerCutText{},
|
|
|
|
}
|
|
|
|
|
2017-06-26 14:16:03 +03:00
|
|
|
var (
|
|
|
|
DefaultClientHandlers []ClientHandler = []ClientHandler{
|
|
|
|
&DefaultClientVersionHandler{},
|
|
|
|
&DefaultClientSecurityHandler{},
|
|
|
|
&DefaultClientClientInitHandler{},
|
|
|
|
&DefaultClientServerInitHandler{},
|
2017-06-29 00:09:31 +03:00
|
|
|
&DefaultClientMessageHandler{},
|
2017-06-26 14:16:03 +03:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2017-06-12 14:11:23 +03:00
|
|
|
func Connect(ctx context.Context, c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
|
|
|
conn, err := NewClientConn(c, cfg)
|
|
|
|
if err != nil {
|
|
|
|
conn.Close()
|
2017-06-26 14:16:03 +03:00
|
|
|
cfg.ErrorCh <- err
|
2017-06-12 14:11:23 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
|
2017-06-26 14:16:03 +03:00
|
|
|
if len(cfg.Handlers) == 0 {
|
|
|
|
cfg.Handlers = DefaultClientHandlers
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
|
2017-06-26 14:16:03 +03:00
|
|
|
for _, h := range cfg.Handlers {
|
|
|
|
if err := h.Handle(conn); err != nil {
|
|
|
|
conn.Close()
|
|
|
|
cfg.ErrorCh <- err
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
|
2017-06-12 14:11:23 +03:00
|
|
|
return conn, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Conn = (*ClientConn)(nil)
|
|
|
|
|
2017-06-26 14:16:03 +03:00
|
|
|
func (c *ClientConn) Config() interface{} {
|
|
|
|
return c.cfg
|
|
|
|
}
|
|
|
|
|
2017-06-29 00:09:31 +03:00
|
|
|
func (c *ClientConn) Wait() {
|
|
|
|
<-c.quit
|
|
|
|
}
|
|
|
|
|
2017-06-13 01:52:07 +03:00
|
|
|
func (c *ClientConn) Conn() net.Conn {
|
|
|
|
return c.c
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ClientConn) SetProtoVersion(pv string) {
|
|
|
|
c.protocol = pv
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ClientConn) SetEncodings(encs []EncodingType) error {
|
|
|
|
|
|
|
|
msg := &SetEncodings{
|
|
|
|
EncNum: uint16(len(encs)),
|
|
|
|
Encodings: encs,
|
|
|
|
}
|
|
|
|
|
|
|
|
return msg.Write(c)
|
|
|
|
}
|
|
|
|
|
2017-06-12 14:11:23 +03:00
|
|
|
func (c *ClientConn) Flush() error {
|
|
|
|
return c.bw.Flush()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ClientConn) Close() error {
|
2017-06-29 00:09:31 +03:00
|
|
|
if c.quit != nil {
|
|
|
|
close(c.quit)
|
|
|
|
c.quit = nil
|
|
|
|
}
|
2017-06-29 15:19:04 +03:00
|
|
|
if c.quitCh != nil {
|
|
|
|
close(c.quitCh)
|
|
|
|
}
|
2017-06-12 14:11:23 +03:00
|
|
|
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
|
|
|
|
}
|
2017-06-26 14:16:03 +03:00
|
|
|
func (c *ClientConn) DesktopName() []byte {
|
2017-06-12 14:11:23 +03:00
|
|
|
return c.desktopName
|
|
|
|
}
|
|
|
|
func (c *ClientConn) PixelFormat() *PixelFormat {
|
|
|
|
return c.pixelFormat
|
|
|
|
}
|
2017-06-26 14:16:03 +03:00
|
|
|
func (c *ClientConn) SetDesktopName(name []byte) {
|
2017-06-29 15:19:04 +03:00
|
|
|
copy(c.desktopName, name)
|
2017-06-13 01:52:07 +03:00
|
|
|
}
|
|
|
|
func (c *ClientConn) SetPixelFormat(pf *PixelFormat) error {
|
|
|
|
c.pixelFormat = pf
|
|
|
|
return nil
|
|
|
|
}
|
2017-06-12 14:11:23 +03:00
|
|
|
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
|
2017-06-13 01:52:07 +03:00
|
|
|
m sync.Mutex
|
2017-06-12 14:11:23 +03:00
|
|
|
// 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.
|
2017-06-26 14:16:03 +03:00
|
|
|
desktopName []byte
|
2017-06-12 14:11:23 +03:00
|
|
|
|
|
|
|
// 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
|
|
|
|
|
2017-06-26 14:16:03 +03:00
|
|
|
quitCh chan struct{}
|
2017-06-29 00:09:31 +03:00
|
|
|
quit chan struct{}
|
2017-06-26 14:16:03 +03:00
|
|
|
errorCh chan error
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewClientConn(c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
|
|
|
|
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,
|
2017-06-26 14:16:03 +03:00
|
|
|
quitCh: cfg.QuitCh,
|
|
|
|
errorCh: cfg.ErrorCh,
|
2017-06-12 14:11:23 +03:00
|
|
|
pixelFormat: cfg.PixelFormat,
|
2017-06-29 00:09:31 +03:00
|
|
|
quit: make(chan struct{}),
|
2017-06-12 14:11:23 +03:00
|
|
|
}, 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 {
|
2017-06-13 16:20:35 +03:00
|
|
|
_ [3]byte // padding
|
|
|
|
PF PixelFormat // pixel-format
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*SetPixelFormat) Type() ClientMessageType {
|
2017-06-13 01:52:07 +03:00
|
|
|
return SetPixelFormatMsgType
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *SetPixelFormat) Write(c Conn) error {
|
2017-06-13 16:20:35 +03:00
|
|
|
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
2017-06-12 14:11:23 +03:00
|
|
|
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{})
|
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
return c.Flush()
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*SetPixelFormat) Read(c Conn) (ClientMessage, error) {
|
|
|
|
msg := SetPixelFormat{}
|
|
|
|
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &msg, nil
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetEncodings holds the wire format message, sans encoding-type field.
|
|
|
|
type SetEncodings struct {
|
|
|
|
_ [1]byte // padding
|
|
|
|
EncNum uint16 // number-of-encodings
|
2017-06-13 01:52:07 +03:00
|
|
|
Encodings []EncodingType
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*SetEncodings) Type() ClientMessageType {
|
2017-06-13 01:52:07 +03:00
|
|
|
return SetEncodingsMsgType
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*SetEncodings) Read(c Conn) (ClientMessage, error) {
|
|
|
|
msg := SetEncodings{}
|
2017-06-12 14:11:23 +03:00
|
|
|
var pad [1]byte
|
|
|
|
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
2017-06-13 16:20:35 +03:00
|
|
|
return nil, err
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 01:52:07 +03:00
|
|
|
if err := binary.Read(c, binary.BigEndian, &msg.EncNum); err != nil {
|
2017-06-13 16:20:35 +03:00
|
|
|
return nil, err
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
var enc EncodingType
|
2017-06-12 14:11:23 +03:00
|
|
|
for i := uint16(0); i < msg.EncNum; i++ {
|
|
|
|
if err := binary.Read(c, binary.BigEndian, &enc); err != nil {
|
2017-06-13 16:20:35 +03:00
|
|
|
return nil, err
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
msg.Encodings = append(msg.Encodings, enc)
|
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
c.SetEncodings(msg.Encodings)
|
2017-06-13 16:20:35 +03:00
|
|
|
return &msg, nil
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *SetEncodings) Write(c Conn) error {
|
2017-06-13 16:20:35 +03:00
|
|
|
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
2017-06-12 14:11:23 +03:00
|
|
|
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 {
|
|
|
|
Inc uint8 // incremental
|
|
|
|
X, Y uint16 // x-, y-position
|
|
|
|
Width, Height uint16 // width, height
|
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*FramebufferUpdateRequest) Type() ClientMessageType {
|
2017-06-13 01:52:07 +03:00
|
|
|
return FramebufferUpdateRequestMsgType
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*FramebufferUpdateRequest) Read(c Conn) (ClientMessage, error) {
|
|
|
|
msg := FramebufferUpdateRequest{}
|
|
|
|
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &msg, nil
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *FramebufferUpdateRequest) Write(c Conn) error {
|
2017-06-13 16:20:35 +03:00
|
|
|
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return c.Flush()
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// KeyEvent holds the wire format message.
|
|
|
|
type KeyEvent struct {
|
2017-06-13 16:20:35 +03:00
|
|
|
Down uint8 // down-flag
|
|
|
|
_ [2]byte // padding
|
|
|
|
Key Key // key
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*KeyEvent) Type() ClientMessageType {
|
2017-06-13 01:52:07 +03:00
|
|
|
return KeyEventMsgType
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*KeyEvent) Read(c Conn) (ClientMessage, error) {
|
|
|
|
msg := KeyEvent{}
|
|
|
|
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &msg, nil
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *KeyEvent) Write(c Conn) error {
|
2017-06-13 16:20:35 +03:00
|
|
|
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return c.Flush()
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// PointerEventMessage holds the wire format message.
|
|
|
|
type PointerEvent struct {
|
2017-06-13 16:20:35 +03:00
|
|
|
Mask uint8 // button-mask
|
|
|
|
X, Y uint16 // x-, y-position
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*PointerEvent) Type() ClientMessageType {
|
2017-06-13 01:52:07 +03:00
|
|
|
return PointerEventMsgType
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*PointerEvent) Read(c Conn) (ClientMessage, error) {
|
|
|
|
msg := PointerEvent{}
|
|
|
|
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &msg, nil
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *PointerEvent) Write(c Conn) error {
|
2017-06-13 16:20:35 +03:00
|
|
|
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
if err := binary.Write(c, binary.BigEndian, msg); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return c.Flush()
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// ClientCutText holds the wire format message, sans the text field.
|
|
|
|
type ClientCutText struct {
|
2017-06-13 16:20:35 +03:00
|
|
|
_ [3]byte // padding
|
|
|
|
Length uint32 // length
|
|
|
|
Text []byte
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*ClientCutText) Type() ClientMessageType {
|
2017-06-13 01:52:07 +03:00
|
|
|
return ClientCutTextMsgType
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
func (*ClientCutText) Read(c Conn) (ClientMessage, error) {
|
|
|
|
msg := ClientCutText{}
|
2017-06-12 14:11:23 +03:00
|
|
|
var pad [3]byte
|
|
|
|
if err := binary.Read(c, binary.BigEndian, &pad); err != nil {
|
2017-06-13 16:20:35 +03:00
|
|
|
return nil, err
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 01:52:07 +03:00
|
|
|
if err := binary.Read(c, binary.BigEndian, &msg.Length); err != nil {
|
2017-06-13 16:20:35 +03:00
|
|
|
return nil, err
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-13 16:20:35 +03:00
|
|
|
msg.Text = make([]byte, msg.Length)
|
|
|
|
if err := binary.Read(c, binary.BigEndian, &msg.Text); err != nil {
|
|
|
|
return nil, err
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
2017-06-13 16:20:35 +03:00
|
|
|
return &msg, nil
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (msg *ClientCutText) Write(c Conn) error {
|
2017-06-13 16:20:35 +03:00
|
|
|
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
|
2017-06-12 14:11:23 +03:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
|
2017-06-26 14:16:03 +03:00
|
|
|
type DefaultClientMessageHandler struct{}
|
|
|
|
|
|
|
|
// listens to a VNC server and handles server messages.
|
|
|
|
func (*DefaultClientMessageHandler) Handle(c Conn) error {
|
|
|
|
cfg := c.Config().(*ClientConfig)
|
2017-06-12 14:11:23 +03:00
|
|
|
var err error
|
2017-06-13 01:52:07 +03:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(2)
|
2017-06-12 14:11:23 +03:00
|
|
|
defer c.Close()
|
|
|
|
|
|
|
|
serverMessages := make(map[ServerMessageType]ServerMessage)
|
2017-06-26 14:16:03 +03:00
|
|
|
for _, m := range cfg.ServerMessages {
|
2017-06-12 14:11:23 +03:00
|
|
|
serverMessages[m.Type()] = m
|
|
|
|
}
|
|
|
|
|
2017-06-26 14:16:03 +03:00
|
|
|
go func() {
|
2017-06-13 01:52:07 +03:00
|
|
|
defer wg.Done()
|
|
|
|
for {
|
|
|
|
select {
|
2017-06-26 14:16:03 +03:00
|
|
|
case msg := <-cfg.ClientMessageCh:
|
2017-06-13 01:52:07 +03:00
|
|
|
if err = msg.Write(c); err != nil {
|
2017-06-26 14:16:03 +03:00
|
|
|
cfg.ErrorCh <- err
|
|
|
|
return
|
2017-06-13 01:52:07 +03:00
|
|
|
}
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
}()
|
|
|
|
|
2017-06-26 14:16:03 +03:00
|
|
|
go func() {
|
2017-06-13 01:52:07 +03:00
|
|
|
defer wg.Done()
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
default:
|
|
|
|
var messageType ServerMessageType
|
|
|
|
if err = binary.Read(c, binary.BigEndian, &messageType); err != nil {
|
2017-06-26 14:16:03 +03:00
|
|
|
cfg.ErrorCh <- err
|
|
|
|
return
|
2017-06-13 01:52:07 +03:00
|
|
|
}
|
|
|
|
msg, ok := serverMessages[messageType]
|
|
|
|
if !ok {
|
2017-06-26 14:16:03 +03:00
|
|
|
err = fmt.Errorf("unknown message-type: %v", messageType)
|
|
|
|
cfg.ErrorCh <- err
|
|
|
|
return
|
2017-06-13 01:52:07 +03:00
|
|
|
}
|
2017-06-13 16:20:35 +03:00
|
|
|
parsedMsg, err := msg.Read(c)
|
|
|
|
if err != nil {
|
2017-06-26 14:16:03 +03:00
|
|
|
cfg.ErrorCh <- err
|
|
|
|
return
|
2017-06-13 01:52:07 +03:00
|
|
|
}
|
2017-06-26 14:16:03 +03:00
|
|
|
cfg.ServerMessageCh <- parsedMsg
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
}
|
2017-06-13 01:52:07 +03:00
|
|
|
}()
|
2017-06-26 14:16:03 +03:00
|
|
|
|
2017-06-13 01:52:07 +03:00
|
|
|
wg.Wait()
|
2017-06-26 14:16:03 +03:00
|
|
|
return nil
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|
|
|
|
|
2017-06-26 14:16:03 +03:00
|
|
|
type ClientHandler interface {
|
|
|
|
Handle(Conn) error
|
|
|
|
}
|
2017-06-12 14:11:23 +03:00
|
|
|
|
|
|
|
// 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 {
|
2017-06-26 14:16:03 +03:00
|
|
|
Handlers []ClientHandler
|
|
|
|
SecurityHandlers []SecurityHandler
|
|
|
|
Encodings []Encoding
|
|
|
|
PixelFormat *PixelFormat
|
|
|
|
ColorMap *ColorMap
|
|
|
|
ClientMessageCh chan ClientMessage
|
|
|
|
ServerMessageCh chan ServerMessage
|
|
|
|
Exclusive bool
|
|
|
|
ServerMessages []ServerMessage
|
|
|
|
QuitCh chan struct{}
|
|
|
|
ErrorCh chan error
|
2017-06-29 00:09:31 +03:00
|
|
|
quit chan struct{}
|
2017-06-12 14:11:23 +03:00
|
|
|
}
|