/** @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; });