diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 3d1d2a3..52c4091 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,17 +2,29 @@ - + + + + + + + + + + + + + + - - - + - + + @@ -45,11 +57,103 @@ - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -66,37 +170,40 @@ - rfbreadhelper{ - mainLoop - NewServerConn - Serve - uint16 - l - client - tcp - ln - client. - se - secur - securi - auth - c. - upgrade - read - EncodingType - loop - BellMessage - ServerCutTextMessage - SetEncodings - enc - fra - FramebufferUpdate - e - encodin - encoding - tight - conn. + vnc-server + problem writing to port + listener consume + WriteTo.Consume + writeToDisk + Recorder.Consume + rect hdr data + sending segment to server + s + segment + rsegment + rfsegment + rfbsegment + SendMessageSeparator + got ClientMessage + done! + sending segment + servermessage + got ServerMessage + Recorder.HandleRfbSegment + paddedSize + rect hdr + encodingType + read & parsed ServerMessage + pr + prox. + prox + proxy + proxy.go + vncpass + + C:\Users\betzalel\Dropbox\go\src\vncproxy + @@ -140,8 +258,10 @@ - @@ -196,6 +316,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -224,59 +444,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + @@ -739,10 +915,22 @@ - + + + + + + + + + + + + + @@ -772,39 +960,39 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - @@ -816,41 +1004,65 @@ - + - - + + + + + + + + + + + + + - + + + + + + + + + + + + + + - - - + - - - + - - - - - - - + + + + + + + + + + + @@ -889,84 +1101,124 @@ - file://$PROJECT_DIR$/main.go - 13 - - - file://$PROJECT_DIR$/main.go - 16 - - - file://$PROJECT_DIR$/main.go - 20 - - - file://$PROJECT_DIR$/server/server_test.go - 35 - - - file://$PROJECT_DIR$/server/server_test.go - 36 - - - file://$PROJECT_DIR$/common/encoding.go - 162 - - - file://$PROJECT_DIR$/server/ws-server-gorilla.go - 98 - - - file://$PROJECT_DIR$/../github.com/gorilla/websocket/server.go - 219 - - - file://$PROJECT_DIR$/server/ws-server-go.go - 43 - - - file://$PROJECT_DIR$/server/ws-server-go.go - 31 - - - file://$PROJECT_DIR$/server/server.go - 113 - - - file://$PROJECT_DIR$/tee-listeners/recorder.go - 171 - - - file://$PROJECT_DIR$/tee-listeners/recorder.go - 26 - - file://$PROJECT_DIR$/client/client-conn.go - 467 - + + file://$PROJECT_DIR$/client/client-conn.go + 345 + + + + file://$PROJECT_DIR$/tee-listeners/recorder.go + 147 + + + + file://$PROJECT_DIR$/tee-listeners/recorder.go + 153 + + + + file://$PROJECT_DIR$/client/client-conn.go + 508 + + + + file://$PROJECT_DIR$/client/client-conn.go + 516 + + + + file://$PROJECT_DIR$/client/client-conn.go + 521 + + + + file://$PROJECT_DIR$/client/client-conn.go + 502 + + + + file://$PROJECT_DIR$/client/client-conn.go + 501 + + + + file://$PROJECT_DIR$/client/client-conn.go + 503 + + + + file://$PROJECT_DIR$/client/client-conn.go + 511 + + + + file://$PROJECT_DIR$/client/client-conn.go + 500 + + + + file://$PROJECT_DIR$/tee-listeners/write-to.go + 20 + + + + file://$PROJECT_DIR$/tee-listeners/write-to.go + 26 + + + + file://$PROJECT_DIR$/common/multiListener.go + 13 + + + + file://$PROJECT_DIR$/tee-listeners/write-to.go + 16 + + + + file://$PROJECT_DIR$/client/server-messages.go + 34 + + - file://$PROJECT_DIR$/tee-listeners/recorder.go - 31 - + + file://$PROJECT_DIR$/client/server-messages.go + 62 + + - @@ -975,9 +1227,6 @@ - - - @@ -985,67 +1234,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -1053,9 +1246,6 @@ - - - @@ -1072,7 +1262,7 @@ - + @@ -1082,12 +1272,7 @@ - - - - - - + @@ -1105,7 +1290,21 @@ - + + + + + + + + + + + + + + + @@ -1123,12 +1322,7 @@ - - - - - - + @@ -1137,7 +1331,10 @@ - + + + + @@ -1152,7 +1349,9 @@ - + + + @@ -1160,32 +1359,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -1193,87 +1367,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -1286,17 +1384,6 @@ - - - - - - - - - - - @@ -1305,22 +1392,7 @@ - - - - - - - - - - - - - - - - + @@ -1333,24 +1405,6 @@ - - - - - - - - - - - - - - - - - - @@ -1359,10 +1413,285 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.vscode/launch.json b/.vscode/launch.json index c89bbc7..0cb3b68 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,7 +2,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Launch Test", + "name": "Launch Server Test", "type": "go", "request": "launch", "mode": "test", @@ -24,6 +24,29 @@ }, "showLog": true }, + { + "name": "Launch Proxy Test", + "type": "go", + "request": "launch", + "mode": "test", + "remotePath": "", + "port": 2345, + "program": "${workspaceRoot}/proxy", + "args": [ + "-test.v" + ], + "osx": { + "env": { + //"GOPATH": "/Users/amitbet/Dropbox/go" + } + }, + "windows": { + "env": { + //"GOPATH": "${env.USERPROFILE}\\Dropbox\\go" + } + }, + "showLog": true + }, { "name": "Launch", "type": "go", diff --git a/client/client-conn.go b/client/client-conn.go index 2411393..0d0c8d8 100644 --- a/client/client-conn.go +++ b/client/client-conn.go @@ -8,6 +8,7 @@ import ( "net" "unicode" "vncproxy/common" + "vncproxy/logger" ) // A ServerMessage implements a message sent from the server to the client. @@ -52,7 +53,7 @@ type ClientConn struct { // SetPixelFormat method. PixelFormat common.PixelFormat - Listener common.SegmentConsumer + Listeners *common.MultiListener } // A ClientConfig structure is used to configure a ClientConn. After @@ -80,20 +81,26 @@ type ClientConfig struct { ServerMessages []common.ServerMessage } -func Client(c net.Conn, cfg *ClientConfig) (*ClientConn, error) { +func NewClientConn(c net.Conn, cfg *ClientConfig) (*ClientConn, error) { conn := &ClientConn{ - conn: c, - config: cfg, + conn: c, + config: cfg, + Listeners: &common.MultiListener{}, } + return conn, nil +} + +func (conn *ClientConn) Connect() error { if err := conn.handshake(); err != nil { + logger.Errorf("ClientConn.Connect error: %v", err) conn.Close() - return nil, err + return err } go conn.mainLoop() - return conn, nil + return nil } func (c *ClientConn) Close() error { @@ -360,11 +367,12 @@ func (c *ClientConn) handshake() error { // 7.1.2 Security Handshake from server var numSecurityTypes uint8 if err = binary.Read(c.conn, binary.BigEndian, &numSecurityTypes); err != nil { + return fmt.Errorf("Error reading security types: %v", err) return err } if numSecurityTypes == 0 { - return fmt.Errorf("no security types: %s", c.readErrorReason()) + return fmt.Errorf("Error: no security types: %s", c.readErrorReason()) } securityTypes := make([]uint8, numSecurityTypes) @@ -455,9 +463,8 @@ FindAuth: PixelFormat: c.PixelFormat, } rfbSeg := &common.RfbSegment{SegmentType: common.SegmentServerInitMessage, Message: &srvInit} - c.Listener.Consume(rfbSeg) - return nil + return c.Listeners.Consume(rfbSeg) } // mainLoop reads messages sent from the server and routes them to the @@ -465,7 +472,7 @@ FindAuth: func (c *ClientConn) mainLoop() { defer c.Close() - reader := &common.RfbReadHelper{Reader: c.conn, Listener: c.Listener} + reader := &common.RfbReadHelper{Reader: c.conn, Listeners: c.Listeners} // Build the map of available server messages typeMap := make(map[uint8]common.ServerMessage) @@ -486,6 +493,10 @@ func (c *ClientConn) mainLoop() { } } + defer func(){ + logger.Warn("ClientConn.MainLoop: exiting!") + }() + for { var messageType uint8 if err := binary.Read(c.conn, binary.BigEndian, &messageType); err != nil { @@ -497,6 +508,7 @@ func (c *ClientConn) mainLoop() { // Unsupported message type! Bad! break } + logger.Debugf("ClientConn.MainLoop: got ServerMessage:%s", common.ServerMessageType(messageType)) reader.SendMessageSeparator(common.ServerMessageType(messageType)) reader.PublishBytes([]byte{byte(messageType)}) @@ -504,6 +516,7 @@ func (c *ClientConn) mainLoop() { if err != nil { break } + logger.Debugf("ClientConn.MainLoop: read & parsed ServerMessage:%s, %v", parsedMsg.Type(), parsedMsg) if c.config.ServerMessageCh == nil { continue diff --git a/client/pixel-format.go b/client/pixel-format.go index 2e50f89..39fc02b 100644 --- a/client/pixel-format.go +++ b/client/pixel-format.go @@ -29,7 +29,7 @@ func readPixelFormat(r io.Reader, result *common.PixelFormat) error { if pfBoolByte != 0 { // Big endian is true - result.BigEndian = true + result.BigEndian = 1 } if err := binary.Read(brPF, binary.BigEndian, &pfBoolByte); err != nil { @@ -38,7 +38,7 @@ func readPixelFormat(r io.Reader, result *common.PixelFormat) error { if pfBoolByte != 0 { // True Color is true. So we also have to read all the color max & shifts. - result.TrueColor = true + result.TrueColor = 1 if err := binary.Read(brPF, binary.BigEndian, &result.RedMax); err != nil { return err @@ -82,7 +82,7 @@ func writePixelFormat(format *common.PixelFormat) ([]byte, error) { } var boolByte byte - if format.BigEndian { + if format.BigEndian == 1 { boolByte = 1 } else { boolByte = 0 @@ -93,7 +93,7 @@ func writePixelFormat(format *common.PixelFormat) ([]byte, error) { return nil, err } - if format.TrueColor { + if format.TrueColor == 1 { boolByte = 1 } else { boolByte = 0 @@ -106,7 +106,7 @@ func writePixelFormat(format *common.PixelFormat) ([]byte, error) { // If we have true color enabled then we have to fill in the rest of the // structure with the color values. - if format.TrueColor { + if format.TrueColor == 1 { if err := binary.Write(&buf, binary.BigEndian, format.RedMax); err != nil { return nil, err } diff --git a/client/server-messages.go b/client/server-messages.go index a1cd60a..36cc722 100644 --- a/client/server-messages.go +++ b/client/server-messages.go @@ -7,6 +7,8 @@ import ( "io" "vncproxy/common" "vncproxy/encodings" + "vncproxy/logger" + "strings" ) // FramebufferUpdateMessage consists of a sequence of rectangles of @@ -49,13 +51,13 @@ func (fbm *FramebufferUpdateMessage) Read(c common.IClientConn, r *common.RfbRea // We must always support the raw encoding rawEnc := new(encodings.RawEncoding) encMap[rawEnc.Type()] = rawEnc - fmt.Printf("numrects= %d\n", numRects) + logger.Debugf("numrects= %d", numRects) rects := make([]common.Rectangle, numRects) for i := uint16(0); i < numRects; i++ { - fmt.Printf("###############rect################: %d\n", i) + logger.Debugf("###############rect################: %d\n", i) - var encodingType int32 + var encodingTypeInt int32 r.SendRectSeparator(-1) rect := &rects[i] data := []interface{}{ @@ -63,34 +65,45 @@ func (fbm *FramebufferUpdateMessage) Read(c common.IClientConn, r *common.RfbRea &rect.Y, &rect.Width, &rect.Height, - &encodingType, + &encodingTypeInt, } for _, val := range data { if err := binary.Read(r, binary.BigEndian, val); err != nil { - fmt.Printf("err: %v\n", err) + logger.Errorf("err: %v", err) return nil, err } } jBytes, _ := json.Marshal(data) - fmt.Printf("rect hdr data: %s\n", string(jBytes)) - //fmt.Printf(" encoding type: %d", encodingType) - enc, ok := encMap[encodingType] - if !ok { - return nil, fmt.Errorf("unsupported encoding type: %d\n", encodingType) + encType := common.EncodingType(encodingTypeInt) + + logger.Debugf("rect hdr data: enctype=%s, data: %s\n", encType, string(jBytes)) + enc, supported := encMap[encodingTypeInt] + if supported { + var err error + rect.Enc, err = enc.Read(c.CurrentPixelFormat(), rect, r) + if err != nil { + return nil, err + } + } else { + if strings.Contains(encType.String(), "Pseudo") { + rect.Enc = &encodings.PseudoEncoding{encodingTypeInt} + } else { + return nil, fmt.Errorf("unsupported encoding type: %d, %s", encodingTypeInt, encType) + } + } - var err error - rect.Enc, err = enc.Read(c.CurrentPixelFormat(), rect, r) - if err != nil { - return nil, err - } } return &FramebufferUpdateMessage{rects}, nil } + + + + // SetColorMapEntriesMessage is sent by the server to set values into // the color map. This message will automatically update the color map // for the associated connection, but contains the color change data diff --git a/common/Logger.go b/common/Logger.go deleted file mode 100644 index fc70af6..0000000 --- a/common/Logger.go +++ /dev/null @@ -1,14 +0,0 @@ -package common - -type Logger interface { - Debug(v ...interface{}) - Debugf(format string, v ...interface{}) - Info(v ...interface{}) - Infof(format string, v ...interface{}) - Warn(v ...interface{}) - Warnf(format string, v ...interface{}) - Error(v ...interface{}) - Errorf(format string, v ...interface{}) - Fatal(v ...interface{}) - Fatalf(format string, v ...interface{}) -} diff --git a/common/client-message.go b/common/client-message.go index 5918af3..8d643ad 100644 --- a/common/client-message.go +++ b/common/client-message.go @@ -1,6 +1,9 @@ package common -import "io" +import ( + "io" + +) type ClientMessageType uint8 @@ -8,7 +11,7 @@ type ClientMessageType uint8 // Client-to-Server message types. const ( - SetPixelFormatMsgType ClientMessageType = iota + SetPixelFormatMsgType ClientMessageType = iota _ SetEncodingsMsgType FramebufferUpdateRequestMsgType @@ -54,3 +57,21 @@ type ClientMessage interface { Read(io.Reader) (ClientMessage, error) Write(io.Writer) error } + +func (cmt ClientMessageType) String() string { + switch cmt { + case SetPixelFormatMsgType: + return "SetPixelFormatMsgType" + case SetEncodingsMsgType: + return "SetEncodingsMsgType" + case FramebufferUpdateRequestMsgType: + return "FramebufferUpdateRequestMsgType" + case KeyEventMsgType: + return "KeyEventMsgType" + case PointerEventMsgType: + return "PointerEventMsgType" + case ClientCutTextMsgType: + return "ClientCutTextMsgType" + } + return "" +} diff --git a/common/encoding.go b/common/encoding.go index 5bb5e1e..495aff7 100644 --- a/common/encoding.go +++ b/common/encoding.go @@ -21,6 +21,124 @@ type Encoding interface { // EncodingType represents a known VNC encoding type. type EncodingType int32 +func (enct EncodingType) String() string { + switch enct { + case EncRaw: + return "EncRaw" + case EncCopyRect: + return "EncCopyRect" + case EncRRE: + return "EncRRE" + case EncCoRRE: + return "EncCoRRE" + case EncHextile: + return "EncHextile" + case EncZlib: + return "EncZlib" + case EncTight: + return "EncTight" + case EncZlibHex: + return "EncZlibHex" + case EncUltra1: + return "EncUltra1" + case EncUltra2: + return "EncUltra2" + case EncJPEG: + return "EncJPEG" + case EncJRLE: + return "EncJRLE" + case EncTRLE: + return "EncTRLE" + case EncZRLE: + return "EncZRLE" + case EncJPEGQualityLevelPseudo10: + return "EncJPEGQualityLevelPseudo10" + case EncJPEGQualityLevelPseudo9: + return "EncJPEGQualityLevelPseudo9" + case EncJPEGQualityLevelPseudo8: + return "EncJPEGQualityLevelPseudo8" + case EncJPEGQualityLevelPseudo7: + return "EncJPEGQualityLevelPseudo7" + case EncJPEGQualityLevelPseudo6: + return "EncJPEGQualityLevelPseudo6" + case EncJPEGQualityLevelPseudo5: + return "EncJPEGQualityLevelPseudo5" + case EncJPEGQualityLevelPseudo4: + return "EncJPEGQualityLevelPseudo4" + case EncJPEGQualityLevelPseudo3: + return "EncJPEGQualityLevelPseudo3" + case EncJPEGQualityLevelPseudo2: + return "EncJPEGQualityLevelPseudo2" + case EncJPEGQualityLevelPseudo1: + return "EncJPEGQualityLevelPseudo1" + case EncColorPseudo: + return "EncColorPseudo" + case EncDesktopSizePseudo: + return "EncDesktopSizePseudo" + case EncLastRectPseudo: + return "EncLastRectPseudo" + case EncCompressionLevel10: + return "EncCompressionLevel10" + case EncCompressionLevel9: + return "EncCompressionLevel9" + case EncCompressionLevel8: + return "EncCompressionLevel8" + case EncCompressionLevel7: + return "EncCompressionLevel7" + case EncCompressionLevel6: + return "EncCompressionLevel6" + case EncCompressionLevel5: + return "EncCompressionLevel5" + case EncCompressionLevel4: + return "EncCompressionLevel4" + case EncCompressionLevel3: + return "EncCompressionLevel3" + case EncCompressionLevel2: + return "EncCompressionLevel2" + case EncCompressionLevel1: + return "EncCompressionLevel1" + case EncQEMUPointerMotionChangePseudo: + return "EncQEMUPointerMotionChangePseudo" + case EncQEMUExtendedKeyEventPseudo: + return "EncQEMUExtendedKeyEventPseudo" + case EncTightPng: + return "EncTightPng" + case EncExtendedDesktopSizePseudo: + return "EncExtendedDesktopSizePseudo" + case EncXvpPseudo: + return "EncXvpPseudo" + case EncFencePseudo: + return "EncFencePseudo" + case EncContinuousUpdatesPseudo: + return "EncContinuousUpdatesPseudo" + case EncClientRedirect: + return "EncClientRedirect" + case EncTightPNGBase64: + return "EncTightPNGBase64" + case EncTightDiffComp: + return "EncTightDiffComp" + case EncVMWDefineCursor: + return "EncVMWDefineCursor" + case EncVMWCursorState: + return "EncVMWCursorState" + case EncVMWCursorPosition: + return "EncVMWCursorPosition" + case EncVMWTypematicInfo: + return "EncVMWTypematicInfo" + case EncVMWLEDState: + return "EncVMWLEDState" + case EncVMWServerPush2: + return "EncVMWServerPush2" + case EncVMWServerCaps: + return "EncVMWServerCaps" + case EncVMWFrameStamp: + return "EncVMWFrameStamp" + case EncOffscreenCopyRect: + return "EncOffscreenCopyRect" + } + return "" +} + const ( EncRaw EncodingType = 0 EncCopyRect EncodingType = 1 @@ -86,8 +204,8 @@ const ( type PixelFormat struct { BPP uint8 Depth uint8 - BigEndian bool - TrueColor bool + BigEndian uint8 + TrueColor uint8 RedMax uint16 GreenMax uint16 BlueMax uint16 @@ -110,7 +228,7 @@ func (format *PixelFormat) WriteTo(w io.Writer) error { } var boolByte byte - if format.BigEndian { + if format.BigEndian == 1 { boolByte = 1 } else { boolByte = 0 @@ -121,7 +239,7 @@ func (format *PixelFormat) WriteTo(w io.Writer) error { return err } - if format.TrueColor { + if format.TrueColor == 1 { boolByte = 1 } else { boolByte = 0 @@ -134,7 +252,7 @@ func (format *PixelFormat) WriteTo(w io.Writer) error { // If we have true color enabled then we have to fill in the rest of the // structure with the color values. - if format.TrueColor { + if format.TrueColor == 1 { if err := binary.Write(&buf, binary.BigEndian, format.RedMax); err != nil { return err } @@ -165,19 +283,19 @@ func (format *PixelFormat) WriteTo(w io.Writer) error { } func NewPixelFormat(bpp uint8) *PixelFormat { - bigEndian := false + bigEndian := 0 // rgbMax := uint16(math.Exp2(float64(bpp))) - 1 rMax := uint16(255) gMax := uint16(255) bMax := uint16(255) var ( - tc = true + tc = 1 rs, gs, bs uint8 depth uint8 ) switch bpp { case 8: - tc = false + tc = 0 depth = 8 rs, gs, bs = 0, 0, 0 case 16: @@ -189,5 +307,5 @@ func NewPixelFormat(bpp uint8) *PixelFormat { rs, gs, bs = 16, 8, 0 } - return &PixelFormat{bpp, depth, bigEndian, tc, rMax, gMax, bMax, rs, gs, bs} + return &PixelFormat{bpp, depth, uint8(bigEndian), uint8(tc), rMax, gMax, bMax, rs, gs, bs} } diff --git a/common/multiListener.go b/common/multiListener.go new file mode 100644 index 0000000..55f6e98 --- /dev/null +++ b/common/multiListener.go @@ -0,0 +1,20 @@ +package common + +type MultiListener struct { + listeners []SegmentConsumer +} + +func (m *MultiListener) AddListener(listener SegmentConsumer) { + m.listeners = append(m.listeners, listener) +} + +func (m *MultiListener) Consume(seg *RfbSegment) error { + for _, li := range m.listeners { + + err := li.Consume(seg) + if err != nil { + return err + } + } + return nil +} diff --git a/common/readers.go b/common/readers.go index 3126b6c..2eae840 100644 --- a/common/readers.go +++ b/common/readers.go @@ -2,14 +2,14 @@ package common import ( "encoding/binary" - "fmt" "io" + "vncproxy/logger" ) var TightMinToCompress = 12 const ( - SegmentBytes SegmentType = iota + SegmentBytes SegmentType = iota SegmentMessageSeparator SegmentRectSeparator SegmentFullyParsedClientMessage @@ -19,6 +19,24 @@ const ( type SegmentType int +func (seg SegmentType ) String() string { + switch seg { + case SegmentBytes: + return "SegmentBytes" + case SegmentMessageSeparator: + return "SegmentMessageSeparator" + case SegmentRectSeparator: + return "SegmentRectSeparator" + case SegmentFullyParsedClientMessage: + return "SegmentFullyParsedClientMessage" + case SegmentFullyParsedServerMessage: + return "SegmentFullyParsedServerMessage" + case SegmentServerInitMessage: + return "SegmentServerInitMessage" + } + return "" +} + type RfbSegment struct { Bytes []byte SegmentType SegmentType @@ -32,7 +50,7 @@ type SegmentConsumer interface { type RfbReadHelper struct { io.Reader - Listener SegmentConsumer + Listeners *MultiListener } func (r *RfbReadHelper) ReadDiscrete(p []byte) (int, error) { @@ -41,27 +59,17 @@ func (r *RfbReadHelper) ReadDiscrete(p []byte) (int, error) { func (r *RfbReadHelper) SendRectSeparator(upcomingRectType int) error { seg := &RfbSegment{SegmentType: SegmentRectSeparator, UpcomingObjectType: upcomingRectType} - if r.Listener != nil { - return nil - } - return r.Listener.Consume(seg) - + return r.Listeners.Consume(seg) } func (r *RfbReadHelper) SendMessageSeparator(upcomingMessageType ServerMessageType) error { seg := &RfbSegment{SegmentType: SegmentMessageSeparator, UpcomingObjectType: int(upcomingMessageType)} - if r.Listener == nil { - return nil - } - return r.Listener.Consume(seg) + return r.Listeners.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) + return r.Listeners.Consume(seg) } func (r *RfbReadHelper) Read(p []byte) (n int, err error) { @@ -71,13 +79,11 @@ func (r *RfbReadHelper) Read(p []byte) (n int, err error) { } //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) + err = r.Listeners.Consume(seg) if err != nil { return 0, err } + return readLen, err } @@ -97,7 +103,7 @@ func (r *RfbReadHelper) ReadUint8() (uint8, error) { if err := binary.Read(r, binary.BigEndian, &myUint); err != nil { return 0, err } - //fmt.Printf("myUint=%d", myUint) + return myUint, nil } func (r *RfbReadHelper) ReadUint16() (uint16, error) { @@ -105,7 +111,7 @@ func (r *RfbReadHelper) ReadUint16() (uint16, error) { if err := binary.Read(r, binary.BigEndian, &myUint); err != nil { return 0, err } - //fmt.Printf("myUint=%d", myUint) + return myUint, nil } func (r *RfbReadHelper) ReadUint32() (uint32, error) { @@ -113,7 +119,7 @@ func (r *RfbReadHelper) ReadUint32() (uint32, error) { if err := binary.Read(r, binary.BigEndian, &myUint); err != nil { return 0, err } - //fmt.Printf("myUint=%d", myUint) + return myUint, nil } func (r *RfbReadHelper) ReadCompactLen() (int, error) { @@ -144,7 +150,7 @@ func (r *RfbReadHelper) ReadTightData(dataSize int) ([]byte, error) { return r.ReadBytes(int(dataSize)) } zlibDataLen, err := r.ReadCompactLen() - fmt.Printf("compactlen=%d\n", zlibDataLen) + logger.Debugf("compactlen=%d", zlibDataLen) if err != nil { return nil, err } diff --git a/common/server-message.go b/common/server-message.go index 0afa0c2..c1b5c9a 100644 --- a/common/server-message.go +++ b/common/server-message.go @@ -1,32 +1,46 @@ -package common - -type IClientConn interface { - CurrentPixelFormat() *PixelFormat - CurrentColorMap() *ColorMap - Encodings() []Encoding -} - -type ServerMessage interface { - // The type of the message that is sent down on the wire. - Type() uint8 - String() string - // Read reads the contents of the message from the reader. At the point - // this is called, the message type has already been read from the reader. - // This should return a new ServerMessage that is the appropriate type. - Read(IClientConn, *RfbReadHelper) (ServerMessage, error) -} -type ServerMessageType int8 - -const ( - FramebufferUpdate ServerMessageType = iota - SetColourMapEntries - Bell - ServerCutText -) - -type ServerInit struct { - FBWidth, FBHeight uint16 - PixelFormat PixelFormat - NameLength uint32 - NameText []byte -} +package common + +type IClientConn interface { + CurrentPixelFormat() *PixelFormat + CurrentColorMap() *ColorMap + Encodings() []Encoding +} + +type ServerMessage interface { + // The type of the message that is sent down on the wire. + Type() uint8 + String() string + // Read reads the contents of the message from the reader. At the point + // this is called, the message type has already been read from the reader. + // This should return a new ServerMessage that is the appropriate type. + Read(IClientConn, *RfbReadHelper) (ServerMessage, error) +} +type ServerMessageType int8 + +const ( + FramebufferUpdate ServerMessageType = iota + SetColourMapEntries + Bell + ServerCutText +) + +func (typ ServerMessageType) String() string { + switch typ { + case FramebufferUpdate: + return "FramebufferUpdate" + case SetColourMapEntries: + return "SetColourMapEntries" + case Bell: + return "Bell" + case ServerCutText: + return "ServerCutText" + } + return "" +} + +type ServerInit struct { + FBWidth, FBHeight uint16 + PixelFormat PixelFormat + NameLength uint32 + NameText []byte +} diff --git a/encodings/enc-copy-rect.go b/encodings/enc-copy-rect.go index ae7ec15..05d372f 100644 --- a/encodings/enc-copy-rect.go +++ b/encodings/enc-copy-rect.go @@ -1,20 +1,20 @@ -package encodings - -import "vncproxy/common" - -type CopyRectEncoding struct { - //Colors []Color - copyRectSrcX uint16 - copyRectSrcY uint16 -} - -func (z *CopyRectEncoding) Type() int32 { - return 1 -} -func (z *CopyRectEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) { - z.copyRectSrcX, _ = r.ReadUint16() - z.copyRectSrcY, _ = r.ReadUint16() - return z, nil -} - -////////// +package encodings + +import "vncproxy/common" + +type CopyRectEncoding struct { + //Colors []Color + copyRectSrcX uint16 + copyRectSrcY uint16 +} + +func (z *CopyRectEncoding) Type() int32 { + return 1 +} +func (z *CopyRectEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.Encoding, error) { + z.copyRectSrcX, _ = r.ReadUint16() + z.copyRectSrcY, _ = r.ReadUint16() + return z, nil +} + +////////// diff --git a/encodings/enc-hextile.go b/encodings/enc-hextile.go index fd2c811..b171d67 100644 --- a/encodings/enc-hextile.go +++ b/encodings/enc-hextile.go @@ -1,6 +1,9 @@ package encodings -import "vncproxy/common" +import ( + "vncproxy/common" + "vncproxy/logger" +) const ( HextileRaw = 1 @@ -34,16 +37,16 @@ func (z *HextileEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectan //handle Hextile Subrect(tx, ty, tw, th): subencoding, err := r.ReadUint8() - //fmt.Printf("hextile reader tile: (%d,%d) subenc=%d\n", ty, tx, subencoding) + //logger.Debugf("hextile reader tile: (%d,%d) subenc=%d\n", ty, tx, subencoding) if err != nil { - //fmt.Printf("error in hextile reader: %v\n", err) + logger.Errorf("HextileEncoding.Read: error in hextile reader: %v", err) return nil, err } if (subencoding & HextileRaw) != 0 { //ReadRawRect(c, rect, r) r.ReadBytes(tw * th * bytesPerPixel) - //fmt.Printf("hextile reader: HextileRaw\n") + //logger.Debug("hextile reader: HextileRaw\n") continue } if (subencoding & HextileBackgroundSpecified) != 0 { @@ -53,10 +56,10 @@ func (z *HextileEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectan r.ReadBytes(int(bytesPerPixel)) } if (subencoding & HextileAnySubrects) == 0 { - //fmt.Printf("hextile reader: no Subrects\n") + //logger.Debug("hextile reader: no Subrects") continue } - //fmt.Printf("hextile reader: handling Subrects\n") + nSubrects, err := r.ReadUint8() if err != nil { return nil, err diff --git a/encodings/enc-pseudo.go b/encodings/enc-pseudo.go new file mode 100644 index 0000000..565077a --- /dev/null +++ b/encodings/enc-pseudo.go @@ -0,0 +1,15 @@ +package encodings + +import "vncproxy/common" + +type PseudoEncoding struct { + Typ int32 +} + +func (pe *PseudoEncoding ) Type() int32{ + return pe.Typ +} + +func (pe *PseudoEncoding) Read(*common.PixelFormat, *common.Rectangle, *common.RfbReadHelper) (common.Encoding, error){ + return pe, nil +} diff --git a/encodings/enc-tight.go b/encodings/enc-tight.go index a708fb9..0646aed 100644 --- a/encodings/enc-tight.go +++ b/encodings/enc-tight.go @@ -21,7 +21,7 @@ const ( type TightEncoding struct { //output io.Writer - logger common.Logger + //logger common.Logger } // func (t *TightEncoding) SetOutput(output io.Writer) { diff --git a/encodings/enc-tightpng.go b/encodings/enc-tightpng.go index 1fc2229..3d20a2d 100644 --- a/encodings/enc-tightpng.go +++ b/encodings/enc-tightpng.go @@ -3,6 +3,7 @@ package encodings import ( "fmt" "vncproxy/common" + "vncproxy/logger" ) type TightPngEncoding struct { @@ -16,15 +17,15 @@ func (t *TightPngEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Recta //var subencoding uint8 compctl, err := r.ReadUint8() if err != nil { - fmt.Printf("error in handling tight encoding: %v\n", err) + logger.Errorf("error in handling tight encoding: %v", err) return nil, err } - fmt.Printf("bytesPixel= %d, subencoding= %d\n", bytesPixel, compctl) + logger.Debugf("bytesPixel= %d, subencoding= %d", bytesPixel, compctl) //move it to position (remove zlib flush commands) compType := compctl >> 4 & 0x0F - fmt.Printf("afterSHL:%d\n", compType) + logger.Debugf("afterSHL:%d", compType) switch compType { case TightPNG: len, err := r.ReadCompactLen() diff --git a/logger/logger.go b/logger/logger.go new file mode 100644 index 0000000..8831ec2 --- /dev/null +++ b/logger/logger.go @@ -0,0 +1,52 @@ +package logger + +import "fmt" + +type Logger interface { + Debug(v ...interface{}) + Debugf(format string, v ...interface{}) + Info(v ...interface{}) + Infof(format string, v ...interface{}) + Warn(v ...interface{}) + Warnf(format string, v ...interface{}) + Error(v ...interface{}) + Errorf(format string, v ...interface{}) + Fatal(v ...interface{}) + Fatalf(format string, v ...interface{}) +} + +func Debug(v ...interface{}) { + fmt.Print("[Debug] ") + fmt.Println(v...) +} +func Debugf(format string, v ...interface{}) { + fmt.Printf("[Debug] "+format+"\n", v...) +} +func Info(v ...interface{}) { + fmt.Print("[Info] ") + fmt.Println(v...) +} +func Infof(format string, v ...interface{}) { + fmt.Printf("[Info] "+format+"\n", v...) +} +func Warn(v ...interface{}) { + fmt.Print("[Warn] ") + fmt.Println(v...) +} +func Warnf(format string, v ...interface{}) { + fmt.Printf("[Warn] "+format+"\n", v...) +} +func Error(v ...interface{}) { + fmt.Print("[Error] ") + fmt.Println(v...) +} +func Errorf(format string, v ...interface{}) { + fmt.Printf("[Error] "+format+"\n", v...) +} +func Fatal(v ...interface{}) { + fmt.Print("[Fatal] ") + fmt.Println(v...) +} +func Fatalf(format string, v ...interface{}) { + fmt.Printf("[Fatal] "+format+"\n", v) +} diff --git a/main.go b/main.go index f6f7bd8..ad04430 100644 --- a/main.go +++ b/main.go @@ -1,22 +1,22 @@ package main import ( - "fmt" "net" "time" "vncproxy/client" "vncproxy/common" "vncproxy/encodings" + "vncproxy/logger" listeners "vncproxy/tee-listeners" ) func main() { - //fmt.Println("") + //nc, err := net.Dial("tcp", "192.168.1.101:5903") nc, err := net.Dial("tcp", "localhost:5903") if err != nil { - fmt.Printf("error connecting to vnc server: %s", err) + logger.Errorf("error connecting to vnc server: %s", err) } var noauth client.ClientAuthNone authArr := []client.ClientAuth{&client.PasswordAuth{Password: "Ch_#!T@8"}, &noauth} @@ -25,23 +25,22 @@ func main() { rec := listeners.NewRecorder("c:/Users/betzalel/recording.rbs") - split := &listeners.MultiListener{} - split.AddListener(rec) - - clientConn, err := client.Client(nc, + clientConn, err := client.NewClientConn(nc, &client.ClientConfig{ Auth: authArr, ServerMessageCh: vncSrvMessagesChan, Exclusive: true, }) - clientConn.Listener = split - + + clientConn.Listeners.AddListener(rec) + clientConn.Connect() + if err != nil { - fmt.Printf("error creating client: %s", err) + logger.Errorf("error creating client: %s", err) } // err = clientConn.FramebufferUpdateRequest(false, 0, 0, 1024, 768) // if err != nil { - // fmt.Printf("error requesting fb update: %s\n", err) + // logger.Errorf("error requesting fb update: %s", err) // } tight := encodings.TightEncoding{} @@ -62,7 +61,7 @@ func main() { for { err = clientConn.FramebufferUpdateRequest(true, 0, 0, 1280, 800) if err != nil { - fmt.Printf("error requesting fb update: %s\n", err) + logger.Errorf("error requesting fb update: %s", err) } time.Sleep(500 * time.Millisecond) } @@ -70,7 +69,7 @@ func main() { //go func() { for msg := range vncSrvMessagesChan { - fmt.Printf("message type: %d, content: %v\n", msg.Type(), msg) + logger.Debugf("message type: %d, content: %v\n", msg.Type(), msg) } //}() diff --git a/proxy/proxy.go b/proxy/proxy.go index 283e9ef..0a562ba 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -1,7 +1,6 @@ package proxy import ( - "fmt" "log" "net" "path" @@ -10,6 +9,7 @@ import ( "vncproxy/client" "vncproxy/common" "vncproxy/encodings" + "vncproxy/logger" "vncproxy/server" listeners "vncproxy/tee-listeners" ) @@ -20,16 +20,16 @@ type VncProxy struct { recordingDir string // empty = no recording proxyPassword string // empty = no auth targetServersPassword string //empty = no auth - singleSession *VncSession // to be used when not using sessions - usingSessions bool //false = single session - defined in the var above + SingleSession *VncSession // to be used when not using sessions + UsingSessions bool //false = single session - defined in the var above sessionManager *SessionManager } -func (vp *VncProxy) connectToVncServer(targetServerUrl string) (*client.ClientConn, error) { +func (vp *VncProxy) createClientConnection(targetServerUrl string) (*client.ClientConn, error) { nc, err := net.Dial("tcp", targetServerUrl) if err != nil { - fmt.Printf("error connecting to vnc server: %s", err) + logger.Errorf("error connecting to vnc server: %s", err) return nil, err } @@ -38,14 +38,7 @@ func (vp *VncProxy) connectToVncServer(targetServerUrl string) (*client.ClientCo vncSrvMessagesChan := make(chan common.ServerMessage) - //rec := listeners.NewRecorder("recording.rbs") - - // split := &listeners.MultiListener{} - // for _, listener := range rfbListeners { - // split.AddListener(listener) - // } - - clientConn, err := client.Client(nc, + clientConn, err := client.NewClientConn(nc, &client.ClientConfig{ Auth: authArr, ServerMessageCh: vncSrvMessagesChan, @@ -54,71 +47,89 @@ func (vp *VncProxy) connectToVncServer(targetServerUrl string) (*client.ClientCo //clientConn.Listener = split if err != nil { - fmt.Printf("error creating client: %s", err) + logger.Errorf("error creating client: %s", err) return nil, err } - tight := encodings.TightEncoding{} - tightPng := encodings.TightPngEncoding{} - rre := encodings.RREEncoding{} - zlib := encodings.ZLibEncoding{} - zrle := encodings.ZRLEEncoding{} - cpyRect := encodings.CopyRectEncoding{} - coRRE := encodings.CoRREEncoding{} - hextile := encodings.HextileEncoding{} - - clientConn.SetEncodings([]common.Encoding{&cpyRect, &tightPng, &tight, &hextile, &coRRE, &rre, &zlib, &zrle}) return clientConn, nil } // if sessions not enabled, will always return the configured target server (only one) func (vp *VncProxy) getTargetServerFromSession(sessionId string) (*VncSession, error) { - if !vp.usingSessions { - return vp.singleSession, nil + if !vp.UsingSessions { + if vp.SingleSession == nil { + logger.Errorf("SingleSession is empty, use sessions or populate the SingleSession member of the VncProxy struct.") + } + return vp.SingleSession, nil } return vp.sessionManager.GetSession(sessionId) } -func (vp *VncProxy) newServerConnHandler(cfg *server.ServerConfig, sconn *server.ServerConn, rfbListeners []common.SegmentConsumer) error { +func (vp *VncProxy) newServerConnHandler(cfg *server.ServerConfig, sconn *server.ServerConn) error { recFile := "recording" + strconv.FormatInt(time.Now().Unix(), 10) + ".rbs" recPath := path.Join(vp.recordingDir, recFile) rec := listeners.NewRecorder(recPath) session, err := vp.getTargetServerFromSession(sconn.SessionId) if err != nil { - fmt.Printf("Proxy.newServerConnHandler can't get session: %d\n", sconn.SessionId) + logger.Errorf("Proxy.newServerConnHandler can't get session: %d", sconn.SessionId) return err } - serverSplitter := &listeners.MultiListener{} - for _, l := range rfbListeners { - serverSplitter.AddListener(l) + // for _, l := range rfbListeners { + // sconn.Listeners.AddListener(l) + // } + sconn.Listeners.AddListener(rec) + + //clientSplitter := &common.MultiListener{} + + cconn, err := vp.createClientConnection(session.TargetHostname + ":" + session.TargetPort) + if err != nil { + logger.Errorf("Proxy.newServerConnHandler error creating connection: %s", err) + return err } - serverSplitter.AddListener(rec) - sconn.Listener = serverSplitter - - clientSplitter := &listeners.MultiListener{} - clientSplitter.AddListener(rec) - - cconn, err := vp.connectToVncServer(session.TargetHostname + ":" + session.TargetPort) - cconn.Listener = clientSplitter + cconn.Listeners.AddListener(rec) + //cconn.Listener = clientSplitter //creating cross-listeners between server and client parts to pass messages through the proxy: // gets the bytes from the actual vnc server on the env (client part of the proxy) // and writes them through the server socket to the vnc-client - serverMsgRepeater := &listeners.WriteTo{sconn, "vnc-client bound"} - clientSplitter.AddListener(serverMsgRepeater) + serverMsgRepeater := &listeners.WriteTo{sconn, "vnc-client-bound"} + cconn.Listeners.AddListener(serverMsgRepeater) // gets the messages from the server part (from vnc-client), // and write through the client to the actual vnc-server - clientMsgRepeater := &listeners.WriteTo{cconn, "vnc-server bound"} - serverSplitter.AddListener(clientMsgRepeater) + clientMsgRepeater := &listeners.WriteTo{cconn, "vnc-server-bound"} + sconn.Listeners.AddListener(clientMsgRepeater) + + err = cconn.Connect() + if err != nil { + logger.Errorf("Proxy.newServerConnHandler error connecting to client: %s", err) + return err + } + + encs := []common.Encoding{ + &encodings.RawEncoding{}, + &encodings.TightEncoding{}, + //encodings.TightPngEncoding{}, + //encodings.RREEncoding{}, + //encodings.ZLibEncoding{}, + //encodings.ZRLEEncoding{}, + //encodings.CopyRectEncoding{}, + //encodings.CoRREEncoding{}, + //encodings.HextileEncoding{}, + } + err = cconn.SetEncodings(encs) + if err != nil { + logger.Errorf("Proxy.newServerConnHandler error connecting to client: %s", err) + return err + } return nil } -func (vp *VncProxy) StartListening(rfbListeners []common.SegmentConsumer) { +func (vp *VncProxy) StartListening() { //chServer := make(chan common.ClientMessage) chClient := make(chan common.ServerMessage) @@ -137,10 +148,12 @@ func (vp *VncProxy) StartListening(rfbListeners []common.SegmentConsumer) { DesktopName: []byte("workDesk"), Height: uint16(768), Width: uint16(1024), - NewConnHandler: func(cfg *server.ServerConfig, conn *server.ServerConn) error { - vp.newServerConnHandler(cfg, conn, rfbListeners) - return nil - }, + NewConnHandler: vp.newServerConnHandler, + UseDummySession: !vp.UsingSessions, + // func(cfg *server.ServerConfig, conn *server.ServerConn) error { + // vp.newServerConnHandler(cfg, conn) + // return nil + // }, } if vp.wsListeningUrl != "" { diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go new file mode 100644 index 0000000..6963149 --- /dev/null +++ b/proxy/proxy_test.go @@ -0,0 +1,24 @@ +package proxy + +import "testing" + +func TestProxy(t *testing.T) { + //create default session if required + + proxy := &VncProxy{ + wsListeningUrl: "http://localhost:7777/", // empty = not listening on ws + recordingDir: "c:\\vncRec", // empty = no recording + targetServersPassword: "Ch_#!T@8", //empty = no auth + SingleSession: &VncSession{ + TargetHostname: "localhost", + TargetPort: "5903", + TargetPassword: "vncPass", + ID: "dummySession", + Status: SessionStatusActive, + Type: SessionTypeRecordingProxy, + }, // to be used when not using sessions + UsingSessions: false, //false = single session - defined in the var above + } + + proxy.StartListening() +} diff --git a/server/server-conn.go b/server/server-conn.go index 6108757..376897b 100644 --- a/server/server-conn.go +++ b/server/server-conn.go @@ -6,6 +6,7 @@ import ( "io" "sync" "vncproxy/common" + "vncproxy/logger" ) type ServerConn struct { @@ -40,7 +41,7 @@ type ServerConn struct { pixelFormat *common.PixelFormat // a consumer for the parsed messages, to allow for recording and proxy - Listener common.SegmentConsumer + Listeners *common.MultiListener SessionId string @@ -70,6 +71,7 @@ func NewServerConn(c io.ReadWriter, cfg *ServerConfig) (*ServerConn, error) { pixelFormat: cfg.PixelFormat, fbWidth: cfg.Width, fbHeight: cfg.Height, + Listeners: &common.MultiListener{}, }, nil } @@ -183,7 +185,7 @@ func (c *ServerConn) handle() error { for { select { case msg := <-c.cfg.ServerMessageCh: - fmt.Printf("%v", msg) + logger.Debugf("%v", msg) // if err = msg.Write(c); err != nil { // return err // } @@ -204,25 +206,32 @@ func (c *ServerConn) handle() error { default: var messageType common.ClientMessageType if err := binary.Read(c, binary.BigEndian, &messageType); err != nil { - fmt.Printf("Error: %v\n", err) + logger.Errorf("Error: %v", err) return err } msg, ok := clientMessages[messageType] if !ok { - return fmt.Errorf("unsupported message-type: %v", messageType) - + return fmt.Errorf("ServerConn.Handle: unsupported message-type: %v", messageType) } + parsedMsg, err := msg.Read(c) + + if err != nil { + logger.Errorf("srv err %s", err.Error()) + return err + } + seg := &common.RfbSegment{ SegmentType: common.SegmentFullyParsedClientMessage, Message: parsedMsg, } - c.Listener.Consume(seg) + err = c.Listeners.Consume(seg) if err != nil { - fmt.Printf("srv err %s\n", err.Error()) + logger.Errorf("ServerConn.Handle: listener consume err %s", err.Error()) return err } - fmt.Printf("message:%s, %v\n", parsedMsg.Type(), parsedMsg) + + logger.Debugf("ServerConn.Handle got ClientMessage: %s, %v", parsedMsg.Type(), parsedMsg) //c.cfg.ClientMessageCh <- parsedMsg } } diff --git a/server/server.go b/server/server.go index ac09d0f..d14eb52 100644 --- a/server/server.go +++ b/server/server.go @@ -60,7 +60,7 @@ type ServerConfig struct { DesktopName []byte Height uint16 Width uint16 - + UseDummySession bool //handler to allow for registering for messages, this can't be a channel //because of the websockets handler function which will kill the connection on exit if conn.handle() is run on another thread NewConnHandler ServerHandler @@ -70,7 +70,7 @@ func wsHandlerFunc(ws io.ReadWriter, cfg *ServerConfig, sessionId string) { // header := ws.Request().Header // url := ws.Request().URL // //stam := header.Get("Origin") - // fmt.Printf("header: %v\nurl: %v\n", header, url) + // logger.Debugf("header: %v\nurl: %v", header, url) // io.Copy(ws, ws) err := attachNewServerConn(ws, cfg, sessionId) @@ -96,7 +96,7 @@ func TcpServe(url string, cfg *ServerConfig) error { if err != nil { return err } - go attachNewServerConn(c, cfg, "tcpDummySession") + go attachNewServerConn(c, cfg, "dummySession") // if err != nil { // return err // } @@ -131,7 +131,11 @@ func attachNewServerConn(c io.ReadWriter, cfg *ServerConfig, sessionId string) e conn.Close() return err } + conn.SessionId = sessionId + if cfg.UseDummySession { + conn.SessionId = "dummySession" + } cfg.NewConnHandler(cfg, conn) //go here will kill ws connections diff --git a/server/ws-server-go.go b/server/ws-server-go.go index a8853c4..3094a85 100644 --- a/server/ws-server-go.go +++ b/server/ws-server-go.go @@ -1,10 +1,10 @@ package server import ( - "fmt" "io" "net/http" "net/url" + "vncproxy/logger" "golang.org/x/net/websocket" ) @@ -31,7 +31,7 @@ func (wsServer *WsServer) Listen(urlStr string, handlerFunc WsHandler) { } url, err := url.Parse(urlStr) if err != nil { - fmt.Println("error while parsing url: ", err) + logger.Errorf("error while parsing url: ", err) } // http.HandleFunc(url.Path, diff --git a/server/ws-server-gorilla.go b/server/ws-server-gorilla.go index 6536b0b..1e09179 100644 --- a/server/ws-server-gorilla.go +++ b/server/ws-server-gorilla.go @@ -1,11 +1,11 @@ package server import ( - "fmt" "io" "log" "net/http" "net/url" + "vncproxy/logger" "bytes" @@ -92,7 +92,7 @@ func (wsServer *WsServer1) Listen(urlStr string, handlerFunc WsHandler) { } url, err := url.Parse(urlStr) if err != nil { - fmt.Println("error while parsing url: ", err) + logger.Errorf("error while parsing url: ", err) } http.HandleFunc(url.Path, handleConnection) diff --git a/server/ws_test.go b/server/ws_test.go index 02adafc..abb4e43 100644 --- a/server/ws_test.go +++ b/server/ws_test.go @@ -1,33 +1 @@ package server - -// import ( -// "fmt" -// "io" -// "net/http" -// "testing" - -// "golang.org/x/net/websocket" -// ) - -// func TestWsServer(t *testing.T) { -// server := WsServer{} -// server.Listen(":8090") -// } - -// // Echo the data received on the WebSocket. -// func EchoHandler(ws *websocket.Conn) { -// header := ws.Request().Header -// url := ws.Request().URL -// //stam := header.Get("Origin") -// fmt.Printf("header: %v\nurl: %v\n", header, url) -// io.Copy(ws, ws) -// } - -// // This example demonstrates a trivial echo server. -// func TestGoWsServer(t *testing.T) { -// http.Handle("/", websocket.Handler(EchoHandler)) -// err := http.ListenAndServe(":11111", nil) -// if err != nil { -// panic("ListenAndServe: " + err.Error()) -// } -// } diff --git a/tee-listeners/multiListener.go b/tee-listeners/multiListener.go deleted file mode 100644 index fe5dddf..0000000 --- a/tee-listeners/multiListener.go +++ /dev/null @@ -1,22 +0,0 @@ -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 -} diff --git a/tee-listeners/recorder.go b/tee-listeners/recorder.go index 84bf011..018006f 100644 --- a/tee-listeners/recorder.go +++ b/tee-listeners/recorder.go @@ -4,18 +4,18 @@ import ( "bytes" "encoding/binary" "errors" - "fmt" "os" "time" "vncproxy/common" + "vncproxy/logger" "vncproxy/server" ) type Recorder struct { //common.BytesListener - RBSFileName string - writer *os.File - logger common.Logger + RBSFileName string + writer *os.File + //logger common.Logger startTime int buffer bytes.Buffer serverInitMessage *common.ServerInit @@ -38,7 +38,7 @@ func NewRecorder(saveFilePath string) *Recorder { rec.writer, err = os.OpenFile(saveFilePath, os.O_RDWR|os.O_CREATE, 0755) if err != nil { - fmt.Printf("unable to open file: %s, error: %v", saveFilePath, err) + logger.Errorf("unable to open file: %s, error: %v", saveFilePath, err) return nil } @@ -54,18 +54,6 @@ func NewRecorder(saveFilePath string) *Recorder { return &rec } -// func (rec *Recorder) startSession(desktopName string, fbWidth uint16, fbHeight uint16) error { - -// err := rec.writeStartSession(desktopName, fbWidth, fbHeight) - -// if err != nil { -// fmt.Printf("Recorder was unable to write StartSession to file error: %v", err) -// return nil -// } - -// return nil -// } - const versionMsg_3_3 = "RFB 003.003\n" const versionMsg_3_7 = "RFB 003.007\n" const versionMsg_3_8 = "RFB 003.008\n" @@ -115,27 +103,33 @@ func (r *Recorder) writeStartSession(initMsg *common.ServerInit) error { } func (r *Recorder) Consume(data *common.RfbSegment) error { - //using async writes so if chan buffer overflows, proxy will not be affected select { case r.segmentChan <- data: default: - fmt.Println("error: recorder queue is full") + logger.Error("error: recorder queue is full") } return nil } func (r *Recorder) HandleRfbSegment(data *common.RfbSegment) error { + defer func() { + if r := recover(); r != nil { + logger.Error("Recovered in HandleRfbSegment: ", r) + } + }() switch data.SegmentType { case common.SegmentMessageSeparator: if !r.sessionStartWritten { + logger.Debugf("Recorder.HandleRfbSegment: writing start session segment: %v",r.serverInitMessage) r.writeStartSession(r.serverInitMessage) } switch common.ServerMessageType(data.UpcomingObjectType) { case common.FramebufferUpdate: + logger.Debugf("Recorder.HandleRfbSegment: saving FramebufferUpdate segment") r.writeToDisk() case common.SetColourMapEntries: case common.Bell: @@ -145,6 +139,7 @@ func (r *Recorder) HandleRfbSegment(data *common.RfbSegment) error { } case common.SegmentRectSeparator: + logger.Debugf("Recorder.HandleRfbSegment: writing start rect start") r.writeToDisk() case common.SegmentBytes: _, err := r.buffer.Write(data.Bytes) @@ -157,9 +152,10 @@ func (r *Recorder) HandleRfbSegment(data *common.RfbSegment) error { switch clientMsg.Type() { case common.SetPixelFormatMsgType: clientMsg := data.Message.(*server.SetPixelFormat) + logger.Debugf("Recorder.HandleRfbSegment: client message %v", *clientMsg) r.serverInitMessage.PixelFormat = clientMsg.PF default: - return errors.New("unknown client message type:" + string(data.UpcomingObjectType)) + //return errors.New("unknown client message type:" + string(data.UpcomingObjectType)) } default: @@ -180,11 +176,11 @@ func (r *Recorder) writeToDisk() error { paddedSize := (bytesLen + 3) & 0x7FFFFFFC paddingSize := paddedSize - bytesLen - fmt.Printf("paddedSize=%d paddingSize=%d bytesLen=%d", paddedSize, paddingSize, bytesLen) + //logger.Debugf("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) + //logger.Debugf("padding=%v ", padding) binary.Write(r.writer, binary.BigEndian, padding) diff --git a/tee-listeners/write-to.go b/tee-listeners/write-to.go index fe1e360..20c3227 100644 --- a/tee-listeners/write-to.go +++ b/tee-listeners/write-to.go @@ -1,9 +1,9 @@ package listeners import ( - "errors" "io" "vncproxy/common" + "vncproxy/logger" ) type WriteTo struct { @@ -12,17 +12,26 @@ type WriteTo struct { } func (p *WriteTo) Consume(seg *common.RfbSegment) error { + + logger.Debugf("WriteTo.Consume ("+p.Name+"): sending segment type=%s", seg.SegmentType) switch seg.SegmentType { case common.SegmentMessageSeparator: case common.SegmentRectSeparator: case common.SegmentBytes: _, err := p.Writer.Write(seg.Bytes) + if (err != nil) { + logger.Errorf("WriteTo.Consume ("+p.Name+" SegmentBytes): problem writing to port: %s", err) + } return err case common.SegmentFullyParsedClientMessage: clientMsg := seg.Message.(common.ClientMessage) - clientMsg.Write(p.Writer) + err := clientMsg.Write(p.Writer) + if (err != nil) { + logger.Errorf("WriteTo.Consume ("+p.Name+" SegmentFullyParsedClientMessage): problem writing to port: %s", err) + } + return err default: - return errors.New("undefined RfbSegment type") + //return errors.New("WriteTo.Consume: undefined RfbSegment type") } return nil }