mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-03-09 15:40:18 +00:00
Added SMTP email support, email verification and password reset support
This commit is contained in:
parent
e740045b39
commit
72ee422623
24 changed files with 2586 additions and 166 deletions
281
agents/modules_meshcmd/amt_heci.js
Normal file
281
agents/modules_meshcmd/amt_heci.js
Normal file
|
@ -0,0 +1,281 @@
|
|||
var Q = require('queue');
|
||||
|
||||
function amt_heci() {
|
||||
var emitterUtils = require('events').inherits(this);
|
||||
emitterUtils.createEvent('error');
|
||||
emitterUtils.createEvent('connect');
|
||||
|
||||
var heci = require('heci');
|
||||
|
||||
this._amt = heci.create();
|
||||
this._amt.BiosVersionLen = 65;
|
||||
this._amt.UnicodeStringLen = 20;
|
||||
|
||||
this._amt.rq = new Q();
|
||||
this._amt.Parent = this;
|
||||
this._amt.on('error', function (e) { this.Parent.emit('error', e); });
|
||||
this._amt.on('connect', function () {
|
||||
this.Parent.emit('connect');
|
||||
this.on('data', function (chunk) {
|
||||
//console.log("Received: " + chunk.length + " bytes");
|
||||
var header = this.Parent.getCommand(chunk);
|
||||
//console.log("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse);
|
||||
|
||||
var user = this.rq.deQueue();
|
||||
var params = user.optional;
|
||||
var callback = user.func;
|
||||
|
||||
params.unshift(header);
|
||||
callback.apply(this.Parent, params);
|
||||
});
|
||||
});
|
||||
this._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 });
|
||||
|
||||
this.getCommand = function (chunk) {
|
||||
var command = chunk.length == 0 ? (this._amt.rq.peekQueue().cmd | 0x800000) : chunk.readUInt32LE(4);
|
||||
var ret = { IsResponse: (command & 0x800000) == 0x800000 ? true : false, Command: (command & 0x7FFFFF), Status: chunk.length != 0 ? chunk.readUInt32LE(12) : -1, Data: chunk.length != 0 ? chunk.slice(16) : null };
|
||||
return (ret);
|
||||
};
|
||||
|
||||
this.sendCommand = function () {
|
||||
if (arguments.length < 3 || typeof (arguments[0]) != 'number' || typeof (arguments[1]) != 'object' || typeof (arguments[2]) != 'function') { throw ('invalid parameters'); }
|
||||
var args = [];
|
||||
for (var i = 3; i < arguments.length; ++i) { args.push(arguments[i]); }
|
||||
|
||||
this._amt.rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args });
|
||||
|
||||
var header = Buffer.from('010100000000000000000000', 'hex');
|
||||
header.writeUInt32LE(arguments[0] | 0x04000000, 4);
|
||||
header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8);
|
||||
|
||||
this._amt.write(arguments[1] == null ? header : Buffer.concat([header, arguments[1]]));
|
||||
}
|
||||
|
||||
this.getVersion = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(26, null, function (header, fn, opt) {
|
||||
if (header.Status == 0) {
|
||||
var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, this._amt.BiosVersionLen), Versions: [] }, v = CodeVersion.slice(this._amt.BiosVersionLen + 4);
|
||||
for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen) ; ++i) {
|
||||
val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + this._amt.UnicodeStringLen, 4 + this._amt.UnicodeStringLen + v.readUInt16LE(2 + this._amt.UnicodeStringLen)).toString() };
|
||||
v = v.slice(4 + (2 * this._amt.UnicodeStringLen));
|
||||
}
|
||||
opt.unshift(val);
|
||||
} else {
|
||||
opt.unshift(null);
|
||||
}
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
};
|
||||
|
||||
this.getProvisioningState = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(17, null, function (header, fn, opt) {
|
||||
if (header.Status == 0) {
|
||||
var result = {};
|
||||
result.state = header.Data.readUInt32LE(0);
|
||||
if (result.state < 3) { result.stateStr = ["PRE", "IN", "POST"][result.state]; }
|
||||
opt.unshift(result);
|
||||
} else {
|
||||
opt.unshift(null);
|
||||
}
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
};
|
||||
this.getProvisioningMode = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(8, null, function (header, fn, opt) {
|
||||
if (header.Status == 0) {
|
||||
var result = {};
|
||||
result.mode = header.Data.readUInt32LE(0);
|
||||
if (result.mode < 4) { result.modeStr = ["NONE", "ENTERPRISE", "SMALL_BUSINESS", "REMOTE_ASSISTANCE"][result.mode]; }
|
||||
result.legacy = header.Data.readUInt32LE(4) == 0 ? false : true;
|
||||
opt.unshift(result);
|
||||
} else {
|
||||
opt.unshift(null);
|
||||
}
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
};
|
||||
this.getEHBCState = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(132, null, function (header, fn, opt) {
|
||||
if (header.Status == 0) {
|
||||
opt.unshift({ EHBC: header.Data.readUInt32LE(0) != 0 });
|
||||
} else {
|
||||
opt.unshift(null);
|
||||
}
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
};
|
||||
this.getControlMode = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(107, null, function (header, fn, opt) {
|
||||
if (header.Status == 0) {
|
||||
var result = {};
|
||||
result.controlMode = header.Data.readUInt32LE(0);
|
||||
if (result.controlMode < 3) { result.controlModeStr = ["NONE_RPAT", "CLIENT", "ADMIN", "REMOTE_ASSISTANCE"][result.controlMode]; }
|
||||
opt.unshift(result);
|
||||
} else {
|
||||
opt.unshift(null);
|
||||
}
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
};
|
||||
this.getMACAddresses = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(37, null, function (header, fn, opt) {
|
||||
if (header.Status == 0) {
|
||||
opt.unshift({ DedicatedMAC: header.Data.slice(0, 6).toString('hex:'), HostMAC: header.Data.slice(6, 12).toString('hex:') });
|
||||
} else { opt.unshift({ DedicatedMAC: null, HostMAC: null }); }
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
};
|
||||
this.getDnsSuffix = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(54, null, function (header, fn, opt) {
|
||||
if (header.Status == 0) {
|
||||
var resultLen = header.Data.readUInt16LE(0);
|
||||
if (resultLen > 0) { opt.unshift(header.Data.slice(2, 2 + resultLen).toString()); } else { opt.unshift(null); }
|
||||
} else {
|
||||
opt.unshift(null);
|
||||
}
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
};
|
||||
this.getHashHandles = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(0x2C, null, function (header, fn, opt) {
|
||||
var result = [];
|
||||
if (header.Status == 0) {
|
||||
var resultLen = header.Data.readUInt32LE(0);
|
||||
for (var i = 0; i < resultLen; ++i) {
|
||||
result.push(header.Data.readUInt32LE(4 + (4 * i)));
|
||||
}
|
||||
}
|
||||
opt.unshift(result);
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
};
|
||||
this.getCertHashEntry = function (handle, callback) {
|
||||
var optional = [];
|
||||
for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
|
||||
var data = new Buffer(4);
|
||||
data.writeUInt32LE(handle, 0);
|
||||
|
||||
this.sendCommand(0x2D, data, function (header, fn, opt) {
|
||||
if (header.Status == 0) {
|
||||
var result = {};
|
||||
result.isDefault = header.Data.readUInt32LE(0);
|
||||
result.isActive = header.Data.readUInt32LE(4);
|
||||
result.hashAlgorithm = header.Data.readUInt8(72);
|
||||
if (result.hashAlgorithm < 4) {
|
||||
result.hashAlgorithmStr = ["MD5", "SHA1", "SHA256", "SHA512"][result.hashAlgorithm];
|
||||
result.hashAlgorithmSize = [16, 20, 32, 64][result.hashAlgorithm];
|
||||
result.certificateHash = header.Data.slice(8, 8 + result.hashAlgorithmSize).toString('hex');
|
||||
}
|
||||
result.name = header.Data.slice(73 + 2, 73 + 2 + header.Data.readUInt16LE(73)).toString();
|
||||
opt.unshift(result);
|
||||
} else {
|
||||
opt.unshift(null);
|
||||
}
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
};
|
||||
this.getCertHashEntries = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
|
||||
this.getHashHandles(function (handles, fn, opt) {
|
||||
var entries = [];
|
||||
this.getCertHashEntry(handles.shift(), this._getHashEntrySink, fn, opt, entries, handles);
|
||||
}, callback, optional);
|
||||
};
|
||||
this._getHashEntrySink = function (result, fn, opt, entries, handles) {
|
||||
entries.push(result);
|
||||
if (handles.length > 0) {
|
||||
this.getCertHashEntry(handles.shift(), this._getHashEntrySink, fn, opt, entries, handles);
|
||||
} else {
|
||||
opt.unshift(entries);
|
||||
fn.apply(this, opt);
|
||||
}
|
||||
}
|
||||
this.getLocalSystemAccount = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) {
|
||||
if (header.Data.length == 68) { opt.unshift({ user: header.Data.slice(0, 34).toString(), pass: header.Data.slice(34, 67).toString(), raw: header.Data }); } else { opt.unshift(null); }
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
}
|
||||
this.unprovision = function (mode, callback) {
|
||||
var optional = [];
|
||||
for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
var data = new Buffer(4);
|
||||
data.writeUInt32LE(mode, 0);
|
||||
this.sendCommand(16, data, function (header, fn, opt) {
|
||||
opt.unshift(header.Status);
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
}
|
||||
this.startConfiguration = function () {
|
||||
var optional = [];
|
||||
for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(0x29, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
|
||||
}
|
||||
this.stopConfiguration = function () {
|
||||
var optional = [];
|
||||
for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(0x5E, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
|
||||
}
|
||||
this.openUserInitiatedConnection = function () {
|
||||
var optional = [];
|
||||
for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(0x44, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
|
||||
}
|
||||
this.closeUserInitiatedConnection = function () {
|
||||
var optional = [];
|
||||
for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(0x45, data, function (header, fn, opt) { opt.unshift(header.Status); fn.apply(this, opt); }, callback, optional);
|
||||
}
|
||||
this.getRemoteAccessConnectionStatus = function () {
|
||||
var optional = [];
|
||||
for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
|
||||
this.sendCommand(0x46, data, function (header, fn, opt) {
|
||||
if (header.Status == 0) {
|
||||
var hostname = v.slice(14, header.Data.readUInt16LE(12) + 14).toString()
|
||||
opt.unshift({ status: header.Status, networkStatus: header.Data.readUInt32LE(0), remoteAccessStatus: header.Data.readUInt32LE(4), remoteAccessTrigger: header.Data.readUInt32LE(8), mpsHostname: hostname, raw: header.Data });
|
||||
} else {
|
||||
opt.unshift({ status: header.Status });
|
||||
}
|
||||
fn.apply(this, opt);
|
||||
}, callback, optional);
|
||||
}
|
||||
this.getProtocolVersion = function (callback) {
|
||||
var optional = [];
|
||||
for (var i = 1; i < arguments.length; ++i) { opt.push(arguments[i]); }
|
||||
|
||||
heci.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) {
|
||||
if (status == 0) {
|
||||
var result = buffer.readUInt8(0).toString() + '.' + buffer.readUInt8(1).toString() + '.' + buffer.readUInt8(2).toString() + '.' + buffer.readUInt16BE(3).toString();
|
||||
opt.unshift(result);
|
||||
fn.apply(self, opt);
|
||||
}
|
||||
else {
|
||||
opt.unshift(null);
|
||||
fn.apply(self, opt);
|
||||
}
|
||||
}, this, callback, optional);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = amt_heci;
|
354
agents/modules_meshcmd/lme_heci.js
Normal file
354
agents/modules_meshcmd/lme_heci.js
Normal file
|
@ -0,0 +1,354 @@
|
|||
|
||||
var MemoryStream = require('MemoryStream');
|
||||
var lme_id = 0;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
// 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)
|
||||
{
|
||||
// drained
|
||||
buffered.emit('drain');
|
||||
}
|
||||
else
|
||||
{
|
||||
// not drained
|
||||
buffered.emit('readable');
|
||||
}
|
||||
}, this);
|
||||
return (Buffer.concat(list));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function lme_heci()
|
||||
{
|
||||
var emitterUtils = require('events').inherits(this);
|
||||
emitterUtils.createEvent('error');
|
||||
emitterUtils.createEvent('connect');
|
||||
|
||||
var heci = require('heci');
|
||||
this.INITIAL_RXWINDOW_SIZE = 4096;
|
||||
|
||||
this._LME = heci.create();
|
||||
this._LME.LMS = this;
|
||||
this._LME.on('error', function (e) { this.Parent.emit('error', e); });
|
||||
this._LME.on('connect', function ()
|
||||
{
|
||||
this.LMS.emit('connect');
|
||||
this.on('data', function (chunk)
|
||||
{
|
||||
// this = HECI
|
||||
var cmd = chunk.readUInt8(0);
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
default:
|
||||
//console.log('Received ' + chunk.length + ' bytes of data for LMS');
|
||||
//console.log('Command = ' + cmd);
|
||||
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] = {};
|
||||
}
|
||||
this[name][port] = require('net').createServer();
|
||||
this[name][port].HECI = this;
|
||||
this[name][port].listen({ port: port });
|
||||
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);
|
||||
});
|
||||
var outBuffer = Buffer.alloc(5);
|
||||
outBuffer.writeUInt8(81, 0);
|
||||
outBuffer.writeUInt32BE(port, 1);
|
||||
this.write(outBuffer);
|
||||
break;
|
||||
case 'cancel-tcpip-forward':
|
||||
break;
|
||||
case 'udp-send-to@amt.intel.com':
|
||||
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[rChannelId] != undefined)
|
||||
{
|
||||
this.sockets[rChannelId].pendingBytes.push(data.length);
|
||||
this.sockets[rChannelId].write(data, function ()
|
||||
{
|
||||
var written = this.pendingBytes.shift();
|
||||
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
|
||||
{
|
||||
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_DATA');
|
||||
}
|
||||
break;
|
||||
case APF_CHANNEL_CLOSE:
|
||||
var rChannelId = chunk.readUInt32BE(1);
|
||||
if (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
|
||||
{
|
||||
//console.log('Unknown Recipient ID/' + rChannelId + ' for APF_CHANNEL_CLOSE');
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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;
|
||||
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 });
|
||||
}
|
||||
|
||||
module.exports = lme_heci;
|
Loading…
Add table
Add a link
Reference in a new issue