689 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			689 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//var clog = clog;
							 | 
						||
| 
								 | 
							
								//var clog = function() {};
							 | 
						||
| 
								 | 
							
								var clog = console.log;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var util = require('util'); // util.inherits
							 | 
						||
| 
								 | 
							
								var net = require('net');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var EventEmitter = require('events').EventEmitter;
							 | 
						||
| 
								 | 
							
								var PackStream = require('./unpackstream');
							 | 
						||
| 
								 | 
							
								var hexy = require('./hexy').hexy;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// constants
							 | 
						||
| 
								 | 
							
								var rfb = require('./constants');
							 | 
						||
| 
								 | 
							
								for (var key in rfb)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								     module.exports[key] = rfb[key];
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function RfbClient(stream, params)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    EventEmitter.call(this);
							 | 
						||
| 
								 | 
							
								    this.params = params;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								    cli.stream = stream;
							 | 
						||
| 
								 | 
							
								    cli.pack_stream = new PackStream();
							 | 
						||
| 
								 | 
							
								    cli.pack_stream.on('data', function( data ) {
							 | 
						||
| 
								 | 
							
								        //clog(hexy(data, {prefix: 'from client '}));
							 | 
						||
| 
								 | 
							
								        cli.stream.write(data);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								    stream.on('data', function( data ) {
							 | 
						||
| 
								 | 
							
								        //var dump = data.length >  20 ? data.slice(0,20) : data;
							 | 
						||
| 
								 | 
							
								        //clog(hexy(dump, {prefix: 'from server '}));
							 | 
						||
| 
								 | 
							
								        cli.pack_stream.write(data);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // TODO: check if I need that at all
							 | 
						||
| 
								 | 
							
								    cli.pack_stream.serverBigEndian = !true;
							 | 
						||
| 
								 | 
							
								    cli.pack_stream.clientBigEndian = !true;
							 | 
						||
| 
								 | 
							
								    cli.readServerVersion();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								util.inherits(RfbClient, EventEmitter);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PackStream.prototype.readString = function(strcb)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this;
							 | 
						||
| 
								 | 
							
								    stream.unpack('L', function(res) {
							 | 
						||
| 
								 | 
							
								        //clog(res[0]);
							 | 
						||
| 
								 | 
							
								        stream.get(res[0], function(strBuff) {
							 | 
						||
| 
								 | 
							
								            strcb(strBuff.toString());
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.terminate = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    debugger;
							 | 
						||
| 
								 | 
							
								    this.stream.end();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readError = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								    this.pack_stream.readString(function(str) {
							 | 
						||
| 
								 | 
							
								         console.error(str);
							 | 
						||
| 
								 | 
							
								         cli.emit('error', str);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readServerVersion = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								    stream.get(12, function(rfbver) {
							 | 
						||
| 
								 | 
							
								        cli.serverVersion = rfbver.toString('ascii');
							 | 
						||
| 
								 | 
							
								        console.log(['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', rfbver]);
							 | 
						||
| 
								 | 
							
								        stream.pack('a', [ rfb.versionstring.V3_008 ]).flush();
							 | 
						||
| 
								 | 
							
								        if (cli.serverVersion == rfb.versionstring.V3_003) 
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            stream.unpack('L', function(secType) {
							 | 
						||
| 
								 | 
							
								                var type = secType[0];
							 | 
						||
| 
								 | 
							
								                console.error('3.003 security type: ' + type);
							 | 
						||
| 
								 | 
							
								                if (type == 0)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    cli.readError();
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                    cli.securityType = type;
							 | 
						||
| 
								 | 
							
								                    // 3.003 version does not send result for None security
							 | 
						||
| 
								 | 
							
								                    if (type == rfb.security.None) 
							 | 
						||
| 
								 | 
							
								                        cli.clientInit();
							 | 
						||
| 
								 | 
							
								                    else    
							 | 
						||
| 
								 | 
							
								                        cli.processSecurity();
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                                
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								 
							 | 
						||
| 
								 | 
							
								        // read security types
							 | 
						||
| 
								 | 
							
								        stream.unpack('C', function(res) {
							 | 
						||
| 
								 | 
							
								            var numSecTypes = res[0];
							 | 
						||
| 
								 | 
							
								            if (numSecTypes == 0) {
							 | 
						||
| 
								 | 
							
								                console.error(['zero num sec types', res]);
							 | 
						||
| 
								 | 
							
								                cli.readError();
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                stream.get(numSecTypes, function(secTypes) {
							 | 
						||
| 
								 | 
							
								                    // TODO: check what is in options
							 | 
						||
| 
								 | 
							
								                    //
							 | 
						||
| 
								 | 
							
								                    // send sec type we are going to use
							 | 
						||
| 
								 | 
							
								                    //cli.securityType = rfb.security.None;
							 | 
						||
| 
								 | 
							
								                    cli.securityType = rfb.security.VNC;
							 | 
						||
| 
								 | 
							
								                    stream.pack('C', [cli.securityType]).flush();
							 | 
						||
| 
								 | 
							
								                    cli.processSecurity();
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }); 
							 | 
						||
| 
								 | 
							
								   });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readSecurityResult = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								    stream.unpack('L', function(securityResult) {
							 | 
						||
| 
								 | 
							
								        if (securityResult[0] == 0)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            cli.clientInit();
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            stream.readString(function(message) {
							 | 
						||
| 
								 | 
							
								                console.error(message);
							 | 
						||
| 
								 | 
							
								                process.exit(0);
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        } 
							 | 
						||
| 
								 | 
							
								    });  
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.processSecurity = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								    switch(cli.securityType) {
							 | 
						||
| 
								 | 
							
								    case rfb.security.None:
							 | 
						||
| 
								 | 
							
								        // do nothing
							 | 
						||
| 
								 | 
							
								        cli.readSecurityResult();
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    case rfb.security.VNC:
							 | 
						||
| 
								 | 
							
								        stream.get(16, function(challenge) {
							 | 
						||
| 
								 | 
							
								            var response = require('./d3des').response(challenge, cli.params.password);
							 | 
						||
| 
								 | 
							
								            stream.pack('a', [response]).flush();
							 | 
						||
| 
								 | 
							
								            cli.readSecurityResult();
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								        break;
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								        console.error('unknown security type: ' + cli.securityType);
							 | 
						||
| 
								 | 
							
								        process.exit(1);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.clientInit = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var initMessage = cli.disconnectOthers ? rfb.connectionFlag.Exclusive : rfb.connectionFlag.Shared;
							 | 
						||
| 
								 | 
							
								    stream.pack('C', [ initMessage ]).flush();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stream.unpackTo(
							 | 
						||
| 
								 | 
							
								        cli,
							 | 
						||
| 
								 | 
							
								        [
							 | 
						||
| 
								 | 
							
								        "S width",
							 | 
						||
| 
								 | 
							
								        "S height",
							 | 
						||
| 
								 | 
							
								        "C bpp", // 16-bytes pixel format
							 | 
						||
| 
								 | 
							
								        "C depth",
							 | 
						||
| 
								 | 
							
								        "C isBigEndian",
							 | 
						||
| 
								 | 
							
								        "C isTrueColor",
							 | 
						||
| 
								 | 
							
								        "S redMax",
							 | 
						||
| 
								 | 
							
								        "S greenMax",
							 | 
						||
| 
								 | 
							
								        "S blueMax",
							 | 
						||
| 
								 | 
							
								        "C redShift",
							 | 
						||
| 
								 | 
							
								        "C greenShift",
							 | 
						||
| 
								 | 
							
								        "C blueShift",
							 | 
						||
| 
								 | 
							
								        "xxx",
							 | 
						||
| 
								 | 
							
								        "L titleLength"        
							 | 
						||
| 
								 | 
							
								        ],
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        function() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // TODO: remove next 3 lines 
							 | 
						||
| 
								 | 
							
								            stream.serverBigEndian = false; //cli.isBigEndian; 
							 | 
						||
| 
								 | 
							
								            stream.clientBigEndian = false; //cli.isBigEndian; 
							 | 
						||
| 
								 | 
							
								            //stream.bigEndian = false; //cli.isBigEndian; 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            stream.get(cli.titleLength, function(titleBuf) {
							 | 
						||
| 
								 | 
							
								                cli.title = titleBuf.toString();
							 | 
						||
| 
								 | 
							
								                delete cli.titleLength;
							 | 
						||
| 
								 | 
							
								                cli.setPixelFormat();
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.setPixelFormat = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								    stream.pack('CxxxCCCCSSSCCCxxx',
							 | 
						||
| 
								 | 
							
								        [0, cli.bpp, cli.depth, cli.isBigEndian, cli.isTrueColor, cli.redMax, cli.greenMax, cli.blueMax, 
							 | 
						||
| 
								 | 
							
								            cli.redShift, cli.greenShift, cli.blueShift]
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								    stream.flush();
							 | 
						||
| 
								 | 
							
								    cli.setEncodings();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function repeat(str, num)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var res = '';
							 | 
						||
| 
								 | 
							
								    for (var i=0; i < num; ++i)
							 | 
						||
| 
								 | 
							
								        res += str;
							 | 
						||
| 
								 | 
							
								    return res;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.setEncodings = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // build encodings list
							 | 
						||
| 
								 | 
							
								    // TODO: API
							 | 
						||
| 
								 | 
							
								    var encodings = [rfb.encodings.raw, rfb.encodings.copyRect, rfb.encodings.pseudoDesktopSize, rfb.encodings.hextile];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stream.pack('CxS', [rfb.clientMsgTypes.setEncodings, encodings.length]);
							 | 
						||
| 
								 | 
							
								    stream.pack(repeat('l', encodings.length), encodings);
							 | 
						||
| 
								 | 
							
								    stream.flush();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    cli.requestUpdate(false, 0, 0, cli.width, cli.height);    
							 | 
						||
| 
								 | 
							
								    cli.expectNewMessage();
							 | 
						||
| 
								 | 
							
								    console.log('handshake performed');
							 | 
						||
| 
								 | 
							
								    this.emit('connect');
							 | 
						||
| 
								 | 
							
								    console.log('emitted CONNECT');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.expectNewMessage = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								    stream.get(1, function(buff) {
							 | 
						||
| 
								 | 
							
								        console.log('server message:' + buff[0]);
							 | 
						||
| 
								 | 
							
								        switch(buff[0]) {
							 | 
						||
| 
								 | 
							
								        case rfb.serverMsgTypes.fbUpdate: cli.readFbUpdate(); break;
							 | 
						||
| 
								 | 
							
								        case rfb.serverMsgTypes.setColorMap: cli.readColorMap(); break;
							 | 
						||
| 
								 | 
							
								        case rfb.serverMsgTypes.bell: cli.readBell(); break;
							 | 
						||
| 
								 | 
							
								        case rfb.serverMsgTypes.cutText: cli.readClipboardUpdate(); break;
							 | 
						||
| 
								 | 
							
								        default:
							 | 
						||
| 
								 | 
							
								            clog('unsopported server message: ' + buff[0]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var decodeHandlers = {
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readFbUpdate = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    clog('fb update');
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stream.unpack('xS', function(res) {
							 | 
						||
| 
								 | 
							
								        var numRects = res[0];
							 | 
						||
| 
								 | 
							
								        // decode each rectangle
							 | 
						||
| 
								 | 
							
								        var numRectsLeft = numRects;
							 | 
						||
| 
								 | 
							
								        clog('number of rectngles in fb updte message: ' + numRects);
							 | 
						||
| 
								 | 
							
								        function unpackRect() {
							 | 
						||
| 
								 | 
							
								            if (numRectsLeft == 0)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                cli.expectNewMessage();
							 | 
						||
| 
								 | 
							
								                cli.requestUpdate(true, 0, 0, cli.width, cli.height);  
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            numRectsLeft--;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            var rect = {};
							 | 
						||
| 
								 | 
							
								            stream.unpackTo(rect,
							 | 
						||
| 
								 | 
							
								                ['S x', 'S y', 'S width', 'S height', 'l encoding'],
							 | 
						||
| 
								 | 
							
								                function() {
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								                    // TODO: rewrite using decodeHandlers                 
							 | 
						||
| 
								 | 
							
								                    switch(rect.encoding) {
							 | 
						||
| 
								 | 
							
								                    case rfb.encodings.raw:
							 | 
						||
| 
								 | 
							
								                        cli.readRawRect(rect, unpackRect);
							 | 
						||
| 
								 | 
							
								                        break;
							 | 
						||
| 
								 | 
							
								                    case rfb.encodings.copyRect:
							 | 
						||
| 
								 | 
							
								                        cli.readCopyRect(rect, unpackRect);
							 | 
						||
| 
								 | 
							
								                        break;
							 | 
						||
| 
								 | 
							
								                    case rfb.encodings.pseudoDesktopSize:
							 | 
						||
| 
								 | 
							
								                        clog(['Resize', rect]);
							 | 
						||
| 
								 | 
							
								                        cli.width = rect.width;
							 | 
						||
| 
								 | 
							
								                        cli.height = rect.height;
							 | 
						||
| 
								 | 
							
								                        cli.emit('resize', rect);
							 | 
						||
| 
								 | 
							
								                        unpackRect();
							 | 
						||
| 
								 | 
							
								                        break;
							 | 
						||
| 
								 | 
							
								                    case rfb.encodings.hextile:
							 | 
						||
| 
								 | 
							
								                        cli.readHextile(rect, unpackRect);
							 | 
						||
| 
								 | 
							
								                        break;
							 | 
						||
| 
								 | 
							
								                    default:
							 | 
						||
| 
								 | 
							
								                        clog('unknown encoding!!! ' + rect.encoding);
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            );
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        unpackRect();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readHextile = function(rect, cb)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    rect.emitter = new EventEmitter();
							 | 
						||
| 
								 | 
							
								    rect.on = function(eventname, cb) {
							 | 
						||
| 
								 | 
							
								        rect.emitter.on(eventname, cb);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    rect.emit = function(eventname, param) {
							 | 
						||
| 
								 | 
							
								        rect.emitter.emit(eventname, param);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    rect.widthTiles = (rect.width >>> 4);
							 | 
						||
| 
								 | 
							
								    rect.heightTiles = (rect.height >>> 4);
							 | 
						||
| 
								 | 
							
								    clog(['tiles: ', rect.widthTiles, rect.heightTiles]);
							 | 
						||
| 
								 | 
							
								    rect.rightRectWidth = rect.width & 0x0f;
							 | 
						||
| 
								 | 
							
								    rect.bottomRectHeight = rect.height & 0x0f;
							 | 
						||
| 
								 | 
							
								    rect.tilex = 0;
							 | 
						||
| 
								 | 
							
								    rect.tiley = 0;
							 | 
						||
| 
								 | 
							
								    rect.tiles = [];
							 | 
						||
| 
								 | 
							
								    console.log('===== emitting rect');
							 | 
						||
| 
								 | 
							
								    this.emit('rect', rect);
							 | 
						||
| 
								 | 
							
								    this.readHextileTile(rect, cb); 
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readHextileTile = function(rect, cb)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var tile = {};
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    tile.x = rect.tilex;
							 | 
						||
| 
								 | 
							
								    tile.y = rect.tiley;
							 | 
						||
| 
								 | 
							
								    tile.width = 16;
							 | 
						||
| 
								 | 
							
								    if (tile.x == rect.widthTiles && rect.rightRectWidth > 0)
							 | 
						||
| 
								 | 
							
								         tile.width = rect.rightRectWidt;
							 | 
						||
| 
								 | 
							
								    tile.height = 16;
							 | 
						||
| 
								 | 
							
								    if (tile.y == rect.heightTiles && rect.bottomRectHeight > 0)
							 | 
						||
| 
								 | 
							
								         tile.height = rect.bottomRectHeight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // calculate next tilex & tiley and move up 'stack' if we at the last tile
							 | 
						||
| 
								 | 
							
								    function nextTile()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        clog('nextTile');
							 | 
						||
| 
								 | 
							
								        rect.emit('tile', tile);
							 | 
						||
| 
								 | 
							
								        tile = {};
							 | 
						||
| 
								 | 
							
								        if (rect.tilex < rect.widthTiles)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            rect.tilex++;
							 | 
						||
| 
								 | 
							
								            //clog([rect.tilex, rect.tiley]);
							 | 
						||
| 
								 | 
							
								            return cli.readHextileTile(rect, cb);
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            clog('===================== new row! ' + rect.tiley);
							 | 
						||
| 
								 | 
							
								            rect.tilex = 0;
							 | 
						||
| 
								 | 
							
								            if (rect.tiley < rect.heightTiles)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                rect.tiley++;
							 | 
						||
| 
								 | 
							
								                //clog([rect.tilex, rect.tiley]);
							 | 
						||
| 
								 | 
							
								                return cli.readHextileTile(rect, cb);
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                clog('====================')
							 | 
						||
| 
								 | 
							
								                clog(rect);
							 | 
						||
| 
								 | 
							
								                return cb();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }   
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var bytesPerPixel = cli.bpp >> 3;
							 | 
						||
| 
								 | 
							
								    console.log('bytesPerPixel: ' + bytesPerPixel);
							 | 
						||
| 
								 | 
							
								    var tilebuflen = bytesPerPixel*tile.width*tile.height;
							 | 
						||
| 
								 | 
							
								    stream.unpack('C', function(subEnc) {
							 | 
						||
| 
								 | 
							
								        clog('tile flags: ' + subEnc[0]);
							 | 
						||
| 
								 | 
							
								        tile.subEncoding = subEnc[0];
							 | 
						||
| 
								 | 
							
								        var hextile = rfb.subEncodings.hextile;
							 | 
						||
| 
								 | 
							
								        if (tile.subEncoding & hextile.raw) {
							 | 
						||
| 
								 | 
							
								            stream.get(tilebuflen, function(rawbuff)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                clog('raw tile');
							 | 
						||
| 
								 | 
							
								                tile.buffer = rawbuff;
							 | 
						||
| 
								 | 
							
								                nextTile();
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								            return;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        tile.buffer = new Buffer(tilebuflen);
							 | 
						||
| 
								 | 
							
								     
							 | 
						||
| 
								 | 
							
								        function solidBackground() {
							 | 
						||
| 
								 | 
							
								            clog('solidBackground');
							 | 
						||
| 
								 | 
							
								            // the whole tile is just single colored width x height
							 | 
						||
| 
								 | 
							
								            for (var i=0; i < tilebuflen; i+= bytesPerPixel)
							 | 
						||
| 
								 | 
							
								                tile.backgroundColor.copy(tile.buffer, i); 
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								        function readBackground() {
							 | 
						||
| 
								 | 
							
								            clog('readBackground');
							 | 
						||
| 
								 | 
							
								            if (tile.subEncoding & hextile.backgroundSpecified) {
							 | 
						||
| 
								 | 
							
								                clog('hextile.backgroundSpecified');
							 | 
						||
| 
								 | 
							
								                stream.get(bytesPerPixel, function(pixelValue)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    clog(['tile.backgroundColor', pixelValue, tile.subEncoding]);
							 | 
						||
| 
								 | 
							
								                    tile.backgroundColor = pixelValue;
							 | 
						||
| 
								 | 
							
								                    rect.backgroundColor = pixelValue;
							 | 
						||
| 
								 | 
							
								                    readForeground(); 
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                tile.backgroundColor = rect.backgroundColor;
							 | 
						||
| 
								 | 
							
								                readForeground(); 
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        function readForeground() {
							 | 
						||
| 
								 | 
							
								            clog('readForeground');
							 | 
						||
| 
								 | 
							
								            // we should have background color set here
							 | 
						||
| 
								 | 
							
								            solidBackground();
							 | 
						||
| 
								 | 
							
								            if (rect.subEncoding & hextile.foregroundSpecified) {
							 | 
						||
| 
								 | 
							
								                clog('foreground specified');
							 | 
						||
| 
								 | 
							
								                stream.get(bytesPerPixel, function(pixelValue)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    tile.foreroundColor = pixelValue;
							 | 
						||
| 
								 | 
							
								                    rect.foreroundColor = pixelValue;
							 | 
						||
| 
								 | 
							
								                    console.log(rect);
							 | 
						||
| 
								 | 
							
								                    readSubrects();
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                clog('foreground NOT specified');
							 | 
						||
| 
								 | 
							
								                clog(rect);
							 | 
						||
| 
								 | 
							
								                tile.foregroundColor = rect.foregroundColor;
							 | 
						||
| 
								 | 
							
								                readSubrects();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        function readSubrects() {
							 | 
						||
| 
								 | 
							
								            clog('readSubrects');
							 | 
						||
| 
								 | 
							
								            if (tile.subEncoding & hextile.anySubrects) {
							 | 
						||
| 
								 | 
							
								                clog('have subrects');
							 | 
						||
| 
								 | 
							
								                // read number of subrectangles
							 | 
						||
| 
								 | 
							
								                stream.get('C', function(subrectsNum) {
							 | 
						||
| 
								 | 
							
								                    tile.subrectsNum = subrectsNum[0];
							 | 
						||
| 
								 | 
							
								                    clog('number of subrects = ' + tile.subrectsNum);
							 | 
						||
| 
								 | 
							
								                    readSubrect();
							 | 
						||
| 
								 | 
							
								                });        
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                nextTile();
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        function drawRect(x, y, w, h)
							 | 
						||
| 
								 | 
							
								        {
							 | 
						||
| 
								 | 
							
								            console.log(tile);
							 | 
						||
| 
								 | 
							
								            console.log(['drawRect', x, y, w, h, tile.foregroundColor]);
							 | 
						||
| 
								 | 
							
								            // TODO: optimise
							 | 
						||
| 
								 | 
							
								            for(var px = x; px < x+w; ++px)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                for(var py = x; py < y+h; ++py)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    var offset = bytesPerPixel*(tile.width*py + px);
							 | 
						||
| 
								 | 
							
								                    tile.foregroundColor.copy(tile.buffer, offset);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        function readSubrect() {
							 | 
						||
| 
								 | 
							
								            clog('readSubrect');
							 | 
						||
| 
								 | 
							
								            if (tile.subEncoding & hextile.subrectsColored) {
							 | 
						||
| 
								 | 
							
								                // we have color + rect data
							 | 
						||
| 
								 | 
							
								                stream.get(bytesPerPixel, function(pixelValue)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    clog(['coloredSubrect: ', pixelValue]);
							 | 
						||
| 
								 | 
							
								                    tile.foreroundColor = pixelValue;
							 | 
						||
| 
								 | 
							
								                    rect.foreroundColor = pixelValue;
							 | 
						||
| 
								 | 
							
								                    readSubrectRect(); 
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								            } else // we have just rect data
							 | 
						||
| 
								 | 
							
								                readSubrectRect();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        function readSubrectRect() {
							 | 
						||
| 
								 | 
							
								            clog('readSubrectRect');
							 | 
						||
| 
								 | 
							
								            // read subrect x y w h encoded in two bytes
							 | 
						||
| 
								 | 
							
								            stream.get(2, function(subrectRaw) {
							 | 
						||
| 
								 | 
							
								                var x = (subrectRaw[0] & 0xf0) >> 4;
							 | 
						||
| 
								 | 
							
								                var y = (subrectRaw[0] & 0x0f);
							 | 
						||
| 
								 | 
							
								                var width  = (subrectRaw[1] & 0xf0) >> 4 + 1;
							 | 
						||
| 
								 | 
							
								                var height = (subrectRaw[1] & 0x0f) + 1;
							 | 
						||
| 
								 | 
							
								                clog(['readSubrectRect', x, y, width, height, tile.subrectsNum]);
							 | 
						||
| 
								 | 
							
								                drawRect(x, y, width, height);
							 | 
						||
| 
								 | 
							
								                tile.subrectsNum--;
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                if (tile.subrectsNum === 0)
							 | 
						||
| 
								 | 
							
								                {
							 | 
						||
| 
								 | 
							
								                    nextTile();
							 | 
						||
| 
								 | 
							
								                } else
							 | 
						||
| 
								 | 
							
								                    readSubrect();
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        readBackground();
							 | 
						||
| 
								 | 
							
								    }); 
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readCopyRect = function(rect, cb)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stream.unpack('SS', function(src) {
							 | 
						||
| 
								 | 
							
								        rect.src = { x: src[0], y: src[1] };
							 | 
						||
| 
								 | 
							
								        clog(['copy rect', src, rect]);
							 | 
						||
| 
								 | 
							
								        cli.emit('rect', rect);
							 | 
						||
| 
								 | 
							
								        cb(rect);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readRawRect = function(rect, cb)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    var bytesPerPixel = cli.bpp >> 3;
							 | 
						||
| 
								 | 
							
								    stream.get(bytesPerPixel*rect.width*rect.height, function(rawbuff)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        //clog('arrived ' + rawbuff.length + ' bytes of fb update');
							 | 
						||
| 
								 | 
							
								        rect.buffer = rawbuff;
							 | 
						||
| 
								 | 
							
								        cli.emit('rect', rect);
							 | 
						||
| 
								 | 
							
								        cb(rect);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readColorMap = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    clog('color map');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readBell = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    clog('bell');
							 | 
						||
| 
								 | 
							
								    this.expectNewMessage();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.readClipboardUpdate = function()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    clog('clipboard update');
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    var cli = this;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stream.unpack('xxxL', function(res) {
							 | 
						||
| 
								 | 
							
								         clog(res[0] + ' bytes string in the buffer');
							 | 
						||
| 
								 | 
							
								         stream.get(res[0], function(buf) {
							 | 
						||
| 
								 | 
							
								             clog(buf.toString());
							 | 
						||
| 
								 | 
							
								             cli.expectNewMessage();
							 | 
						||
| 
								 | 
							
								         })
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.pointerEvent = function(x, y, buttons)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								    stream.pack('CCSS', [rfb.clientMsgTypes.pointerEvent, buttons, x, y]);
							 | 
						||
| 
								 | 
							
								    stream.flush();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.keyEvent = function(keysym, isDown)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								    stream.pack('CCxxL', [rfb.clientMsgTypes.keyEvent, isDown, keysym]);
							 | 
						||
| 
								 | 
							
								    stream.flush();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RfbClient.prototype.requestUpdate = function(incremental, x, y, width, height)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = this.pack_stream;
							 | 
						||
| 
								 | 
							
								    stream.pack('CCSSSS', [rfb.clientMsgTypes.fbUpdate, incremental, x, y, width, height]);
							 | 
						||
| 
								 | 
							
								    stream.flush();
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// TODO: add client cutText event!
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var fs = require('fs');
							 | 
						||
| 
								 | 
							
								function createRfbStream(name)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream = new EventEmitter();
							 | 
						||
| 
								 | 
							
								    var fileStream = fs.createReadStream(name);
							 | 
						||
| 
								 | 
							
								    var pack = new PackStream();
							 | 
						||
| 
								 | 
							
								    fileStream.on('data', function( data ) {
							 | 
						||
| 
								 | 
							
									//fileStream.pause();
							 | 
						||
| 
								 | 
							
								        //setTimeout(function() {
							 | 
						||
| 
								 | 
							
								            pack.write(data);
							 | 
						||
| 
								 | 
							
								            //clog('received from filestream:' + data.length);
							 | 
						||
| 
								 | 
							
								            //fileStream.resume();
							 | 
						||
| 
								 | 
							
								        //}, 10);
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								 
							 | 
						||
| 
								 | 
							
								    var start = +new Date();
							 | 
						||
| 
								 | 
							
								    function readData()
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        pack.unpack('L', function(size) {
							 | 
						||
| 
								 | 
							
								            pack.get(size[0], function(databuf) {
							 | 
						||
| 
								 | 
							
								                pack.unpack('L', function(timestamp) {
							 | 
						||
| 
								 | 
							
								                    var padding = 3 - ((size - 1) & 0x03);
							 | 
						||
| 
								 | 
							
								                    pack.get(padding, function() {
							 | 
						||
| 
								 | 
							
								                        if (!stream.ending) {
							 | 
						||
| 
								 | 
							
								                            stream.emit('data', databuf);
							 | 
						||
| 
								 | 
							
								                            var now = +new Date - start; 
							 | 
						||
| 
								 | 
							
								                            var timediff = timestamp[0] - now;
							 | 
						||
| 
								 | 
							
								                            stream.timeout = setTimeout(readData, timediff);
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    });
							 | 
						||
| 
								 | 
							
								                });
							 | 
						||
| 
								 | 
							
								            }); 
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pack.get(12, function(fileVersion) {
							 | 
						||
| 
								 | 
							
								         readData();
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stream.end = function() {
							 | 
						||
| 
								 | 
							
								        stream.ending = true;
							 | 
						||
| 
								 | 
							
								        if (stream.timeout)
							 | 
						||
| 
								 | 
							
								            clearTimeout(stream.timeout);
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    stream.write = function(buf) {
							 | 
						||
| 
								 | 
							
								        // ignore
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return stream;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function createConnection(params)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    var stream;
							 | 
						||
| 
								 | 
							
								    if (params.rfbfile)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        console.log('reading from ' + params.rfbfile);
							 | 
						||
| 
								 | 
							
								        stream = createRfbStream(params.rfbfile);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        console.log('connecting to ' + params.host + ':' + params.port);
							 | 
						||
| 
								 | 
							
								        stream = net.createConnection(params.port, params.host);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (params.rfbFileOut)
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        var start = +new Date();
							 | 
						||
| 
								 | 
							
								        var wstream = fs.createWriteStream(params.rfbFileOut);
							 | 
						||
| 
								 | 
							
								        wstream.write('FBS 001.001\n');
							 | 
						||
| 
								 | 
							
								        stream.on('data', function(data) {
							 | 
						||
| 
								 | 
							
								            var sizeBuf = new Buffer(4);
							 | 
						||
| 
								 | 
							
								            var timeBuf = new Buffer(4);
							 | 
						||
| 
								 | 
							
								            var size = data.length;
							 | 
						||
| 
								 | 
							
								            sizeBuf.writeInt32BE(size, 0);
							 | 
						||
| 
								 | 
							
								            wstream.write(sizeBuf);
							 | 
						||
| 
								 | 
							
								            wstream.write(data);
							 | 
						||
| 
								 | 
							
								            timeBuf.writeInt32BE(+new Date() - start, 0);
							 | 
						||
| 
								 | 
							
								            wstream.write(timeBuf);
							 | 
						||
| 
								 | 
							
								            var padding = 3 - ((size - 1) & 0x03);
							 | 
						||
| 
								 | 
							
								            var pbuf = new Buffer(padding);
							 | 
						||
| 
								 | 
							
								            wstream.write(pbuf);             
							 | 
						||
| 
								 | 
							
								        }).on('end', function() {
							 | 
						||
| 
								 | 
							
								            wstream.end();
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return new RfbClient(stream, params);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								exports.createConnection = createConnection;
							 |