mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			462 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			462 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
| Copyright 2018-2020 Intel Corporation
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| var MemoryStream = require('MemoryStream');
 | |
| var lme_id = 0;             // Our next channel identifier
 | |
| var lme_port_offset = 0;    // Debug: Set this to "-100" to bind to 16892 & 16893 and IN_ADDRANY. This is for LMS debugging.
 | |
| var xmlParser = null;
 | |
| try { xmlParser = require('amt-xml'); } catch (ex) { }
 | |
| 
 | |
| // Documented in: https://software.intel.com/sites/manageability/AMT_Implementation_and_Reference_Guide/HTMLDocuments/MPSDocuments/Intel%20AMT%20Port%20Forwarding%20Protocol%20Reference%20Manual.pdf
 | |
| var APF_DISCONNECT = 1;
 | |
| var APF_SERVICE_REQUEST = 5;
 | |
| var APF_SERVICE_ACCEPT = 6;
 | |
| var APF_USERAUTH_REQUEST = 50;
 | |
| var APF_USERAUTH_FAILURE = 51;
 | |
| var APF_USERAUTH_SUCCESS = 52;
 | |
| var APF_GLOBAL_REQUEST = 80;
 | |
| var APF_REQUEST_SUCCESS = 81;
 | |
| var APF_REQUEST_FAILURE = 82;
 | |
| var APF_CHANNEL_OPEN = 90;
 | |
| var APF_CHANNEL_OPEN_CONFIRMATION = 91;
 | |
| var APF_CHANNEL_OPEN_FAILURE = 92;
 | |
| var APF_CHANNEL_WINDOW_ADJUST = 93;
 | |
| var APF_CHANNEL_DATA = 94;
 | |
| var APF_CHANNEL_CLOSE = 97;
 | |
| var APF_PROTOCOLVERSION = 192;
 | |
| 
 | |
| 
 | |
| function lme_object() {
 | |
|     this.ourId = ++lme_id;
 | |
|     this.amtId = -1;
 | |
|     this.LME_CHANNEL_STATUS = 'LME_CS_FREE';
 | |
|     this.txWindow = 0;
 | |
|     this.rxWindow = 0;
 | |
|     this.localPort = 0;
 | |
|     this.errorCount = 0;
 | |
| }
 | |
| 
 | |
| function stream_bufferedWrite() {
 | |
|     var emitterUtils = require('events').inherits(this);
 | |
|     this.buffer = [];
 | |
|     this._readCheckImmediate = undefined;
 | |
|     this._ObjectID = "bufferedWriteStream";
 | |
|     // Writable Events
 | |
|     emitterUtils.createEvent('close');
 | |
|     emitterUtils.createEvent('drain');
 | |
|     emitterUtils.createEvent('error');
 | |
|     emitterUtils.createEvent('finish');
 | |
|     emitterUtils.createEvent('pipe');
 | |
|     emitterUtils.createEvent('unpipe');
 | |
|     
 | |
|     // Readable Events
 | |
|     emitterUtils.createEvent('readable');
 | |
|     this.isEmpty = function () {
 | |
|         return (this.buffer.length == 0);
 | |
|     };
 | |
|     this.isWaiting = function () {
 | |
|         return (this._readCheckImmediate == undefined);
 | |
|     };
 | |
|     this.write = function (chunk) {
 | |
|         for (var args in arguments) { if (typeof (arguments[args]) == 'function') { this.once('drain', arguments[args]); break; } }
 | |
|         var tmp = Buffer.alloc(chunk.length);
 | |
|         chunk.copy(tmp);
 | |
|         this.buffer.push({ offset: 0, data: tmp });
 | |
|         this.emit('readable');
 | |
|         return (this.buffer.length == 0 ? true : false);
 | |
|     };
 | |
|     this.read = function () {
 | |
|         var size = arguments.length == 0 ? undefined : arguments[0];
 | |
|         var bytesRead = 0;
 | |
|         var list = [];
 | |
|         while ((size == undefined || bytesRead < size) && this.buffer.length > 0) {
 | |
|             var len = this.buffer[0].data.length - this.buffer[0].offset;
 | |
|             var offset = this.buffer[0].offset;
 | |
|             
 | |
|             if (len > (size - bytesRead)) {
 | |
|                 // Only reading a subset
 | |
|                 list.push(this.buffer[0].data.slice(offset, offset + size - bytesRead));
 | |
|                 this.buffer[0].offset += (size - bytesRead);
 | |
|                 bytesRead += (size - bytesRead);
 | |
|             } else {
 | |
|                 // Reading the entire thing
 | |
|                 list.push(this.buffer[0].data.slice(offset));
 | |
|                 bytesRead += len;
 | |
|                 this.buffer.shift();
 | |
|             }
 | |
|         }
 | |
|         this._readCheckImmediate = setImmediate(function (buffered) {
 | |
|             buffered._readCheckImmediate = undefined;
 | |
|             if (buffered.buffer.length == 0) {
 | |
|                 buffered.emit('drain'); // Drained
 | |
|             } else {
 | |
|                 buffered.emit('readable'); // Not drained
 | |
|             }
 | |
|         }, this);
 | |
|         return (Buffer.concat(list));
 | |
|     };
 | |
| }
 | |
| 
 | |
| 
 | |
| function lme_heci(options) {
 | |
|     var emitterUtils = require('events').inherits(this);
 | |
|     emitterUtils.createEvent('error');
 | |
|     emitterUtils.createEvent('connect');
 | |
|     emitterUtils.createEvent('notify');
 | |
|     emitterUtils.createEvent('bind');
 | |
|     
 | |
|     this.on('newListener', function (name, func) { if (name == 'connect' && this._LME._connected == true) { func.call(this);} });
 | |
|     if ((options != null) && (options.debug == true)) { lme_port_offset = -100; } // LMS debug mode
 | |
| 
 | |
|     var heci = require('heci');
 | |
|     this.INITIAL_RXWINDOW_SIZE = 4096;
 | |
|     
 | |
|     this._ObjectID = "lme";
 | |
|     this._LME = heci.create();
 | |
|     this._LME._connected = false;
 | |
|     this._LME.descriptorMetadata = "amt-lme";
 | |
|     this._LME._binded = {};
 | |
|     this._LME.LMS = this;
 | |
|     this._LME.on('error', function (e) { this.LMS.emit('error', e); });
 | |
|     this._LME.on('connect', function ()
 | |
|     {
 | |
|         this._connected = true;
 | |
|         this.on('data', function (chunk) {
 | |
|             // this = HECI
 | |
|             var cmd = chunk.readUInt8(0);
 | |
|             //console.log('LME Command ' + cmd + ', ' + chunk.length + ' byte(s).');
 | |
|             
 | |
|             switch (cmd) {
 | |
|                 default:
 | |
|                     console.log('Unhandled LME Command ' + cmd + ', ' + chunk.length + ' byte(s).');
 | |
|                     break;
 | |
|                 case APF_SERVICE_REQUEST:
 | |
|                     var nameLen = chunk.readUInt32BE(1);
 | |
|                     var name = chunk.slice(5, nameLen + 5);
 | |
|                     //console.log("Service Request for: " + name);
 | |
|                     if (name == 'pfwd@amt.intel.com' || name == 'auth@amt.intel.com') {
 | |
|                         var outBuffer = Buffer.alloc(5 + nameLen);
 | |
|                         outBuffer.writeUInt8(6, 0);
 | |
|                         outBuffer.writeUInt32BE(nameLen, 1);
 | |
|                         outBuffer.write(name.toString(), 5);
 | |
|                         this.write(outBuffer);
 | |
|                         //console.log('Answering APF_SERVICE_REQUEST');
 | |
|                     } else {
 | |
|                         //console.log('UNKNOWN APF_SERVICE_REQUEST');
 | |
|                     }
 | |
|                     break;
 | |
|                 case APF_GLOBAL_REQUEST:
 | |
|                     var nameLen = chunk.readUInt32BE(1);
 | |
|                     var name = chunk.slice(5, nameLen + 5).toString();
 | |
| 
 | |
|                     switch (name) {
 | |
|                         case 'tcpip-forward':
 | |
|                             var len = chunk.readUInt32BE(nameLen + 6);
 | |
|                             var port = chunk.readUInt32BE(nameLen + 10 + len);
 | |
|                             //console.log("[" + chunk.length + "/" + len + "] APF_GLOBAL_REQUEST for: " + name + " on port " + port);
 | |
|                             if (this[name] == undefined) { this[name] = {}; }
 | |
|                             if (this[name][port] != null) { // Close the existing binding
 | |
|                                 for (var i in this.sockets) {
 | |
|                                     var channel = this.sockets[i];
 | |
|                                     if (channel.localPort == port) { this.sockets[i].end(); delete this.sockets[i]; } // Close this socket
 | |
|                                 }
 | |
|                             }
 | |
|                             if (this[name][port] == null)
 | |
|                             {
 | |
|                                 try {
 | |
|                                     // Bind a new server socket if not already present
 | |
|                                     this[name][port] = require('net').createServer();
 | |
|                                     this[name][port].descriptorMetadata = 'amt-lme (port: ' + port + ')';
 | |
|                                     this[name][port].HECI = this;
 | |
|                                     if (lme_port_offset == 0) {
 | |
|                                         this[name][port].listen({ port: port, host: '127.0.0.1' }); // Normal mode
 | |
|                                     } else {
 | |
|                                         this[name][port].listen({ port: (port + lme_port_offset) }); // Debug mode
 | |
|                                     }
 | |
|                                     this[name][port].on('connection', function (socket) {
 | |
|                                         //console.log('New [' + socket.remoteFamily + '] TCP Connection on: ' + socket.remoteAddress + ' :' + socket.localPort);
 | |
|                                         this.HECI.LMS.bindDuplexStream(socket, socket.remoteFamily, socket.localPort - lme_port_offset);
 | |
|                                     });
 | |
|                                     this._binded[port] = true;
 | |
|                                     this.LMS.emit('bind', this._binded);
 | |
|                                 } catch (ex) { console.log(ex, 'Port ' + port); }
 | |
|                             }
 | |
|                             var outBuffer = Buffer.alloc(5);
 | |
|                             outBuffer.writeUInt8(81, 0);
 | |
|                             outBuffer.writeUInt32BE(port, 1);
 | |
|                             this.write(outBuffer);
 | |
|                             break;
 | |
|                         case 'cancel-tcpip-forward':
 | |
|                             var outBuffer = Buffer.alloc(1);
 | |
|                             outBuffer.writeUInt8(APF_REQUEST_SUCCESS, 0);
 | |
|                             this.write(outBuffer);
 | |
|                             break;
 | |
|                         case 'udp-send-to@amt.intel.com':
 | |
|                             var outBuffer = Buffer.alloc(1);
 | |
|                             outBuffer.writeUInt8(APF_REQUEST_FAILURE, 0);
 | |
|                             this.write(outBuffer);
 | |
|                             break;
 | |
|                         default:
 | |
|                             //console.log("Unknown APF_GLOBAL_REQUEST for: " + name);
 | |
|                             break;
 | |
|                     }
 | |
|                     break;
 | |
|                 case APF_CHANNEL_OPEN_CONFIRMATION:
 | |
|                     var rChannel = chunk.readUInt32BE(1);
 | |
|                     var sChannel = chunk.readUInt32BE(5);
 | |
|                     var wSize = chunk.readUInt32BE(9);
 | |
|                     //console.log('rChannel/' + rChannel + ', sChannel/' + sChannel + ', wSize/' + wSize);
 | |
|                     if (this.sockets[rChannel] != undefined) {
 | |
|                         this.sockets[rChannel].lme.amtId = sChannel;
 | |
|                         this.sockets[rChannel].lme.rxWindow = wSize;
 | |
|                         this.sockets[rChannel].lme.txWindow = wSize;
 | |
|                         this.sockets[rChannel].lme.LME_CHANNEL_STATUS = 'LME_CS_CONNECTED';
 | |
|                         //console.log('LME_CS_CONNECTED');
 | |
|                         this.sockets[rChannel].bufferedStream = new stream_bufferedWrite();
 | |
|                         this.sockets[rChannel].bufferedStream.socket = this.sockets[rChannel];
 | |
|                         this.sockets[rChannel].bufferedStream.on('readable', function () {
 | |
|                             if (this.socket.lme.txWindow > 0) {
 | |
|                                 var buffer = this.read(this.socket.lme.txWindow);
 | |
|                                 var packet = Buffer.alloc(9 + buffer.length);
 | |
|                                 packet.writeUInt8(APF_CHANNEL_DATA, 0);
 | |
|                                 packet.writeUInt32BE(this.socket.lme.amtId, 1);
 | |
|                                 packet.writeUInt32BE(buffer.length, 5);
 | |
|                                 buffer.copy(packet, 9);
 | |
|                                 this.socket.lme.txWindow -= buffer.length;
 | |
|                                 this.socket.HECI.write(packet);
 | |
|                             }
 | |
|                         });
 | |
|                         this.sockets[rChannel].bufferedStream.on('drain', function () {
 | |
|                             this.socket.resume();
 | |
|                         });
 | |
|                         this.sockets[rChannel].on('data', function (chunk) {
 | |
|                             if (!this.bufferedStream.write(chunk)) { this.pause(); }
 | |
|                         });
 | |
|                         this.sockets[rChannel].on('end', function () {
 | |
|                             var outBuffer = Buffer.alloc(5);
 | |
|                             outBuffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
 | |
|                             outBuffer.writeUInt32BE(this.lme.amtId, 1);
 | |
|                             this.HECI.write(outBuffer);
 | |
|                         });
 | |
|                         this.sockets[rChannel].resume();
 | |
|                     }
 | |
|                     
 | |
|                     break;
 | |
|                 case APF_PROTOCOLVERSION:
 | |
|                     var major = chunk.readUInt32BE(1);
 | |
|                     var minor = chunk.readUInt32BE(5);
 | |
|                     var reason = chunk.readUInt32BE(9);
 | |
|                     var outBuffer = Buffer.alloc(93);
 | |
|                     outBuffer.writeUInt8(192, 0);
 | |
|                     outBuffer.writeUInt32BE(1, 1);
 | |
|                     outBuffer.writeUInt32BE(0, 5);
 | |
|                     outBuffer.writeUInt32BE(reason, 9);
 | |
|                     //console.log('Answering PROTOCOL_VERSION');
 | |
|                     this.write(outBuffer);
 | |
|                     break;
 | |
|                 case APF_CHANNEL_WINDOW_ADJUST:
 | |
|                     var rChannelId = chunk.readUInt32BE(1);
 | |
|                     var bytesToAdd = chunk.readUInt32BE(5);
 | |
|                     if (this.sockets[rChannelId] != undefined) {
 | |
|                         this.sockets[rChannelId].lme.txWindow += bytesToAdd;
 | |
|                         if (!this.sockets[rChannelId].bufferedStream.isEmpty() && this.sockets[rChannelId].bufferedStream.isWaiting()) {
 | |
|                             this.sockets[rChannelId].bufferedStream.emit('readable');
 | |
|                         }
 | |
|                     } else {
 | |
|                         console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_WINDOW_ADJUST');
 | |
|                     }
 | |
|                     break;
 | |
|                 case APF_CHANNEL_DATA:
 | |
|                     var rChannelId = chunk.readUInt32BE(1);
 | |
|                     var dataLen = chunk.readUInt32BE(5);
 | |
|                     var data = chunk.slice(9, 9 + dataLen);
 | |
|                     if ((this.sockets != null) && (this.sockets[rChannelId] != undefined)) {
 | |
|                         this.sockets[rChannelId].pendingBytes.push(data.length);
 | |
|                         this.sockets[rChannelId].write(data, function () {
 | |
|                             var written = this.pendingBytes.shift();
 | |
|                             //console.log('adjust', this.lme.amtId, written);
 | |
|                             var outBuffer = Buffer.alloc(9);
 | |
|                             outBuffer.writeUInt8(APF_CHANNEL_WINDOW_ADJUST, 0);
 | |
|                             outBuffer.writeUInt32BE(this.lme.amtId, 1);
 | |
|                             outBuffer.writeUInt32BE(written, 5);
 | |
|                             this.HECI.write(outBuffer);
 | |
|                         });
 | |
|                     } else if ((this.insockets != null) && (this.insockets[rChannelId] != undefined)) {
 | |
|                         var channel = this.insockets[rChannelId];
 | |
|                         if (channel.data == null) { channel.data = data.toString(); } else { channel.data += data.toString(); }
 | |
|                         channel.rxWindow += dataLen;
 | |
|                         //console.log('IN DATA', channel.rxWindow, channel.data.length, dataLen, channel.amtId, data.toString());
 | |
|                         var httpData = parseHttp(channel.data);
 | |
|                         if ((httpData != null) || (channel.data.length >= 8000)) {
 | |
|                             // Parse the WSMAN
 | |
|                             var notify = null;
 | |
|                             if (xmlParser != null) { try { notify = xmlParser.ParseWsman(httpData); } catch (e) { } }
 | |
| 
 | |
|                             // Event the http data
 | |
|                             if (notify != null) { this.LMS.emit('notify', notify, channel.options, _lmsNotifyToCode(notify)); }
 | |
| 
 | |
|                             // Send channel close
 | |
|                             var buffer = Buffer.alloc(5);
 | |
|                             buffer.writeUInt8(APF_CHANNEL_CLOSE, 0);
 | |
|                             buffer.writeUInt32BE(amtId, 1);
 | |
|                             this.write(buffer);
 | |
|                         } else {
 | |
|                             if (channel.rxWindow > 6000) {
 | |
|                                 // Send window adjust
 | |
|                                 var buffer = Buffer.alloc(9);
 | |
|                                 buffer.writeUInt8(APF_CHANNEL_WINDOW_ADJUST, 0);
 | |
|                                 buffer.writeUInt32BE(channel.amtId, 1);
 | |
|                                 buffer.writeUInt32BE(channel.rxWindow, 5);
 | |
|                                 this.write(buffer);
 | |
|                                 channel.rxWindow = 0;
 | |
|                             }
 | |
|                         }
 | |
|                     } else {
 | |
|                         console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_DATA');
 | |
|                     }
 | |
|                     break;
 | |
|                 case APF_CHANNEL_OPEN_FAILURE:
 | |
|                     var rChannelId = chunk.readUInt32BE(1);
 | |
|                     var reasonCode = chunk.readUInt32BE(5);
 | |
|                     if ((this.sockets != null) && (this.sockets[rChannelId] != undefined)) {
 | |
|                         this.sockets[rChannelId].end();
 | |
|                         delete this.sockets[rChannelId];
 | |
|                     } else if ((this.insockets != null) && (this.insockets[rChannelId] != undefined)) {
 | |
|                         delete this.insockets[rChannelId];
 | |
|                     } else {
 | |
|                         console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_OPEN_FAILURE');
 | |
|                     }
 | |
|                     break;
 | |
|                 case APF_CHANNEL_CLOSE:
 | |
|                     var rChannelId = chunk.readUInt32BE(1);
 | |
|                     if ((this.sockets != null) && (this.sockets[rChannelId] != undefined)) {
 | |
|                         this.sockets[rChannelId].end();
 | |
|                         var amtId = this.sockets[rChannelId].lme.amtId;
 | |
|                         var buffer = Buffer.alloc(5);
 | |
|                         delete this.sockets[rChannelId];
 | |
|                         
 | |
|                         buffer.writeUInt8(APF_CHANNEL_CLOSE, 0); // ????????????????????????????
 | |
|                         buffer.writeUInt32BE(amtId, 1);
 | |
|                         this.write(buffer);
 | |
|                     } else if ((this.insockets != null) && (this.insockets[rChannelId] != undefined)) {
 | |
|                         delete this.insockets[rChannelId];
 | |
|                         // Should I send a close back????
 | |
|                     } else {
 | |
|                         console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_CLOSE');
 | |
|                     }
 | |
|                     break;
 | |
|                 case APF_CHANNEL_OPEN:
 | |
|                     var nameLen = chunk.readUInt32BE(1);
 | |
|                     var name = chunk.slice(5, nameLen + 5).toString();
 | |
|                     var channelSender = chunk.readUInt32BE(nameLen + 5);
 | |
|                     var initialWindowSize = chunk.readUInt32BE(nameLen + 9);
 | |
|                     var hostToConnectLen = chunk.readUInt32BE(nameLen + 17);
 | |
|                     var hostToConnect = chunk.slice(nameLen + 21, nameLen + 21 + hostToConnectLen).toString();
 | |
|                     var portToConnect = chunk.readUInt32BE(nameLen + 21 + hostToConnectLen);
 | |
|                     var originatorIpLen = chunk.readUInt32BE(nameLen + 25 + hostToConnectLen);
 | |
|                     var originatorIp = chunk.slice(nameLen + 29 + hostToConnectLen, nameLen + 29 + hostToConnectLen + originatorIpLen).toString();
 | |
|                     var originatorPort = chunk.readUInt32BE(nameLen + 29 + hostToConnectLen + originatorIpLen);
 | |
|                     //console.log('APF_CHANNEL_OPEN', name, channelSender, initialWindowSize, 'From: ' + originatorIp + ':' + originatorPort, 'To: ' + hostToConnect + ':' + portToConnect);
 | |
| 
 | |
|                     if (this.insockets == null) { this.insockets = {}; }
 | |
|                     var ourId = ++lme_id;
 | |
|                     var insocket = new lme_object();
 | |
|                     insocket.ourId = ourId;
 | |
|                     insocket.amtId = channelSender;
 | |
|                     insocket.txWindow = initialWindowSize;
 | |
|                     insocket.rxWindow = 0;
 | |
|                     insocket.options = { target: hostToConnect, targetPort: portToConnect, source: originatorIp, sourcePort: originatorPort };
 | |
|                     this.insockets[ourId] = insocket;
 | |
| 
 | |
|                     var buffer = Buffer.alloc(17);
 | |
|                     buffer.writeUInt8(APF_CHANNEL_OPEN_CONFIRMATION, 0);
 | |
|                     buffer.writeUInt32BE(channelSender, 1);     // Intel AMT sender channel
 | |
|                     buffer.writeUInt32BE(ourId, 5);             // Our receiver channel id
 | |
|                     buffer.writeUInt32BE(4000, 9);              // Initial Window Size
 | |
|                     buffer.writeUInt32BE(0xFFFFFFFF, 13);       // Reserved
 | |
|                     this.write(buffer);
 | |
| 
 | |
|                     /*
 | |
|                     var buffer = Buffer.alloc(17);
 | |
|                     buffer.writeUInt8(APF_CHANNEL_OPEN_FAILURE, 0);
 | |
|                     buffer.writeUInt32BE(channelSender, 1);     // Intel AMT sender channel
 | |
|                     buffer.writeUInt32BE(2, 5);                 // Reason code
 | |
|                     buffer.writeUInt32BE(0, 9);                 // Reserved
 | |
|                     buffer.writeUInt32BE(0, 13);                // Reserved
 | |
|                     this.write(buffer);
 | |
|                     console.log('Sent APF_CHANNEL_OPEN_FAILURE', channelSender);
 | |
|                     */
 | |
| 
 | |
|                     break;
 | |
|             }
 | |
|         });
 | |
|         this.LMS.emit('connect');
 | |
|         this.resume();
 | |
| 
 | |
|     });
 | |
|     
 | |
|     this.bindDuplexStream = function (duplexStream, remoteFamily, localPort) {
 | |
|         var socket = duplexStream;
 | |
|         //console.log('New [' + remoteFamily + '] Virtual Connection/' + socket.localPort);
 | |
|         socket.pendingBytes = [];
 | |
|         socket.HECI = this._LME;
 | |
|         socket.LMS = this;
 | |
|         socket.lme = new lme_object();
 | |
|         socket.lme.Socket = socket;
 | |
|         socket.localPort = localPort;
 | |
|         var buffer = new MemoryStream();
 | |
|         buffer.writeUInt8(0x5A);
 | |
|         buffer.writeUInt32BE(15);
 | |
|         buffer.write('forwarded-tcpip');
 | |
|         buffer.writeUInt32BE(socket.lme.ourId);
 | |
|         buffer.writeUInt32BE(this.INITIAL_RXWINDOW_SIZE);
 | |
|         buffer.writeUInt32BE(0xFFFFFFFF);
 | |
|         for (var i = 0; i < 2; ++i) {
 | |
|             if (remoteFamily == 'IPv6') {
 | |
|                 buffer.writeUInt32BE(3);
 | |
|                 buffer.write('::1');
 | |
|             } else {
 | |
|                 buffer.writeUInt32BE(9);
 | |
|                 buffer.write('127.0.0.1');
 | |
|             }
 | |
|             buffer.writeUInt32BE(localPort);
 | |
|         }
 | |
|         this._LME.write(buffer.buffer);
 | |
|         if (this._LME.sockets == undefined) { this._LME.sockets = {}; }
 | |
|         this._LME.sockets[socket.lme.ourId] = socket;
 | |
|         socket.pause();
 | |
|     };
 | |
|     
 | |
|     this._LME.connect(heci.GUIDS.LME, { noPipeline: 0 });
 | |
| }
 | |
| 
 | |
| function parseHttp(httpData) {
 | |
|     var i = httpData.indexOf('\r\n\r\n');
 | |
|     if ((i == -1) || (httpData.length < (i + 2))) { return null; }
 | |
|     var headers = require('http-headers')(httpData.substring(0, i), true);
 | |
|     var contentLength = parseInt(headers['content-length']);
 | |
|     if (httpData.length >= contentLength + i + 4) { return httpData.substring(i + 4, i + 4 + contentLength); }
 | |
|     return null;
 | |
| }
 | |
| 
 | |
| function _lmsNotifyToCode(notify) {
 | |
|     if ((notify == null) || (notify.Body == null) || (notify.Body.MessageID == null)) return null;
 | |
|     var msgid = notify.Body.MessageID;
 | |
|     try { msgid += '-' + notify.Body.MessageArguments[0]; } catch (e) { }
 | |
|     return msgid;
 | |
| }
 | |
| 
 | |
| module.exports = lme_heci;
 |