added RfbReaderHelper which wraps the connection reader and allows to add listeners like the recorder or proxy

added fbs recorder, and tested it against vine vnc server 5.0.1 and rfbplayer 1.4 —> works! (there is still some problem with tight VNC server)
This commit is contained in:
amit bezalel 2017-06-17 11:02:06 +03:00
parent a74fe9e60c
commit 007e748c61
39 changed files with 3792 additions and 3367 deletions

4
.gitignore vendored
View File

@ -1,2 +1,2 @@
*.bin *.bin
debug debug

View File

@ -1,22 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<resourceExtensions /> <resourceExtensions />
<wildcardResourcePatterns> <wildcardResourcePatterns>
<entry name="!?*.java" /> <entry name="!?*.java" />
<entry name="!?*.form" /> <entry name="!?*.form" />
<entry name="!?*.class" /> <entry name="!?*.class" />
<entry name="!?*.groovy" /> <entry name="!?*.groovy" />
<entry name="!?*.scala" /> <entry name="!?*.scala" />
<entry name="!?*.flex" /> <entry name="!?*.flex" />
<entry name="!?*.kt" /> <entry name="!?*.kt" />
<entry name="!?*.clj" /> <entry name="!?*.clj" />
<entry name="!?*.aj" /> <entry name="!?*.aj" />
</wildcardResourcePatterns> </wildcardResourcePatterns>
<annotationProcessing> <annotationProcessing>
<profile default="true" name="Default" enabled="false"> <profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" /> <processorPath useClasspath="true" />
</profile> </profile>
</annotationProcessing> </annotationProcessing>
</component> </component>
</project> </project>

View File

@ -1,3 +1,3 @@
<component name="CopyrightManager"> <component name="CopyrightManager">
<settings default="" /> <settings default="" />
</component> </component>

View File

@ -1,42 +1,42 @@
<component name="libraryTable"> <component name="libraryTable">
<library name="GOPATH &lt;vncproxy&gt;"> <library name="GOPATH &lt;vncproxy&gt;">
<CLASSES> <CLASSES>
<root url="file://$PROJECT_DIR$/../elastictrail" /> <root url="file://$PROJECT_DIR$/../elastictrail" />
<root url="file://$PROJECT_DIR$/../gopkg.in" /> <root url="file://$PROJECT_DIR$/../gopkg.in" />
<root url="file://$PROJECT_DIR$/../vncproxy1" /> <root url="file://$PROJECT_DIR$/../vncproxy1" />
<root url="file://$PROJECT_DIR$/../GoProjExample" /> <root url="file://$PROJECT_DIR$/../GoProjExample" />
<root url="file://$PROJECT_DIR$/../srf.opb" /> <root url="file://$PROJECT_DIR$/../srf.opb" />
<root url="file://$PROJECT_DIR$/../sourcegraph.com" /> <root url="file://$PROJECT_DIR$/../sourcegraph.com" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/github.com" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/github.com" />
<root url="file://$PROJECT_DIR$/../github.com" /> <root url="file://$PROJECT_DIR$/../github.com" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/gopkg.in" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/gopkg.in" />
<root url="file://$PROJECT_DIR$/../golang.org" /> <root url="file://$PROJECT_DIR$/../golang.org" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/golang.org" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/golang.org" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/srf" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/srf" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/version" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/version" />
<root url="file://$PROJECT_DIR$/../srf.storage" /> <root url="file://$PROJECT_DIR$/../srf.storage" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/sourcegraph.com" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/sourcegraph.com" />
</CLASSES> </CLASSES>
<JAVADOC /> <JAVADOC />
<SOURCES> <SOURCES>
<root url="file://$PROJECT_DIR$/../elastictrail" /> <root url="file://$PROJECT_DIR$/../elastictrail" />
<root url="file://$PROJECT_DIR$/../gopkg.in" /> <root url="file://$PROJECT_DIR$/../gopkg.in" />
<root url="file://$PROJECT_DIR$/../vncproxy1" /> <root url="file://$PROJECT_DIR$/../vncproxy1" />
<root url="file://$PROJECT_DIR$/../GoProjExample" /> <root url="file://$PROJECT_DIR$/../GoProjExample" />
<root url="file://$PROJECT_DIR$/../srf.opb" /> <root url="file://$PROJECT_DIR$/../srf.opb" />
<root url="file://$PROJECT_DIR$/../sourcegraph.com" /> <root url="file://$PROJECT_DIR$/../sourcegraph.com" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/github.com" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/github.com" />
<root url="file://$PROJECT_DIR$/../github.com" /> <root url="file://$PROJECT_DIR$/../github.com" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/gopkg.in" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/gopkg.in" />
<root url="file://$PROJECT_DIR$/../golang.org" /> <root url="file://$PROJECT_DIR$/../golang.org" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/golang.org" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/golang.org" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/srf" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/srf" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/version" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/version" />
<root url="file://$PROJECT_DIR$/../srf.storage" /> <root url="file://$PROJECT_DIR$/../srf.storage" />
<root url="file://$USER_HOME$/srf/experience.center.opb/src/sourcegraph.com" /> <root url="file://$USER_HOME$/srf/experience.center.opb/src/sourcegraph.com" />
</SOURCES> </SOURCES>
<excluded> <excluded>
<root url="file://$PROJECT_DIR$" /> <root url="file://$PROJECT_DIR$" />
</excluded> </excluded>
</library> </library>
</component> </component>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GOROOT" path="/usr/local/Cellar/go/1.8.3/libexec" /> <component name="GOROOT" path="/usr/local/Cellar/go/1.8.3/libexec" />
</project> </project>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/.idea/vncproxy.iml" filepath="$PROJECT_DIR$/.idea/vncproxy.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/vncproxy.iml" filepath="$PROJECT_DIR$/.idea/vncproxy.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="$PROJECT_DIR$" vcs="Git" />
</component> </component>
</project> </project>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4"> <module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="GOPATH &lt;vncproxy&gt;" level="project" /> <orderEntry type="library" name="GOPATH &lt;vncproxy&gt;" level="project" />
</component> </component>
</module> </module>

File diff suppressed because it is too large Load Diff

144
.vscode/launch.json vendored
View File

@ -1,73 +1,73 @@
{ {
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Launch Test", "name": "Launch Test",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "test", "mode": "test",
"remotePath": "", "remotePath": "",
"port": 2345, "port": 2345,
"program": "${workspaceRoot}/reader", "program": "${workspaceRoot}/reader",
"args": [ "args": [
"-test.v" "-test.v"
], ],
"osx": { "osx": {
"env": { "env": {
//"GOPATH": "/Users/amitbet/Dropbox/go" //"GOPATH": "/Users/amitbet/Dropbox/go"
} }
}, },
"windows": { "windows": {
"env": { "env": {
//"GOPATH": "${env.USERPROFILE}\\Dropbox\\go" //"GOPATH": "${env.USERPROFILE}\\Dropbox\\go"
} }
}, },
"showLog": true "showLog": true
}, },
{ {
"name": "Launch Grouper Tests", "name": "Launch Grouper Tests",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "test", "mode": "test",
"remotePath": "", "remotePath": "",
"port": 2345, "port": 2345,
"program": "${workspaceRoot}/consumer", "program": "${workspaceRoot}/consumer",
"args": [ "args": [
"-test.v" "-test.v"
], ],
"osx": { "osx": {
"env": { "env": {
//"GOPATH": "${env.HOME}/Dropbox/go" //"GOPATH": "${env.HOME}/Dropbox/go"
} }
}, },
"windows": { "windows": {
"env": { "env": {
//"GOPATH": "${env.USERPROFILE}\\Dropbox\\go" //"GOPATH": "${env.USERPROFILE}\\Dropbox\\go"
} }
}, },
"showLog": true "showLog": true
}, },
{ {
"name": "Launch", "name": "Launch",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "debug", "mode": "debug",
"remotePath": "", "remotePath": "",
"port": 2345, "port": 2345,
"host": "127.0.0.1", "host": "127.0.0.1",
"program": "${workspaceRoot}/", "program": "${workspaceRoot}/",
"osx": { "osx": {
"env": { "env": {
//"GOPATH": "${env.HOME}/Dropbox/go" //"GOPATH": "${env.HOME}/Dropbox/go"
} }
}, },
"windows": { "windows": {
"env": { "env": {
//"GOPATH": "${env.USERPROFILE}\\Dropbox\\go" //"GOPATH": "${env.USERPROFILE}\\Dropbox\\go"
} }
}, },
"args": [], "args": [],
"showLog": true "showLog": true
} }
] ]
} }

90
.vscode/tasks.json vendored
View File

@ -1,46 +1,46 @@
{ {
"version": "0.1.0", "version": "0.1.0",
"command": "go", "command": "go",
"isShellCommand": true, "isShellCommand": true,
"echoCommand": true, "echoCommand": true,
"showOutput": "always", "showOutput": "always",
// "showOutput": "silent", // "showOutput": "silent",
"options": { "options": {
// "env": { // "env": {
// "GOPATH": "/Users/lukeh/dd/go" // "GOPATH": "/Users/lukeh/dd/go"
// } // }
}, },
"tasks": [ "tasks": [
{ {
"taskName": "install", "taskName": "install",
"args": [ "args": [
"-v", "-v",
"./..." "./..."
], ],
"osx": { "osx": {
"options": { "options": {
"env": { "env": {
//"GOPATH": "${env.HOME}/Dropbox/go" //"GOPATH": "${env.HOME}/Dropbox/go"
} }
} }
}, },
"windows": { "windows": {
"options": { "options": {
"env": { "env": {
//"GOPATH": "${env.USERPROFILE}\\Dropbox\\go" //"GOPATH": "${env.USERPROFILE}\\Dropbox\\go"
} }
} }
}, },
"isBuildCommand": true, "isBuildCommand": true,
"problemMatcher": "$go" "problemMatcher": "$go"
}, },
{ {
"taskName": "test", "taskName": "test",
"args": [ "args": [
"-v", "-v",
"./..." "./..."
], ],
"isTestCommand": true "isTestCommand": true
} }
] ]
} }

42
LICENSE
View File

@ -1,21 +1,21 @@
MIT License MIT License
Copyright (c) 2017 Amit Bezalel Copyright (c) 2017 Amit Bezalel
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
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

View File

@ -1,7 +1,7 @@
# VncProxy # VncProxy
A RFB proxy, written in go that can save and replay RBS files A RFB proxy, written in go that can save and replay RBS files
Still a work in progress, but the client side already includes all the required encodings Still a work in progress, but the client side already includes all the required encodings
understanding the RemoteFrameBuffer protocol is important since we need to save the frameResponses with timestamps understanding the RemoteFrameBuffer protocol is important since we need to save the frameResponses with timestamps
some server code will be added shortly, with the proxying logics. some server code will be added shortly, with the proxying logics.

View File

@ -1,14 +1,14 @@
package common package common
type Logger interface { type Logger interface {
Debug(v ...interface{}) Debug(v ...interface{})
Debugf(format string, v ...interface{}) Debugf(format string, v ...interface{})
Info(v ...interface{}) Info(v ...interface{})
Infof(format string, v ...interface{}) Infof(format string, v ...interface{})
Warn(v ...interface{}) Warn(v ...interface{})
Warnf(format string, v ...interface{}) Warnf(format string, v ...interface{})
Error(v ...interface{}) Error(v ...interface{})
Errorf(format string, v ...interface{}) Errorf(format string, v ...interface{})
Fatal(v ...interface{}) Fatal(v ...interface{})
Fatalf(format string, v ...interface{}) Fatalf(format string, v ...interface{})
} }

View File

@ -1,9 +1,5 @@
package common package common
import (
"io"
)
// An Encoding implements a method for encoding pixel data that is // An Encoding implements a method for encoding pixel data that is
// sent by the server to the client. // sent by the server to the client.
type Encoding interface { type Encoding interface {
@ -13,7 +9,7 @@ type Encoding interface {
// Read reads the contents of the encoded pixel data from the reader. // Read reads the contents of the encoded pixel data from the reader.
// This should return a new Encoding implementation that contains // This should return a new Encoding implementation that contains
// the proper data. // the proper data.
Read(*PixelFormat, *Rectangle, io.Reader) (Encoding, error) Read(*PixelFormat, *Rectangle, *RfbReadHelper) (Encoding, error)
} }
const ( const (

View File

@ -1,45 +1,85 @@
// Package vnc implements a VNC client.
//
// References:
// [PROTOCOL]: http://tools.ietf.org/html/rfc6143
package common package common
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io" "io"
) )
// type DataSource struct { var TightMinToCompress = 12
// conn io.Reader
// output io.Writer
// passThrough bool
// PixelFormat PixelFormat
// }Color
type RfbReader struct {
reader io.Reader
saveBytes bool
savedBuff bytes.Buffer
}
func (r *RfbReader) Read(p []byte) (n int, err error) { const (
readLen, err := r.reader.Read(p) SegmentBytes SegmentType = iota
r.savedBuff.Write(p) SegmentMessageSeparator
return readLen, err SegmentRectSeparator
)
type SegmentType int
type RfbSegment struct {
Bytes []byte
SegmentType SegmentType
UpcomingObjectType int
} }
func (r *RfbReader) SavedBuff() bytes.Buffer { type SegmentConsumer interface {
return r.savedBuff Consume(*RfbSegment) error
} }
type RfbReadHelper struct { type RfbReadHelper struct {
io.Reader io.Reader
Listener SegmentConsumer
} }
func (d *RfbReadHelper) ReadBytes(count int) ([]byte, error) { func (r *RfbReadHelper) ReadDiscrete(p []byte) (int, error) {
return r.Read(p)
}
func (r *RfbReadHelper) SendRectSeparator(upcomingRectType int) error {
seg := &RfbSegment{SegmentType: SegmentRectSeparator, UpcomingObjectType: upcomingRectType}
if r.Listener != nil {
return nil
}
return r.Listener.Consume(seg)
}
func (r *RfbReadHelper) SendMessageSeparator(upcomingMessageType int) error {
seg := &RfbSegment{SegmentType: SegmentMessageSeparator, UpcomingObjectType: upcomingMessageType}
if r.Listener == nil {
return nil
}
return r.Listener.Consume(seg)
}
func (r *RfbReadHelper) PublishBytes(p []byte) error {
seg := &RfbSegment{Bytes: p, SegmentType: SegmentBytes}
if r.Listener == nil {
return nil
}
return r.Listener.Consume(seg)
}
func (r *RfbReadHelper) Read(p []byte) (n int, err error) {
readLen, err := r.Reader.Read(p)
if err != nil {
return 0, err
}
//write the bytes to the Listener for further processing
seg := &RfbSegment{Bytes: p, SegmentType: SegmentBytes}
if r.Listener == nil {
return 0,nil
}
r.Listener.Consume(seg)
if err != nil {
return 0, err
}
return readLen, err
}
func (r *RfbReadHelper) ReadBytes(count int) ([]byte, error) {
buff := make([]byte, count) buff := make([]byte, count)
_, err := io.ReadFull(d.Reader, buff) _, err := io.ReadFull(r, buff)
if err != nil { if err != nil {
//if err := binary.Read(d.conn, binary.BigEndian, &buff); err != nil { //if err := binary.Read(d.conn, binary.BigEndian, &buff); err != nil {
return nil, err return nil, err
@ -47,41 +87,41 @@ func (d *RfbReadHelper) ReadBytes(count int) ([]byte, error) {
return buff, nil return buff, nil
} }
func (d *RfbReadHelper) ReadUint8() (uint8, error) { func (r *RfbReadHelper) ReadUint8() (uint8, error) {
var myUint uint8 var myUint uint8
if err := binary.Read(d.Reader, binary.BigEndian, &myUint); err != nil { if err := binary.Read(r, binary.BigEndian, &myUint); err != nil {
return 0, err return 0, err
} }
//fmt.Printf("myUint=%d", myUint) //fmt.Printf("myUint=%d", myUint)
return myUint, nil return myUint, nil
} }
func (d *RfbReadHelper) ReadUint16() (uint16, error) { func (r *RfbReadHelper) ReadUint16() (uint16, error) {
var myUint uint16 var myUint uint16
if err := binary.Read(d.Reader, binary.BigEndian, &myUint); err != nil { if err := binary.Read(r, binary.BigEndian, &myUint); err != nil {
return 0, err return 0, err
} }
//fmt.Printf("myUint=%d", myUint) //fmt.Printf("myUint=%d", myUint)
return myUint, nil return myUint, nil
} }
func (d *RfbReadHelper) ReadUint32() (uint32, error) { func (r *RfbReadHelper) ReadUint32() (uint32, error) {
var myUint uint32 var myUint uint32
if err := binary.Read(d.Reader, binary.BigEndian, &myUint); err != nil { if err := binary.Read(r, binary.BigEndian, &myUint); err != nil {
return 0, err return 0, err
} }
//fmt.Printf("myUint=%d", myUint) //fmt.Printf("myUint=%d", myUint)
return myUint, nil return myUint, nil
} }
func (d *RfbReadHelper) ReadCompactLen() (int, error) { func (r *RfbReadHelper) ReadCompactLen() (int, error) {
var err error var err error
part, err := d.ReadUint8() part, err := r.ReadUint8()
//byteCount := 1 //byteCount := 1
len := uint32(part & 0x7F) len := uint32(part & 0x7F)
if (part & 0x80) != 0 { if (part & 0x80) != 0 {
part, err = d.ReadUint8() part, err = r.ReadUint8()
//byteCount++ //byteCount++
len |= uint32(part&0x7F) << 7 len |= uint32(part&0x7F) << 7
if (part & 0x80) != 0 { if (part & 0x80) != 0 {
part, err = d.ReadUint8() part, err = r.ReadUint8()
//byteCount++ //byteCount++
len |= uint32(part&0xFF) << 14 len |= uint32(part&0xFF) << 14
} }
@ -94,8 +134,6 @@ func (d *RfbReadHelper) ReadCompactLen() (int, error) {
return int(len), err return int(len), err
} }
var TightMinToCompress int = 12
func (r *RfbReadHelper) ReadTightData(dataSize int) ([]byte, error) { func (r *RfbReadHelper) ReadTightData(dataSize int) ([]byte, error) {
if int(dataSize) < TightMinToCompress { if int(dataSize) < TightMinToCompress {
return r.ReadBytes(int(dataSize)) return r.ReadBytes(int(dataSize))

View File

@ -1,34 +1,34 @@
package common package common
import ( import (
"fmt" "fmt"
) )
// Rectangle represents a rectangle of pixel data. // Rectangle represents a rectangle of pixel data.
type Rectangle struct { type Rectangle struct {
X uint16 X uint16
Y uint16 Y uint16
Width uint16 Width uint16
Height uint16 Height uint16
Enc Encoding Enc Encoding
} }
func (r *Rectangle) String() string { func (r *Rectangle) String() string {
return fmt.Sprintf("(%d,%d) (width: %d, height: %d), Enc= %d", r.X, r.Y, r.Width, r.Height, r.Enc.Type()) return fmt.Sprintf("(%d,%d) (width: %d, height: %d), Enc= %d", r.X, r.Y, r.Width, r.Height, r.Enc.Type())
} }
// PixelFormat describes the way a pixel is formatted for a VNC connection. // PixelFormat describes the way a pixel is formatted for a VNC connection.
// //
// See RFC 6143 Section 7.4 for information on each of the fields. // See RFC 6143 Section 7.4 for information on each of the fields.
type PixelFormat struct { type PixelFormat struct {
BPP uint8 BPP uint8
Depth uint8 Depth uint8
BigEndian bool BigEndian bool
TrueColor bool TrueColor bool
RedMax uint16 RedMax uint16
GreenMax uint16 GreenMax uint16
BlueMax uint16 BlueMax uint16
RedShift uint8 RedShift uint8
GreenShift uint8 GreenShift uint8
BlueShift uint8 BlueShift uint8
} }

View File

@ -1,26 +1,20 @@
package encodings package encodings
import ( import "vncproxy/common"
"io"
"vncproxy/common" type CopyRectEncoding struct {
) //Colors []Color
copyRectSrcX uint16
type CopyRectEncoding struct { copyRectSrcY uint16
//Colors []Color }
copyRectSrcX uint16
copyRectSrcY uint16 func (z *CopyRectEncoding) Type() int32 {
} return 1
}
func (z *CopyRectEncoding) Type() int32 { func (z *CopyRectEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) {
return 1 z.copyRectSrcX, _ = r.ReadUint16()
} z.copyRectSrcY, _ = r.ReadUint16()
func (z *CopyRectEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r io.Reader) (common.Encoding, error) { return z, nil
conn := common.RfbReadHelper{r} }
//conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat}
//bytesPerPixel := c.PixelFormat.BPP / 8 //////////
z.copyRectSrcX, _ = conn.ReadUint16()
z.copyRectSrcY, _ = conn.ReadUint16()
return z, nil
}
//////////

View File

@ -1,7 +1,6 @@
package encodings package encodings
import ( import (
"io"
"vncproxy/common" "vncproxy/common"
) )
@ -13,16 +12,15 @@ func (z *CoRREEncoding) Type() int32 {
return 4 return 4
} }
func (z *CoRREEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r io.Reader) (common.Encoding, error) { func (z *CoRREEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) {
conn := common.RfbReadHelper{r}
bytesPerPixel := int(pixelFmt.BPP / 8) bytesPerPixel := int(pixelFmt.BPP / 8)
numOfSubrectangles, _ := conn.ReadUint32() numOfSubrectangles, _ := r.ReadUint32()
//read whole rect background color //read whole rect background color
conn.ReadBytes(bytesPerPixel) r.ReadBytes(bytesPerPixel)
//read all individual rects (color=BPP + x=16b + y=16b + w=16b + h=16b) //read all individual rects (color=BPP + x=16b + y=16b + w=16b + h=16b)
_, err := conn.ReadBytes(int(numOfSubrectangles) * (bytesPerPixel + 4)) _, err := r.ReadBytes(int(numOfSubrectangles) * (bytesPerPixel + 4))
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,85 +1,80 @@
package encodings package encodings
import ( import "vncproxy/common"
"io"
"vncproxy/common" const (
) HextileRaw = 1
HextileBackgroundSpecified = 2
const ( HextileForegroundSpecified = 4
HextileRaw = 1 HextileAnySubrects = 8
HextileBackgroundSpecified = 2 HextileSubrectsColoured = 16
HextileForegroundSpecified = 4 )
HextileAnySubrects = 8
HextileSubrectsColoured = 16 type HextileEncoding struct {
) //Colors []Color
}
type HextileEncoding struct {
//Colors []Color func (z *HextileEncoding) Type() int32 {
} return 5
}
func (z *HextileEncoding) Type() int32 { func (z *HextileEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) {
return 5 bytesPerPixel := int(pixelFmt.BPP) / 8
}
func (z *HextileEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r io.Reader) (common.Encoding, error) { for ty := rect.Y; ty < rect.Y+rect.Height; ty += 16 {
conn := common.RfbReadHelper{r} th := 16
//conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat} if rect.Y+rect.Height-ty < 16 {
bytesPerPixel := int(pixelFmt.BPP) / 8 th = int(rect.Y) + int(rect.Height) - int(ty)
//buf := make([]byte, bytesPerPixel) }
for ty := rect.Y; ty < rect.Y+rect.Height; ty += 16 {
th := 16 for tx := rect.X; tx < rect.X+rect.Width; tx += 16 {
if rect.Y+rect.Height-ty < 16 { tw := 16
th = int(rect.Y) + int(rect.Height) - int(ty) if rect.X+rect.Width-tx < 16 {
} tw = int(rect.X) + int(rect.Width) - int(tx)
}
for tx := rect.X; tx < rect.X+rect.Width; tx += 16 {
tw := 16 //handle Hextile Subrect(tx, ty, tw, th):
if rect.X+rect.Width-tx < 16 { subencoding, err := r.ReadUint8()
tw = int(rect.X) + int(rect.Width) - int(tx) //fmt.Printf("hextile reader tile: (%d,%d) subenc=%d\n", ty, tx, subencoding)
} if err != nil {
//fmt.Printf("error in hextile reader: %v\n", err)
//handle Hextile Subrect(tx, ty, tw, th): return nil, err
subencoding, err := conn.ReadUint8() }
//fmt.Printf("hextile reader tile: (%d,%d) subenc=%d\n", ty, tx, subencoding)
if err != nil { if (subencoding & HextileRaw) != 0 {
//fmt.Printf("error in hextile reader: %v\n", err) //ReadRawRect(c, rect, r)
return nil, err r.ReadBytes(tw * th * bytesPerPixel)
} //fmt.Printf("hextile reader: HextileRaw\n")
continue
if (subencoding & HextileRaw) != 0 { }
//ReadRawRect(c, rect, r) if (subencoding & HextileBackgroundSpecified) != 0 {
conn.ReadBytes(tw * th * bytesPerPixel) r.ReadBytes(int(bytesPerPixel))
//fmt.Printf("hextile reader: HextileRaw\n") }
continue if (subencoding & HextileForegroundSpecified) != 0 {
} r.ReadBytes(int(bytesPerPixel))
if (subencoding & HextileBackgroundSpecified) != 0 { }
conn.ReadBytes(int(bytesPerPixel)) if (subencoding & HextileAnySubrects) == 0 {
} //fmt.Printf("hextile reader: no Subrects\n")
if (subencoding & HextileForegroundSpecified) != 0 { continue
conn.ReadBytes(int(bytesPerPixel)) }
} //fmt.Printf("hextile reader: handling Subrects\n")
if (subencoding & HextileAnySubrects) == 0 { nSubrects, err := r.ReadUint8()
//fmt.Printf("hextile reader: no Subrects\n") if err != nil {
continue return nil, err
} }
//fmt.Printf("hextile reader: handling Subrects\n") bufsize := int(nSubrects) * 2
nSubrects, err := conn.ReadUint8() if (subencoding & HextileSubrectsColoured) != 0 {
if err != nil { bufsize += int(nSubrects) * int(bytesPerPixel)
return nil, err }
} //byte[] buf = new byte[bufsize];
bufsize := int(nSubrects) * 2 r.ReadBytes(bufsize)
if (subencoding & HextileSubrectsColoured) != 0 { }
bufsize += int(nSubrects) * int(bytesPerPixel) }
}
//byte[] buf = new byte[bufsize]; // len, _ := readUint32(c.c)
conn.ReadBytes(bufsize) // _, err := readBytes(c.c, int(len))
}
} // if err != nil {
// return nil, err
// len, _ := readUint32(c.c) // }
// _, err := readBytes(c.c, int(len)) return z, nil
}
// if err != nil {
// return nil, err
// }
return z, nil
}

View File

@ -1,7 +1,6 @@
package encodings package encodings
import ( import (
"io"
"vncproxy/common" "vncproxy/common"
) )
@ -16,9 +15,9 @@ func (*RawEncoding) Type() int32 {
return 0 return 0
} }
func (*RawEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r io.Reader) (common.Encoding, error) { func (*RawEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) {
//conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat} //conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat}
conn := common.RfbReadHelper{r} //conn := common.RfbReadHelper{Reader:r}
bytesPerPixel := int(pixelFmt.BPP / 8) bytesPerPixel := int(pixelFmt.BPP / 8)
//pixelBytes := make([]uint8, bytesPerPixel) //pixelBytes := make([]uint8, bytesPerPixel)
@ -31,7 +30,7 @@ func (*RawEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r
for y := uint16(0); y < rect.Height; y++ { for y := uint16(0); y < rect.Height; y++ {
for x := uint16(0); x < rect.Width; x++ { for x := uint16(0); x < rect.Width; x++ {
if _, err := conn.ReadBytes(bytesPerPixel); err != nil { if _, err := r.ReadBytes(bytesPerPixel); err != nil {
return nil, err return nil, err
} }

View File

@ -1,28 +1,27 @@
package encodings package encodings
import "io" import "vncproxy/common"
import "vncproxy/common"
type RREEncoding struct {
type RREEncoding struct { //Colors []Color
//Colors []Color }
}
func (z *RREEncoding) Type() int32 {
func (z *RREEncoding) Type() int32 { return 2
return 2 }
} func (z *RREEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) {
func (z *RREEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r io.Reader) (common.Encoding, error) { //conn := common.RfbReadHelper{Reader:r}
conn := common.RfbReadHelper{r} bytesPerPixel := int(pixelFmt.BPP / 8)
bytesPerPixel := int(pixelFmt.BPP / 8) numOfSubrectangles, _ := r.ReadUint32()
numOfSubrectangles, _ := conn.ReadUint32()
//read whole rect background color
//read whole rect background color r.ReadBytes(bytesPerPixel)
conn.ReadBytes(bytesPerPixel)
//read all individual rects (color=BPP + x=16b + y=16b + w=16b + h=16b)
//read all individual rects (color=BPP + x=16b + y=16b + w=16b + h=16b) _, err := r.ReadBytes(int(numOfSubrectangles) * (bytesPerPixel + 8))
_, err := conn.ReadBytes(int(numOfSubrectangles) * (bytesPerPixel + 8))
if err != nil {
if err != nil { return nil, err
return nil, err }
} return z, nil
return z, nil }
}

View File

@ -1,334 +1,334 @@
package encodings package encodings
import ( import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"vncproxy/common" "vncproxy/common"
) )
var TightMinToCompress int = 12 var TightMinToCompress int = 12
const ( const (
TightExplicitFilter = 0x04 TightExplicitFilter = 0x04
TightFill = 0x08 TightFill = 0x08
TightJpeg = 0x09 TightJpeg = 0x09
TightMaxSubencoding = 0x09 TightMaxSubencoding = 0x09
TightFilterCopy = 0x00 TightFilterCopy = 0x00
TightFilterPalette = 0x01 TightFilterPalette = 0x01
TightFilterGradient = 0x02 TightFilterGradient = 0x02
) )
type TightEncoding struct { type TightEncoding struct {
output io.Writer output io.Writer
logger common.Logger logger common.Logger
} }
func (t *TightEncoding) SetOutput(output io.Writer) { func (t *TightEncoding) SetOutput(output io.Writer) {
t.output = output t.output = output
} }
func (*TightEncoding) Type() int32 { func (*TightEncoding) Type() int32 {
return 7 return 7
} }
// func ReadAndRecBytes(conn io.Reader, rec io.Writer, count int) ([]byte, error) { // func ReadAndRecBytes(conn io.Reader, rec io.Writer, count int) ([]byte, error) {
// buf, err := readBytes(conn, count) // buf, err := readBytes(conn, count)
// rec.Write(buf) // rec.Write(buf)
// return buf, err // return buf, err
// } // }
// func ReadAndRecUint8(conn io.Reader, rec io.Writer) (uint8, error) { // func ReadAndRecUint8(conn io.Reader, rec io.Writer) (uint8, error) {
// myUint, err := readUint8(conn) // myUint, err := readUint8(conn)
// buf := make([]byte, 1) // buf := make([]byte, 1)
// buf[0] = byte(myUint) // cast int8 to byte // buf[0] = byte(myUint) // cast int8 to byte
// rec.Write(buf) // rec.Write(buf)
// return myUint, err // return myUint, err
// } // }
// func ReadAndRecUint16(conn io.Reader, rec io.Writer) (uint16, error) { // func ReadAndRecUint16(conn io.Reader, rec io.Writer) (uint16, error) {
// myUint, err := readUint16(conn) // myUint, err := readUint16(conn)
// buf := make([]byte, 2) // buf := make([]byte, 2)
// //buf[0] = byte(myUint) // cast int8 to byte // //buf[0] = byte(myUint) // cast int8 to byte
// //var i int16 = 41 // //var i int16 = 41
// //b := make([]byte, 2) // //b := make([]byte, 2)
// binary.LittleEndian.PutUint16(buf, uint16(myUint)) // binary.LittleEndian.PutUint16(buf, uint16(myUint))
// rec.Write(buf) // rec.Write(buf)
// return myUint, err // return myUint, err
// } // }
func calcTightBytePerPixel(pf *common.PixelFormat) int { func calcTightBytePerPixel(pf *common.PixelFormat) int {
bytesPerPixel := int(pf.BPP / 8) bytesPerPixel := int(pf.BPP / 8)
var bytesPerPixelTight int var bytesPerPixelTight int
if 24 == pf.Depth && 32 == pf.BPP { if 24 == pf.Depth && 32 == pf.BPP {
bytesPerPixelTight = 3 bytesPerPixelTight = 3
} else { } else {
bytesPerPixelTight = bytesPerPixel bytesPerPixelTight = bytesPerPixel
} }
return bytesPerPixelTight return bytesPerPixelTight
} }
func (t *TightEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, reader io.Reader) (common.Encoding, error) { func (t *TightEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) {
bytesPixel := calcTightBytePerPixel(pixelFmt) bytesPixel := calcTightBytePerPixel(pixelFmt)
conn := common.RfbReadHelper{reader} //conn := common.RfbReadHelper{Reader:reader}
//conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat} //conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat}
//var subencoding uint8 //var subencoding uint8
subencoding, err := conn.ReadUint8() subencoding, err := r.ReadUint8()
if err != nil { if err != nil {
fmt.Printf("error in handling tight encoding: %v\n", err) fmt.Printf("error in handling tight encoding: %v\n", err)
return nil, err return nil, err
} }
fmt.Printf("bytesPixel= %d, subencoding= %d\n", bytesPixel, subencoding) fmt.Printf("bytesPixel= %d, subencoding= %d\n", bytesPixel, subencoding)
// if err := binary.Read(conn.c, binary.BigEndian, &subencoding); err != nil { // if err := binary.Read(conn.c, binary.BigEndian, &subencoding); err != nil {
// return t, err // return t, err
// } // }
//move it to position (remove zlib flush commands) //move it to position (remove zlib flush commands)
compType := subencoding >> 4 & 0x0F compType := subencoding >> 4 & 0x0F
// for stream_id := 0; stream_id < 4; stream_id++ { // for stream_id := 0; stream_id < 4; stream_id++ {
// // if ((comp_ctl & 1) != 0 && tightInflaters[stream_id] != null) { // // if ((comp_ctl & 1) != 0 && tightInflaters[stream_id] != null) {
// // tightInflaters[stream_id] = null; // // tightInflaters[stream_id] = null;
// // } // // }
// subencoding >>= 1 // subencoding >>= 1
// } // }
fmt.Printf("afterSHL:%d\n", compType) fmt.Printf("afterSHL:%d\n", compType)
switch compType { switch compType {
case TightFill: case TightFill:
fmt.Printf("reading fill size=%d\n", bytesPixel) fmt.Printf("reading fill size=%d\n", bytesPixel)
//read color //read color
conn.ReadBytes(int(bytesPixel)) r.ReadBytes(int(bytesPixel))
return t, nil return t, nil
case TightJpeg: case TightJpeg:
if pixelFmt.BPP == 8 { if pixelFmt.BPP == 8 {
return nil, errors.New("Tight encoding: JPEG is not supported in 8 bpp mode") return nil, errors.New("Tight encoding: JPEG is not supported in 8 bpp mode")
} }
len, err := conn.ReadCompactLen() len, err := r.ReadCompactLen()
if err != nil { if err != nil {
return nil, err return nil, err
} }
fmt.Printf("reading jpeg size=%d\n", len) fmt.Printf("reading jpeg size=%d\n", len)
conn.ReadBytes(len) r.ReadBytes(len)
return t, nil return t, nil
default: default:
if compType > TightJpeg { if compType > TightJpeg {
fmt.Println("Compression control byte is incorrect!") fmt.Println("Compression control byte is incorrect!")
} }
handleTightFilters(subencoding, pixelFmt, rect, reader) handleTightFilters(subencoding, pixelFmt, rect, r)
return t, nil return t, nil
} }
} }
func handleTightFilters(subencoding uint8, pixelFmt *common.PixelFormat, rect *common.Rectangle, reader io.Reader) { func handleTightFilters(subencoding uint8, pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) {
conn := common.RfbReadHelper{reader} //conn := common.RfbReadHelper{Reader:reader}
var FILTER_ID_MASK uint8 = 0x40 var FILTER_ID_MASK uint8 = 0x40
//var STREAM_ID_MASK uint8 = 0x30 //var STREAM_ID_MASK uint8 = 0x30
//decoderId := (subencoding & STREAM_ID_MASK) >> 4 //decoderId := (subencoding & STREAM_ID_MASK) >> 4
var filterid uint8 var filterid uint8
var err error var err error
if (subencoding & FILTER_ID_MASK) > 0 { // filter byte presence if (subencoding & FILTER_ID_MASK) > 0 { // filter byte presence
filterid, err = conn.ReadUint8() filterid, err = r.ReadUint8()
if err != nil { if err != nil {
fmt.Printf("error in handling tight encoding, reading filterid: %v\n", err) fmt.Printf("error in handling tight encoding, reading filterid: %v\n", err)
return return
} }
fmt.Printf("read filter: %d\n", filterid) fmt.Printf("read filter: %d\n", filterid)
} }
//var numColors uint8 //var numColors uint8
bytesPixel := calcTightBytePerPixel(pixelFmt) bytesPixel := calcTightBytePerPixel(pixelFmt)
fmt.Printf("filter: %d\n", filterid) fmt.Printf("filter: %d\n", filterid)
// if rfb.rec != null { // if rfb.rec != null {
// rfb.rec.writeByte(filter_id) // rfb.rec.writeByte(filter_id)
// } // }
lengthCurrentbpp := int(bytesPixel) * int(rect.Width) * int(rect.Height) lengthCurrentbpp := int(bytesPixel) * int(rect.Width) * int(rect.Height)
switch filterid { switch filterid {
case TightFilterPalette: //PALETTE_FILTER case TightFilterPalette: //PALETTE_FILTER
colorCount, err := conn.ReadUint8() colorCount, err := r.ReadUint8()
paletteSize := colorCount + 1 // add one more paletteSize := colorCount + 1 // add one more
fmt.Printf("----PALETTE_FILTER: paletteSize=%d bytesPixel=%d\n", paletteSize, bytesPixel) fmt.Printf("----PALETTE_FILTER: paletteSize=%d bytesPixel=%d\n", paletteSize, bytesPixel)
//complete palette //complete palette
conn.ReadBytes(int(paletteSize) * bytesPixel) r.ReadBytes(int(paletteSize) * bytesPixel)
var dataLength int var dataLength int
if paletteSize == 2 { if paletteSize == 2 {
dataLength = int(rect.Height) * ((int(rect.Width) + 7) / 8) dataLength = int(rect.Height) * ((int(rect.Width) + 7) / 8)
} else { } else {
dataLength = int(rect.Width * rect.Height) dataLength = int(rect.Width * rect.Height)
} }
_, err = conn.ReadTightData(dataLength) _, err = r.ReadTightData(dataLength)
if err != nil { if err != nil {
fmt.Printf("error in handling tight encoding, Reading Palette: %v\n", err) fmt.Printf("error in handling tight encoding, Reading Palette: %v\n", err)
return return
} }
case TightFilterGradient: //GRADIENT_FILTER case TightFilterGradient: //GRADIENT_FILTER
fmt.Printf("----GRADIENT_FILTER: bytesPixel=%d\n", bytesPixel) fmt.Printf("----GRADIENT_FILTER: bytesPixel=%d\n", bytesPixel)
//useGradient = true //useGradient = true
fmt.Printf("usegrad: %d\n", filterid) fmt.Printf("usegrad: %d\n", filterid)
conn.ReadTightData(lengthCurrentbpp) r.ReadTightData(lengthCurrentbpp)
case TightFilterCopy: //BASIC_FILTER case TightFilterCopy: //BASIC_FILTER
fmt.Printf("----BASIC_FILTER: bytesPixel=%d\n", bytesPixel) fmt.Printf("----BASIC_FILTER: bytesPixel=%d\n", bytesPixel)
conn.ReadTightData(lengthCurrentbpp) r.ReadTightData(lengthCurrentbpp)
default: default:
fmt.Printf("Bad tight filter id: %d\n", filterid) fmt.Printf("Bad tight filter id: %d\n", filterid)
return return
} }
//////////// ////////////
// if numColors == 0 && bytesPixel == 4 { // if numColors == 0 && bytesPixel == 4 {
// rowSize1 *= 3 // rowSize1 *= 3
// } // }
// rowSize := (int(rect.Width)*bitsPixel + 7) / 8 // rowSize := (int(rect.Width)*bitsPixel + 7) / 8
// dataSize := int(rect.Height) * rowSize // dataSize := int(rect.Height) * rowSize
// dataSize1 := rect.Height * rowSize1 // dataSize1 := rect.Height * rowSize1
// fmt.Printf("datasize: %d, origDatasize: %d", dataSize, dataSize1) // fmt.Printf("datasize: %d, origDatasize: %d", dataSize, dataSize1)
// // Read, optionally uncompress and decode data. // // Read, optionally uncompress and decode data.
// if int(dataSize1) < TightMinToCompress { // if int(dataSize1) < TightMinToCompress {
// // Data size is small - not compressed with zlib. // // Data size is small - not compressed with zlib.
// if numColors != 0 { // if numColors != 0 {
// // Indexed colors. // // Indexed colors.
// //indexedData := make([]byte, dataSize) // //indexedData := make([]byte, dataSize)
// readBytes(conn.c, int(dataSize1)) // readBytes(conn.c, int(dataSize1))
// //readFully(indexedData); // //readFully(indexedData);
// // if (rfb.rec != null) { // // if (rfb.rec != null) {
// // rfb.rec.write(indexedData); // // rfb.rec.write(indexedData);
// // } // // }
// // if (numColors == 2) { // // if (numColors == 2) {
// // // Two colors. // // // Two colors.
// // if (bytesPixel == 1) { // // if (bytesPixel == 1) {
// // decodeMonoData(x, y, w, h, indexedData, palette8); // // decodeMonoData(x, y, w, h, indexedData, palette8);
// // } else { // // } else {
// // decodeMonoData(x, y, w, h, indexedData, palette24); // // decodeMonoData(x, y, w, h, indexedData, palette24);
// // } // // }
// // } else { // // } else {
// // // 3..255 colors (assuming bytesPixel == 4). // // // 3..255 colors (assuming bytesPixel == 4).
// // int i = 0; // // int i = 0;
// // for (int dy = y; dy < y + h; dy++) { // // for (int dy = y; dy < y + h; dy++) {
// // for (int dx = x; dx < x + w; dx++) { // // for (int dx = x; dx < x + w; dx++) {
// // pixels24[dy * rfb.framebufferWidth + dx] = palette24[indexedData[i++] & 0xFF]; // // pixels24[dy * rfb.framebufferWidth + dx] = palette24[indexedData[i++] & 0xFF];
// // } // // }
// // } // // }
// // } // // }
// } else if useGradient { // } else if useGradient {
// // "Gradient"-processed data // // "Gradient"-processed data
// //buf := make ( []byte,w * h * 3); // //buf := make ( []byte,w * h * 3);
// dataByteCount := int(3) * int(rect.Width) * int(rect.Height) // dataByteCount := int(3) * int(rect.Width) * int(rect.Height)
// readBytes(conn.c, dataByteCount) // readBytes(conn.c, dataByteCount)
// // rfb.readFully(buf); // // rfb.readFully(buf);
// // if (rfb.rec != null) { // // if (rfb.rec != null) {
// // rfb.rec.write(buf); // // rfb.rec.write(buf);
// // } // // }
// // decodeGradientData(x, y, w, h, buf); // // decodeGradientData(x, y, w, h, buf);
// } else { // } else {
// // Raw truecolor data. // // Raw truecolor data.
// dataByteCount := int(bytesPixel) * int(rect.Width) * int(rect.Height) // dataByteCount := int(bytesPixel) * int(rect.Width) * int(rect.Height)
// readBytes(conn.c, dataByteCount) // readBytes(conn.c, dataByteCount)
// // if (bytesPixel == 1) { // // if (bytesPixel == 1) {
// // for (int dy = y; dy < y + h; dy++) { // // for (int dy = y; dy < y + h; dy++) {
// // rfb.readFully(pixels8, dy * rfb.framebufferWidth + x, w); // // rfb.readFully(pixels8, dy * rfb.framebufferWidth + x, w);
// // if (rfb.rec != null) { // // if (rfb.rec != null) {
// // rfb.rec.write(pixels8, dy * rfb.framebufferWidth + x, w); // // rfb.rec.write(pixels8, dy * rfb.framebufferWidth + x, w);
// // } // // }
// // } // // }
// // } else { // // } else {
// // byte[] buf = new byte[w * 3]; // // byte[] buf = new byte[w * 3];
// // int i, offset; // // int i, offset;
// // for (int dy = y; dy < y + h; dy++) { // // for (int dy = y; dy < y + h; dy++) {
// // rfb.readFully(buf); // // rfb.readFully(buf);
// // if (rfb.rec != null) { // // if (rfb.rec != null) {
// // rfb.rec.write(buf); // // rfb.rec.write(buf);
// // } // // }
// // offset = dy * rfb.framebufferWidth + x; // // offset = dy * rfb.framebufferWidth + x;
// // for (i = 0; i < w; i++) { // // for (i = 0; i < w; i++) {
// // pixels24[offset + i] = (buf[i * 3] & 0xFF) << 16 | (buf[i * 3 + 1] & 0xFF) << 8 | (buf[i * 3 + 2] & 0xFF); // // pixels24[offset + i] = (buf[i * 3] & 0xFF) << 16 | (buf[i * 3 + 1] & 0xFF) << 8 | (buf[i * 3 + 2] & 0xFF);
// // } // // }
// // } // // }
// // } // // }
// } // }
// } else { // } else {
// // Data was compressed with zlib. // // Data was compressed with zlib.
// zlibDataLen, err := readCompactLen(conn.c) // zlibDataLen, err := readCompactLen(conn.c)
// fmt.Printf("compactlen=%d\n", zlibDataLen) // fmt.Printf("compactlen=%d\n", zlibDataLen)
// if err != nil { // if err != nil {
// return nil, err // return nil, err
// } // }
// //byte[] zlibData = new byte[zlibDataLen]; // //byte[] zlibData = new byte[zlibDataLen];
// //rfb.readFully(zlibData); // //rfb.readFully(zlibData);
// readBytes(conn.c, zlibDataLen) // readBytes(conn.c, zlibDataLen)
// // if (rfb.rec != null) { // // if (rfb.rec != null) {
// // rfb.rec.write(zlibData); // // rfb.rec.write(zlibData);
// // } // // }
// // int stream_id = comp_ctl & 0x03; // // int stream_id = comp_ctl & 0x03;
// // if (tightInflaters[stream_id] == null) { // // if (tightInflaters[stream_id] == null) {
// // tightInflaters[stream_id] = new Inflater(); // // tightInflaters[stream_id] = new Inflater();
// // } // // }
// // Inflater myInflater = tightInflaters[stream_id]; // // Inflater myInflater = tightInflaters[stream_id];
// // myInflater.setInput(zlibData); // // myInflater.setInput(zlibData);
// // byte[] buf = new byte[dataSize]; // // byte[] buf = new byte[dataSize];
// // myInflater.inflate(buf); // // myInflater.inflate(buf);
// // if (rfb.rec != null && !rfb.recordFromBeginning) { // // if (rfb.rec != null && !rfb.recordFromBeginning) {
// // rfb.recordCompressedData(buf); // // rfb.recordCompressedData(buf);
// // } // // }
// // if (numColors != 0) { // // if (numColors != 0) {
// // // Indexed colors. // // // Indexed colors.
// // if (numColors == 2) { // // if (numColors == 2) {
// // // Two colors. // // // Two colors.
// // if (bytesPixel == 1) { // // if (bytesPixel == 1) {
// // decodeMonoData(x, y, w, h, buf, palette8); // // decodeMonoData(x, y, w, h, buf, palette8);
// // } else { // // } else {
// // decodeMonoData(x, y, w, h, buf, palette24); // // decodeMonoData(x, y, w, h, buf, palette24);
// // } // // }
// // } else { // // } else {
// // // More than two colors (assuming bytesPixel == 4). // // // More than two colors (assuming bytesPixel == 4).
// // int i = 0; // // int i = 0;
// // for (int dy = y; dy < y + h; dy++) { // // for (int dy = y; dy < y + h; dy++) {
// // for (int dx = x; dx < x + w; dx++) { // // for (int dx = x; dx < x + w; dx++) {
// // pixels24[dy * rfb.framebufferWidth + dx] = palette24[buf[i++] & 0xFF]; // // pixels24[dy * rfb.framebufferWidth + dx] = palette24[buf[i++] & 0xFF];
// // } // // }
// // } // // }
// // } // // }
// // } else if (useGradient) { // // } else if (useGradient) {
// // // Compressed "Gradient"-filtered data (assuming bytesPixel == 4). // // // Compressed "Gradient"-filtered data (assuming bytesPixel == 4).
// // decodeGradientData(x, y, w, h, buf); // // decodeGradientData(x, y, w, h, buf);
// // } else { // // } else {
// // // Compressed truecolor data. // // // Compressed truecolor data.
// // if (bytesPixel == 1) { // // if (bytesPixel == 1) {
// // int destOffset = y * rfb.framebufferWidth + x; // // int destOffset = y * rfb.framebufferWidth + x;
// // for (int dy = 0; dy < h; dy++) { // // for (int dy = 0; dy < h; dy++) {
// // System.arraycopy(buf, dy * w, pixels8, destOffset, w); // // System.arraycopy(buf, dy * w, pixels8, destOffset, w);
// // destOffset += rfb.framebufferWidth; // // destOffset += rfb.framebufferWidth;
// // } // // }
// // } else { // // } else {
// // int srcOffset = 0; // // int srcOffset = 0;
// // int destOffset, i; // // int destOffset, i;
// // for (int dy = 0; dy < h; dy++) { // // for (int dy = 0; dy < h; dy++) {
// // myInflater.inflate(buf); // // myInflater.inflate(buf);
// // destOffset = (y + dy) * rfb.framebufferWidth + x; // // destOffset = (y + dy) * rfb.framebufferWidth + x;
// // for (i = 0; i < w; i++) { // // for (i = 0; i < w; i++) {
// // pixels24[destOffset + i] = (buf[srcOffset] & 0xFF) << 16 | (buf[srcOffset + 1] & 0xFF) << 8 // // pixels24[destOffset + i] = (buf[srcOffset] & 0xFF) << 16 | (buf[srcOffset + 1] & 0xFF) << 8
// // | (buf[srcOffset + 2] & 0xFF); // // | (buf[srcOffset + 2] & 0xFF);
// // srcOffset += 3; // // srcOffset += 3;
// // } // // }
// // } // // }
// // } // // }
// // } // // }
// } // }
return return
} }

View File

@ -1,24 +1,23 @@
package encodings package encodings
import "io" import "vncproxy/common"
import "vncproxy/common"
type ZLibEncoding struct {
type ZLibEncoding struct { //Colors []Color
//Colors []Color }
}
func (z *ZLibEncoding) Type() int32 {
func (z *ZLibEncoding) Type() int32 { return 6
return 6 }
} func (z *ZLibEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) {
func (z *ZLibEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r io.Reader) (common.Encoding, error) { //conn := common.RfbReadHelper{Reader:r}
conn := common.RfbReadHelper{r} //conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat}
//conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat} //bytesPerPixel := c.PixelFormat.BPP / 8
//bytesPerPixel := c.PixelFormat.BPP / 8 len, _ := r.ReadUint32()
len, _ := conn.ReadUint32() _, err := r.ReadBytes(int(len))
_, err := conn.ReadBytes(int(len))
if err != nil {
if err != nil { return nil, err
return nil, err }
} return z, nil
return z, nil }
}

View File

@ -1,24 +1,23 @@
package encodings package encodings
import "io" import "vncproxy/common"
import "vncproxy/common"
type ZRLEEncoding struct {
type ZRLEEncoding struct { //Colors []Color
//Colors []Color }
}
func (z *ZRLEEncoding) Type() int32 {
func (z *ZRLEEncoding) Type() int32 { return 16
return 16 }
} func (z *ZRLEEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) {
func (z *ZRLEEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r io.Reader) (common.Encoding, error) { //conn := common.RfbReadHelper{Reader: r}
conn := common.RfbReadHelper{r} //conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat}
//conn := &DataSource{conn: conn.c, PixelFormat: conn.PixelFormat} //bytesPerPixel := c.PixelFormat.BPP / 8
//bytesPerPixel := c.PixelFormat.BPP / 8 len, _ := r.ReadUint32()
len, _ := conn.ReadUint32() _, err := r.ReadBytes(int(len))
_, err := conn.ReadBytes(int(len))
if err != nil {
if err != nil { return nil, err
return nil, err }
} return z, nil
return z, nil }
}

View File

@ -0,0 +1,22 @@
package listeners
import "vncproxy/common"
type MultiListener struct {
listeners []common.SegmentConsumer
}
func (m *MultiListener) AddListener(listener common.SegmentConsumer) {
m.listeners = append(m.listeners, listener)
}
func (m *MultiListener) Consume(seg *common.RfbSegment) error {
for _, li := range m.listeners {
//fmt.Println(li)
err := li.Consume(seg)
if err != nil {
return err
}
}
return nil
}

12
listeners/pass-to.go Normal file
View File

@ -0,0 +1,12 @@
package listeners
import "vncproxy/common"
import "io"
type PassListener struct {
io.Writer
}
func (*PassListener) Consume(seg *common.RfbSegment) error {
return nil
}

155
listeners/recorder.go Normal file
View File

@ -0,0 +1,155 @@
package listeners
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"os"
"time"
"vncproxy/common"
)
type Recorder struct {
//common.BytesListener
RBSFileName string
writer *os.File
logger common.Logger
startTime int
buffer bytes.Buffer
}
func getNowMillisec() int {
return int(time.Now().UnixNano() / int64(time.Millisecond))
}
func NewRecorder(saveFilePath string, desktopName string, fbWidth uint16, fbHeight uint16) *Recorder {
//delete file if it exists
if _, err := os.Stat(saveFilePath); err == nil {
os.Remove(saveFilePath)
}
rec := Recorder{RBSFileName: saveFilePath, startTime: getNowMillisec()}
var err error
rec.writer, err = os.OpenFile(saveFilePath, os.O_RDWR|os.O_CREATE, 0755)
rec.writeStartSession(desktopName, fbWidth, fbHeight)
if err != nil {
fmt.Printf("unable to open file: %s, error: %v", saveFilePath, err)
return nil
}
return &rec
}
const (
FramebufferUpdate = 0
SetColourMapEntries = 1
Bell = 2
ServerCutText = 3
)
const versionMsg_3_3 = "RFB 003.003\n"
const versionMsg_3_7 = "RFB 003.007\n"
const versionMsg_3_8 = "RFB 003.008\n"
// Security types
const (
SecTypeInvalid = 0
SecTypeNone = 1
SecTypeVncAuth = 2
SecTypeTight = 16
)
// func (r *Recorder) writeHeader() error {
// _, err := r.writer.WriteString("FBS 001.000\n")
// return err
// // df.write("FBS 001.000\n".getBytes());
// }
func (r *Recorder) writeStartSession(desktopName string, framebufferWidth uint16, framebufferHeight uint16) error {
//write rfb header information (the only part done without the [size|data|timestamp] block wrapper)
r.buffer.WriteString("FBS 001.000\n")
r.buffer.WriteTo(r.writer)
r.buffer.Reset()
//push the version message into the buffer so it will be written in the first rbs block
r.buffer.WriteString(versionMsg_3_3)
//push sec type and fb dimensions
binary.Write(&r.buffer, binary.BigEndian, int32(SecTypeNone))
binary.Write(&r.buffer, binary.BigEndian, int16(framebufferWidth))
binary.Write(&r.buffer, binary.BigEndian, int16(framebufferHeight))
var fbsServerInitMsg = []byte{32, 24, 0, 1, 0, byte(0xFF), 0, byte(0xFF), 0, byte(0xFF), 16, 8, 0, 0, 0, 0}
r.buffer.Write(fbsServerInitMsg)
binary.Write(&r.buffer, binary.BigEndian, uint32(len(desktopName)+1))
r.buffer.WriteString(desktopName)
binary.Write(&r.buffer, binary.BigEndian, byte(0)) // add null termination for desktop string
return nil
}
func (r *Recorder) Consume(data *common.RfbSegment) error {
switch data.SegmentType {
case common.SegmentMessageSeparator:
switch data.UpcomingObjectType {
case FramebufferUpdate:
r.writeToDisk()
case SetColourMapEntries:
case Bell:
case ServerCutText:
default:
return errors.New("unknown message type:" + string(data.UpcomingObjectType))
}
case common.SegmentRectSeparator:
r.writeToDisk()
case common.SegmentBytes:
_, err := r.buffer.Write(data.Bytes)
return err
default:
return errors.New("undefined RfbSegment type")
}
return nil
}
func (r *Recorder) writeToDisk() error {
timeSinceStart := getNowMillisec() - r.startTime
if r.buffer.Len() == 0 {
return nil
}
//write buff length
bytesLen := r.buffer.Len()
binary.Write(r.writer, binary.BigEndian, uint32(bytesLen))
paddedSize := (bytesLen + 3) & 0x7FFFFFFC
paddingSize := paddedSize - bytesLen
fmt.Printf("paddedSize=%d paddingSize=%d bytesLen=%d", paddedSize, paddingSize, bytesLen)
//write buffer padded to 32bit
_, err := r.buffer.WriteTo(r.writer)
padding := make([]byte, paddingSize)
fmt.Printf("padding=%v ", padding)
binary.Write(r.writer, binary.BigEndian, padding)
//write timestamp
binary.Write(r.writer, binary.BigEndian, uint32(timeSinceStart))
r.buffer.Reset()
return err
}
// func (r *Recorder) WriteUInt8(data uint8) error {
// buf := make([]byte, 1)
// buf[0] = byte(data) // cast int8 to byte
// return r.Write(buf)
// }
func (r *Recorder) Close() {
r.writer.Close()
}

View File

@ -16,7 +16,7 @@ func main() {
nc, err := net.Dial("tcp", "localhost:5903") nc, err := net.Dial("tcp", "localhost:5903")
if err != nil { if err != nil {
fmt.Printf(";error connecting to vnc server: %s", err) fmt.Printf("error connecting to vnc server: %s", err)
} }
var noauth vnc.ClientAuthNone var noauth vnc.ClientAuthNone
authArr := []vnc.ClientAuth{&vnc.PasswordAuth{Password: "Ch_#!T@8"}, &noauth} authArr := []vnc.ClientAuth{&vnc.PasswordAuth{Password: "Ch_#!T@8"}, &noauth}

View File

@ -1,16 +1,16 @@
# VNC Library for Go # VNC Library for Go
go-vnc is a VNC library for Go, initially supporting VNC clients but go-vnc is a VNC library for Go, initially supporting VNC clients but
with the goal of eventually implementing a VNC server. with the goal of eventually implementing a VNC server.
This library implements [RFC 6143](http://tools.ietf.org/html/rfc6143). This library implements [RFC 6143](http://tools.ietf.org/html/rfc6143).
## Usage & Installation ## Usage & Installation
The library is installable via standard `go get`. The package name is `vnc`. The library is installable via standard `go get`. The package name is `vnc`.
``` ```
$ go get github.com/mitchellh/go-vnc $ go get github.com/mitchellh/go-vnc
``` ```
Documentation is available on GoDoc: http://godoc.org/github.com/mitchellh/go-vnc Documentation is available on GoDoc: http://godoc.org/github.com/mitchellh/go-vnc

File diff suppressed because it is too large Load Diff

View File

@ -1,114 +1,114 @@
package vnc package vnc
import ( import (
"net" "net"
"crypto/des" "crypto/des"
"encoding/binary" "encoding/binary"
) )
// ClientAuthNone is the "none" authentication. See 7.2.1 // ClientAuthNone is the "none" authentication. See 7.2.1
type ClientAuthNone byte type ClientAuthNone byte
func (*ClientAuthNone) SecurityType() uint8 { func (*ClientAuthNone) SecurityType() uint8 {
return 1 return 1
} }
func (*ClientAuthNone) Handshake(net.Conn) error { func (*ClientAuthNone) Handshake(net.Conn) error {
return nil return nil
} }
// PasswordAuth is VNC authentication, 7.2.2 // PasswordAuth is VNC authentication, 7.2.2
type PasswordAuth struct { type PasswordAuth struct {
Password string Password string
} }
func (p *PasswordAuth) SecurityType() uint8 { func (p *PasswordAuth) SecurityType() uint8 {
return 2 return 2
} }
func (p *PasswordAuth) Handshake(c net.Conn) error { func (p *PasswordAuth) Handshake(c net.Conn) error {
randomValue := make([]uint8, 16) randomValue := make([]uint8, 16)
if err := binary.Read(c, binary.BigEndian, &randomValue); err != nil { if err := binary.Read(c, binary.BigEndian, &randomValue); err != nil {
return err return err
} }
crypted, err := p.encrypt(p.Password, randomValue) crypted, err := p.encrypt(p.Password, randomValue)
if (err != nil) { if (err != nil) {
return err return err
} }
if err := binary.Write(c, binary.BigEndian, &crypted); err != nil { if err := binary.Write(c, binary.BigEndian, &crypted); err != nil {
return err return err
} }
return nil return nil
} }
func (p *PasswordAuth) reverseBits(b byte) byte { func (p *PasswordAuth) reverseBits(b byte) byte {
var reverse = [256]int{ var reverse = [256]int{
0, 128, 64, 192, 32, 160, 96, 224, 0, 128, 64, 192, 32, 160, 96, 224,
16, 144, 80, 208, 48, 176, 112, 240, 16, 144, 80, 208, 48, 176, 112, 240,
8, 136, 72, 200, 40, 168, 104, 232, 8, 136, 72, 200, 40, 168, 104, 232,
24, 152, 88, 216, 56, 184, 120, 248, 24, 152, 88, 216, 56, 184, 120, 248,
4, 132, 68, 196, 36, 164, 100, 228, 4, 132, 68, 196, 36, 164, 100, 228,
20, 148, 84, 212, 52, 180, 116, 244, 20, 148, 84, 212, 52, 180, 116, 244,
12, 140, 76, 204, 44, 172, 108, 236, 12, 140, 76, 204, 44, 172, 108, 236,
28, 156, 92, 220, 60, 188, 124, 252, 28, 156, 92, 220, 60, 188, 124, 252,
2, 130, 66, 194, 34, 162, 98, 226, 2, 130, 66, 194, 34, 162, 98, 226,
18, 146, 82, 210, 50, 178, 114, 242, 18, 146, 82, 210, 50, 178, 114, 242,
10, 138, 74, 202, 42, 170, 106, 234, 10, 138, 74, 202, 42, 170, 106, 234,
26, 154, 90, 218, 58, 186, 122, 250, 26, 154, 90, 218, 58, 186, 122, 250,
6, 134, 70, 198, 38, 166, 102, 230, 6, 134, 70, 198, 38, 166, 102, 230,
22, 150, 86, 214, 54, 182, 118, 246, 22, 150, 86, 214, 54, 182, 118, 246,
14, 142, 78, 206, 46, 174, 110, 238, 14, 142, 78, 206, 46, 174, 110, 238,
30, 158, 94, 222, 62, 190, 126, 254, 30, 158, 94, 222, 62, 190, 126, 254,
1, 129, 65, 193, 33, 161, 97, 225, 1, 129, 65, 193, 33, 161, 97, 225,
17, 145, 81, 209, 49, 177, 113, 241, 17, 145, 81, 209, 49, 177, 113, 241,
9, 137, 73, 201, 41, 169, 105, 233, 9, 137, 73, 201, 41, 169, 105, 233,
25, 153, 89, 217, 57, 185, 121, 249, 25, 153, 89, 217, 57, 185, 121, 249,
5, 133, 69, 197, 37, 165, 101, 229, 5, 133, 69, 197, 37, 165, 101, 229,
21, 149, 85, 213, 53, 181, 117, 245, 21, 149, 85, 213, 53, 181, 117, 245,
13, 141, 77, 205, 45, 173, 109, 237, 13, 141, 77, 205, 45, 173, 109, 237,
29, 157, 93, 221, 61, 189, 125, 253, 29, 157, 93, 221, 61, 189, 125, 253,
3, 131, 67, 195, 35, 163, 99, 227, 3, 131, 67, 195, 35, 163, 99, 227,
19, 147, 83, 211, 51, 179, 115, 243, 19, 147, 83, 211, 51, 179, 115, 243,
11, 139, 75, 203, 43, 171, 107, 235, 11, 139, 75, 203, 43, 171, 107, 235,
27, 155, 91, 219, 59, 187, 123, 251, 27, 155, 91, 219, 59, 187, 123, 251,
7, 135, 71, 199, 39, 167, 103, 231, 7, 135, 71, 199, 39, 167, 103, 231,
23, 151, 87, 215, 55, 183, 119, 247, 23, 151, 87, 215, 55, 183, 119, 247,
15, 143, 79, 207, 47, 175, 111, 239, 15, 143, 79, 207, 47, 175, 111, 239,
31, 159, 95, 223, 63, 191, 127, 255, 31, 159, 95, 223, 63, 191, 127, 255,
} }
return byte(reverse[int(b)]) return byte(reverse[int(b)])
} }
func (p *PasswordAuth) encrypt(key string, bytes []byte) ([]byte, error) { func (p *PasswordAuth) encrypt(key string, bytes []byte) ([]byte, error) {
keyBytes := []byte{0,0,0,0,0,0,0,0} keyBytes := []byte{0,0,0,0,0,0,0,0}
if len(key) > 8 { if len(key) > 8 {
key = key[:8] key = key[:8]
} }
for i := 0; i < len(key); i++ { for i := 0; i < len(key); i++ {
keyBytes[i] = p.reverseBits(key[i]) keyBytes[i] = p.reverseBits(key[i])
} }
block, err := des.NewCipher(keyBytes) block, err := des.NewCipher(keyBytes)
if err != nil { if err != nil {
return nil, err return nil, err
} }
result1 := make([]byte, 8) result1 := make([]byte, 8)
block.Encrypt(result1, bytes) block.Encrypt(result1, bytes)
result2 := make([]byte, 8) result2 := make([]byte, 8)
block.Encrypt(result2, bytes[8:]) block.Encrypt(result2, bytes[8:])
crypted := append(result1, result2...) crypted := append(result1, result2...)
return crypted, nil return crypted, nil
} }

View File

@ -1,169 +1,169 @@
package vnc package vnc
import ( import (
"testing" "testing"
"net" "net"
"time" "time"
"bytes" "bytes"
) )
type fakeNetConnection struct { type fakeNetConnection struct {
DataToSend []byte DataToSend []byte
Test *testing.T Test *testing.T
ExpectData []byte ExpectData []byte
Finished bool Finished bool
Matched bool Matched bool
} }
func (fc fakeNetConnection) Read(b []byte) (n int, err error) { func (fc fakeNetConnection) Read(b []byte) (n int, err error) {
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
b[i] = fc.DataToSend[i] b[i] = fc.DataToSend[i]
} }
fc.Finished = false fc.Finished = false
return len(b), nil return len(b), nil
} }
func (fc *fakeNetConnection) Write(b []byte) (n int, err error) { func (fc *fakeNetConnection) Write(b []byte) (n int, err error) {
fc.Matched = bytes.Equal(b, fc.ExpectData) fc.Matched = bytes.Equal(b, fc.ExpectData)
fc.Finished = true fc.Finished = true
return len(b), nil return len(b), nil
} }
func (fc *fakeNetConnection) Close() error { return nil; } func (fc *fakeNetConnection) Close() error { return nil; }
func (fc *fakeNetConnection) LocalAddr() net.Addr { return nil; } func (fc *fakeNetConnection) LocalAddr() net.Addr { return nil; }
func (fc *fakeNetConnection) RemoteAddr() net.Addr { return nil; } func (fc *fakeNetConnection) RemoteAddr() net.Addr { return nil; }
func (fc *fakeNetConnection) SetDeadline(t time.Time) error { return nil; } func (fc *fakeNetConnection) SetDeadline(t time.Time) error { return nil; }
func (fc *fakeNetConnection) SetReadDeadline(t time.Time) error { return nil; } func (fc *fakeNetConnection) SetReadDeadline(t time.Time) error { return nil; }
func (fc *fakeNetConnection) SetWriteDeadline(t time.Time) error { return nil; } func (fc *fakeNetConnection) SetWriteDeadline(t time.Time) error { return nil; }
func TestClientAuthNone_Impl(t *testing.T) { func TestClientAuthNone_Impl(t *testing.T) {
var raw interface{} var raw interface{}
raw = new(ClientAuthNone) raw = new(ClientAuthNone)
if _, ok := raw.(ClientAuth); !ok { if _, ok := raw.(ClientAuth); !ok {
t.Fatal("ClientAuthNone doesn't implement ClientAuth") t.Fatal("ClientAuthNone doesn't implement ClientAuth")
} }
} }
func TestClientAuthPasswordSuccess_Impl(t *testing.T) { func TestClientAuthPasswordSuccess_Impl(t *testing.T) {
// Values ripped using WireShark // Values ripped using WireShark
randomValue := []byte{ randomValue := []byte{
0xa4, 0xa4,
0x51, 0x51,
0x3f, 0x3f,
0xa5, 0xa5,
0x1f, 0x1f,
0x87, 0x87,
0x06, 0x06,
0x10, 0x10,
0xa4, 0xa4,
0x5f, 0x5f,
0xae, 0xae,
0xbf, 0xbf,
0x4d, 0x4d,
0xac, 0xac,
0x12, 0x12,
0x22, 0x22,
} }
expectedResponse := []byte{ expectedResponse := []byte{
0x71, 0x71,
0xe4, 0xe4,
0x41, 0x41,
0x30, 0x30,
0x43, 0x43,
0x65, 0x65,
0x4e, 0x4e,
0x39, 0x39,
0xda, 0xda,
0x6d, 0x6d,
0x49, 0x49,
0x93, 0x93,
0x43, 0x43,
0xf6, 0xf6,
0x5e, 0x5e,
0x29, 0x29,
} }
raw := PasswordAuth{Password: "Ch_#!T@8"} raw := PasswordAuth{Password: "Ch_#!T@8"}
// Only about 12 hours into Go at the moment... // Only about 12 hours into Go at the moment...
// if _, ok := raw.(ClientAuth); !ok { // if _, ok := raw.(ClientAuth); !ok {
// t.Fatal("PasswordAuth doesn't implement ClientAuth") // t.Fatal("PasswordAuth doesn't implement ClientAuth")
// } // }
conn := &fakeNetConnection{DataToSend: randomValue, ExpectData: expectedResponse, Test: t} conn := &fakeNetConnection{DataToSend: randomValue, ExpectData: expectedResponse, Test: t}
err := raw.Handshake(conn) err := raw.Handshake(conn)
if (err != nil) { if (err != nil) {
t.Fatal(err) t.Fatal(err)
} }
if !conn.Matched { if !conn.Matched {
t.Fatal("PasswordAuth didn't pass the right response back to the wire") t.Fatal("PasswordAuth didn't pass the right response back to the wire")
} }
if !conn.Finished { if !conn.Finished {
t.Fatal("PasswordAuth didn't complete properly") t.Fatal("PasswordAuth didn't complete properly")
} }
} }
func TestClientAuthPasswordReject_Impl(t *testing.T) { func TestClientAuthPasswordReject_Impl(t *testing.T) {
// Values ripped using WireShark // Values ripped using WireShark
randomValue := []byte{ randomValue := []byte{
0xa4, 0xa4,
0x51, 0x51,
0x3f, 0x3f,
0xa5, 0xa5,
0x1f, 0x1f,
0x87, 0x87,
0x06, 0x06,
0x10, 0x10,
0xa4, 0xa4,
0x5f, 0x5f,
0xae, 0xae,
0xbf, 0xbf,
0x4d, 0x4d,
0xac, 0xac,
0x12, 0x12,
0x22, 0x22,
} }
expectedResponse := []byte{ expectedResponse := []byte{
0x71, 0x71,
0xe4, 0xe4,
0x41, 0x41,
0x30, 0x30,
0x43, 0x43,
0x65, 0x65,
0x4e, 0x4e,
0x39, 0x39,
0xda, 0xda,
0x6d, 0x6d,
0x49, 0x49,
0x93, 0x93,
0x43, 0x43,
0xf6, 0xf6,
0x5e, 0x5e,
0x29, 0x29,
} }
raw := PasswordAuth{Password: "Ch_#!T@"} raw := PasswordAuth{Password: "Ch_#!T@"}
conn := &fakeNetConnection{DataToSend: randomValue, ExpectData: expectedResponse, Test: t} conn := &fakeNetConnection{DataToSend: randomValue, ExpectData: expectedResponse, Test: t}
err := raw.Handshake(conn) err := raw.Handshake(conn)
if (err != nil) { if (err != nil) {
t.Fatal(err) t.Fatal(err)
} }
if conn.Matched { if conn.Matched {
t.Fatal("PasswordAuth didn't pass the right response back to the wire") t.Fatal("PasswordAuth didn't pass the right response back to the wire")
} }
if !conn.Finished { if !conn.Finished {
t.Fatal("PasswordAuth didn't complete properly") t.Fatal("PasswordAuth didn't complete properly")
} }
} }

View File

@ -1,95 +1,95 @@
package vnc package vnc
import ( import (
"fmt" "fmt"
"net" "net"
"testing" "testing"
) )
func newMockServer(t *testing.T, version string) string { func newMockServer(t *testing.T, version string) string {
ln, err := net.Listen("tcp", "127.0.0.1:0") ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil { if err != nil {
t.Fatalf("error listening: %s", err) t.Fatalf("error listening: %s", err)
} }
go func() { go func() {
defer ln.Close() defer ln.Close()
c, err := ln.Accept() c, err := ln.Accept()
if err != nil { if err != nil {
t.Fatalf("error accepting conn: %s", err) t.Fatalf("error accepting conn: %s", err)
} }
defer c.Close() defer c.Close()
_, err = c.Write([]byte(fmt.Sprintf("RFB %s\n", version))) _, err = c.Write([]byte(fmt.Sprintf("RFB %s\n", version)))
if err != nil { if err != nil {
t.Fatal("failed writing version") t.Fatal("failed writing version")
} }
}() }()
return ln.Addr().String() return ln.Addr().String()
} }
func TestClient_LowMajorVersion(t *testing.T) { func TestClient_LowMajorVersion(t *testing.T) {
nc, err := net.Dial("tcp", newMockServer(t, "002.009")) nc, err := net.Dial("tcp", newMockServer(t, "002.009"))
if err != nil { if err != nil {
t.Fatalf("error connecting to mock server: %s", err) t.Fatalf("error connecting to mock server: %s", err)
} }
_, err = Client(nc, &ClientConfig{}) _, err = Client(nc, &ClientConfig{})
if err == nil { if err == nil {
t.Fatal("error expected") t.Fatal("error expected")
} }
if err.Error() != "unsupported major version, less than 3: 2" { if err.Error() != "unsupported major version, less than 3: 2" {
t.Fatalf("unexpected error: %s", err) t.Fatalf("unexpected error: %s", err)
} }
} }
func TestClient_LowMinorVersion(t *testing.T) { func TestClient_LowMinorVersion(t *testing.T) {
nc, err := net.Dial("tcp", newMockServer(t, "003.007")) nc, err := net.Dial("tcp", newMockServer(t, "003.007"))
if err != nil { if err != nil {
t.Fatalf("error connecting to mock server: %s", err) t.Fatalf("error connecting to mock server: %s", err)
} }
_, err = Client(nc, &ClientConfig{}) _, err = Client(nc, &ClientConfig{})
if err == nil { if err == nil {
t.Fatal("error expected") t.Fatal("error expected")
} }
if err.Error() != "unsupported minor version, less than 8: 7" { if err.Error() != "unsupported minor version, less than 8: 7" {
t.Fatalf("unexpected error: %s", err) t.Fatalf("unexpected error: %s", err)
} }
} }
func TestParseProtocolVersion(t *testing.T) { func TestParseProtocolVersion(t *testing.T) {
tests := []struct { tests := []struct {
proto []byte proto []byte
major, minor uint major, minor uint
isErr bool isErr bool
}{ }{
// Valid ProtocolVersion messages. // Valid ProtocolVersion messages.
{[]byte{82, 70, 66, 32, 48, 48, 51, 46, 48, 48, 56, 10}, 3, 8, false}, // RFB 003.008\n {[]byte{82, 70, 66, 32, 48, 48, 51, 46, 48, 48, 56, 10}, 3, 8, false}, // RFB 003.008\n
{[]byte{82, 70, 66, 32, 48, 48, 51, 46, 56, 56, 57, 10}, 3, 889, false}, // RFB 003.889\n -- OS X 10.10.3 {[]byte{82, 70, 66, 32, 48, 48, 51, 46, 56, 56, 57, 10}, 3, 889, false}, // RFB 003.889\n -- OS X 10.10.3
{[]byte{82, 70, 66, 32, 48, 48, 48, 46, 48, 48, 48, 10}, 0, 0, false}, // RFB 000.0000\n {[]byte{82, 70, 66, 32, 48, 48, 48, 46, 48, 48, 48, 10}, 0, 0, false}, // RFB 000.0000\n
// Invalid messages. // Invalid messages.
{[]byte{82, 70, 66, 32, 51, 46, 56, 10}, 0, 0, true}, // RFB 3.8\n -- too short; not zero padded {[]byte{82, 70, 66, 32, 51, 46, 56, 10}, 0, 0, true}, // RFB 3.8\n -- too short; not zero padded
{[]byte{82, 70, 66, 10}, 0, 0, true}, // RFB\n -- too short {[]byte{82, 70, 66, 10}, 0, 0, true}, // RFB\n -- too short
{[]byte{}, 0, 0, true}, // (empty) -- too short {[]byte{}, 0, 0, true}, // (empty) -- too short
} }
for _, tt := range tests { for _, tt := range tests {
major, minor, err := parseProtocolVersion(tt.proto) major, minor, err := parseProtocolVersion(tt.proto)
if err != nil && !tt.isErr { if err != nil && !tt.isErr {
t.Fatalf("parseProtocolVersion(%v) unexpected error %v", tt.proto, err) t.Fatalf("parseProtocolVersion(%v) unexpected error %v", tt.proto, err)
} }
if err == nil && tt.isErr { if err == nil && tt.isErr {
t.Fatalf("parseProtocolVersion(%v) expected error", tt.proto) t.Fatalf("parseProtocolVersion(%v) expected error", tt.proto)
} }
if major != tt.major { if major != tt.major {
t.Errorf("parseProtocolVersion(%v) major = %v, want %v", tt.proto, major, tt.major) t.Errorf("parseProtocolVersion(%v) major = %v, want %v", tt.proto, major, tt.major)
} }
if major != tt.major { if major != tt.major {
t.Errorf("parseProtocolVersion(%v) minor = %v, want %v", tt.proto, minor, tt.minor) t.Errorf("parseProtocolVersion(%v) minor = %v, want %v", tt.proto, minor, tt.minor)
} }
} }
} }

View File

@ -1,6 +1,6 @@
package vnc package vnc
// Color represents a single color in a color map. // Color represents a single color in a color map.
type Color struct { type Color struct {
R, G, B uint16 R, G, B uint16
} }

View File

@ -1,136 +1,136 @@
package vnc package vnc
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"io" "io"
"vncproxy/common" "vncproxy/common"
) )
func readPixelFormat(r io.Reader, result *common.PixelFormat) error { func readPixelFormat(r io.Reader, result *common.PixelFormat) error {
var rawPixelFormat [16]byte var rawPixelFormat [16]byte
if _, err := io.ReadFull(r, rawPixelFormat[:]); err != nil { if _, err := io.ReadFull(r, rawPixelFormat[:]); err != nil {
return err return err
} }
var pfBoolByte uint8 var pfBoolByte uint8
brPF := bytes.NewReader(rawPixelFormat[:]) brPF := bytes.NewReader(rawPixelFormat[:])
if err := binary.Read(brPF, binary.BigEndian, &result.BPP); err != nil { if err := binary.Read(brPF, binary.BigEndian, &result.BPP); err != nil {
return err return err
} }
if err := binary.Read(brPF, binary.BigEndian, &result.Depth); err != nil { if err := binary.Read(brPF, binary.BigEndian, &result.Depth); err != nil {
return err return err
} }
if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil { if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil {
return err return err
} }
if pfBoolByte != 0 { if pfBoolByte != 0 {
// Big endian is true // Big endian is true
result.BigEndian = true result.BigEndian = true
} }
if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil { if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil {
return err return err
} }
if pfBoolByte != 0 { if pfBoolByte != 0 {
// True Color is true. So we also have to read all the color max & shifts. // True Color is true. So we also have to read all the color max & shifts.
result.TrueColor = true result.TrueColor = true
if err := binary.Read(brPF, binary.BigEndian, &result.RedMax); err != nil { if err := binary.Read(brPF, binary.BigEndian, &result.RedMax); err != nil {
return err return err
} }
if err := binary.Read(brPF, binary.BigEndian, &result.GreenMax); err != nil { if err := binary.Read(brPF, binary.BigEndian, &result.GreenMax); err != nil {
return err return err
} }
if err := binary.Read(brPF, binary.BigEndian, &result.BlueMax); err != nil { if err := binary.Read(brPF, binary.BigEndian, &result.BlueMax); err != nil {
return err return err
} }
if err := binary.Read(brPF, binary.BigEndian, &result.RedShift); err != nil { if err := binary.Read(brPF, binary.BigEndian, &result.RedShift); err != nil {
return err return err
} }
if err := binary.Read(brPF, binary.BigEndian, &result.GreenShift); err != nil { if err := binary.Read(brPF, binary.BigEndian, &result.GreenShift); err != nil {
return err return err
} }
if err := binary.Read(brPF, binary.BigEndian, &result.BlueShift); err != nil { if err := binary.Read(brPF, binary.BigEndian, &result.BlueShift); err != nil {
return err return err
} }
} }
return nil return nil
} }
func writePixelFormat(format *common.PixelFormat) ([]byte, error) { func writePixelFormat(format *common.PixelFormat) ([]byte, error) {
var buf bytes.Buffer var buf bytes.Buffer
// Byte 1 // Byte 1
if err := binary.Write(&buf, binary.BigEndian, format.BPP); err != nil { if err := binary.Write(&buf, binary.BigEndian, format.BPP); err != nil {
return nil, err return nil, err
} }
// Byte 2 // Byte 2
if err := binary.Write(&buf, binary.BigEndian, format.Depth); err != nil { if err := binary.Write(&buf, binary.BigEndian, format.Depth); err != nil {
return nil, err return nil, err
} }
var boolByte byte var boolByte byte
if format.BigEndian { if format.BigEndian {
boolByte = 1 boolByte = 1
} else { } else {
boolByte = 0 boolByte = 0
} }
// Byte 3 (BigEndian) // Byte 3 (BigEndian)
if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil { if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil {
return nil, err return nil, err
} }
if format.TrueColor { if format.TrueColor {
boolByte = 1 boolByte = 1
} else { } else {
boolByte = 0 boolByte = 0
} }
// Byte 4 (TrueColor) // Byte 4 (TrueColor)
if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil { if err := binary.Write(&buf, binary.BigEndian, boolByte); err != nil {
return nil, err return nil, err
} }
// If we have true color enabled then we have to fill in the rest of the // If we have true color enabled then we have to fill in the rest of the
// structure with the color values. // structure with the color values.
if format.TrueColor { if format.TrueColor {
if err := binary.Write(&buf, binary.BigEndian, format.RedMax); err != nil { if err := binary.Write(&buf, binary.BigEndian, format.RedMax); err != nil {
return nil, err return nil, err
} }
if err := binary.Write(&buf, binary.BigEndian, format.GreenMax); err != nil { if err := binary.Write(&buf, binary.BigEndian, format.GreenMax); err != nil {
return nil, err return nil, err
} }
if err := binary.Write(&buf, binary.BigEndian, format.BlueMax); err != nil { if err := binary.Write(&buf, binary.BigEndian, format.BlueMax); err != nil {
return nil, err return nil, err
} }
if err := binary.Write(&buf, binary.BigEndian, format.RedShift); err != nil { if err := binary.Write(&buf, binary.BigEndian, format.RedShift); err != nil {
return nil, err return nil, err
} }
if err := binary.Write(&buf, binary.BigEndian, format.GreenShift); err != nil { if err := binary.Write(&buf, binary.BigEndian, format.GreenShift); err != nil {
return nil, err return nil, err
} }
if err := binary.Write(&buf, binary.BigEndian, format.BlueShift); err != nil { if err := binary.Write(&buf, binary.BigEndian, format.BlueShift); err != nil {
return nil, err return nil, err
} }
} }
return buf.Bytes()[0:16], nil return buf.Bytes()[0:16], nil
} }

View File

@ -1,16 +1,16 @@
package vnc package vnc
// ButtonMask represents a mask of pointer presses/releases. // ButtonMask represents a mask of pointer presses/releases.
type ButtonMask uint8 type ButtonMask uint8
// All available button mask components. // All available button mask components.
const ( const (
ButtonLeft ButtonMask = 1 << iota ButtonLeft ButtonMask = 1 << iota
ButtonMiddle ButtonMiddle
ButtonRight ButtonRight
Button4 Button4
Button5 Button5
Button6 Button6
Button7 Button7
Button8 Button8
) )

View File

@ -1,38 +0,0 @@
package vnc
import (
"os"
"vncproxy/common"
)
type Recorder struct {
RBSFileName string
fileHandle *os.File
logger common.Logger
}
func NewRecorder(saveFilePath string, logger common.Logger) *Recorder {
rec := Recorder{RBSFileName: saveFilePath}
var err error
rec.fileHandle, err = os.OpenFile(saveFilePath, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
logger.Errorf("unable to open file: %s, error: %v", saveFilePath, err)
return nil
}
return &rec
}
func (r *Recorder) Write(data []byte) error {
_, err := r.fileHandle.Write(data)
return err
}
// func (r *Recorder) WriteUInt8(data uint8) error {
// buf := make([]byte, 1)
// buf[0] = byte(data) // cast int8 to byte
// return r.Write(buf)
// }
func (r *Recorder) Close() {
r.fileHandle.Close()
}

View File

@ -27,7 +27,8 @@ func (*FramebufferUpdateMessage) Type() uint8 {
return 0 return 0
} }
func (*FramebufferUpdateMessage) Read(c *ClientConn, r io.Reader) (ServerMessage, error) { func (fbm *FramebufferUpdateMessage) Read(c *ClientConn, r *common.RfbReadHelper) (ServerMessage, error) {
// Read off the padding // Read off the padding
var padding [1]byte var padding [1]byte
if _, err := io.ReadFull(r, padding[:]); err != nil { if _, err := io.ReadFull(r, padding[:]); err != nil {
@ -53,8 +54,9 @@ func (*FramebufferUpdateMessage) Read(c *ClientConn, r io.Reader) (ServerMessage
rects := make([]common.Rectangle, numRects) rects := make([]common.Rectangle, numRects)
for i := uint16(0); i < numRects; i++ { for i := uint16(0); i < numRects; i++ {
fmt.Printf("###############rect################: %d\n", i) fmt.Printf("###############rect################: %d\n", i)
var encodingType int32
var encodingType int32
r.SendRectSeparator(-1)
rect := &rects[i] rect := &rects[i]
data := []interface{}{ data := []interface{}{
&rect.X, &rect.X,
@ -108,7 +110,7 @@ func (*SetColorMapEntriesMessage) Type() uint8 {
return 1 return 1
} }
func (*SetColorMapEntriesMessage) Read(c *ClientConn, r io.Reader) (ServerMessage, error) { func (*SetColorMapEntriesMessage) Read(c *ClientConn, r *common.RfbReadHelper) (ServerMessage, error) {
// Read off the padding // Read off the padding
var padding [1]byte var padding [1]byte
if _, err := io.ReadFull(r, padding[:]); err != nil { if _, err := io.ReadFull(r, padding[:]); err != nil {
@ -161,7 +163,7 @@ func (*BellMessage) Type() uint8 {
return 2 return 2
} }
func (*BellMessage) Read(*ClientConn, io.Reader) (ServerMessage, error) { func (*BellMessage) Read(*ClientConn, *common.RfbReadHelper) (ServerMessage, error) {
return new(BellMessage), nil return new(BellMessage), nil
} }
@ -180,22 +182,31 @@ func (*ServerCutTextMessage) Type() uint8 {
return 3 return 3
} }
func (*ServerCutTextMessage) Read(conn *ClientConn, r io.Reader) (ServerMessage, error) { func (*ServerCutTextMessage) Read(conn *ClientConn, r *common.RfbReadHelper) (ServerMessage, error) {
//reader := common.RfbReadHelper{Reader: r}
// Read off the padding // Read off the padding
var padding [1]byte var padding [3]byte
if _, err := io.ReadFull(r, padding[:]); err != nil { if _, err := io.ReadFull(r, padding[:]); err != nil {
return nil, err return nil, err
} }
textLength, err := r.ReadUint32()
var textLength uint32 if err != nil {
if err := binary.Read(r, binary.BigEndian, &textLength); err != nil {
return nil, err return nil, err
} }
textBytes, err := r.ReadBytes(int(textLength))
textBytes := make([]uint8, textLength) if err != nil {
if err := binary.Read(r, binary.BigEndian, &textBytes); err != nil {
return nil, err return nil, err
} }
//var textLength uint32
// if err := binary.Read(r, binary.BigEndian, &textLength); err != nil {
// return nil, err
// }
// textBytes := make([]uint8, textLength)
// if err := binary.Read(r, binary.BigEndian, &textBytes); err != nil {
// return nil, err
// }
return &ServerCutTextMessage{string(textBytes)}, nil return &ServerCutTextMessage{string(textBytes)}, nil
} }