Let UDP node better share same port instance if required

This commit is contained in:
Dave Conway-Jones 2016-09-17 14:05:26 +01:00
parent ea8c6d5cce
commit 29e9740668
2 changed files with 45 additions and 25 deletions

View File

@ -83,7 +83,9 @@
if (this.multicast=="false") { if (this.multicast=="false") {
return this.name||"udp "+this.port; return this.name||"udp "+this.port;
} }
else return this.name||"udp "+(this.group+":"+this.port); else {
return this.name||"udp "+(this.group+":"+this.port);
}
}, },
labelStyle: function() { labelStyle: function() {
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
@ -107,7 +109,7 @@
var portsInUse = {}; var portsInUse = {};
$.getJSON('udp-ports/'+this.id,function(data) { $.getJSON('udp-ports/'+this.id,function(data) {
portsInUse = data || {}; portsInUse = data || {};
$('#udpporttip').html(porttip + Object.keys(data||{})); $('#udpporttip').html(porttip + data);
}); });
$("#node-input-port").change(function() { $("#node-input-port").change(function() {
var portnew = $("#node-input-port").val(); var portnew = $("#node-input-port").val();
@ -201,7 +203,7 @@
var bindrandom = this._("udp.bind.random"); var bindrandom = this._("udp.bind.random");
var bindtarget = this._("udp.bind.target"); var bindtarget = this._("udp.bind.target");
var type = this.outport==""?"random":"fixed"; var type = this.outport===""?"random":"fixed";
$("#node-input-outport-type").val(type); $("#node-input-outport-type").val(type);
$("#node-input-outport-type").change(function() { $("#node-input-outport-type").change(function() {

View File

@ -29,11 +29,18 @@ module.exports = function(RED) {
this.multicast = n.multicast; this.multicast = n.multicast;
this.ipv = n.ipv || "udp4"; this.ipv = n.ipv || "udp4";
var node = this; var node = this;
var opts = {type:node.ipv, reuseAddr:true};
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
var server;
if (!udpInputPortsInUse.hasOwnProperty(this.port)) { if (!udpInputPortsInUse.hasOwnProperty(this.port)) {
udpInputPortsInUse[this.port] = n.id; server = dgram.createSocket(opts); // default to udp4
udpInputPortsInUse[this.port] = server;
} }
else { else {
node.warn(RED._("udp.errors.alreadyused",node.port)); node.warn(RED._("udp.errors.alreadyused",node.port));
server = udpInputPortsInUse[this.port]; // re-use existing
} }
var opts = {type:node.ipv, reuseAddr:true}; var opts = {type:node.ipv, reuseAddr:true};
@ -83,24 +90,26 @@ module.exports = function(RED) {
}); });
node.on("close", function() { node.on("close", function() {
if (udpInputPortsInUse[node.port] === node.id) { if (udpInputPortsInUse.hasOwnProperty(node.port)) {
delete udpInputPortsInUse[node.port]; delete udpInputPortsInUse[node.port];
} }
try { try {
server.close(); server.close();
node.log(RED._("udp.status.listener-stopped")); node.log(RED._("udp.status.listener-stopped"));
} catch (err) { } catch (err) {
node.error(err); //node.error(err);
} }
}); });
server.bind(node.port,node.iface); try { server.bind(node.port,node.iface); }
catch(e) { } // Don't worry if already bound
} }
RED.httpAdmin.get('/udp-ports/:id', RED.auth.needsPermission('udp-in.read'), function(req,res) { RED.httpAdmin.get('/udp-ports/:id', RED.auth.needsPermission('udp-in.read'), function(req,res) {
res.json(udpInputPortsInUse); res.json(Object.keys(udpInputPortsInUse));
}); });
RED.nodes.registerType("udp in",UDPin); RED.nodes.registerType("udp in",UDPin);
// The Output Node // The Output Node
function UDPout(n) { function UDPout(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
@ -116,7 +125,15 @@ module.exports = function(RED) {
var opts = {type:node.ipv, reuseAddr:true}; var opts = {type:node.ipv, reuseAddr:true};
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; } if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
var sock = dgram.createSocket(opts); // default to udp4
var sock;
if (udpInputPortsInUse[this.outport]) {
sock = udpInputPortsInUse[this.outport];
}
else {
sock = dgram.createSocket(opts); // default to udp4
udpInputPortsInUse[this.outport] = sock;
}
sock.on("error", function(err) { sock.on("error", function(err) {
// Any async error will also get reported in the sock.send call. // Any async error will also get reported in the sock.send call.
@ -125,7 +142,7 @@ module.exports = function(RED) {
// down. // down.
}); });
if (node.multicast != "false") { if (node.multicast != "false") {
if (node.outport == "") { node.outport = node.port; } if (node.outport === "") { node.outport = node.port; }
sock.bind(node.outport, function() { // have to bind before you can enable broadcast... sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
sock.setBroadcast(true); // turn on broadcast sock.setBroadcast(true); // turn on broadcast
if (node.multicast == "multi") { if (node.multicast == "multi") {
@ -146,11 +163,9 @@ module.exports = function(RED) {
node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port})); node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port}));
} }
}); });
} else if (node.outport != "") { } else if ((node.outport !== "") && (!udpInputPortsInUse[this.outport])) {
setTimeout( function() {
sock.bind(node.outport); sock.bind(node.outport);
node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port})); node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
}, 250);
} else { } else {
node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port})); node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
} }
@ -159,9 +174,9 @@ module.exports = function(RED) {
if (msg.hasOwnProperty("payload")) { if (msg.hasOwnProperty("payload")) {
var add = node.addr || msg.ip || ""; var add = node.addr || msg.ip || "";
var por = node.port || msg.port || 0; var por = node.port || msg.port || 0;
if (add == "") { if (add === "") {
node.warn(RED._("udp.errors.ip-notset")); node.warn(RED._("udp.errors.ip-notset"));
} else if (por == 0) { } else if (por === 0) {
node.warn(RED._("udp.errors.port-notset")); node.warn(RED._("udp.errors.port-notset"));
} else if (isNaN(por) || (por < 1) || (por > 65535)) { } else if (isNaN(por) || (por < 1) || (por > 65535)) {
node.warn(RED._("udp.errors.port-invalid")); node.warn(RED._("udp.errors.port-invalid"));
@ -185,11 +200,14 @@ module.exports = function(RED) {
}); });
node.on("close", function() { node.on("close", function() {
if (udpInputPortsInUse.hasOwnProperty(node.outport)) {
delete udpInputPortsInUse[node.outport];
}
try { try {
sock.close(); sock.close();
node.log(RED._("udp.status.output-stopped")); node.log(RED._("udp.status.output-stopped"));
} catch (err) { } catch (err) {
node.error(err); //node.error(err);
} }
}); });
} }