Aggiungi override probe TCP keepalive
parent
6b19a8a606
commit
cc4a3ed9c1
|
|
@ -1 +1,2 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
|
native/tcp_keepalive/build/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"target_name": "tcp_keepalive_native",
|
||||||
|
"sources": [ "tcp_keepalive_native.c" ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
#include <node_api.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static napi_value make_boolean(napi_env env, bool value) {
|
||||||
|
napi_value result;
|
||||||
|
napi_get_boolean(env, value, &result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static napi_value set_keepalive_probes(napi_env env, napi_callback_info info) {
|
||||||
|
size_t argc = 2;
|
||||||
|
napi_value args[2];
|
||||||
|
int32_t fd = -1;
|
||||||
|
int32_t probes = 0;
|
||||||
|
|
||||||
|
napi_get_cb_info(env, info, &argc, args, NULL, NULL);
|
||||||
|
if (argc < 2) {
|
||||||
|
return make_boolean(env, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (napi_get_value_int32(env, args[0], &fd) != napi_ok ||
|
||||||
|
napi_get_value_int32(env, args[1], &probes) != napi_ok ||
|
||||||
|
fd < 0 || probes <= 0) {
|
||||||
|
return make_boolean(env, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
return make_boolean(env, setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &probes, sizeof(probes)) == 0);
|
||||||
|
#else
|
||||||
|
return make_boolean(env, false);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static napi_value init(napi_env env, napi_value exports) {
|
||||||
|
napi_value fn;
|
||||||
|
|
||||||
|
napi_create_function(env, "setKeepAliveProbes", NAPI_AUTO_LENGTH, set_keepalive_probes, NULL, &fn);
|
||||||
|
napi_set_named_property(env, exports, "setKeepAliveProbes", fn);
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
NAPI_MODULE(NODE_GYP_MODULE_NAME, init)
|
||||||
|
|
@ -6,7 +6,8 @@
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "red-briq-nodes",
|
"name": "red-briq-nodes",
|
||||||
"version": "0.2.5",
|
"version": "0.2.6",
|
||||||
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"denque": "^1.4.1",
|
"denque": "^1.4.1",
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
"name": "red-briq-nodes",
|
"name": "red-briq-nodes",
|
||||||
"version": "0.2.6",
|
"version": "0.2.6",
|
||||||
"description": "Various forked and original nodes",
|
"description": "Various forked and original nodes",
|
||||||
|
"scripts": {
|
||||||
|
"install": "node scripts/build-tcp-keepalive.js"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"denque": "^1.4.1",
|
"denque": "^1.4.1",
|
||||||
"simple-xmpp": "^1.3.1",
|
"simple-xmpp": "^1.3.1",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
let native = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
native = require("../../native/tcp_keepalive/build/Release/tcp_keepalive_native");
|
||||||
|
} catch (err) {
|
||||||
|
native = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseKeepAliveProbes(value) {
|
||||||
|
if (value === undefined || value === null || value === "") {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = Number(value);
|
||||||
|
if (!Number.isFinite(value) || value < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.floor(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setKeepAliveProbes(socket, probes) {
|
||||||
|
if (!native || probes <= 0 || !socket || !socket._handle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fd = socket._handle.fd;
|
||||||
|
if (!Number.isInteger(fd) || fd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return native.setKeepAliveProbes(fd, probes) === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
available: !!native,
|
||||||
|
parseKeepAliveProbes,
|
||||||
|
setKeepAliveProbes
|
||||||
|
};
|
||||||
|
|
@ -44,6 +44,10 @@
|
||||||
<label><i class="fa fa-clock-o"></i> <span>Keepalive</span></label>
|
<label><i class="fa fa-clock-o"></i> <span>Keepalive</span></label>
|
||||||
<input type="text" id="node-input-keepalive" style="text-align:end; width:200px !important">
|
<input type="text" id="node-input-keepalive" style="text-align:end; width:200px !important">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label><i class="fa fa-times-circle"></i> <span>Missed keepalives</span></label>
|
||||||
|
<input type="text" id="node-input-keepaliveProbes" style="text-align:end; width:120px !important">
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="node-row-newline" class="form-row hidden" style="padding-left:110px;">
|
<div id="node-row-newline" class="form-row hidden" style="padding-left:110px;">
|
||||||
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;">
|
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;">
|
||||||
|
|
@ -72,6 +76,7 @@
|
||||||
datatype: { value: "buffer" },
|
datatype: { value: "buffer" },
|
||||||
newline: { value: "" },
|
newline: { value: "" },
|
||||||
keepalive: { value: "120000" },
|
keepalive: { value: "120000" },
|
||||||
|
keepaliveProbes: { value: "0" },
|
||||||
topic: { value: "" },
|
topic: { value: "" },
|
||||||
base64: {/*deprecated*/ value: false, required: true }
|
base64: {/*deprecated*/ value: false, required: true }
|
||||||
},
|
},
|
||||||
|
|
@ -109,6 +114,7 @@
|
||||||
$("#node-input-datatype").change(updateOptions);
|
$("#node-input-datatype").change(updateOptions);
|
||||||
$("#node-input-datamode").change(updateOptions);
|
$("#node-input-datamode").change(updateOptions);
|
||||||
$("#node-input-keepalive").spinner({ min: 1 });
|
$("#node-input-keepalive").spinner({ min: 1 });
|
||||||
|
$("#node-input-keepaliveProbes").spinner({ min: 0 });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ module.exports = function(RED) {
|
||||||
var reconnectTime = RED.settings.socketReconnectTime||10000;
|
var reconnectTime = RED.settings.socketReconnectTime||10000;
|
||||||
const msgQueueSize = RED.settings.tcpMsgQueueSize || 1000;
|
const msgQueueSize = RED.settings.tcpMsgQueueSize || 1000;
|
||||||
const Denque = require('denque');
|
const Denque = require('denque');
|
||||||
|
const tcpKeepAlive = require('./tcp-keepalive');
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
|
|
||||||
var connectionPool = {};
|
var connectionPool = {};
|
||||||
|
|
@ -45,6 +46,14 @@ module.exports = function(RED) {
|
||||||
*/
|
*/
|
||||||
const dequeue = queue => queue.shift();
|
const dequeue = queue => queue.shift();
|
||||||
|
|
||||||
|
function setKeepAlive(socket, delay, probes, node) {
|
||||||
|
socket.setKeepAlive(true, delay);
|
||||||
|
if (probes > 0 && !tcpKeepAlive.setKeepAliveProbes(socket, probes) && !node.keepaliveProbesWarned) {
|
||||||
|
node.keepaliveProbesWarned = true;
|
||||||
|
node.warn("TCP keepalive probe count override is not available on this platform/runtime");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function TcpIn(n) {
|
function TcpIn(n) {
|
||||||
RED.nodes.createNode(this,n);
|
RED.nodes.createNode(this,n);
|
||||||
this.host = n.host;
|
this.host = n.host;
|
||||||
|
|
@ -55,6 +64,7 @@ module.exports = function(RED) {
|
||||||
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
|
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
|
||||||
this.base64 = n.base64;
|
this.base64 = n.base64;
|
||||||
this.keepalive = parseInt(n.keepalive) || 120000;
|
this.keepalive = parseInt(n.keepalive) || 120000;
|
||||||
|
this.keepaliveProbes = tcpKeepAlive.parseKeepAliveProbes(n.keepaliveProbes);
|
||||||
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
|
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
|
||||||
this.closing = false;
|
this.closing = false;
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
|
|
@ -76,7 +86,7 @@ module.exports = function(RED) {
|
||||||
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
node.log(RED._("tcpin.status.connected",{host:node.host,port:node.port}));
|
||||||
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
node.status({fill:"green",shape:"dot",text:"common.status.connected"});
|
||||||
});
|
});
|
||||||
client.setKeepAlive(true, node.keepalive);
|
setKeepAlive(client, node.keepalive, node.keepaliveProbes, node);
|
||||||
connectionPool[id] = client;
|
connectionPool[id] = client;
|
||||||
|
|
||||||
client.on('data', function (data) {
|
client.on('data', function (data) {
|
||||||
|
|
@ -151,7 +161,7 @@ module.exports = function(RED) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var server = net.createServer(function (socket) {
|
var server = net.createServer(function (socket) {
|
||||||
socket.setKeepAlive(true, node.keepalive);
|
setKeepAlive(socket, node.keepalive, node.keepaliveProbes, node);
|
||||||
var id = (1+Math.random()*4294967295).toString(16);
|
var id = (1+Math.random()*4294967295).toString(16);
|
||||||
var fromi;
|
var fromi;
|
||||||
var fromp;
|
var fromp;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
const { spawnSync } = require("child_process");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
if (process.platform !== "linux") {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nativeDir = path.join(__dirname, "..", "native", "tcp_keepalive");
|
||||||
|
|
||||||
|
function runNodeGyp(command, args) {
|
||||||
|
const result = spawnSync(command, args, {
|
||||||
|
cwd: nativeDir,
|
||||||
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
return result.error ? false : result.status === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let built = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const nodeGyp = require.resolve("node-gyp/bin/node-gyp.js");
|
||||||
|
built = runNodeGyp(process.execPath, [nodeGyp, "rebuild"]);
|
||||||
|
} catch (err) {
|
||||||
|
built = runNodeGyp("node-gyp", ["rebuild"]);
|
||||||
|
if (!built) {
|
||||||
|
built = runNodeGyp("npx", ["node-gyp", "rebuild"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!built) {
|
||||||
|
console.warn("tcp keepalive native helper was not built; TCP_KEEPCNT override will be disabled");
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue