control-freak-ide/server/nodejs/nxapp/protocols/Tcp.js
plastic-hub-dev-node-saturn 538369cff7 latest
2021-05-12 18:35:18 +02:00

442 lines
11 KiB
JavaScript

/** @module nxapp/protocols/Tcp */
define([
'dcl/dcl',
"nxapp/utils",
'nxapp/protocols/ProtocolBase',
"dojo/node!net",
"dojo/node!child_process",
"dojo/node!util",
"dojo/node!path",
"xide/mixins/EventedMixin",
"xide/mixins/ReloadMixin",
"xide/types",
"dojo/Deferred",
"dojo/node!evilscan",
"dojo/node!ipaddr.js",
"dojo/node!os"
], function (dcl, utils, ProtocolBase, net, child, util, path, EventedMixin, ReloadMixin, types, Deferred, evilscan, ipaddr, os) {
var debug = false;
/**
* Tcp protocol client
* @class module:nxapp/protocols/Tcp
* @extends module:nxapp/protocols/ProtocolBase
* @implements module:nxapp/protocols/ProtocolBase
*/
var Module = dcl(ProtocolBase, {
declaredClass: "nxapp.protocols.Tcp",
/**
* @member _socket {module:net/Socket | module:net/Server}
*/
_socket: null,
protocolName: 'tcp',
/**
* @member delegate {module:nxapp/manager/ConnectionManager}
*/
delegate: null,
driverInstance: null,
_handleSocketEmits: function (socket) {
var self = this;
self.clients = [];
var connection = self.connection;
var scope = this.blockScope;
var responseVariable = scope.getVariable('value');
var responseVariables = scope.getVariables({
group: types.BLOCK_GROUPS.CF_DRIVER_RESPONSE_VARIABLES
});
var responseBlocks = scope.getBlocks({
group: types.BLOCK_GROUPS.CF_DRIVER_RESPONSE_BLOCKS
});
socket.on('connection', function (conn) {
self.socket = conn;
self.clients.push(conn);
conn.on('data', function (data) {
var messages = [{
string: data.toString(),
bytes: data.join(",")
}];
for (var i = 0; i < messages.length; i++) {
if (messages[i].length === 0) {
continue;
}
responseVariable.value = new String(messages[i].string);
responseVariable.value.setBytes(messages[i].bytes);
//now run each top variable block in 'conditional process'
for (var j = 0; j < responseVariables.length; j++) {
var _var = responseVariables[j];
if (responseVariables[j].title == 'value') {
continue;
}
var _varResult = null;
var _cValue = responseVariable.value;
if (!(typeof _cValue == "number")) {
_cValue = '' + _cValue;
_cValue = "'" + _cValue + "'";
}
var prefix = "var value = " + _cValue + ";";
_varResult = _cValue;
if (_var.target && _var.target != 'None' && _varResult !== null && _varResult != 'null' && _varResult != "'null'") {
var targetVariable = scope.getVariable(_var.target);
if (targetVariable) {
targetVariable.value = _varResult;
this.publish(types.EVENTS.ON_DRIVER_VARIABLE_CHANGED, {
item: targetVariable,
scope: scope,
owner: this,
save: false,
source: types.MESSAGE_SOURCE.BLOX //for prioritizing
});
}
}
}
for (var k = 0; k < messages.length; k++) {
var __message = messages[k];
if (_.isObject(__message)) {
if (__message.src) {
var block = scope.getBlockById(__message.src);
if (block && block.onData) {
block.onData(__message);
}
}
}
}
for (var l = 0; l < responseBlocks.length; l++) {
var block = responseBlocks[l];
if (block.enabled === false) {
continue;
}
block.override = {
args: [responseVariable.value]
};
try {
scope.solveBlock(responseBlocks[l], {
highlight: false
});
} catch (e) {
console.log('----solving response block crashed ', e);
console.trace();
}
}
}
});
conn.on('close', function () {
debug && console.info('close client connection ');
});
});
},
_creatingServer: false,
makeServer: function () {
if (this._creatingServer) {
return;
}
this._creatingServer = true;
try {
debug && console.log('create server');
var options = this.options;
var port = options.port;
var host = options.host;
var connectionManager = this.owner;
var context = connectionManager.ctx;
var driverManager = context.getDriverManager();
var dfd = driverManager.createDriverInstance(options);
var self = this;
dfd.then(function (data) {
self.blockScope = data.blockScope;
self.driverInstance = data.driverInstance;
});
var server = new net.Server();
server.listen(port, host);
self._socket = server;
server.writable = true;
self._handleSocketEmits(server);
self.connection.connected = true;
self.delegate.onConnect2(self.connection);
this.subscribe(types.EVENTS.ON_DEVICE_CONNECTED, this.onDeviceConnected);
this.subscribe(types.EVENTS.ON_DEVICE_DISCONNECTED, this.onDeviceDisconnected);
} catch (e) {
console.error('error creating server', e);
}
return this;
},
/**
* @member {module:nxapp/model/Connection []}
*/
connections: null,
/**
* @param evt {object}
* @param evt.connection {module:nxapp/model/Connection}
*/
onDeviceConnected: function (evt) {
var connection = evt.connection;
if (!connection) {
return;
}
var cOptions = connection.options;
var options = this.options;
if (!this.connections) {
this.connections = [];
}
if (connection.id === this.connection.id) {
return;
}
var exists = this.delegate.getConnectionById(connection.id);
if (exists && options.host === cOptions.host && options.port === cOptions.port && options.protocol === cOptions.protocol && !connection.isServer()) {
if (this.connections.indexOf(connection) === -1) {
this.connections.push(connection);
}
}
},
/**
* @param evt {object}
* @param evt.connection {module:nxapp/model/Connection}
*/
onDeviceDisconnected: function (evt) {
var connection = evt.connection;
if (!connection) {
return;
}
if (!this.connections) {
this.connections = [];
}
if (this.connections.indexOf(connection) !== -1) {
this.connections.remove(connection);
}
},
/**
* Implement connect
* @returns {module:nxapp/protocols/Tcp}
*/
connect: function () {
var isServer = this.isServer();
// console.log('is server', isServer, this.options);
if (isServer) {
return this.makeServer();
}
var options = this.options;
var port = this.options.port;
var host = this.options.host;
this.clients = [];
this._socket = new net.Socket(utils.mixin({
allowHalfOpen: true,
writable: true,
readable: true
}, options.options));
var self = this;
this.isDebug() && console.log('TCP-Client->Connect to ' + this.options.host + ' : ' + this.options.port + ' @ ' + this.protocolName);
this._socket.connect(port, host, function () {
self.connection.connected = true;
self.delegate.onConnect2(self.connection);
});
this._socket.setNoDelay(true);
this._socket.setKeepAlive(true, 0);
this._socket.owner = this;
this._setupEventListeners(this._socket, this.delegate);
return this;
},
broadCastMessage: function (eventName, _data) {
var self = this;
var data = _data;
if (this.connections) {
_.each(this.connections, function (connection) {
if (connection && connection._destroyed) {
self.connections.remove(connection);
}
if (connection) {
if (connection.client) {
connection.client.delegate.onData(connection, data.toString(), data);
} else {
console.error('not at a real connection', connection);
}
} else {
console.error('invalid connection', connection);
}
});
}
},
/**
* Implement send
* @implements module:nxapp/protocols/ProtocolBase~send
* @inheritDoc
* @param cmd {string} the raw string to send
*/
send: function (cmd) {
if (cmd == null) {
console.error('TCP : invalid command');
return;
}
var intArray = utils.bufferFromDecString(cmd);
var buffer = new Buffer(intArray);
if (this.isServer()) {
this.broadCastMessage(types.EVENTS.ON_DEVICE_MESSAGE, buffer);
} else {
this._socket.write(buffer);
}
},
destroy: function () {
console.log('destroy');
if (!this.isServer()) {
this._socket.end();
} else {
this._socket.close();
}
this.blockScope && this.blockScope.destroy();
this.driverInstance && this.driverInstance.destroy();
delete this.blockScope;
delete this.driverInstance;
delete this.connections;
delete this.clients;
delete this._socket;
this._destroyed = true;
},
/**
* Implement close
* @inheritDoc
*/
close: function () {
if (!this.isServer()) {
this._socket.end();
} else {
this._socket.close();
this.destroy();
}
}
});
Module.net = net;
Module.ls = function (query) {
try {
var dfd = new Deferred();
var ifaces = os.networkInterfaces();
var ips = [];
Object.keys(ifaces).forEach(function (ifname) {
var alias = 0;
ifaces[ifname].forEach(function (iface) {
if ('IPv4' !== iface.family || iface.internal !== false) {
// skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
return;
}
if (alias >= 1) {
// this single interface has multiple ipv4 addresses
ips.push({
face: ifname + alias,
ip: iface.address
})
} else {
ips.push({
face: ifname,
ip: iface.address
})
}
++alias;
});
});
var results = {}
function checkResults() {
var done = true;
_.each(results, function (item) {
if (!item.done) {
done = false;
}
})
if (done) {
var result = [];
results = _.filter(results, function (result) {
return result.list.length > 0
});
_.each(results, function (item) {
result = result.concat(item.list);
});
dfd.resolve(result);
}
}
_.each(ips, function (ip) {
var range = ipaddr.parse(ip.ip);
var octets = range.octets;
octets[octets.length - 1] = 0;
var target = octets.join('.') + '-254';
var testPorts = [query.ports || '80'];
var options = {
target: target,
port: testPorts.join(','),
status: 'Open', // Timeout, Refused, Open, Unreachable
timeout: 500,
banner: false
}
var scanner = new evilscan(options);
if (!results[target]) {
results[target] = {
done: false
};
results[target].list = [];
}
scanner.on('result', function (data) {
// fired when item is matching options
if (data.status === 'open') {
results[target].list.push({
host: data.ip,
port: data.port,
description: ip.face + ' ' + ip.ip,
"interface": ip.face
});
}
});
scanner.on('error', function (err) {
dfd.reject("error scanning tcp");
});
scanner.on('done', function () {
//console.log('done');
results[target].done = true;
checkResults();
});
scanner.run();
})
} catch (e) {
console.error('error', e);
}
return dfd;
}
Module.options = function (query) {
var dfd = new Deferred();
var ECIType = types.ECIType;
var NetworkGroup = 'Network';
var cis = [
utils.createCI('allowHalfOpen', ECIType.BOOL, true, {
group: NetworkGroup
}),
utils.createCI('readable', ECIType.BOOL, true, {
group: NetworkGroup
}),
utils.createCI('writable', ECIType.BOOL, true, {
group: NetworkGroup
})
]
dfd.resolve(cis);
return dfd;
}
return Module;
});