diff --git a/js/x11/core/examples/vncviewer/rfbserver.js b/js/x11/core/examples/vncviewer/rfbserver.js new file mode 100644 index 0000000..60f94c9 --- /dev/null +++ b/js/x11/core/examples/vncviewer/rfbserver.js @@ -0,0 +1,193 @@ +"use strict"; +var util = require('util'); +var net = require('net'); +var PackStream = require('./unpackstream'); +var EventEmitter = require('events').EventEmitter; +var rfb = require('./constants'); + +function RfbServer(stream, params) +{ + EventEmitter.call(this); + this.params = params; + var serv = this; + serv.stream = stream; + serv.pack_stream = new PackStream(); + serv.pack_stream.on('data', function( data ) { + serv.stream.write(data); + }); + stream.on('data', function( data ) { + serv.pack_stream.write(data); + }); + serv.writeServerVersion(); + serv.params = {}; + serv.params.password = 'tetris'; +} +util.inherits(RfbServer, EventEmitter); + +RfbServer.prototype.writeServerVersion = function() +{ + var serv = this; + this.stream.write(rfb.versionstring.V3_008); + this.pack_stream.get(12, function(buf) { + serv.emit('clientversion', buf.toString('ascii')); + console.log(['client version', buf]); + serv.writeSecurityTypes(); + }); +} + +RfbServer.prototype.writeSecurityTypes = function() +{ + console.log("RfbServer.prototype.writeSecurityTypes"); + var serv = this; + var sectypes = [rfb.security.VNC]; + serv.pack_stream.pack('C', [sectypes.length]); + serv.pack_stream.flush(); + for (var i=0; i < sectypes.length; ++i) + serv.pack_stream.pack('C', [sectypes[i]]); + serv.pack_stream.flush(); + serv.pack_stream.unpack('C', function(cliSecType) { + serv.securityType = cliSecType[0]; + serv.processSecurity(); + }); +} + +RfbServer.prototype.processSecurity = function() +{ + console.log("RfbServer.prototype.processSecurity"); + var serv = this; + switch(serv.securityType) + { + case rfb.security.None: + console.log('not yet'); + break; + case rfb.security.VNC: + // generate random 16 byte challenge + serv.challenge = new Buffer(16); + serv.challenge.write('1234567890abcdef'); + console.log(['sending challenge', serv.challenge]); + serv.pack_stream.pack('a', [serv.challenge]).flush(); + serv.pack_stream.get(16, function(clientResponseBuf) + { + var response = require('./d3des').response(serv.challenge, serv.params.password).toString('binary'); + var clientResponse = clientResponseBuf.toString('binary'); + console.log([response, clientResponse]); + if (response === clientResponse) { + serv.pack_stream.pack('L', [0]).flush(); + serv.readClientInit(); + return; + } else { + console.error('invalid password!'); + process.exit(0); + } + }) + break; + } +} + +RfbServer.prototype.readClientInit = function() +{ + // TODO: read options, add 'disconnect others' code + var serv = this; + serv.pack_stream.unpack('C', function(isShared) { + console.log([isShared]); + serv.writeServerInit(); + }); +} + +RfbServer.prototype.writeServerInit = function() +{ + var serv = this; + var title = 'Param-pam-pam'; + serv.pack_stream.pack('SSCCCCSSSCCCxxxLa', [ + 800, //serv.width, + 600, //serv.height, + 32, //serv.bpp, + 24, //serv.depth, + 1, // bigEndien + 1, // trueColor + 255, // red max + 255, // green + 255, // blue + 16, // red shift + 8, // green + 0, // blue + title.length, + title + ]); + serv.pack_stream.flush(); + serv.expectMessage(); +} + +function repeat(str, num) +{ + var res = ''; + for (var i=0; i < num; ++i) + res += str; + return res; +} + +RfbServer.prototype.expectMessage = function() +{ + var serv = this; + serv.pack_stream.get(1, function(msgType) { + switch(msgType[0]) { + case rfb.clientMsgTypes.setPixelFormat: + case rfb.clientMsgTypes.fbUpdate: + var updateRequest = {}; + serv.pack_stream.unpackTo(updateRequest, [ + 'C incremental', + 'S width', + 'S height', + 'S x', + 'S y'], + function() { + serv.emit('fbUpdate', updateRequest); + serv.expectMessage(); + }); + break; + case rfb.clientMsgTypes.setEncodings: + serv.pack_stream.unpack('xS', function(numEnc) + { + serv.pack_stream.unpack(repeat('L', numEnc), function(res) { + serv.emit('setEncodings', res); + console.log(['setEncodings', res]); + serv.expectMessage(); + }) + }); + break; + case rfb.clientMsgTypes.pointerEvent: + serv.pack_stream.unpack('CSS', function(res) { + var pointerEvent = { + buttons: res[0], + x: res[1], + y: res[2] + }; + serv.emit('pointer', pointerEvent); + console.log(['pointer', pointerEvent]); + serv.expectMessage(); + }); + break; + case rfb.clientMsgTypes.keyEvent: + serv.pack_stream.unpack('CxxL', function(res) { + var keyEvent = { + isDown: res[0], + keysym: res[1] + }; + serv.emit('key', keyEvent); + console.log(['key', keyEvent]); + serv.expectMessage(); + }); + break; + case rfb.clientMsgTypes.cutText: + break; + console.log('Got message from client: ' + msgType[0]); + } + + }); +} + + +var s = net.createServer(function(conn) { + var rfbserv = new RfbServer(conn); +}); +s.listen(5910);