194 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "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);
 |