some lint fixes

Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
This commit is contained in:
Василий Толстов 2017-07-04 01:36:10 +03:00
parent 3aba31d655
commit 2024b32082
12 changed files with 352 additions and 177 deletions

31
aten.go
View File

@ -5,6 +5,7 @@ import (
"fmt"
)
// Aten IKVM message types.
const (
AteniKVMFrontGroundEventMsgType ServerMessageType = 4
AteniKVMKeepAliveEventMsgType ServerMessageType = 22
@ -14,18 +15,22 @@ const (
AteniKVMGetViewerLangMsgType ServerMessageType = 60
)
// AteniKVMFrontGroundEvent unknown aten ikvm message
type AteniKVMFrontGroundEvent struct {
_ [20]byte
}
// String return string representation
func (msg *AteniKVMFrontGroundEvent) String() string {
return fmt.Sprintf("%s", msg.Type())
}
// Type return ServerMessageType
func (*AteniKVMFrontGroundEvent) Type() ServerMessageType {
return AteniKVMFrontGroundEventMsgType
}
// Read unmarshal message from conn
func (*AteniKVMFrontGroundEvent) Read(c Conn) (ServerMessage, error) {
msg := &AteniKVMFrontGroundEvent{}
var pad [20]byte
@ -35,6 +40,7 @@ func (*AteniKVMFrontGroundEvent) Read(c Conn) (ServerMessage, error) {
return msg, nil
}
// Write marshal message to conn
func (*AteniKVMFrontGroundEvent) Write(c Conn) error {
var pad [20]byte
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
@ -43,18 +49,22 @@ func (*AteniKVMFrontGroundEvent) Write(c Conn) error {
return nil
}
// AteniKVMKeepAliveEvent unknown aten ikvm message
type AteniKVMKeepAliveEvent struct {
_ [1]byte
}
// String return string representation
func (msg *AteniKVMKeepAliveEvent) String() string {
return fmt.Sprintf("%s", msg.Type())
}
// Type return ServerMessageType
func (*AteniKVMKeepAliveEvent) Type() ServerMessageType {
return AteniKVMKeepAliveEventMsgType
}
// Read unmarshal message from conn
func (*AteniKVMKeepAliveEvent) Read(c Conn) (ServerMessage, error) {
msg := &AteniKVMKeepAliveEvent{}
var pad [1]byte
@ -64,6 +74,7 @@ func (*AteniKVMKeepAliveEvent) Read(c Conn) (ServerMessage, error) {
return msg, nil
}
// Write marshal message to conn
func (*AteniKVMKeepAliveEvent) Write(c Conn) error {
var pad [1]byte
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
@ -72,18 +83,22 @@ func (*AteniKVMKeepAliveEvent) Write(c Conn) error {
return nil
}
// AteniKVMVideoGetInfo unknown aten ikvm message
type AteniKVMVideoGetInfo struct {
_ [20]byte
}
// String return string representation
func (msg *AteniKVMVideoGetInfo) String() string {
return fmt.Sprintf("%s", msg.Type())
}
// Type return ServerMessageType
func (*AteniKVMVideoGetInfo) Type() ServerMessageType {
return AteniKVMVideoGetInfoMsgType
}
// Read unmarshal message from conn
func (*AteniKVMVideoGetInfo) Read(c Conn) (ServerMessage, error) {
msg := &AteniKVMVideoGetInfo{}
var pad [40]byte
@ -93,6 +108,7 @@ func (*AteniKVMVideoGetInfo) Read(c Conn) (ServerMessage, error) {
return msg, nil
}
// Write marshal message to conn
func (*AteniKVMVideoGetInfo) Write(c Conn) error {
var pad [4]byte
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
@ -101,18 +117,22 @@ func (*AteniKVMVideoGetInfo) Write(c Conn) error {
return nil
}
// AteniKVMMouseGetInfo unknown aten ikvm message
type AteniKVMMouseGetInfo struct {
_ [2]byte
}
// String return string representation
func (msg *AteniKVMMouseGetInfo) String() string {
return fmt.Sprintf("%s", msg.Type())
}
// Type return ServerMessageType
func (*AteniKVMMouseGetInfo) Type() ServerMessageType {
return AteniKVMMouseGetInfoMsgType
}
// Read unmarshal message from conn
func (*AteniKVMMouseGetInfo) Read(c Conn) (ServerMessage, error) {
msg := &AteniKVMFrontGroundEvent{}
var pad [2]byte
@ -122,6 +142,7 @@ func (*AteniKVMMouseGetInfo) Read(c Conn) (ServerMessage, error) {
return msg, nil
}
// Write marshal message to conn
func (*AteniKVMMouseGetInfo) Write(c Conn) error {
var pad [2]byte
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
@ -130,18 +151,22 @@ func (*AteniKVMMouseGetInfo) Write(c Conn) error {
return nil
}
// AteniKVMSessionMessage unknown aten ikvm message
type AteniKVMSessionMessage struct {
_ [264]byte
}
// String return string representation
func (msg *AteniKVMSessionMessage) String() string {
return fmt.Sprintf("%s", msg.Type())
}
// Type return ServerMessageType
func (*AteniKVMSessionMessage) Type() ServerMessageType {
return AteniKVMFrontGroundEventMsgType
}
// Read unmarshal message from conn
func (*AteniKVMSessionMessage) Read(c Conn) (ServerMessage, error) {
msg := &AteniKVMSessionMessage{}
var pad [264]byte
@ -151,6 +176,7 @@ func (*AteniKVMSessionMessage) Read(c Conn) (ServerMessage, error) {
return msg, nil
}
// Write marshal message to conn
func (*AteniKVMSessionMessage) Write(c Conn) error {
var pad [264]byte
if err := binary.Write(c, binary.BigEndian, pad); err != nil {
@ -159,18 +185,22 @@ func (*AteniKVMSessionMessage) Write(c Conn) error {
return nil
}
// AteniKVMGetViewerLang unknown aten ikvm message
type AteniKVMGetViewerLang struct {
_ [8]byte
}
// String return string representation
func (msg *AteniKVMGetViewerLang) String() string {
return fmt.Sprintf("%s", msg.Type())
}
// Type return ServerMessageType
func (*AteniKVMGetViewerLang) Type() ServerMessageType {
return AteniKVMGetViewerLangMsgType
}
// Read unmarshal message from conn
func (*AteniKVMGetViewerLang) Read(c Conn) (ServerMessage, error) {
msg := &AteniKVMGetViewerLang{}
var pad [8]byte
@ -180,6 +210,7 @@ func (*AteniKVMGetViewerLang) Read(c Conn) (ServerMessage, error) {
return msg, nil
}
// Write marshal message to conn
func (*AteniKVMGetViewerLang) Write(c Conn) error {
var pad [8]byte
if err := binary.Write(c, binary.BigEndian, pad); err != nil {

View File

@ -18,6 +18,7 @@ const (
BtnNone Button = 0
)
// Mask returns button mask
func Mask(button Button) uint8 {
return uint8(button)
}

View File

@ -10,7 +10,8 @@ import (
)
var (
DefaultClientHandlers []ClientHandler = []ClientHandler{
// DefaultClientHandlers represents default client handlers
DefaultClientHandlers = []ClientHandler{
&DefaultClientVersionHandler{},
&DefaultClientSecurityHandler{},
&DefaultClientClientInitHandler{},
@ -19,6 +20,7 @@ var (
}
)
// Connect handshake with remote server using underlining net.Conn
func Connect(ctx context.Context, c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
conn, err := NewClientConn(c, cfg)
if err != nil {
@ -44,22 +46,27 @@ func Connect(ctx context.Context, c net.Conn, cfg *ClientConfig) (*ClientConn, e
var _ Conn = (*ClientConn)(nil)
// Config returns connection config
func (c *ClientConn) Config() interface{} {
return c.cfg
}
// Wait waiting for connection close
func (c *ClientConn) Wait() {
<-c.quit
}
// Conn return underlining net.Conn
func (c *ClientConn) Conn() net.Conn {
return c.c
}
// SetProtoVersion sets proto version
func (c *ClientConn) SetProtoVersion(pv string) {
c.protocol = pv
}
// SetEncodings write SetEncodings message
func (c *ClientConn) SetEncodings(encs []EncodingType) error {
msg := &SetEncodings{
@ -70,10 +77,12 @@ func (c *ClientConn) SetEncodings(encs []EncodingType) error {
return msg.Write(c)
}
// Flush flushes data to conn
func (c *ClientConn) Flush() error {
return c.bw.Flush()
}
// Close closing conn
func (c *ClientConn) Close() error {
if c.quit != nil {
close(c.quit)
@ -85,61 +94,85 @@ func (c *ClientConn) Close() error {
return c.c.Close()
}
// Read reads data from conn
func (c *ClientConn) Read(buf []byte) (int, error) {
return c.br.Read(buf)
}
// Write data to conn must be Flushed
func (c *ClientConn) Write(buf []byte) (int, error) {
return c.bw.Write(buf)
}
// ColorMap returns color map
func (c *ClientConn) ColorMap() ColorMap {
return c.colorMap
}
// SetColorMap sets color map
func (c *ClientConn) SetColorMap(cm ColorMap) {
c.colorMap = cm
}
// DesktopName returns connection desktop name
func (c *ClientConn) DesktopName() []byte {
return c.desktopName
}
// PixelFormat returns connection pixel format
func (c *ClientConn) PixelFormat() PixelFormat {
return c.pixelFormat
}
// SetDesktopName sets desktop name
func (c *ClientConn) SetDesktopName(name []byte) {
copy(c.desktopName, name)
}
// SetPixelFormat sets pixel format
func (c *ClientConn) SetPixelFormat(pf PixelFormat) error {
c.pixelFormat = pf
return nil
}
// Encodings returns client encodings
func (c *ClientConn) Encodings() []Encoding {
return c.encodings
}
// Width returns width
func (c *ClientConn) Width() uint16 {
return c.fbWidth
}
// Height returns height
func (c *ClientConn) Height() uint16 {
return c.fbHeight
}
// Protocol returns protocol
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
// SetWidth sets width of client conn
func (c *ClientConn) SetWidth(width uint16) {
c.fbWidth = width
}
// The ClientConn type holds client connection information.
// SetHeight sets height of client conn
func (c *ClientConn) SetHeight(height uint16) {
c.fbHeight = height
}
// The ClientConn type holds client connection information
type ClientConn struct {
c net.Conn
br *bufio.Reader
bw *bufio.Writer
cfg *ClientConfig
protocol string
m sync.Mutex
// 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.
@ -169,6 +202,7 @@ type ClientConn struct {
errorCh chan error
}
// NewClientConn creates new client conn using config
func NewClientConn(c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
if len(cfg.Encodings) == 0 {
return nil, fmt.Errorf("client can't handle encodings")
@ -186,9 +220,10 @@ func NewClientConn(c net.Conn, cfg *ClientConfig) (*ClientConn, error) {
}, nil
}
// DefaultClientMessageHandler represents default client message handler
type DefaultClientMessageHandler struct{}
// listens to a VNC server and handles server messages.
// Handle handles server messages.
func (*DefaultClientMessageHandler) Handle(c Conn) error {
cfg := c.Config().(*ClientConfig)
var err error

View File

@ -5,6 +5,7 @@ import (
"net"
)
// Conn represents vnc conection
type Conn interface {
io.ReadWriteCloser
Conn() net.Conn

View File

@ -2,6 +2,7 @@ package vnc
import (
"bytes"
"image"
"sync"
)
@ -11,8 +12,11 @@ type EncodingType int32
//go:generate stringer -type=EncodingType
const (
EncRaw EncodingType = 0
EncCopyRect EncodingType = 1
// EncRaw raw encoding
EncRaw EncodingType = 0
// EncCopyRect copyrect encoding
EncCopyRect EncodingType = 1
EncRRE EncodingType = 2
EncCoRRE EncodingType = 4
EncHextile EncodingType = 5
@ -74,6 +78,7 @@ var bPool = sync.Pool{
},
}
// Encoding represents interface for vnc encoding
type Encoding interface {
Type() EncodingType
Read(Conn, *Rectangle) error
@ -99,3 +104,11 @@ func getBit(n uint8, pos uint8) uint8 {
n = n & (1 << pos)
return n
}
func newRGBAImage(rgba []byte, rect *Rectangle) image.Image {
img := &image.RGBA{Stride: 4 * int(rect.Width)}
img.Pix = rgba
img.Rect.Max.X = int(rect.Width)
img.Rect.Max.Y = int(rect.Height)
return img
}

View File

@ -74,7 +74,6 @@ func (enc *AtenHermon) Read(c Conn, rect *Rectangle) error {
for aten_length > 0 {
switch aten_type {
case 0: //subrects
panic("unknown subrect")
var a uint16
var b uint16
var x uint8
@ -97,6 +96,7 @@ func (enc *AtenHermon) Read(c Conn, rect *Rectangle) error {
}
aten_length -= 6 + (16 * 16 * uint32(c.PixelFormat().BPP))
panic("subrect!")
case 1: //raw
fmt.Printf("raw reader %d %s\n", aten_length, rect)
encRaw := &RawEncoding{}

45
encoding_cursor.go Normal file
View File

@ -0,0 +1,45 @@
package vnc
import "encoding/binary"
type CursorPseudoEncoding struct {
Colors []Color
BitMask []byte
}
func (*CursorPseudoEncoding) Type() EncodingType { return EncCursorPseudo }
func (enc *CursorPseudoEncoding) Read(c Conn, rect *Rectangle) error {
rgba := make([]byte, int(rect.Height)*int(rect.Width)*int(c.PixelFormat().BPP/8))
if err := binary.Read(c, binary.BigEndian, &rgba); err != nil {
return err
}
bitmask := make([]byte, int((rect.Width+7)/8*rect.Height))
if err := binary.Read(c, binary.BigEndian, &bitmask); err != nil {
return err
}
/*
rectStride := 4 * rect.Width
for i := uint16(0); i < rect.Height; i++ {
for j := uint16(0); j < rect.Width; j += 8 {
for idx, k := j/8, 7; k >= 0; k-- {
if (bitmask[idx] & (1 << uint(k))) == 0 {
pIdx := j*4 + i*rectStride
rgbaBuffer[pIdx] = 0
rgbaBuffer[pIdx+1] = 0
rgbaBuffer[pIdx+2] = 0
rgbaBuffer[pIdx+3] = 0
}
}
}
}
*/
return nil
}
func (enc *CursorPseudoEncoding) Write(c Conn, rect *Rectangle) error {
return nil
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
)
// ClientHandler represents client handler
type ClientHandler interface {
Handle(Conn) error
}
@ -17,6 +18,7 @@ type ClientMessage interface {
Write(Conn) error
}
// ServerHandler represents server handler
type ServerHandler interface {
Handle(Conn) error
}
@ -29,14 +31,19 @@ type ServerMessage interface {
Write(Conn) error
}
// ProtoVersionLength protocol version length
const ProtoVersionLength = 12
const (
// ProtoVersionUnknown unknown version
ProtoVersionUnknown = ""
ProtoVersion33 = "RFB 003.003\n"
ProtoVersion38 = "RFB 003.008\n"
// ProtoVersion33 sets if proto 003.003
ProtoVersion33 = "RFB 003.003\n"
// ProtoVersion38 sets if proto 003.008
ProtoVersion38 = "RFB 003.008\n"
)
// ParseProtoVersion parse protocol version
func ParseProtoVersion(pv []byte) (uint, uint, error) {
var major, minor uint
@ -46,7 +53,7 @@ func ParseProtoVersion(pv []byte) (uint, uint, error) {
l, err := fmt.Sscanf(string(pv), "RFB %d.%d\n", &major, &minor)
if l != 2 {
return 0, 0, fmt.Errorf("error parsing ProtocolVersion.")
return 0, 0, fmt.Errorf("error parsing protocol version")
}
if err != nil {
return 0, 0, err
@ -55,8 +62,10 @@ func ParseProtoVersion(pv []byte) (uint, uint, error) {
return major, minor, nil
}
// DefaultClientVersionHandler represents default handler
type DefaultClientVersionHandler struct{}
// Handle provide version handler for client side
func (*DefaultClientVersionHandler) Handle(c Conn) error {
var version [ProtoVersionLength]byte
@ -88,8 +97,10 @@ func (*DefaultClientVersionHandler) Handle(c Conn) error {
return c.Flush()
}
// DefaultServerVersionHandler represents default server handler
type DefaultServerVersionHandler struct{}
// Handle provide server version handler
func (*DefaultServerVersionHandler) Handle(c Conn) error {
var version [ProtoVersionLength]byte
if err := binary.Write(c, binary.BigEndian, []byte(ProtoVersion38)); err != nil {
@ -122,8 +133,10 @@ func (*DefaultServerVersionHandler) Handle(c Conn) error {
return nil
}
// DefaultClientSecurityHandler used for client security handler
type DefaultClientSecurityHandler struct{}
// Handle provide client side security handler
func (*DefaultClientSecurityHandler) Handle(c Conn) error {
cfg := c.Config().(*ClientConfig)
var numSecurityTypes uint8
@ -177,8 +190,10 @@ func (*DefaultClientSecurityHandler) Handle(c Conn) error {
return nil
}
// DefaultServerSecurityHandler used for server security handler
type DefaultServerSecurityHandler struct{}
// Handle provide server side security handler
func (*DefaultServerSecurityHandler) Handle(c Conn) error {
cfg := c.Config().(*ServerConfig)
if err := binary.Write(c, binary.BigEndian, uint8(len(cfg.SecurityHandlers))); err != nil {
@ -236,8 +251,10 @@ func (*DefaultServerSecurityHandler) Handle(c Conn) error {
return nil
}
// DefaultClientServerInitHandler default client server init handler
type DefaultClientServerInitHandler struct{}
// Handle provide default server init handler
func (*DefaultClientServerInitHandler) Handle(c Conn) error {
srvInit := ServerInit{}
@ -320,8 +337,10 @@ func (*DefaultClientServerInitHandler) Handle(c Conn) error {
return nil
}
// DefaultServerServerInitHandler default server server init handler
type DefaultServerServerInitHandler struct{}
// Handle provide default server server init handler
func (*DefaultServerServerInitHandler) Handle(c Conn) error {
if err := binary.Write(c, binary.BigEndian, c.Width()); err != nil {
return err
@ -341,8 +360,10 @@ func (*DefaultServerServerInitHandler) Handle(c Conn) error {
return c.Flush()
}
// DefaultClientClientInitHandler default client client init handler
type DefaultClientClientInitHandler struct{}
// Handle provide default client client init handler
func (*DefaultClientClientInitHandler) Handle(c Conn) error {
cfg := c.Config().(*ClientConfig)
var shared uint8
@ -357,8 +378,10 @@ func (*DefaultClientClientInitHandler) Handle(c Conn) error {
return c.Flush()
}
// DefaultServerClientInitHandler default server client init handler
type DefaultServerClientInitHandler struct{}
// Handle provide default server client init handler
func (*DefaultServerClientInitHandler) Handle(c Conn) error {
var shared uint8
if err := binary.Read(c, binary.BigEndian, &shared); err != nil {

127
image.go
View File

@ -17,9 +17,10 @@ type Color struct {
R, G, B uint16
}
// ColorMap represent color map
type ColorMap [256]Color
// NewColor returns a new Color object.
// NewColor returns a new Color object
func NewColor(pf *PixelFormat, cm *ColorMap) *Color {
return &Color{
pf: pf,
@ -27,7 +28,7 @@ func NewColor(pf *PixelFormat, cm *ColorMap) *Color {
}
}
// Rectangle represents a rectangle of pixel data.
// Rectangle represents a rectangle of pixel data
type Rectangle struct {
X, Y uint16
Width, Height uint16
@ -35,14 +36,17 @@ type Rectangle struct {
Enc Encoding
}
// String return string representation
func (rect *Rectangle) String() string {
return fmt.Sprintf("rect x: %d, y: %d, width: %d, height: %d, enc: %s", rect.X, rect.Y, rect.Width, rect.Height, rect.EncType)
}
// NewRectangle returns new rectangle
func NewRectangle() *Rectangle {
return &Rectangle{}
}
// Write marshal color to conn
func (clr *Color) Write(c Conn) error {
var err error
order := clr.pf.order()
@ -65,32 +69,7 @@ func (clr *Color) Write(c Conn) error {
return err
}
// 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
}
// Read unmarshal color from conn
func (clr *Color) Read(c Conn) error {
order := clr.pf.order()
var pixel uint32
@ -127,36 +106,6 @@ func (clr *Color) Read(c Conn) error {
return 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)
@ -174,72 +123,76 @@ func colorsToImage(x, y, width, height uint16, colors []Color) *image.RGBA64 {
return rgba
}
// Marshal implements the Marshaler interface.
func (r *Rectangle) Write(c Conn) error {
// Write marshal rectangle to conn
func (rect *Rectangle) Write(c Conn) error {
var err error
if err = binary.Write(c, binary.BigEndian, r.X); err != nil {
if err = binary.Write(c, binary.BigEndian, rect.X); err != nil {
return err
}
if err = binary.Write(c, binary.BigEndian, r.Y); err != nil {
if err = binary.Write(c, binary.BigEndian, rect.Y); err != nil {
return err
}
if err = binary.Write(c, binary.BigEndian, r.Width); err != nil {
if err = binary.Write(c, binary.BigEndian, rect.Width); err != nil {
return err
}
if err = binary.Write(c, binary.BigEndian, r.Height); err != nil {
if err = binary.Write(c, binary.BigEndian, rect.Height); err != nil {
return err
}
if err = binary.Write(c, binary.BigEndian, r.EncType); err != nil {
if err = binary.Write(c, binary.BigEndian, rect.EncType); err != nil {
return err
}
return r.Enc.Write(c, r)
return rect.Enc.Write(c, rect)
}
func (r *Rectangle) Read(c Conn) error {
// Read unmarshal rectangle from conn
func (rect *Rectangle) Read(c Conn) error {
var err error
if err = binary.Read(c, binary.BigEndian, &r.X); err != nil {
if err = binary.Read(c, binary.BigEndian, &rect.X); err != nil {
return err
}
if err = binary.Read(c, binary.BigEndian, &r.Y); err != nil {
if err = binary.Read(c, binary.BigEndian, &rect.Y); err != nil {
return err
}
if err = binary.Read(c, binary.BigEndian, &r.Width); err != nil {
if err = binary.Read(c, binary.BigEndian, &rect.Width); err != nil {
return err
}
if err = binary.Read(c, binary.BigEndian, &r.Height); err != nil {
if err = binary.Read(c, binary.BigEndian, &rect.Height); err != nil {
return err
}
if err = binary.Read(c, binary.BigEndian, &r.EncType); err != nil {
if err = binary.Read(c, binary.BigEndian, &rect.EncType); err != nil {
return err
}
switch r.EncType {
switch rect.EncType {
case EncCopyRect:
r.Enc = &CopyRectEncoding{}
rect.Enc = &CopyRectEncoding{}
case EncTight:
r.Enc = &TightEncoding{}
rect.Enc = &TightEncoding{}
case EncTightPng:
r.Enc = &TightPngEncoding{}
rect.Enc = &TightPngEncoding{}
case EncRaw:
if c.Protocol() == "aten" {
r.Enc = &AtenHermon{}
rect.Enc = &AtenHermon{}
} else {
r.Enc = &RawEncoding{}
rect.Enc = &RawEncoding{}
}
case EncDesktopSizePseudo:
r.Enc = &DesktopSizePseudoEncoding{}
rect.Enc = &DesktopSizePseudoEncoding{}
case EncDesktopNamePseudo:
r.Enc = &DesktopNamePseudoEncoding{}
rect.Enc = &DesktopNamePseudoEncoding{}
case EncXCursorPseudo:
r.Enc = &XCursorPseudoEncoding{}
rect.Enc = &XCursorPseudoEncoding{}
case EncAtenHermon:
r.Enc = &AtenHermon{}
rect.Enc = &AtenHermon{}
default:
return fmt.Errorf("unsupported encoding %s", r.EncType)
return fmt.Errorf("unsupported encoding %s", rect.EncType)
}
return r.Enc.Read(c, r)
return rect.Enc.Read(c, rect)
}
// Area returns the total area in pixels of the Rectangle.
func (r *Rectangle) Area() int { return int(r.Width) * int(r.Height) }
// Area returns the total area in pixels of the Rectangle
func (rect *Rectangle) Area() int { return int(rect.Width) * int(rect.Height) }

View File

@ -5,27 +5,43 @@ import (
"fmt"
)
var DefaultClientMessages = []ClientMessage{
&SetPixelFormat{},
&SetEncodings{},
&FramebufferUpdateRequest{},
&KeyEvent{},
&PointerEvent{},
&ClientCutText{},
}
var (
// DefaultClientMessages slice of default client messages sent to server
DefaultClientMessages = []ClientMessage{
&SetPixelFormat{},
&SetEncodings{},
&FramebufferUpdateRequest{},
&KeyEvent{},
&PointerEvent{},
&ClientCutText{},
}
type ServerInit struct {
FBWidth, FBHeight uint16
PixelFormat PixelFormat
NameLength uint32
NameText []byte
}
// DefaultServerMessages slice of default server messages sent to client
DefaultServerMessages = []ServerMessage{
&FramebufferUpdate{},
&SetColorMapEntries{},
&Bell{},
&ServerCutText{},
}
)
func (srvInit ServerInit) String() string {
return fmt.Sprintf("Width: %d, Height: %d, PixelFormat: %s, NameLength: %d, MameText: %s", srvInit.FBWidth, srvInit.FBHeight, srvInit.PixelFormat, srvInit.NameLength, srvInit.NameText)
}
// ClientMessageType represents a Client-to-Server RFB message type.
type ClientMessageType uint8
// ServerMessage represents a Client-to-Server RFB message type.
//go:generate stringer -type=ClientMessageType
// Client-to-Server message types.
const (
SetPixelFormatMsgType ClientMessageType = iota
_
SetEncodingsMsgType
FramebufferUpdateRequestMsgType
KeyEventMsgType
PointerEventMsgType
ClientCutTextMsgType
)
// ServerMessageType represents a Client-to-Server RFB message type.
type ServerMessageType uint8
//go:generate stringer -type=ServerMessageType
@ -38,6 +54,19 @@ const (
ServerCutTextMsgType
)
// ServerInit struct used in server init handshake
type ServerInit struct {
FBWidth, FBHeight uint16
PixelFormat PixelFormat
NameLength uint32
NameText []byte
}
// String provide stringer
func (srvInit ServerInit) String() string {
return fmt.Sprintf("Width: %d, Height: %d, PixelFormat: %s, NameLength: %d, MameText: %s", srvInit.FBWidth, srvInit.FBHeight, srvInit.PixelFormat, srvInit.NameLength, srvInit.NameText)
}
// FramebufferUpdate holds a FramebufferUpdate wire format message.
type FramebufferUpdate struct {
_ [1]byte // pad
@ -45,14 +74,17 @@ type FramebufferUpdate struct {
Rects []*Rectangle // rectangles
}
// String provide stringer
func (msg *FramebufferUpdate) String() string {
return fmt.Sprintf("rects %d rectangle[]: { %v }", msg.NumRect, msg.Rects)
}
// Type return ServerMessageType
func (*FramebufferUpdate) Type() ServerMessageType {
return FramebufferUpdateMsgType
}
// Read unmarshal message from conn
func (*FramebufferUpdate) Read(c Conn) (ServerMessage, error) {
msg := FramebufferUpdate{}
var pad [1]byte
@ -73,6 +105,7 @@ func (*FramebufferUpdate) Read(c Conn) (ServerMessage, error) {
return &msg, nil
}
// Write marshals message to conn
func (msg *FramebufferUpdate) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
@ -92,20 +125,24 @@ func (msg *FramebufferUpdate) Write(c Conn) error {
return c.Flush()
}
// ServerCutText represents server message
type ServerCutText struct {
_ [1]byte
Length uint32
Text []byte
}
// String returns string
func (msg *ServerCutText) String() string {
return fmt.Sprintf("lenght: %d text: %s", msg.Length, msg.Text)
}
// Type returns ServerMessageType
func (*ServerCutText) Type() ServerMessageType {
return ServerCutTextMsgType
}
// Read unmarshal message from conn
func (*ServerCutText) Read(c Conn) (ServerMessage, error) {
msg := ServerCutText{}
@ -125,6 +162,7 @@ func (*ServerCutText) Read(c Conn) (ServerMessage, error) {
return &msg, nil
}
// Write marshal message to conn
func (msg *ServerCutText) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
@ -147,20 +185,25 @@ func (msg *ServerCutText) Write(c Conn) error {
return c.Flush()
}
// Bell server message
type Bell struct{}
// String return string
func (*Bell) String() string {
return fmt.Sprintf("bell")
}
// Type returns ServerMessageType
func (*Bell) Type() ServerMessageType {
return BellMsgType
}
// Read unmarshal message from conn
func (*Bell) Read(c Conn) (ServerMessage, error) {
return &Bell{}, nil
}
// Write marshal message to conn
func (msg *Bell) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
@ -168,6 +211,7 @@ func (msg *Bell) Write(c Conn) error {
return c.Flush()
}
// SetColorMapEntries server message
type SetColorMapEntries struct {
_ [1]byte
FirstColor uint16
@ -175,14 +219,17 @@ type SetColorMapEntries struct {
Colors []Color
}
// String returns string
func (msg *SetColorMapEntries) String() string {
return fmt.Sprintf("first color: %d, numcolors: %d, colors[]: { %v }", msg.FirstColor, msg.ColorsNum, msg.Colors)
}
// Type returns ServerMessageType
func (*SetColorMapEntries) Type() ServerMessageType {
return SetColorMapEntriesMsgType
}
// Read unmrashal message from conn
func (*SetColorMapEntries) Read(c Conn) (ServerMessage, error) {
msg := SetColorMapEntries{}
var pad [1]byte
@ -212,6 +259,7 @@ func (*SetColorMapEntries) Read(c Conn) (ServerMessage, error) {
return &msg, nil
}
// Write marshal message to conn
func (msg *SetColorMapEntries) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
@ -242,43 +290,23 @@ func (msg *SetColorMapEntries) Write(c Conn) error {
return c.Flush()
}
var DefaultServerMessages = []ServerMessage{
&FramebufferUpdate{},
&SetColorMapEntries{},
&Bell{},
&ServerCutText{},
}
// 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 {
_ [3]byte // padding
PF PixelFormat // pixel-format
}
// String returns string
func (msg *SetPixelFormat) String() string {
return fmt.Sprintf("%s", msg.PF)
}
// Type returns ClientMessageType
func (*SetPixelFormat) Type() ClientMessageType {
return SetPixelFormatMsgType
}
// Write marshal message to conn
func (msg *SetPixelFormat) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
@ -297,6 +325,7 @@ func (msg *SetPixelFormat) Write(c Conn) error {
return c.Flush()
}
// Read unmarshal message from conn
func (*SetPixelFormat) Read(c Conn) (ClientMessage, error) {
msg := SetPixelFormat{}
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
@ -312,14 +341,17 @@ type SetEncodings struct {
Encodings []EncodingType
}
// String return string
func (msg *SetEncodings) String() string {
return fmt.Sprintf("encnum: %d, encodings[]: { %v }", msg.EncNum, msg.Encodings)
}
// Type returns ClientMessageType
func (*SetEncodings) Type() ClientMessageType {
return SetEncodingsMsgType
}
// Read unmarshal message from conn
func (*SetEncodings) Read(c Conn) (ClientMessage, error) {
msg := SetEncodings{}
var pad [1]byte
@ -341,6 +373,7 @@ func (*SetEncodings) Read(c Conn) (ClientMessage, error) {
return &msg, nil
}
// Write marshal message to conn
func (msg *SetEncodings) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
@ -372,14 +405,17 @@ type FramebufferUpdateRequest struct {
Width, Height uint16 // width, height
}
// String returns string
func (msg *FramebufferUpdateRequest) String() string {
return fmt.Sprintf("incremental: %d, x: %d, y: %d, width: %d, height: %d", msg.Inc, msg.X, msg.Y, msg.Width, msg.Height)
}
// Type returns ClientMessageType
func (*FramebufferUpdateRequest) Type() ClientMessageType {
return FramebufferUpdateRequestMsgType
}
// Read unmarshal message from conn
func (*FramebufferUpdateRequest) Read(c Conn) (ClientMessage, error) {
msg := FramebufferUpdateRequest{}
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
@ -388,6 +424,7 @@ func (*FramebufferUpdateRequest) Read(c Conn) (ClientMessage, error) {
return &msg, nil
}
// Write marshal message to conn
func (msg *FramebufferUpdateRequest) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
@ -405,14 +442,17 @@ type KeyEvent struct {
Key Key // key
}
// String returns string
func (msg *KeyEvent) String() string {
return fmt.Sprintf("down: %d, key: %v", msg.Down, msg.Key)
}
// Type returns ClientMessageType
func (*KeyEvent) Type() ClientMessageType {
return KeyEventMsgType
}
// Read unmarshal message from conn
func (*KeyEvent) Read(c Conn) (ClientMessage, error) {
msg := KeyEvent{}
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
@ -421,6 +461,7 @@ func (*KeyEvent) Read(c Conn) (ClientMessage, error) {
return &msg, nil
}
// Write marshal message to conn
func (msg *KeyEvent) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
@ -431,20 +472,23 @@ func (msg *KeyEvent) Write(c Conn) error {
return c.Flush()
}
// PointerEventMessage holds the wire format message.
// PointerEvent message holds the wire format message
type PointerEvent struct {
Mask uint8 // button-mask
X, Y uint16 // x-, y-position
}
// String returns string
func (msg *PointerEvent) String() string {
return fmt.Sprintf("mask %d, x: %d, y: %d", msg.Mask, msg.X, msg.Y)
}
// Type returns ClientMessageType
func (*PointerEvent) Type() ClientMessageType {
return PointerEventMsgType
}
// Read unmarshal message from conn
func (*PointerEvent) Read(c Conn) (ClientMessage, error) {
msg := PointerEvent{}
if err := binary.Read(c, binary.BigEndian, &msg); err != nil {
@ -453,6 +497,7 @@ func (*PointerEvent) Read(c Conn) (ClientMessage, error) {
return &msg, nil
}
// Write marshal message to conn
func (msg *PointerEvent) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
@ -470,14 +515,17 @@ type ClientCutText struct {
Text []byte
}
// String returns string
func (msg *ClientCutText) String() string {
return fmt.Sprintf("length: %d, text: %s", msg.Length, msg.Text)
}
// Type returns ClientMessageType
func (*ClientCutText) Type() ClientMessageType {
return ClientCutTextMsgType
}
// Read unmarshal message from conn
func (*ClientCutText) Read(c Conn) (ClientMessage, error) {
msg := ClientCutText{}
var pad [3]byte
@ -496,6 +544,7 @@ func (*ClientCutText) Read(c Conn) (ClientMessage, error) {
return &msg, nil
}
// Write marshal message to conn
func (msg *ClientCutText) Write(c Conn) error {
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err

View File

@ -10,13 +10,17 @@ import (
)
var (
PixelFormat8bit PixelFormat = NewPixelFormat(8)
PixelFormat16bit PixelFormat = NewPixelFormat(16)
PixelFormat32bit PixelFormat = NewPixelFormat(32)
PixelFormatAten PixelFormat = NewPixelFormatAten()
// PixelFormat8bit returns 8 bit pixel format
PixelFormat8bit = NewPixelFormat(8)
// PixelFormat16bit returns 16 bit pixel format
PixelFormat16bit = NewPixelFormat(16)
// PixelFormat32bit returns 32 bit pixel format
PixelFormat32bit = NewPixelFormat(32)
// PixelFormatAten returns pixel format used in Aten IKVM
PixelFormatAten = NewPixelFormatAten()
)
// PixelFormat describes the way a pixel is formatted for a VNC connection.
// PixelFormat describes the way a pixel is formatted for a VNC connection
type PixelFormat struct {
BPP uint8 // bits-per-pixel
Depth uint8 // depth
@ -27,27 +31,9 @@ type PixelFormat struct {
_ [3]byte // padding
}
/*
qemu:
<field name="vnc.server_red_max" showname="Red maximum: 255" size="2" pos="76" show="255" value="00ff"/>
<field name="vnc.server_green_max" showname="Green maximum: 255" size="2" pos="78" show="255" value="00ff"/>
<field name="vnc.server_blue_max" showname="Blue maximum: 255" size="2" pos="80" show="255" value="00ff"/>
<field name="vnc.server_red_shift" showname="Red shift: 16" size="1" pos="82" show="16" value="10"/>
<field name="vnc.server_green_shift" showname="Green shift: 8" size="1" pos="83" show="8" value="08"/>
<field name="vnc.server_blue_shift" showname="Blue shift: 0" size="1" pos="84" show="0" value="00"/>
*/
/*
<field name="vnc.server_red_max" showname="Red maximum: 65535" size="2" pos="76" show="65535" value="ffff"/>
<field name="vnc.server_green_max" showname="Green maximum: 65535" size="2" pos="78" show="65535" value="ffff"/>
<field name="vnc.server_blue_max" showname="Blue maximum: 65535" size="2" pos="80" show="65535" value="ffff"/>
<field name="vnc.server_red_shift" showname="Red shift: 0" size="1" pos="82" show="0" value="00"/>
<field name="vnc.server_green_shift" showname="Green shift: 8" size="1" pos="83" show="8" value="08"/>
<field name="vnc.server_blue_shift" showname="Blue shift: 16" size="1" pos="84" show="16" value="10"/>
*/
const pixelFormatLen = 16
// NewPixelFormat returns a populated PixelFormat structure.
// NewPixelFormat returns a populated PixelFormat structure
func NewPixelFormat(bpp uint8) PixelFormat {
bigEndian := uint8(0)
// rgbMax := uint16(math.Exp2(float64(bpp))) - 1
@ -75,17 +61,18 @@ func NewPixelFormat(bpp uint8) PixelFormat {
return PixelFormat{bpp, depth, bigEndian, tc, rMax, gMax, bMax, rs, gs, bs, [3]byte{}}
}
// NewPixelFormatAten returns Aten IKVM pixel format
func NewPixelFormatAten() PixelFormat {
return PixelFormat{16, 15, 0, 1, (1 << 5) - 1, (1 << 5) - 1, (1 << 5) - 1, 10, 5, 0, [3]byte{}}
}
// Marshal implements the Marshaler interface.
// 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)
return nil, fmt.Errorf("Invalid BPP value %v; must be 8, 16, or 32", pf.BPP)
}
if pf.Depth < pf.BPP {
@ -94,7 +81,7 @@ func (pf PixelFormat) Marshal() ([]byte, error) {
switch pf.Depth {
case 8, 16, 32:
default:
return nil, fmt.Errorf("Invalid Depth value %v; must be 8, 16, or 32.", pf.Depth)
return nil, fmt.Errorf("Invalid Depth value %v; must be 8, 16, or 32", pf.Depth)
}
// Create the slice of bytes
@ -109,7 +96,7 @@ func (pf PixelFormat) Marshal() ([]byte, error) {
return buf.Bytes(), nil
}
// Read reads from an io.Reader, and populates the PixelFormat.
// 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 {
@ -118,7 +105,7 @@ func (pf PixelFormat) Read(r io.Reader) error {
return pf.Unmarshal(buf)
}
// Unmarshal implements the Unmarshaler interface.
// Unmarshal implements the Unmarshaler interface
func (pf PixelFormat) Unmarshal(data []byte) error {
buf := bPool.Get().(*bytes.Buffer)
buf.Reset()
@ -135,7 +122,7 @@ func (pf PixelFormat) Unmarshal(data []byte) error {
return nil
}
// String implements the fmt.Stringer interface.
// String implements the fmt.Stringer interface
func (pf PixelFormat) String() string {
return fmt.Sprintf("{ bpp: %d depth: %d big-endian: %d true-color: %d 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)

View File

@ -11,18 +11,22 @@ import (
var _ Conn = (*ServerConn)(nil)
// Config returns config for server conn
func (c *ServerConn) Config() interface{} {
return c.cfg
}
// Conn returns underlining server net.Conn
func (c *ServerConn) Conn() net.Conn {
return c.c
}
// Wait waits connection to close
func (c *ServerConn) Wait() {
<-c.quit
}
// SetEncodings ??? sets server connection encodings
func (c *ServerConn) SetEncodings(encs []EncodingType) error {
encodings := make(map[EncodingType]Encoding)
for _, enc := range c.cfg.Encodings {
@ -36,14 +40,17 @@ func (c *ServerConn) SetEncodings(encs []EncodingType) error {
return nil
}
// SetProtoVersion ??? sets proto version
func (c *ServerConn) SetProtoVersion(pv string) {
c.protocol = pv
}
// Flush buffered data to server conn
func (c *ServerConn) Flush() error {
return c.bw.Flush()
}
// Close closing server conn
func (c *ServerConn) Close() error {
if c.quit != nil {
close(c.quit)
@ -52,62 +59,86 @@ func (c *ServerConn) Close() error {
return c.c.Close()
}
// Read reads data from net.Conn
func (c *ServerConn) Read(buf []byte) (int, error) {
return c.br.Read(buf)
}
// Write writes data to net.Conn, must be Flashed
func (c *ServerConn) Write(buf []byte) (int, error) {
return c.bw.Write(buf)
}
// ColorMap returns server connection color map
func (c *ServerConn) ColorMap() ColorMap {
return c.colorMap
}
// SetColorMap sets connection color map
func (c *ServerConn) SetColorMap(cm ColorMap) {
c.colorMap = cm
}
// DesktopName returns connection desktop name
func (c *ServerConn) DesktopName() []byte {
return c.desktopName
}
// PixelFormat return connection pixel format
func (c *ServerConn) PixelFormat() PixelFormat {
return c.pixelFormat
}
// SetDesktopName sets connection desktop name
func (c *ServerConn) SetDesktopName(name []byte) {
copy(c.desktopName, name)
}
// SetPixelFormat sets pixel format for server conn
func (c *ServerConn) SetPixelFormat(pf PixelFormat) error {
c.pixelFormat = pf
return nil
}
// Encodings returns connection encodings
func (c *ServerConn) Encodings() []Encoding {
return c.encodings
}
// Width returns framebuffer width
func (c *ServerConn) Width() uint16 {
return c.fbWidth
}
// Height returns framebuffer height
func (c *ServerConn) Height() uint16 {
return c.fbHeight
}
// Protocol returns protocol
func (c *ServerConn) Protocol() string {
return c.protocol
}
// TODO send desktopsize pseudo encoding
// SetWidth sets framebuffer width
func (c *ServerConn) SetWidth(w uint16) {
// TODO send desktopsize pseudo encoding
c.fbWidth = w
}
// SetHeight sets framebuffer height
func (c *ServerConn) SetHeight(h uint16) {
// TODO send desktopsize pseudo encoding
c.fbHeight = h
}
// ServerConn underlining server conn
type ServerConn struct {
c net.Conn
cfg *ServerConfig
br *bufio.Reader
bw *bufio.Writer
protocol string
m sync.Mutex
// 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.
@ -136,7 +167,8 @@ type ServerConn struct {
}
var (
DefaultServerHandlers []ServerHandler = []ServerHandler{
// DefaultServerHandlers uses default handlers for hanshake
DefaultServerHandlers = []ServerHandler{
&DefaultServerVersionHandler{},
&DefaultServerSecurityHandler{},
&DefaultServerClientInitHandler{},
@ -145,6 +177,7 @@ var (
}
)
// ServerConfig config struct
type ServerConfig struct {
Handlers []ServerHandler
SecurityHandlers []SecurityHandler
@ -160,6 +193,7 @@ type ServerConfig struct {
ErrorCh chan error
}
// NewServerConn returns new Server connection fron net.Conn
func NewServerConn(c net.Conn, cfg *ServerConfig) (*ServerConn, error) {
return &ServerConn{
c: c,
@ -175,6 +209,7 @@ func NewServerConn(c net.Conn, cfg *ServerConfig) (*ServerConn, error) {
}, nil
}
// Serve serves requests from net.Listener using ServerConfig
func Serve(ctx context.Context, ln net.Listener, cfg *ServerConfig) error {
for {
@ -204,8 +239,10 @@ func Serve(ctx context.Context, ln net.Listener, cfg *ServerConfig) error {
}
}
// DefaultServerMessageHandler default package handler
type DefaultServerMessageHandler struct{}
// Handle handles messages from clients
func (*DefaultServerMessageHandler) Handle(c Conn) error {
cfg := c.Config().(*ServerConfig)
var err error