mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
bind to correct port when doing udp broadcast/multicast (#1686)
* bind to correct port when doing broadcast/multicast to allow better re-use of ports. * allow udp multicast to work out if ip address makes life easier for mortals * udp also handle bind to ipv6 multicast if tidy prompts to suit new function * udp node, add face to debug log for multicast if known
This commit is contained in:
parent
e691351976
commit
94cb03f4b5
@ -29,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row node-input-iface">
|
<div class="form-row node-input-iface">
|
||||||
<label for="node-input-iface"><i class="fa fa-random"></i> <span data-i18n="udp.label.interface"></span></label>
|
<label for="node-input-iface"><i class="fa fa-random"></i> <span data-i18n="udp.label.interface"></span></label>
|
||||||
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.label.interfaceprompt">
|
<input type="text" id="node-input-iface" data-i18n="[placeholder]udp.placeholder.interfaceprompt">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.onport"></span></label>
|
<label for="node-input-port"><i class="fa fa-sign-in"></i> <span data-i18n="udp.label.onport"></span></label>
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
module.exports = function(RED) {
|
module.exports = function(RED) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
var os = require('os');
|
||||||
var dgram = require('dgram');
|
var dgram = require('dgram');
|
||||||
var udpInputPortsInUse = {};
|
var udpInputPortsInUse = {};
|
||||||
|
|
||||||
@ -30,6 +31,29 @@ module.exports = function(RED) {
|
|||||||
this.ipv = n.ipv || "udp4";
|
this.ipv = n.ipv || "udp4";
|
||||||
var node = this;
|
var node = this;
|
||||||
|
|
||||||
|
if (node.iface && node.iface.indexOf(".") === -1) {
|
||||||
|
try {
|
||||||
|
if ((os.networkInterfaces())[node.iface][0].hasOwnProperty("scopeid")) {
|
||||||
|
if (node.ipv === "udp4") {
|
||||||
|
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||||
|
} else {
|
||||||
|
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (node.ipv === "udp4") {
|
||||||
|
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||||
|
} else {
|
||||||
|
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
node.warn(RED._("udp.errors.ifnotfound",{iface:node.iface}));
|
||||||
|
node.iface = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 server;
|
var server;
|
||||||
@ -39,7 +63,7 @@ module.exports = function(RED) {
|
|||||||
udpInputPortsInUse[this.port] = server;
|
udpInputPortsInUse[this.port] = server;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.warn(RED._("udp.errors.alreadyused",node.port));
|
node.warn(RED._("udp.errors.alreadyused",{port:node.port}));
|
||||||
server = udpInputPortsInUse[this.port]; // re-use existing
|
server = udpInputPortsInUse[this.port]; // re-use existing
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,12 +145,38 @@ module.exports = function(RED) {
|
|||||||
this.ipv = n.ipv || "udp4";
|
this.ipv = n.ipv || "udp4";
|
||||||
var node = this;
|
var node = this;
|
||||||
|
|
||||||
|
if (node.iface && node.iface.indexOf(".") === -1) {
|
||||||
|
try {
|
||||||
|
if ((os.networkInterfaces())[node.iface][0].hasOwnProperty("scopeid")) {
|
||||||
|
if (node.ipv === "udp4") {
|
||||||
|
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||||
|
} else {
|
||||||
|
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (node.ipv === "udp4") {
|
||||||
|
node.iface = (os.networkInterfaces())[node.iface][0].address;
|
||||||
|
} else {
|
||||||
|
node.iface = (os.networkInterfaces())[node.iface][1].address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
node.warn(RED._("udp.errors.ifnotfound",{iface:node.iface}));
|
||||||
|
node.iface = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
var sock;
|
||||||
if (udpInputPortsInUse[this.outport || this.port]) {
|
var p = this.port;
|
||||||
sock = udpInputPortsInUse[this.outport || this.port];
|
if (node.multicast != "false") { p = this.outport||"0"; }
|
||||||
|
if (udpInputPortsInUse[p]) {
|
||||||
|
sock = udpInputPortsInUse[p];
|
||||||
|
node.log(RED._("udp.status.re-use",{outport:node.outport,host:node.addr,port:node.port}));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sock = dgram.createSocket(opts); // default to udp4
|
sock = dgram.createSocket(opts); // default to udp4
|
||||||
@ -136,18 +186,16 @@ module.exports = function(RED) {
|
|||||||
// prevent it going to the global error handler and shutting node-red
|
// prevent it going to the global error handler and shutting node-red
|
||||||
// down.
|
// down.
|
||||||
});
|
});
|
||||||
udpInputPortsInUse[this.outport || this.port] = sock;
|
udpInputPortsInUse[p] = sock;
|
||||||
}
|
|
||||||
|
|
||||||
if (node.multicast != "false") {
|
if (node.multicast != "false") {
|
||||||
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") {
|
||||||
try {
|
try {
|
||||||
sock.setMulticastTTL(128);
|
sock.setMulticastTTL(128);
|
||||||
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
sock.addMembership(node.addr,node.iface); // Add to the multicast group
|
||||||
node.log(RED._("udp.status.mc-ready",{outport:node.outport,host:node.addr,port:node.port}));
|
node.log(RED._("udp.status.mc-ready",{iface:node.iface,outport:node.outport,host:node.addr,port:node.port}));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.errno == "EINVAL") {
|
if (e.errno == "EINVAL") {
|
||||||
node.error(RED._("udp.errors.bad-mcaddress"));
|
node.error(RED._("udp.errors.bad-mcaddress"));
|
||||||
@ -167,6 +215,7 @@ module.exports = function(RED) {
|
|||||||
} 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}));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node.on("input", function(msg) {
|
node.on("input", function(msg) {
|
||||||
if (msg.hasOwnProperty("payload")) {
|
if (msg.hasOwnProperty("payload")) {
|
||||||
@ -198,8 +247,8 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
node.on("close", function() {
|
node.on("close", function() {
|
||||||
if (udpInputPortsInUse.hasOwnProperty(node.outport || node.port)) {
|
if (udpInputPortsInUse.hasOwnProperty(p)) {
|
||||||
delete udpInputPortsInUse[node.outport || node.port];
|
delete udpInputPortsInUse[p];
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
sock.close();
|
sock.close();
|
||||||
|
@ -495,15 +495,15 @@
|
|||||||
"using": "using",
|
"using": "using",
|
||||||
"output": "Output",
|
"output": "Output",
|
||||||
"group": "Group",
|
"group": "Group",
|
||||||
"interface": "Local IP",
|
"interface": "Local IF",
|
||||||
"interfaceprompt": "(optional) local ip address to bind to",
|
|
||||||
"send": "Send a",
|
"send": "Send a",
|
||||||
"toport": "to port",
|
"toport": "to port",
|
||||||
"address": "Address",
|
"address": "Address",
|
||||||
"decode-base64": "Decode Base64 encoded payload?"
|
"decode-base64": "Decode Base64 encoded payload?"
|
||||||
},
|
},
|
||||||
"placeholder": {
|
"placeholder": {
|
||||||
"interface": "(optional) ip address of eth0",
|
"interface": "(optional) local interface or address to bind to",
|
||||||
|
"interfaceprompt": "(optional) local interface or address to bind to",
|
||||||
"address": "destination ip"
|
"address": "destination ip"
|
||||||
},
|
},
|
||||||
"udpmsgs": "udp messages",
|
"udpmsgs": "udp messages",
|
||||||
@ -531,10 +531,11 @@
|
|||||||
"mc-group": "udp multicast group __group__",
|
"mc-group": "udp multicast group __group__",
|
||||||
"listener-stopped": "udp listener stopped",
|
"listener-stopped": "udp listener stopped",
|
||||||
"output-stopped": "udp output stopped",
|
"output-stopped": "udp output stopped",
|
||||||
"mc-ready": "udp multicast ready: __outport__ -> __host__:__port__",
|
"mc-ready": "udp multicast ready: __iface__:__outport__ -> __host__:__port__",
|
||||||
"bc-ready": "udp broadcast ready: __outport__ -> __host__:__port__",
|
"bc-ready": "udp broadcast ready: __outport__ -> __host__:__port__",
|
||||||
"ready": "udp ready: __outport__ -> __host__:__port__",
|
"ready": "udp ready: __outport__ -> __host__:__port__",
|
||||||
"ready-nolocal": "udp ready: __host__:__port__"
|
"ready-nolocal": "udp ready: __host__:__port__",
|
||||||
|
"re-use": "udp re-use socket: __outport__ -> __host__:__port__"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"access-error": "UDP access error, you may need root access for ports below 1024",
|
"access-error": "UDP access error, you may need root access for ports below 1024",
|
||||||
@ -544,7 +545,8 @@
|
|||||||
"ip-notset": "udp: ip address not set",
|
"ip-notset": "udp: ip address not set",
|
||||||
"port-notset": "udp: port not set",
|
"port-notset": "udp: port not set",
|
||||||
"port-invalid": "udp: port number not valid",
|
"port-invalid": "udp: port number not valid",
|
||||||
"alreadyused": "udp: port already in use"
|
"alreadyused": "udp: port __port__ already in use",
|
||||||
|
"ifnotfound": "udp: interface __iface__ not found"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"switch": {
|
"switch": {
|
||||||
|
@ -526,7 +526,8 @@
|
|||||||
"mc-ready": "udpノードはマルチキャストの準備ができています: __outport__ -> __host__:__port__",
|
"mc-ready": "udpノードはマルチキャストの準備ができています: __outport__ -> __host__:__port__",
|
||||||
"bc-ready": "udpノードはブロードキャストの準備ができています: __outport__ -> __host__:__port__",
|
"bc-ready": "udpノードはブロードキャストの準備ができています: __outport__ -> __host__:__port__",
|
||||||
"ready": "udpノードは準備ができています: __outport__ -> __host__:__port__",
|
"ready": "udpノードは準備ができています: __outport__ -> __host__:__port__",
|
||||||
"ready-nolocal": "udpノードは準備ができています: __host__:__port__"
|
"ready-nolocal": "udpノードは準備ができています: __host__:__port__",
|
||||||
|
"re-use": "udp再利用ソケット: __outport__ -> __host__:__port__"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"access-error": "UDP接続エラー 管理者権限で1024未満のポート番号にアクセスできる必要があります",
|
"access-error": "UDP接続エラー 管理者権限で1024未満のポート番号にアクセスできる必要があります",
|
||||||
|
@ -525,7 +525,8 @@
|
|||||||
"mc-ready": "udp 组播已准备好: __outport__ -> __host__:__port__",
|
"mc-ready": "udp 组播已准备好: __outport__ -> __host__:__port__",
|
||||||
"bc-ready": "udp 广播已准备好: __outport__ -> __host__:__port__",
|
"bc-ready": "udp 广播已准备好: __outport__ -> __host__:__port__",
|
||||||
"ready": "udp 已准备好: __outport__ -> __host__:__port__",
|
"ready": "udp 已准备好: __outport__ -> __host__:__port__",
|
||||||
"ready-nolocal": "udp 已准备好: __host__:__port__"
|
"ready-nolocal": "udp 已准备好: __host__:__port__",
|
||||||
|
"re-use": "udp 重用套接字: __outport__ -> __host__:__port__"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"access-error": "UDP 访问错误, 你可能需要root权限才能接入1024以下的端口",
|
"access-error": "UDP 访问错误, 你可能需要root权限才能接入1024以下的端口",
|
||||||
|
Loading…
Reference in New Issue
Block a user