mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #1945 from node-red/UDP-Node-fixes
Udp node socket binding fixes
This commit is contained in:
commit
4d27ba1bda
@ -58,17 +58,36 @@ module.exports = function(RED) {
|
|||||||
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
|
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
|
||||||
var server;
|
var server;
|
||||||
|
|
||||||
if (!udpInputPortsInUse.hasOwnProperty(this.port)) {
|
if (!udpInputPortsInUse.hasOwnProperty(node.port)) {
|
||||||
server = dgram.createSocket(opts); // default to udp4
|
server = dgram.createSocket(opts); // default to udp4
|
||||||
udpInputPortsInUse[this.port] = server;
|
server.bind(node.port, function() {
|
||||||
|
if (node.multicast == "true") {
|
||||||
|
server.setBroadcast(true);
|
||||||
|
server.setMulticastLoopback(false);
|
||||||
|
try {
|
||||||
|
server.setMulticastTTL(128);
|
||||||
|
server.addMembership(node.group,node.iface);
|
||||||
|
if (node.iface) { node.status({text:n.iface+" : "+node.iface}); }
|
||||||
|
node.log(RED._("udp.status.mc-group",{group:node.group}));
|
||||||
|
} catch (e) {
|
||||||
|
if (e.errno == "EINVAL") {
|
||||||
|
node.error(RED._("udp.errors.bad-mcaddress"));
|
||||||
|
} else if (e.errno == "ENODEV") {
|
||||||
|
node.error(RED._("udp.errors.interface"));
|
||||||
|
} else {
|
||||||
|
node.error(RED._("udp.errors.error",{error:e.errno}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
udpInputPortsInUse[node.port] = server;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.log(RED._("udp.errors.alreadyused",{port:node.port}));
|
node.log(RED._("udp.errors.alreadyused",{port:node.port}));
|
||||||
server = udpInputPortsInUse[this.port]; // re-use existing
|
server = udpInputPortsInUse[node.port]; // re-use existing
|
||||||
|
if (node.iface) { node.status({text:n.iface+" : "+node.iface}); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.version.indexOf("v0.10") === 0) { opts = node.ipv; }
|
|
||||||
|
|
||||||
server.on("error", function (err) {
|
server.on("error", function (err) {
|
||||||
if ((err.code == "EACCES") && (node.port < 1024)) {
|
if ((err.code == "EACCES") && (node.port < 1024)) {
|
||||||
node.error(RED._("udp.errors.access-error"));
|
node.error(RED._("udp.errors.access-error"));
|
||||||
@ -92,39 +111,24 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
server.on('listening', function () {
|
server.on('listening', function () {
|
||||||
var address = server.address();
|
var address = server.address();
|
||||||
node.log(RED._("udp.status.listener-at",{host:address.address,port:address.port}));
|
node.log(RED._("udp.status.listener-at",{host:node.iface||address.address,port:address.port}));
|
||||||
if (node.multicast == "true") {
|
|
||||||
server.setBroadcast(true);
|
|
||||||
try {
|
|
||||||
server.setMulticastTTL(128);
|
|
||||||
server.addMembership(node.group,node.iface);
|
|
||||||
node.log(RED._("udp.status.mc-group",{group:node.group}));
|
|
||||||
} catch (e) {
|
|
||||||
if (e.errno == "EINVAL") {
|
|
||||||
node.error(RED._("udp.errors.bad-mcaddress"));
|
|
||||||
} else if (e.errno == "ENODEV") {
|
|
||||||
node.error(RED._("udp.errors.interface"));
|
|
||||||
} else {
|
|
||||||
node.error(RED._("udp.errors.error",{error:e.errno}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
node.on("close", function() {
|
node.on("close", function() {
|
||||||
if (udpInputPortsInUse.hasOwnProperty(node.port)) {
|
|
||||||
delete udpInputPortsInUse[node.port];
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
|
if (node.multicast == "true") { server.dropMembership(node.group); }
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
if (udpInputPortsInUse.hasOwnProperty(node.port)) {
|
||||||
|
delete udpInputPortsInUse[node.port];
|
||||||
|
}
|
||||||
|
node.status({});
|
||||||
});
|
});
|
||||||
|
|
||||||
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-ports.read'), function(req,res) {
|
RED.httpAdmin.get('/udp-ports/:id', RED.auth.needsPermission('udp-ports.read'), function(req,res) {
|
||||||
res.json(Object.keys(udpInputPortsInUse));
|
res.json(Object.keys(udpInputPortsInUse));
|
||||||
@ -132,6 +136,7 @@ module.exports = function(RED) {
|
|||||||
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);
|
||||||
@ -169,92 +174,98 @@ 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; }
|
|
||||||
|
|
||||||
var sock;
|
var sock;
|
||||||
var p = this.outport || this.port || "0";
|
var p = this.outport || this.port || "0";
|
||||||
if (udpInputPortsInUse[p]) {
|
node.tout = setTimeout(function() {
|
||||||
sock = udpInputPortsInUse[p];
|
if (udpInputPortsInUse[p]) {
|
||||||
node.log(RED._("udp.status.re-use",{outport:node.outport,host:node.addr,port:node.port}));
|
sock = udpInputPortsInUse[p];
|
||||||
}
|
node.log(RED._("udp.status.re-use",{outport:node.outport,host:node.addr,port:node.port}));
|
||||||
else {
|
if (node.iface) { node.status({text:n.iface+" : "+node.iface}); }
|
||||||
sock = dgram.createSocket(opts); // default to udp4
|
}
|
||||||
sock.on("error", function(err) {
|
else {
|
||||||
// Any async error will also get reported in the sock.send call.
|
sock = dgram.createSocket(opts); // default to udp4
|
||||||
// This handler is needed to ensure the error marked as handled to
|
if (node.multicast != "false") {
|
||||||
// prevent it going to the global error handler and shutting node-red
|
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
|
||||||
// down.
|
sock.setBroadcast(true); // turn on broadcast
|
||||||
});
|
sock.setMulticastLoopback(false); // turn off loopback
|
||||||
udpInputPortsInUse[p] = sock;
|
if (node.multicast == "multi") {
|
||||||
|
try {
|
||||||
if (node.multicast != "false") {
|
sock.setMulticastTTL(128);
|
||||||
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
|
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
||||||
sock.setBroadcast(true); // turn on broadcast
|
if (node.iface) { node.status({text:n.iface+" : "+node.iface}); }
|
||||||
if (node.multicast == "multi") {
|
node.log(RED._("udp.status.mc-ready",{iface:node.iface,outport:node.outport,host:node.addr,port:node.port}));
|
||||||
try {
|
} catch (e) {
|
||||||
sock.setMulticastTTL(128);
|
if (e.errno == "EINVAL") {
|
||||||
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
node.error(RED._("udp.errors.bad-mcaddress"));
|
||||||
node.log(RED._("udp.status.mc-ready",{iface:node.iface,outport:node.outport,host:node.addr,port:node.port}));
|
} else if (e.errno == "ENODEV") {
|
||||||
} catch (e) {
|
node.error(RED._("udp.errors.interface"));
|
||||||
if (e.errno == "EINVAL") {
|
} else {
|
||||||
node.error(RED._("udp.errors.bad-mcaddress"));
|
node.error(RED._("udp.errors.error",{error:e.errno}));
|
||||||
} else if (e.errno == "ENODEV") {
|
}
|
||||||
node.error(RED._("udp.errors.interface"));
|
|
||||||
} else {
|
|
||||||
node.error(RED._("udp.errors.error",{error:e.errno}));
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
node.log(RED._("udp.status.bc-ready",{outport:node.outport,host:node.addr,port:node.port}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if ((node.outport !== "") && (!udpInputPortsInUse[node.outport])) {
|
|
||||||
sock.bind(node.outport);
|
|
||||||
node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
|
|
||||||
} else {
|
|
||||||
node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node.on("input", function(msg) {
|
|
||||||
if (msg.hasOwnProperty("payload")) {
|
|
||||||
var add = node.addr || msg.ip || "";
|
|
||||||
var por = node.port || msg.port || 0;
|
|
||||||
if (add === "") {
|
|
||||||
node.warn(RED._("udp.errors.ip-notset"));
|
|
||||||
} else if (por === 0) {
|
|
||||||
node.warn(RED._("udp.errors.port-notset"));
|
|
||||||
} else if (isNaN(por) || (por < 1) || (por > 65535)) {
|
|
||||||
node.warn(RED._("udp.errors.port-invalid"));
|
|
||||||
} else {
|
|
||||||
var message;
|
|
||||||
if (node.base64) {
|
|
||||||
message = Buffer.from(msg.payload, 'base64');
|
|
||||||
} else if (msg.payload instanceof Buffer) {
|
|
||||||
message = msg.payload;
|
|
||||||
} else {
|
|
||||||
message = Buffer.from(""+msg.payload);
|
|
||||||
}
|
|
||||||
sock.send(message, 0, message.length, por, add, function(err, bytes) {
|
|
||||||
if (err) {
|
|
||||||
node.error("udp : "+err,msg);
|
|
||||||
}
|
|
||||||
message = null;
|
|
||||||
});
|
});
|
||||||
|
} else if ((node.outport !== "") && (!udpInputPortsInUse[node.outport])) {
|
||||||
|
sock.bind(node.outport);
|
||||||
|
node.log(RED._("udp.status.ready",{outport:node.outport,host:node.addr,port:node.port}));
|
||||||
|
} else {
|
||||||
|
node.log(RED._("udp.status.ready-nolocal",{host:node.addr,port:node.port}));
|
||||||
}
|
}
|
||||||
|
sock.on("error", function(err) {
|
||||||
|
// Any async error will also get reported in the sock.send call.
|
||||||
|
// This handler is needed to ensure the error marked as handled to
|
||||||
|
// prevent it going to the global error handler and shutting node-red
|
||||||
|
// down.
|
||||||
|
});
|
||||||
|
udpInputPortsInUse[p] = sock;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
node.on("input", function(msg) {
|
||||||
|
if (msg.hasOwnProperty("payload")) {
|
||||||
|
var add = node.addr || msg.ip || "";
|
||||||
|
var por = node.port || msg.port || 0;
|
||||||
|
if (add === "") {
|
||||||
|
node.warn(RED._("udp.errors.ip-notset"));
|
||||||
|
} else if (por === 0) {
|
||||||
|
node.warn(RED._("udp.errors.port-notset"));
|
||||||
|
} else if (isNaN(por) || (por < 1) || (por > 65535)) {
|
||||||
|
node.warn(RED._("udp.errors.port-invalid"));
|
||||||
|
} else {
|
||||||
|
var message;
|
||||||
|
if (node.base64) {
|
||||||
|
message = Buffer.from(msg.payload, 'base64');
|
||||||
|
} else if (msg.payload instanceof Buffer) {
|
||||||
|
message = msg.payload;
|
||||||
|
} else {
|
||||||
|
message = Buffer.from(""+msg.payload);
|
||||||
|
}
|
||||||
|
sock.send(message, 0, message.length, por, add, function(err, bytes) {
|
||||||
|
if (err) {
|
||||||
|
node.error("udp : "+err,msg);
|
||||||
|
}
|
||||||
|
message = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, 150);
|
||||||
|
|
||||||
node.on("close", function() {
|
node.on("close", function() {
|
||||||
if (udpInputPortsInUse.hasOwnProperty(p)) {
|
if (node.tout) { clearTimeout(node.tout); }
|
||||||
delete udpInputPortsInUse[p];
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
|
if (node.multicast == "multi") { sock.dropMembership(node.group); }
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
if (udpInputPortsInUse.hasOwnProperty(p)) {
|
||||||
|
delete udpInputPortsInUse[p];
|
||||||
|
}
|
||||||
|
node.status({});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
RED.nodes.registerType("udp out",UDPout);
|
RED.nodes.registerType("udp out",UDPout);
|
||||||
|
Loading…
Reference in New Issue
Block a user