mirror of
https://github.com/Ylianst/MeshAgent
synced 2026-01-04 09:33:30 +00:00
Much improved, better stability, lots of fixes
This commit is contained in:
281
Debug/amt_heci.js
Normal file
281
Debug/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;
|
||||
61
Debug/amt_test.js
Normal file
61
Debug/amt_test.js
Normal file
@@ -0,0 +1,61 @@
|
||||
var amt_heci = require('amt_heci');
|
||||
var amt = new amt_heci();
|
||||
|
||||
amt.getProtocolVersion(function (result)
|
||||
{
|
||||
console.log('protocol version = ' + result);
|
||||
});
|
||||
amt.on('error', function (e) { console.log(e);});
|
||||
amt.on('connect', function()
|
||||
{
|
||||
console.log("Connected!");
|
||||
|
||||
this.getVersion(OnVersion);
|
||||
this.getProvisioningState(OnProvisioningState);
|
||||
this.getProvisioningMode(OnProvisioningMode);
|
||||
this.getEHBCState(OnEHBC);
|
||||
this.getControlMode(OnEHBC);
|
||||
this.getMACAddresses(OnEHBC);
|
||||
this.getDnsSuffix(OnDns);
|
||||
this.getCertHashEntries(OnHashEntries);
|
||||
//this.getHashHandles(OnGetHashHandles);
|
||||
});
|
||||
function OnGetHashHandles(handles)
|
||||
{
|
||||
console.log(handles.length + " HashHandles");
|
||||
for (var i = 0; i < handles.length; ++i)
|
||||
{
|
||||
amt.getCertHashEntry(handles[i], OnEHBC);
|
||||
}
|
||||
}
|
||||
function OnHashEntries(entries)
|
||||
{
|
||||
for(var i=0;i<entries.length;++i)
|
||||
{
|
||||
console.log(entries[i]);
|
||||
}
|
||||
}
|
||||
function OnDns(dns)
|
||||
{
|
||||
console.log("Dns Suffix = " + dns);
|
||||
}
|
||||
function OnVersion(val)
|
||||
{
|
||||
console.log("Bios Version = " + val.BiosVersion.toString());
|
||||
for(var version in val.Versions)
|
||||
{
|
||||
console.log(" " + val.Versions[version].Description + " = " + val.Versions[version].Version);
|
||||
}
|
||||
}
|
||||
function OnProvisioningState(state)
|
||||
{
|
||||
console.log("ProvisioningState = " + state);
|
||||
}
|
||||
function OnProvisioningMode(result)
|
||||
{
|
||||
console.log("ProvisioningMode = " + result.mode + " [Legacy = " + result.legacy + "]");
|
||||
}
|
||||
function OnEHBC(result)
|
||||
{
|
||||
console.log(result);
|
||||
}
|
||||
34
Debug/exe.js
34
Debug/exe.js
@@ -5,6 +5,39 @@ var js;
|
||||
var sz = new Buffer(8);
|
||||
var exeLen = 0;
|
||||
|
||||
var i;
|
||||
var dependency = [];
|
||||
var addOn = null;
|
||||
for (i = 1; i < process.argv.length; ++i)
|
||||
{
|
||||
if(process.argv[i].startsWith('-i'))
|
||||
{
|
||||
try
|
||||
{
|
||||
dependency.push({ name:process.argv[i].slice(2,process.argv[i].indexOf('.js')), base64: fs.readFileSync(process.argv[i].slice(2)).toString('base64') });
|
||||
process._argv.splice(i, 1);
|
||||
i = 0;
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
console.log(e);
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dependency.length > 0)
|
||||
{
|
||||
console.log("\nIntegrating Dependencies:")
|
||||
addOn = "";
|
||||
for(i=0;i<dependency.length;++i)
|
||||
{
|
||||
addOn += ("addModule('" + dependency[i].name + "', Buffer.from('" + dependency[i].base64 + "', 'base64'));\n");
|
||||
console.log(" " + dependency[i].name);
|
||||
}
|
||||
console.log("");
|
||||
}
|
||||
|
||||
if (process.argv0.endsWith('.js'))
|
||||
{
|
||||
console.log("Non-integrated executable");
|
||||
@@ -47,6 +80,7 @@ else
|
||||
console.log("Original Binary Size: " + exeLen);
|
||||
}
|
||||
|
||||
if (addOn != null) { js = Buffer.concat([Buffer.from(addOn), js]); }
|
||||
console.log("JavaScript Length: " + js.length);
|
||||
w.write(exe.slice(0, exeLen), OnWroteExe);
|
||||
|
||||
|
||||
36
Debug/heci.js
Normal file
36
Debug/heci.js
Normal file
@@ -0,0 +1,36 @@
|
||||
var heci = require('heci');
|
||||
var amt = null;
|
||||
|
||||
console.log("Starting HECI test...");
|
||||
console.log("LME GUID = " + heci.GUIDS.LME.toString('hex'));
|
||||
console.log("AMT GUID = " + heci.GUIDS.AMT.toString('hex'));
|
||||
heci.doIoctl(heci.IOCTL.HECI_VERSION, null, new Buffer(16), OnVersion);
|
||||
|
||||
function OnVersion(status, buffer, arg)
|
||||
{
|
||||
if(status == 0)
|
||||
{
|
||||
console.log("HECI Driver Version = " + buffer[0] + "." + buffer[1]);
|
||||
console.log("Attempting to create AMT/HECI connection");
|
||||
amt = heci.create();
|
||||
amt.connect(heci.GUIDS.AMT);
|
||||
amt.on('connect', OnAMT);
|
||||
amt.on('error', function (e) { console.log(e); });
|
||||
}
|
||||
else {
|
||||
console.log("Could not determine HECI Driver Version");
|
||||
}
|
||||
}
|
||||
function OnAMT()
|
||||
{
|
||||
console.log('AMT Connected');
|
||||
amt.on('data', OnAMTData);
|
||||
|
||||
var header = Buffer.from('010100001A00000400000000', 'hex');
|
||||
amt.write(header);
|
||||
}
|
||||
|
||||
function OnAMTData(chunk)
|
||||
{
|
||||
console.log('Received ' + chunk.length + ' bytes of AMT Data');
|
||||
}
|
||||
56
Debug/httptest.js
Normal file
56
Debug/httptest.js
Normal file
@@ -0,0 +1,56 @@
|
||||
var http = require('http');
|
||||
var https = require('https');
|
||||
var WS;
|
||||
console.log("Starting HTTP (Rewrite) Test");
|
||||
|
||||
var cert = https.generateCertificate('test');
|
||||
|
||||
var server = https.createServer();
|
||||
|
||||
server.on('request', function (imsg, rsp)
|
||||
{
|
||||
console.log('Received inbound request: ' + imsg.method + ' ' + imsg.url);
|
||||
rsp.writeHead(200, 'OK', {'Content-Length': 0});
|
||||
});
|
||||
server.on('upgrade', function (imsg, sck, head)
|
||||
{
|
||||
console.log('Server On Upgrade');
|
||||
WS = sck.upgradeWebSocket();
|
||||
WS.on('pong', function () { console.log('Server received PONG'); WS.write('this is test'); WS.write(Buffer.from("This is a good day")); WS.end();});
|
||||
WS.on('data', function (chunk) { console.log('Server received: ' + chunk); });
|
||||
WS.ping();
|
||||
});
|
||||
|
||||
|
||||
server.listen({ port: 9095, pfx: cert, passphrase: 'test' });
|
||||
//var req = http.get("http://127.0.0.1:9095/test.html");
|
||||
//var req = http.get("ws://127.0.0.1:9095/test.html");
|
||||
var req = http.request({ protocol: 'wss:', host: '127.0.0.1', port: 9095, method: 'GET', path: '/test.html', rejectUnauthorized: false})
|
||||
req.end();
|
||||
|
||||
var req2 = http.request({ protocol: 'https:', host: '127.0.0.1', port: 9095, method: 'GET', path: '/test.html', rejectUnauthorized: false })
|
||||
req2.end();
|
||||
|
||||
req.on('upgrade', function (imsg, sck, head)
|
||||
{
|
||||
console.log('client upgraded to WebSocket');
|
||||
sck.on('ping', function () { console.log('Client received ping'); this.write('Client says hello');});
|
||||
sck.on('data', function (chunk) { console.log('client received: ' + chunk, typeof (chunk)); });
|
||||
sck.on('end', function () { console.log('Client side closed'); });
|
||||
});
|
||||
req.on('response', function (imsg)
|
||||
{
|
||||
console.log('received response', imsg.statusCode, imsg.statusMessage);
|
||||
imsg.on('end', function () {
|
||||
console.log('Done reading IncomingMessageStream');
|
||||
});
|
||||
})
|
||||
req.on('error', function (err) { console.log('error received', err); });
|
||||
|
||||
req2.on('response', function (imsg) {
|
||||
console.log('received response', imsg.statusCode, imsg.statusMessage);
|
||||
imsg.on('end', function () {
|
||||
console.log('Done reading IncomingMessageStream');
|
||||
});
|
||||
})
|
||||
req2.on('error', function (err) { console.log('error received', err); });
|
||||
355
Debug/lme_heci.js
Normal file
355
Debug/lme_heci.js
Normal file
@@ -0,0 +1,355 @@
|
||||
|
||||
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 ()
|
||||
{
|
||||
console.log('emitting connect');
|
||||
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;
|
||||
37
Debug/lme_test.js
Normal file
37
Debug/lme_test.js
Normal file
File diff suppressed because one or more lines are too long
18
Debug/newstringtest.js
Normal file
18
Debug/newstringtest.js
Normal file
@@ -0,0 +1,18 @@
|
||||
var http = require('http');
|
||||
|
||||
console.log('starting client test');
|
||||
console.log('Sending Request');
|
||||
var req = http.request({host: '127.0.0.1', port: 9093, protocol: 'ws:'});
|
||||
|
||||
|
||||
req.on('upgrade', function (res, sk, h)
|
||||
{
|
||||
sk.on('ping', function () { console.log('received ping'); });
|
||||
sk.on('pong', function () { console.log('received pong'); });
|
||||
this.websocket = sk;
|
||||
|
||||
console.log("Upgraded to WebSocket!"); sk.write(JSON.stringify({ a: 'hello' }));
|
||||
});
|
||||
//req.end();
|
||||
|
||||
|
||||
205
Debug/parseXml.js
Normal file
205
Debug/parseXml.js
Normal file
@@ -0,0 +1,205 @@
|
||||
Object.defineProperty(Array.prototype, "peek",
|
||||
{
|
||||
value: function ()
|
||||
{
|
||||
return (this.length > 0 ? this[this.length - 1] : undefined);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function _treeBuilder()
|
||||
{
|
||||
this.tree = [];
|
||||
|
||||
this.push = function (element)
|
||||
{
|
||||
this.tree.push(element);
|
||||
};
|
||||
this.pop = function ()
|
||||
{
|
||||
var element = this.tree.pop();
|
||||
if(this.tree.length>0)
|
||||
{
|
||||
this.tree.peek().childNodes.push(element);
|
||||
}
|
||||
return (element);
|
||||
};
|
||||
this.peek = function()
|
||||
{
|
||||
return (this.tree.peek());
|
||||
}
|
||||
this.addNamespace = function(prefix, namespace)
|
||||
{
|
||||
this.tree.peek().nsTable[prefix] = namespace;
|
||||
if(this.tree.peek().attributes.length > 0)
|
||||
{
|
||||
for(var i = 0; i<this.tree.peek().attributes; ++i)
|
||||
{
|
||||
var a = this.tree.peek().attributes[i];
|
||||
if(prefix == '*' && a.name == a.localName)
|
||||
{
|
||||
a.namespace = namespace;
|
||||
}
|
||||
else if(prefix != '*' && a.name != a.localName)
|
||||
{
|
||||
var pfx = a.name.split(':')[0];
|
||||
if(pfx == prefix)
|
||||
{
|
||||
a.namespace = namespace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.getNamespace = function(prefix)
|
||||
{
|
||||
for(var i=this.tree.length-1;i>=0;--i)
|
||||
{
|
||||
if(this.tree[i].nsTable[prefix] != undefined)
|
||||
{
|
||||
return (this.tree[i].nsTable[prefix]);
|
||||
}
|
||||
}
|
||||
return ('undefined');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This is a drop-in replacement to _turnToXml() that works without xml parser dependency.
|
||||
function _turnToXml(text)
|
||||
{
|
||||
if (text == null) return null;
|
||||
return ({ childNodes: [_turnToXmlRec(text)], getElementsByTagName: _getElementsByTagName, getChildElementsByTagName: _getChildElementsByTagName, getElementsByTagNameNS: _getElementsByTagNameNS });
|
||||
}
|
||||
|
||||
function _getElementsByTagNameNS(ns, name)
|
||||
{
|
||||
var ret = []; _xmlTraverseAllRec(this.childNodes, function (node)
|
||||
{
|
||||
if (node.localName == name && (node.namespace == ns || ns == '*')) { ret.push(node); }
|
||||
}); return ret;
|
||||
}
|
||||
function _getElementsByTagName(name)
|
||||
{
|
||||
var ret = []; _xmlTraverseAllRec(this.childNodes, function (node)
|
||||
{
|
||||
if (node.localName == name) { ret.push(node); }
|
||||
}); return ret;
|
||||
}
|
||||
function _getChildElementsByTagName(name)
|
||||
{
|
||||
var ret = [];
|
||||
if (this.childNodes != undefined)
|
||||
{
|
||||
for (var node in this.childNodes) {
|
||||
if (this.childNodes[node].localName == name) { ret.push(this.childNodes[node]); }
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
function _getChildElementsByTagNameNS(ns, name)
|
||||
{
|
||||
var ret = [];
|
||||
if (this.childNodes != undefined)
|
||||
{
|
||||
for (var node in this.childNodes)
|
||||
{
|
||||
if (this.childNodes[node].localName == name && (ns == '*' || this.childNodes[node].namespace == ns)) { ret.push(this.childNodes[node]); }
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
function _xmlTraverseAllRec(nodes, func) { for (var i in nodes) { func(nodes[i]); if (nodes[i].childNodes) { _xmlTraverseAllRec(nodes[i].childNodes, func); } } }
|
||||
function _turnToXmlRec(text)
|
||||
{
|
||||
var elementStack = new _treeBuilder();
|
||||
var lastElement = null;
|
||||
|
||||
var x1 = text.split('<'), ret = [], element = null, currentElementName = null;
|
||||
for (var i in x1)
|
||||
{
|
||||
var x2 = x1[i].split('>'), x3 = x2[0].split(' '), elementName = x3[0];
|
||||
if ((elementName.length > 0) && (elementName[0] != '?'))
|
||||
{
|
||||
if (elementName[0] != '/')
|
||||
{
|
||||
var localName;
|
||||
var localname2 = elementName.split(' ')[0].split(':'), localName = (localname2.length > 1) ? localname2[1] : localname2[0];
|
||||
var attributes = [];
|
||||
Object.defineProperty(attributes, "get",
|
||||
{
|
||||
value: function ()
|
||||
{
|
||||
if (arguments.length == 1)
|
||||
{
|
||||
for (var a in this) { if (this[a].name == arguments[0]) { return (this[a]); } }
|
||||
}
|
||||
else if (arguments.length == 2)
|
||||
{
|
||||
for (var a in this) { if (this[a].name == arguments[1] && (arguments[0] == '*' || this[a].namespace == arguments[0])) { return (this[a]); } }
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ('attributes.get(): Invalid number of parameters');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
elementStack.push({ name: elementName, localName: localName, getChildElementsByTagName: _getChildElementsByTagName, getElementsByTagNameNS: _getElementsByTagNameNS, getChildElementsByTagNameNS: _getChildElementsByTagNameNS, attributes: attributes, childNodes: [], nsTable: {} });
|
||||
|
||||
// Parse Attributes
|
||||
if (x3.length > 0)
|
||||
{
|
||||
var skip = false;
|
||||
for (var j in x3)
|
||||
{
|
||||
if (x3[j] == '/')
|
||||
{
|
||||
// This is an empty Element
|
||||
elementStack.peek().namespace = elementStack.peek().name == elementStack.peek().localName ? elementStack.getNamespace('*') : elementStack.getNamespace(elementStack.peek().name.substring(0, elementStack.peek().name.indexOf(':')));
|
||||
elementStack.peek().textContent = '';
|
||||
lastElement = elementStack.pop();
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
var k = x3[j].indexOf('=');
|
||||
if (k > 0)
|
||||
{
|
||||
var attrName = x3[j].substring(0, k);
|
||||
var attrValue = x3[j].substring(k + 2, x3[j].length - 1);
|
||||
var attrNS = elementStack.getNamespace('*');
|
||||
|
||||
if (attrName == 'xmlns')
|
||||
{
|
||||
elementStack.addNamespace('*', attrValue);
|
||||
attrNS = attrValue;
|
||||
}
|
||||
else if (attrName.startsWith('xmlns:'))
|
||||
{
|
||||
elementStack.addNamespace(attrName.substring(6), attrValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ax = attrName.split(':');
|
||||
if (ax.length == 2) { attrName = ax[1]; attrNS = elementStack.getNamespace(ax[0]); }
|
||||
}
|
||||
elementStack.peek().attributes.push({ name: attrName, value: attrValue, namespace: attrNS });
|
||||
}
|
||||
}
|
||||
if (skip) { continue; }
|
||||
}
|
||||
elementStack.peek().namespace = elementStack.peek().name == elementStack.peek().localName ? elementStack.getNamespace('*') : elementStack.getNamespace(elementStack.peek().name.substring(0, elementStack.peek().name.indexOf(':')));
|
||||
if (x2[1]) { elementStack.peek().textContent = x2[1]; }
|
||||
}
|
||||
else
|
||||
{
|
||||
lastElement = elementStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return lastElement;
|
||||
}
|
||||
|
||||
module.exports = _turnToXml;
|
||||
243
Debug/serviceManager.js
Normal file
243
Debug/serviceManager.js
Normal file
@@ -0,0 +1,243 @@
|
||||
|
||||
|
||||
function parseServiceStatus(token)
|
||||
{
|
||||
var j = {};
|
||||
var serviceType = token.Deref(0, 4).IntVal;
|
||||
j.isFileSystemDriver = ((serviceType & 0x00000002) == 0x00000002);
|
||||
j.isKernelDriver = ((serviceType & 0x00000001) == 0x00000001);
|
||||
j.isSharedProcess = ((serviceType & 0x00000020) == 0x00000020);
|
||||
j.isOwnProcess = ((serviceType & 0x00000010) == 0x00000010);
|
||||
j.isInteractive = ((serviceType & 0x00000100) == 0x00000100);
|
||||
switch (token.Deref((1 * 4), 4).IntVal)
|
||||
{
|
||||
case 0x00000005:
|
||||
j.state = 'CONTINUE_PENDING';
|
||||
break;
|
||||
case 0x00000006:
|
||||
j.state = 'PAUSE_PENDING';
|
||||
break;
|
||||
case 0x00000007:
|
||||
j.state = 'PAUSED';
|
||||
break;
|
||||
case 0x00000004:
|
||||
j.state = 'RUNNING';
|
||||
break;
|
||||
case 0x00000002:
|
||||
j.state = 'START_PENDING';
|
||||
break;
|
||||
case 0x00000003:
|
||||
j.state = 'STOP_PENDING';
|
||||
break;
|
||||
case 0x00000001:
|
||||
j.state = 'STOPPED';
|
||||
break;
|
||||
}
|
||||
var controlsAccepted = token.Deref((2 * 4), 4).IntVal
|
||||
j.controlsAccepted = [];
|
||||
if ((controlsAccepted & 0x00000010) == 0x00000010)
|
||||
{
|
||||
j.controlsAccepted.push('SERVICE_CONTROL_NETBINDADD');
|
||||
j.controlsAccepted.push('SERVICE_CONTROL_NETBINDREMOVE');
|
||||
j.controlsAccepted.push('SERVICE_CONTROL_NETBINDENABLE');
|
||||
j.controlsAccepted.push('SERVICE_CONTROL_NETBINDDISABLE');
|
||||
}
|
||||
if ((controlsAccepted & 0x00000008) == 0x00000008) { j.controlsAccepted.push('SERVICE_CONTROL_PARAMCHANGE'); }
|
||||
if ((controlsAccepted & 0x00000002) == 0x00000002) { j.controlsAccepted.push('SERVICE_CONTROL_PAUSE'); j.controlsAccepted.push('SERVICE_CONTROL_CONTINUE'); }
|
||||
if ((controlsAccepted & 0x00000100) == 0x00000100) { j.controlsAccepted.push('SERVICE_CONTROL_PRESHUTDOWN'); }
|
||||
if ((controlsAccepted & 0x00000004) == 0x00000004) { j.controlsAccepted.push('SERVICE_CONTROL_SHUTDOWN'); }
|
||||
if ((controlsAccepted & 0x00000001) == 0x00000001) { j.controlsAccepted.push('SERVICE_CONTROL_STOP'); }
|
||||
if ((controlsAccepted & 0x00000020) == 0x00000020) { j.controlsAccepted.push('SERVICE_CONTROL_HARDWAREPROFILECHANGE'); }
|
||||
if ((controlsAccepted & 0x00000040) == 0x00000040) { j.controlsAccepted.push('SERVICE_CONTROL_POWEREVENT'); }
|
||||
if ((controlsAccepted & 0x00000080) == 0x00000080) { j.controlsAccepted.push('SERVICE_CONTROL_SESSIONCHANGE'); }
|
||||
j.pid = token.Deref((7 * 4), 4).IntVal
|
||||
return (j);
|
||||
}
|
||||
|
||||
function serviceManager()
|
||||
{
|
||||
this.GM = require('_GenericMarshal');
|
||||
this.proxy = this.GM.CreateNativeProxy('Advapi32.dll');
|
||||
this.proxy.CreateMethod('OpenSCManagerA');
|
||||
this.proxy.CreateMethod('EnumServicesStatusExA');
|
||||
this.proxy.CreateMethod('OpenServiceA');
|
||||
this.proxy.CreateMethod('QueryServiceStatusEx');
|
||||
this.proxy.CreateMethod('ControlService');
|
||||
this.proxy.CreateMethod('StartServiceA');
|
||||
this.proxy.CreateMethod('CloseServiceHandle');
|
||||
this.proxy.CreateMethod('CreateServiceA');
|
||||
this.proxy.CreateMethod('ChangeServiceConfig2A');
|
||||
this.proxy.CreateMethod('DeleteService');
|
||||
this.proxy2 = this.GM.CreateNativeProxy('Kernel32.dll');
|
||||
this.proxy2.CreateMethod('GetLastError');
|
||||
|
||||
this.enumerateService = function()
|
||||
{
|
||||
var machineName = this.GM.CreatePointer();
|
||||
var dbName = this.GM.CreatePointer();
|
||||
var handle = this.proxy.OpenSCManagerA(0x00, 0x00, 0x0001 | 0x0004);
|
||||
|
||||
var bytesNeeded = this.GM.CreateVariable(4);
|
||||
var servicesReturned = this.GM.CreateVariable(4);
|
||||
var resumeHandle = this.GM.CreateVariable(4);
|
||||
//var services = this.proxy.CreateVariable(262144);
|
||||
|
||||
var success = this.proxy.EnumServicesStatusExA(handle, 0, 0x00000030, 0x00000003, 0x00, 0x00, bytesNeeded, servicesReturned, resumeHandle, 0x00);
|
||||
if(bytesNeeded.IntVal <= 0)
|
||||
{
|
||||
throw ('error enumerating services');
|
||||
}
|
||||
|
||||
var sz = bytesNeeded.IntVal;
|
||||
var services = this.GM.CreateVariable(sz);
|
||||
this.proxy.EnumServicesStatusExA(handle, 0, 0x00000030, 0x00000003, services, sz, bytesNeeded, servicesReturned, resumeHandle, 0x00);
|
||||
console.log("servicesReturned", servicesReturned.IntVal, 'PtrSize = ' + dbName._size);
|
||||
|
||||
var ptrSize = dbName._size;
|
||||
var blockSize = 36 + (2 * ptrSize);
|
||||
console.log('blockSize', blockSize);
|
||||
|
||||
var retVal = [];
|
||||
for (var i = 0; i < servicesReturned.IntVal; ++i)
|
||||
{
|
||||
var token = services.Deref(i * blockSize, blockSize);
|
||||
var j = {};
|
||||
j.name = token.Deref(0, ptrSize).Deref().String;
|
||||
j.displayName = token.Deref(ptrSize, ptrSize).Deref().String;
|
||||
j.status = parseServiceStatus(token.Deref(2 * ptrSize, 36));
|
||||
retVal.push(j);
|
||||
}
|
||||
|
||||
this.proxy.CloseServiceHandle(handle);
|
||||
|
||||
return (retVal);
|
||||
}
|
||||
this.getService = function(name)
|
||||
{
|
||||
var serviceName = this.GM.CreateVariable(name);
|
||||
var ptr = this.GM.CreatePointer();
|
||||
var bytesNeeded = this.GM.CreateVariable(ptr._size);
|
||||
var handle = this.proxy.OpenSCManagerA(0x00, 0x00, 0x0001 | 0x0004 | 0x0020 | 0x0010);
|
||||
if (handle == 0) { throw ('could not open ServiceManager'); }
|
||||
var h = this.proxy.OpenServiceA(handle, serviceName, 0x0004 | 0x0020 | 0x0010 | 0x00010000);
|
||||
if (h != 0)
|
||||
{
|
||||
var success = this.proxy.QueryServiceStatusEx(h, 0, 0, 0, bytesNeeded);
|
||||
var status = this.GM.CreateVariable(bytesNeeded.IntVal);
|
||||
success = this.proxy.QueryServiceStatusEx(h, 0, status, status._size, bytesNeeded);
|
||||
if (success != 0)
|
||||
{
|
||||
retVal = {};
|
||||
retVal.status = parseServiceStatus(status);
|
||||
retVal._scm = handle;
|
||||
retVal._service = h;
|
||||
retVal._GM = this.GM;
|
||||
retVal._proxy = this.proxy;
|
||||
require('events').inherits(retVal);
|
||||
retVal.on('~', function () { this._proxy.CloseServiceHandle(this); this._proxy.CloseServiceHandle(this._scm); });
|
||||
retVal.name = name;
|
||||
retVal.stop = function()
|
||||
{
|
||||
if(this.status.state == 'RUNNING')
|
||||
{
|
||||
var newstate = this._GM.CreateVariable(36);
|
||||
var success = this._proxy.ControlService(this._service, 0x00000001, newstate);
|
||||
if(success == 0)
|
||||
{
|
||||
throw (this.name + '.stop() failed');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ('cannot call ' + this.name + '.stop(), when current state is: ' + this.status.state);
|
||||
}
|
||||
}
|
||||
retVal.start = function()
|
||||
{
|
||||
if(this.status.state == 'STOPPED')
|
||||
{
|
||||
var success = this._proxy.StartServiceA(this._service, 0, 0);
|
||||
if(success == 0)
|
||||
{
|
||||
throw (this.name + '.start() failed');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ('cannot call ' + this.name + '.start(), when current state is: ' + this.status.state);
|
||||
}
|
||||
}
|
||||
return (retVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
this.proxy.CloseServiceHandle(handle);
|
||||
throw ('could not find service: ' + name);
|
||||
}
|
||||
this.installService = function(options)
|
||||
{
|
||||
var handle = this.proxy.OpenSCManagerA(0x00, 0x00, 0x0002);
|
||||
if (handle == 0) { throw ('error opening SCManager'); }
|
||||
var serviceName = this.GM.CreateVariable(options.name);
|
||||
var displayName = this.GM.CreateVariable(options.displayName);
|
||||
var allAccess = 0x000F01FF;
|
||||
var serviceType;
|
||||
var servicePath = this.GM.CreateVariable(options.servicePath);
|
||||
|
||||
switch(options.startType)
|
||||
{
|
||||
case 'BOOT_START':
|
||||
serviceType = 0x00;
|
||||
break;
|
||||
case 'SYSTEM_START':
|
||||
serviceType = 0x01;
|
||||
break;
|
||||
case 'AUTO_START':
|
||||
serviceType = 0x02;
|
||||
break;
|
||||
case 'DEMAND_START':
|
||||
serviceType = 0x03;
|
||||
break;
|
||||
default:
|
||||
serviceType = 0x04; // Disabled
|
||||
break;
|
||||
}
|
||||
var h = this.proxy.CreateServiceA(handle, serviceName, displayName, allAccess, 0x10 | 0x100, serviceType, 0, servicePath, 0, 0, 0, 0, 0);
|
||||
if (h == 0) { this.proxy.CloseServiceHandle(handle); throw ('Error Creating Service'); }
|
||||
if(options.description)
|
||||
{
|
||||
console.log(options.description);
|
||||
|
||||
var dscPtr = this.GM.CreatePointer();
|
||||
dscPtr.Val = this.GM.CreateVariable(options.description);
|
||||
|
||||
if(this.proxy.ChangeServiceConfig2A(h, 1, dscPtr)==0)
|
||||
{
|
||||
this.proxy.CloseServiceHandle(h);
|
||||
this.proxy.CloseServiceHandle(handle);
|
||||
throw ('Unable to set description');
|
||||
}
|
||||
}
|
||||
this.proxy.CloseServiceHandle(h);
|
||||
this.proxy.CloseServiceHandle(handle);
|
||||
return (this.getService(options.name));
|
||||
}
|
||||
this.uninstallService = function(name)
|
||||
{
|
||||
var service = this.getService(name);
|
||||
if(service.status.state == 'STOPPED')
|
||||
{
|
||||
if (this.proxy.DeleteService(service._service) == 0) { throw ('Uninstall Service for: ' + name + ', failed with error: ' + this.proxy2.GetLastError()); }
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ('Cannot uninstall service: ' + name + ', because it is: ' + service.status.state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = serviceManager;
|
||||
655
Debug/upnpcp.js
Normal file
655
Debug/upnpcp.js
Normal file
@@ -0,0 +1,655 @@
|
||||
|
||||
var parseXml = require('parseXml');
|
||||
var http = require('http');
|
||||
var dgram = require('dgram');
|
||||
var os = require('os');
|
||||
var MemoryStream = require('MemoryStream');
|
||||
var net = require('net');
|
||||
|
||||
//var networkMonitor = require('NetworkMonitor');
|
||||
|
||||
function upnpdevice(descriptionUrl, usn, cp)
|
||||
{
|
||||
var d = descriptionUrl.split('/');
|
||||
this.BaseURL = d[0] + '//' + d[2];
|
||||
var emitterUtils = require('events').inherits(this);
|
||||
emitterUtils.createEvent('bye');
|
||||
emitterUtils.createEvent('error');
|
||||
emitterUtils.createEvent('alive');
|
||||
emitterUtils.createEvent('serviceLoaded');
|
||||
this.pendingServices = 0;
|
||||
this.usn = usn;
|
||||
this.cp = cp;
|
||||
this.req = http.get(descriptionUrl);
|
||||
this.req.device = this;
|
||||
this.req.on('error', function ()
|
||||
{
|
||||
this.device.emit('error', 'Error fetching Description Document from ' + this.device.BaseURL);
|
||||
});
|
||||
this.req.on('response', function (msg)
|
||||
{
|
||||
if (msg.statusCode == 200)
|
||||
{
|
||||
msg.device = this.device;
|
||||
this.device.dd = new MemoryStream();
|
||||
this.device.dd.device = this.device;
|
||||
msg.pipe(this.device.dd);
|
||||
this.device.dd.on('end', function ()
|
||||
{
|
||||
upnpdevice_parseXml.apply(this.device, [this.buffer.toString()]);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.device.emit('error', 'Error (' + msg.statusCode + ') Fetching Description Document from: ' + this.device.BaseURL);
|
||||
}
|
||||
});
|
||||
this.loadAllServices = function () { this.rootDevice.loadAllServices(); };
|
||||
this.makeUrl = function (url)
|
||||
{
|
||||
if(url.startsWith('/'))
|
||||
{
|
||||
if (this.BaseURL.endsWith('/'))
|
||||
{
|
||||
return (this.BaseURL + url.substring(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (this.BaseURL + url);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.BaseURL.endsWith('/'))
|
||||
{
|
||||
return (this.BaseURL + url);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (this.BaseURL + '/' + url);
|
||||
}
|
||||
}
|
||||
};
|
||||
this.on('~', upnpdevice_Cleanup);
|
||||
this.on('serviceLoaded', function (svc)
|
||||
{
|
||||
if(--this.pendingServices == 0)
|
||||
{
|
||||
// All Services have been loaded
|
||||
this.cp.emit('device', this);
|
||||
}
|
||||
});
|
||||
this.getDevice = function (udn)
|
||||
{
|
||||
return (this.rootDevice.getDevice(udn));
|
||||
};
|
||||
}
|
||||
|
||||
function upnpdevice_Cleanup()
|
||||
{
|
||||
console.log('Finalizing: ' + this.rootDevice.friendlyName);
|
||||
}
|
||||
function upnpservice(parentDevice, xmlDoc)
|
||||
{
|
||||
var emitterUtils = require('events').inherits(this);
|
||||
this.device = parentDevice;
|
||||
|
||||
this.serviceType = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'serviceType')[0].textContent;
|
||||
this.serviceId = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'serviceId')[0].textContent;
|
||||
this.controlURL = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'controlURL')[0].textContent;
|
||||
this.eventSubURL = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'eventSubURL')[0].textContent;
|
||||
this.SCPDURL = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'SCPDURL')[0].textContent;
|
||||
|
||||
if (!this.controlURL.startsWith('http:') && !this.controlURL.startsWith('https:')) { this.controlURL = this.device.rootDevice.makeUrl(this.controlURL); }
|
||||
if (!this.eventSubURL.startsWith('http:') && !this.eventSubURL.startsWith('https:')) { this.eventSubURL = this.device.rootDevice.makeUrl(this.eventSubURL); }
|
||||
if (!this.SCPDURL.startsWith('http:') && !this.SCPDURL.startsWith('https:')) { this.SCPDURL = this.device.rootDevice.makeUrl(this.SCPDURL); }
|
||||
|
||||
this.load = function ()
|
||||
{
|
||||
++this.device.rootDevice.pendingServices;
|
||||
this.req = http.get(this.SCPDURL);
|
||||
this.req.service = this;
|
||||
this.req.on('error', function () { this.service.device.rootDevice.emit('error', 'Error fetching SCPD from: ' + this.service.SCPDURL); });
|
||||
this.req.on('response', function (msg)
|
||||
{
|
||||
if (msg.statusCode == 200)
|
||||
{
|
||||
msg.service = this.service;
|
||||
this.service.scpdxml = new MemoryStream();
|
||||
this.service.scpdxml.service = this.service;
|
||||
msg.pipe(this.service.scpdxml);
|
||||
this.service.scpdxml.on('end', function ()
|
||||
{
|
||||
try
|
||||
{
|
||||
upnpservice_parseScpd.apply(this.service, [this.buffer.toString()]);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
this.service.device.rootDevice.emit('error', 'error parsing SCPD: ' + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.service.device.rootDevice.emit('error', 'Error loading SCPD from: ' + this.service.SCPDURL);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.getAction = function(name)
|
||||
{
|
||||
for(var a in this.actions)
|
||||
{
|
||||
if (this.actions[a].name == name) { return (this.actions[a]); }
|
||||
}
|
||||
return (undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function upnpargument(action, xmlDoc)
|
||||
{
|
||||
this.action = action;
|
||||
this.name = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'name')[0].textContent;
|
||||
this.direction = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'direction')[0].textContent;
|
||||
this.relatedStateVariable = action.service.stateVariables.get(xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'relatedStateVariable')[0].textContent);
|
||||
}
|
||||
|
||||
function post_response(msg)
|
||||
{
|
||||
if (msg.statusCode != 200)
|
||||
{
|
||||
var userArgs = this.args;
|
||||
if (userArgs.length > 0 && typeof (userArgs[0] == 'function'))
|
||||
{
|
||||
var fn = userArgs.shift();
|
||||
userArgs.unshift(msg.StatusCode ? msg.StatusCode : msg.url);
|
||||
fn.apply(this.action, userArgs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var buff = new MemoryStream();
|
||||
buff.req = this;
|
||||
msg.pipe(buff);
|
||||
buff.on('end', function ()
|
||||
{
|
||||
var body = {};
|
||||
var xml = parseXml(this.buffer.toString());
|
||||
var action = this.req.action;
|
||||
var userArgs = this.req.args;
|
||||
var actionResponse = xml.getElementsByTagNameNS(action.service.serviceType, action.name + 'Response')[0];
|
||||
if(actionResponse)
|
||||
{
|
||||
for(var child in actionResponse.childNodes)
|
||||
{
|
||||
if(action.arguments.get(actionResponse.childNodes[child].name))
|
||||
{
|
||||
body[actionResponse.childNodes[child].name] = actionResponse.childNodes[child].textContent;
|
||||
}
|
||||
}
|
||||
if(userArgs.length > 0 && typeof(userArgs[0]) == 'function')
|
||||
{
|
||||
var fn = userArgs.shift();
|
||||
userArgs.unshift(body);
|
||||
fn.apply(action, userArgs);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function upnpaction(service, xmlDoc)
|
||||
{
|
||||
this.pendingPosts = [];
|
||||
this.arguments = []; Object.defineProperty(this.arguments, "get", { value: function (name) { for (var i in this) { if (this[i].name == name) { return (this[i]); } } return (undefined); } });
|
||||
this.service = service;
|
||||
|
||||
this.name = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'name')[0].textContent;
|
||||
var argumentList = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'argumentList')[0];
|
||||
|
||||
if (argumentList)
|
||||
{
|
||||
var arguments = argumentList.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'argument');
|
||||
for (var i in arguments)
|
||||
{
|
||||
this.arguments.push(new upnpargument(this, arguments[i]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//console.log(this.service.scpdxml.buffer.toString());
|
||||
}
|
||||
|
||||
this.invoke = function (args)
|
||||
{
|
||||
var parameters = '';
|
||||
for (var i in this.arguments)
|
||||
{
|
||||
if(this.arguments[i].direction == 'in' && args[this.arguments[i].name])
|
||||
{
|
||||
parameters += ('<u:' + this.arguments[i].name + '>' + args[this.arguments[i].name] + '</u:' + this.arguments[i].name + '>');
|
||||
}
|
||||
else if(this.arguments.direction == 'in')
|
||||
{
|
||||
throw ('missing parameter: [' + this.arguments[i].name + '] when invoking Action: ' + this.name);
|
||||
}
|
||||
}
|
||||
|
||||
var controlUri = http.parseUri(this.service.controlURL);
|
||||
console.log(controlUri);
|
||||
var headers = { HOST: (controlUri.host + ':' + controlUri.port), SOAPACTION: '"' + this.service.serviceType + '#' + this.name + '"', 'Content-Type': 'text/xml; charset="utf-8"' };
|
||||
this.pendingPosts.push(http.request({ protocol: 'http', host: controlUri.host, port: controlUri.port, method: 'POST', path: controlUri.path, headers: headers }));
|
||||
this.pendingPosts.peek().action = this;
|
||||
this.pendingPosts.peek().args = [];
|
||||
for (var i = 1; i < arguments.length; ++i)
|
||||
{
|
||||
this.pendingPosts.peek().args.push(arguments[i]);
|
||||
}
|
||||
this.pendingPosts.peek().on('response', post_response);
|
||||
|
||||
var txt = '<?xml version="1.0" encoding="utf-8"?>\r\n<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body>';
|
||||
this.pendingPosts.peek().write(txt);
|
||||
console.log(txt);
|
||||
|
||||
txt = '<u:' + this.name + ' xmlns:u="' + this.service.serviceType + '">';
|
||||
this.pendingPosts.peek().write(txt);
|
||||
console.log(txt);
|
||||
|
||||
if (parameters != '')
|
||||
{
|
||||
this.pendingPosts.peek().write(parameters);
|
||||
console.log(parameters);
|
||||
}
|
||||
this.pendingPosts.peek().write('</u:' + this.name + '>');
|
||||
this.pendingPosts.peek().write('</s:Body></s:Envelope>');
|
||||
|
||||
console.log('</u:' + this.name + '>' + '</s:Body></s:Envelope>');
|
||||
|
||||
this.pendingPosts.peek().end();
|
||||
};
|
||||
this.invokeLegacy = function (args)
|
||||
{
|
||||
var controlUri = http.parseUri(this.service.controlURL);
|
||||
var parameters = '';
|
||||
for (var i in this.arguments) {
|
||||
if (this.arguments[i].direction == 'in' && args[this.arguments[i].name]) {
|
||||
parameters += ('<u:' + this.arguments[i].name + '>' + args[this.arguments[i].name] + '</u:' + this.arguments[i].name + '>');
|
||||
}
|
||||
else if (this.arguments.direction == 'in') {
|
||||
throw ('missing parameter: [' + this.arguments[i].name + '] when invoking Action: ' + this.name);
|
||||
}
|
||||
}
|
||||
|
||||
this.pendingPosts.push(net.connect({ host: controlUri.host, port: controlUri.port }));
|
||||
this.pendingPosts.peek().path = controlUri.path;
|
||||
this.pendingPosts.peek().args = args;
|
||||
this.pendingPosts.peek().parameters = parameters;
|
||||
this.pendingPosts.peek().action = this;
|
||||
this.pendingPosts.peek().headers = { HOST: (controlUri.host + ':' + controlUri.port), SOAPACTION: '"' + this.service.serviceType + '#' + this.name + '"', 'Content-Type': 'text/xml; charset="utf-8"' };
|
||||
this.pendingPosts.peek().on('connect', function ()
|
||||
{
|
||||
console.log('legacy connected');
|
||||
this.write('POST ' + this.path + ' HTTP/1.1\r\n');
|
||||
var headers = this.headers;
|
||||
this.write('HOST: ' + headers.HOST + '\r\n');
|
||||
this.write('SOAPACTION: ' + headers.SOAPACTION + '\r\n');
|
||||
this.write('Content-Type: ' + headers['Content-Type'] + '\r\n');
|
||||
|
||||
var txt = '<?xml version="1.0" encoding="utf-8"?>\r\n<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body>';
|
||||
txt += '<u:' + this.action.name + ' xmlns:u="' + this.action.service.serviceType + '">';
|
||||
txt += this.parameters;
|
||||
txt += ('</u:' + this.name + '>' + '</s:Body></s:Envelope>');
|
||||
|
||||
var b = Buffer.from(txt);
|
||||
this.write('Content-Length: ' + b.length + '\r\n\r\n');
|
||||
this.write(b);
|
||||
});
|
||||
this.pendingPosts.peek().http = http.createStream();
|
||||
this.pendingPosts.peek().pipe(this.pendingPosts.peek().http);
|
||||
this.pendingPosts.peek().http.on('response', post_response);
|
||||
};
|
||||
}
|
||||
function upnpvariable(service, xmlDoc)
|
||||
{
|
||||
this.service = service;
|
||||
this.name = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'name')[0].textContent;
|
||||
this.dataType = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'dataType')[0].textContent;
|
||||
this.evented = xmlDoc.attributes.get('sendEvents').value;
|
||||
if (this.evented == 'yes')
|
||||
{
|
||||
this.currentValue = null;
|
||||
}
|
||||
}
|
||||
function upnpservice_parseScpd(scpd)
|
||||
{
|
||||
this.stateVariables = []; Object.defineProperty(this.stateVariables, "get", { value: function (name) { for (var i in this) { if (this[i].name == name) { return (this[i]); } } return (undefined); } });
|
||||
this.actions = []; Object.defineProperty(this.actions, "get", { value: function (name) { for (var i in this) { if (this[i].name == name) { return (this[i]); } } return (undefined); } });
|
||||
var doc = parseXml(scpd);
|
||||
|
||||
var stateTable = doc.getElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'serviceStateTable')[0];
|
||||
var variables = stateTable.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'stateVariable');
|
||||
for (var i in variables)
|
||||
{
|
||||
this.stateVariables.push(new upnpvariable(this, variables[i]));
|
||||
}
|
||||
|
||||
var actionList = doc.getElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'actionList')[0];
|
||||
var actions = actionList.getChildElementsByTagNameNS('urn:schemas-upnp-org:service-1-0', 'action');
|
||||
for (var i in actions)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.actions.push(new upnpaction(this, actions[i]));
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
this.device.rootDevice.emit('error', 'error parsing SCPD/Action: ' + e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.subscribe = function ()
|
||||
{
|
||||
|
||||
};
|
||||
this.device.rootDevice.emit('serviceLoaded', this);
|
||||
}
|
||||
|
||||
function upnpdevice_child(rootDevice, xmlDoc)
|
||||
{
|
||||
this.rootDevice = rootDevice;
|
||||
this.services = []; Object.defineProperty(this.services, "get", { value: function (id) { for (var i in this) { if (this[i].serviceType == id || this[i].serviceId == id) { return (this[i]); } } return (undefined); } });
|
||||
this.embeddedDevices = []; Object.defineProperty(this.embeddedDevices, "get", { value: function (id) { for (var i in this) { if (this[i].UDN == id || this[i].deviceType == id) { return (this[i]); } } return (undefined); } });
|
||||
|
||||
var emitterUtils = require('events').inherits(this);
|
||||
emitterUtils.createEvent('bye');
|
||||
emitterUtils.createEvent('error');
|
||||
|
||||
this.friendlyName = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'friendlyName')[0].textContent;
|
||||
this.deviceType = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'deviceType')[0].textContent;
|
||||
this.UDN = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'UDN')[0].textContent;
|
||||
this.manufacturer = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'manufacturer')[0].textContent;
|
||||
|
||||
var serviceList = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'serviceList')[0]
|
||||
for (var i in serviceList.childNodes)
|
||||
{
|
||||
if(serviceList.childNodes[i].namespace == 'urn:schemas-upnp-org:device-1-0')
|
||||
{
|
||||
this.services.push(new upnpservice(this, serviceList.childNodes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
var deviceList = xmlDoc.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'deviceList')[0]
|
||||
|
||||
if (deviceList != null)
|
||||
{
|
||||
var devices = deviceList.getChildElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'device')
|
||||
for (var device in devices)
|
||||
{
|
||||
this.embeddedDevices.push(new upnpdevice_child(rootDevice, devices[device]));
|
||||
}
|
||||
//console.log(devices);
|
||||
}
|
||||
this.loadAllServices = function () { for (var i in this.services) { this.services[i].load();} for (var i in this.embeddedDevices) { this.embeddedDevices[i].loadAllServices(); } };
|
||||
this.getDevice = function (udn)
|
||||
{
|
||||
if (this.UDN == udn) { return (this); }
|
||||
for(var ed in this.embeddedDevices)
|
||||
{
|
||||
var ret = this.embeddedDevices[ed].getDevice(udn);
|
||||
if (ret) { return (ret); }
|
||||
}
|
||||
return (undefined);
|
||||
};
|
||||
this.getService = function(id)
|
||||
{
|
||||
for (var s in this.services)
|
||||
{
|
||||
if (this.services[s].serviceId == id) { return (this.services[s]); }
|
||||
}
|
||||
return (undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function upnpdevice_parseXml(xml)
|
||||
{
|
||||
this.dd = null;
|
||||
var doc = parseXml(xml);
|
||||
//var URLBase = doc.getElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'URLBase')[0];
|
||||
//if (URLBase != null) { console.log("old base: " + this.BaseURL); this.BaseURL = URLBase.textContent; }
|
||||
|
||||
var root = doc.getElementsByTagNameNS('urn:schemas-upnp-org:device-1-0', 'device')[0];
|
||||
if (root != null)
|
||||
{
|
||||
this.rootDevice = new upnpdevice_child(this, root);
|
||||
if (!this.cp.searchString.startsWith('ssdp:') && !this.cp.searchString.startsWith('upnp:') && !this.cp.searchString.startsWith('urn:') && !this.cp.searchString.startsWith('uuid:'))
|
||||
{
|
||||
// Friendly Name Search
|
||||
if(this.rootDevice.friendlyName == this.cp.searchString)
|
||||
{
|
||||
//console.log(xml);
|
||||
this.rootDevice.loadAllServices();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(this.cp.searchString.split(':')[0]);
|
||||
switch(this.cp.searchString.split(':')[0])
|
||||
{
|
||||
case 'ssdp':
|
||||
break;
|
||||
case 'upnp':
|
||||
this.rootDevice.loadAllServices();
|
||||
break;
|
||||
case 'uuid':
|
||||
break;
|
||||
case 'urn':
|
||||
break;
|
||||
}
|
||||
}
|
||||
//console.log(this.rootDevice.friendlyName);
|
||||
}
|
||||
}
|
||||
|
||||
function upnpcp_onSearch(msg, rinfo)
|
||||
{
|
||||
var header = require('http-headers')(msg);
|
||||
if (header.statusCode != 200) { return; }
|
||||
var usn = header.headers.usn.split('::')[0];
|
||||
|
||||
if(this.cp.deviceTable[usn] == null)
|
||||
{
|
||||
this.cp.deviceTable[usn] = new upnpdevice(header.headers.location, usn, this.cp);
|
||||
this.cp.deviceTable[usn].on('error', function (e) { console.log('Removing Device/' + this.usn + ' due to error: ' + e); this.cp.deviceTable[this.usn] = null; });
|
||||
this.cp.deviceTable[usn].on('alive', function () { this.cp.emit('device', this); });
|
||||
}
|
||||
}
|
||||
|
||||
function upnpcp(search)
|
||||
{
|
||||
this.searchString = search;
|
||||
if (!search.startsWith('ssdp:') && !search.startsWith('upnp:') && !search.startsWith('uuid:') && !search.startsWith('urn:'))
|
||||
{
|
||||
// Search by Friendly Name
|
||||
search = 'upnp:rootdevice';
|
||||
}
|
||||
|
||||
var MSEARCH = 'M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nST: ' + search + '\r\nMAN: "ssdp:discover"\r\nMX: 5\r\nContent-Length: 0\r\n\r\n';
|
||||
var emitterUtils = require('events').inherits(this);
|
||||
emitterUtils.createEvent('device');
|
||||
|
||||
this.searchSocket = dgram.createSocket({ type: 'udp4' });
|
||||
this.searchSocket.cp = this;
|
||||
this.searchSocket.bind({ port: 0, address:'0.0.0.0' });
|
||||
this.deviceTable = {};
|
||||
|
||||
this.searchSocket.on('message', upnpcp_onSearch);
|
||||
|
||||
var interfaces = os.networkInterfaces();
|
||||
for(var name in interfaces)
|
||||
{
|
||||
for (var i in interfaces[name])
|
||||
{
|
||||
if (interfaces[name][i].family == 'IPv4' && interfaces[name][i].status == 'up')
|
||||
{
|
||||
console.log('Sending Multicast on: ' + interfaces[name][i].address + ' to: 239.255.255.250:1900');
|
||||
this.searchSocket.setMulticastTTL(1);
|
||||
this.searchSocket.setMulticastLoopback(true);
|
||||
this.searchSocket.setMulticastInterface(interfaces[name][i].address);
|
||||
this.searchSocket.send(MSEARCH, 1900, '239.255.255.250');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//var testCP = new upnpcp("Samsung CLX-3300 Series (10.128.125.118)");
|
||||
|
||||
function display_device(dv)
|
||||
{
|
||||
if (!dv) { console.log('No match'); return; }
|
||||
console.log('FriendlyName/ ' + dv.friendlyName);
|
||||
console.log(' DeviceType/ ' + dv.deviceType);
|
||||
console.log(' DeviceUDN/ ' + dv.UDN);
|
||||
|
||||
for (var svc in dv.services)
|
||||
{
|
||||
console.log(' ServiceID/ ' + dv.services[svc].serviceId);
|
||||
}
|
||||
for (var ed in dv.embeddedDevices)
|
||||
{
|
||||
console.log(' Embedded Device: ' + dv.embeddedDevices[ed].friendlyName + ' [' + dv.embeddedDevices[ed].UDN + ']');
|
||||
}
|
||||
}
|
||||
function display_action(action)
|
||||
{
|
||||
var argString = null;
|
||||
for (var arg in action.arguments)
|
||||
{
|
||||
if (action.arguments[arg].direction == 'in')
|
||||
{
|
||||
if (argString)
|
||||
{
|
||||
argString += (', ' + action.arguments[arg].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
argString = action.arguments[arg].name;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(' ' + action.name + '(' + (argString?argString:'') + ')');
|
||||
}
|
||||
function display_actionDetail(action)
|
||||
{
|
||||
if (!action) { console.log('no match'); return; }
|
||||
|
||||
console.log('Action: ' + action.name);
|
||||
console.log(' Input Parameters:');
|
||||
console.log(' {');
|
||||
for (var arg in action.arguments)
|
||||
{
|
||||
if (action.arguments[arg].direction == 'in')
|
||||
{
|
||||
console.log(' [' + action.arguments[arg].relatedStateVariable.dataType + '] ' + action.arguments[arg].name);
|
||||
}
|
||||
}
|
||||
console.log(' }');
|
||||
console.log(' Output Parameters:');
|
||||
console.log(' {');
|
||||
for (var arg in action.arguments)
|
||||
{
|
||||
if (action.arguments[arg].direction == 'out')
|
||||
{
|
||||
console.log(' [' + action.arguments[arg].relatedStateVariable.dataType + '] ' + action.arguments[arg].name);
|
||||
}
|
||||
}
|
||||
console.log(' }');
|
||||
}
|
||||
function display_service(svc)
|
||||
{
|
||||
if (!svc) { console.log('No match'); return; }
|
||||
console.log('ServiceID/ ' + svc.serviceId);
|
||||
console.log('ServiceType/ ' + svc.serviceType);
|
||||
console.log('Actions:');
|
||||
for(var action in svc.actions)
|
||||
{
|
||||
display_action(svc.actions[action]);
|
||||
}
|
||||
}
|
||||
|
||||
var testCP;
|
||||
|
||||
if (process.argv.length > 1)
|
||||
{
|
||||
if(process.argv[1].startsWith('discover='))
|
||||
{
|
||||
testCP = new upnpcp(process.argv[1].split('=')[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!testCP) { process.exit(); }
|
||||
testCP.on('device', function (dv)
|
||||
{
|
||||
var selectedDevice = null;
|
||||
var selectedService = null;
|
||||
var selectedAction = null;
|
||||
|
||||
console.log('');
|
||||
|
||||
|
||||
console.log('Device Added: ');
|
||||
display_device(dv.rootDevice);
|
||||
console.log('');
|
||||
|
||||
|
||||
for (var arg in process.argv)
|
||||
{
|
||||
if(process.argv[arg].startsWith('dv='))
|
||||
{
|
||||
var i = parseInt(process.argv[arg].split('=')[1]);
|
||||
console.log('Selected Embedded Device: ' + i);
|
||||
display_device(dv.rootDevice.embeddedDevices[i]);
|
||||
selectedDevice = dv.rootDevice.embeddedDevices[i];
|
||||
}
|
||||
if(process.argv[arg].startsWith('udn='))
|
||||
{
|
||||
console.log('Selected Device: ' + process.argv[arg].split('=')[1]);
|
||||
selectedDevice = dv.getDevice(process.argv[arg].split('=')[1]);
|
||||
display_device(selectedDevice);
|
||||
}
|
||||
if(selectedDevice && process.argv[arg].startsWith('serviceId='))
|
||||
{
|
||||
selectedService = selectedDevice.getService(process.argv[arg].split('=')[1]);
|
||||
display_service(selectedService);
|
||||
}
|
||||
if(selectedService && process.argv[arg].startsWith('action='))
|
||||
{
|
||||
selectedAction = selectedService.getAction(process.argv[arg].split('=')[1]);
|
||||
display_actionDetail(selectedAction);
|
||||
}
|
||||
if(selectedAction && process.argv[arg].startsWith('invoke='))
|
||||
{
|
||||
var txt = process.argv[arg].split('=')[1];
|
||||
|
||||
console.log('Invoking with: ' + txt);
|
||||
selectedAction.invoke(JSON.parse(process.argv[arg].split('=')[1]), function ()
|
||||
{
|
||||
console.log('Response: ', arguments[0]);
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
if (selectedAction && process.argv[arg].startsWith('invokeLegacy=')) {
|
||||
var txt = process.argv[arg].split('=')[1];
|
||||
|
||||
console.log('Invoking with: ' + txt);
|
||||
selectedAction.invokeLegacy(JSON.parse(process.argv[arg].split('=')[1]), function () {
|
||||
console.log('Response: ', arguments[0]);
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user