From f49f692ffa38e74628258c3ebf62b59644cf49d2 Mon Sep 17 00:00:00 2001
From: Dave Conway-Jones
Date: Fri, 3 Nov 2023 11:57:16 +0000
Subject: [PATCH] Better fix for TCP node reset
now handles reply out node,
and can specify which connection to reset.
---
.../@node-red/nodes/core/network/31-tcpin.js | 63 +++++++++++++------
.../nodes/locales/en-US/network/31-tcpin.html | 4 +-
2 files changed, 47 insertions(+), 20 deletions(-)
diff --git a/packages/node_modules/@node-red/nodes/core/network/31-tcpin.js b/packages/node_modules/@node-red/nodes/core/network/31-tcpin.js
index 406ea0247..15401e374 100644
--- a/packages/node_modules/@node-red/nodes/core/network/31-tcpin.js
+++ b/packages/node_modules/@node-red/nodes/core/network/31-tcpin.js
@@ -411,23 +411,33 @@ module.exports = function(RED) {
if (msg._session && msg._session.type == "tcp") {
var client = connectionPool[msg._session.id];
if (client) {
- if (Buffer.isBuffer(msg.payload)) {
- client.write(msg.payload);
- } else if (typeof msg.payload === "string" && node.base64) {
- client.write(Buffer.from(msg.payload,'base64'));
- } else {
- client.write(Buffer.from(""+msg.payload));
+ if (msg?.reset === true) {
+ client.destroy();
+ }
+ else {
+ if (Buffer.isBuffer(msg.payload)) {
+ client.write(msg.payload);
+ } else if (typeof msg.payload === "string" && node.base64) {
+ client.write(Buffer.from(msg.payload,'base64'));
+ } else {
+ client.write(Buffer.from(""+msg.payload));
+ }
}
}
}
else {
for (var i in connectionPool) {
- if (Buffer.isBuffer(msg.payload)) {
- connectionPool[i].write(msg.payload);
- } else if (typeof msg.payload === "string" && node.base64) {
- connectionPool[i].write(Buffer.from(msg.payload,'base64'));
- } else {
- connectionPool[i].write(Buffer.from(""+msg.payload));
+ if (msg?.reset === true) {
+ connectionPool[i].destroy();
+ }
+ else {
+ if (Buffer.isBuffer(msg.payload)) {
+ connectionPool[i].write(msg.payload);
+ } else if (typeof msg.payload === "string" && node.base64) {
+ connectionPool[i].write(Buffer.from(msg.payload,'base64'));
+ } else {
+ connectionPool[i].write(Buffer.from(""+msg.payload));
+ }
}
}
}
@@ -551,15 +561,29 @@ module.exports = function(RED) {
msg.payload = msg.payload.toString();
}
- if (node.out === "sit" && msg?.reset === true && node?.last_id && clients[node.last_id]) {
- node.status({});
- clients[node.last_id].client.destroy();
- delete clients[node.last_id];
- }
-
var host = node.server || msg.host;
var port = node.port || msg.port;
+ if (node.out === "sit" && msg?.reset) {
+ if (msg.reset === true) { // kill all connections
+ for (var cl in clients) {
+ if (clients[cl].hasOwnProperty("client")) {
+ clients[cl].client.destroy();
+ delete clients[cl];
+ }
+ }
+ }
+ if (typeof(msg.reset) === "string" && msg.reset.includes(":")) { // just kill connection host:port
+ if (clients.hasOwnProperty(msg.reset) && clients[msg.reset].hasOwnProperty("client")) {
+ clients[msg.reset].client.destroy();
+ delete clients[msg.reset];
+ }
+ }
+ const cc = Object.keys(clients).length;
+ node.status({fill:"green",shape:cc===0?"ring":"dot",text:RED._("tcpin.status.connections",{count:cc})});
+ if ((host === undefined || port === undefined) && !msg.hasOwnProperty("payload")) { return; }
+ }
+
// Store client information independently
// the clients object will have:
// clients[id].client, clients[id].msg, clients[id].timeout
@@ -627,7 +651,8 @@ module.exports = function(RED) {
clients[connection_id].connecting = true;
clients[connection_id].client.connect(connOpts, function() {
//node.log(RED._("tcpin.errors.client-connected"));
- node.status({fill:"green",shape:"dot",text:"common.status.connected"});
+ // node.status({fill:"green",shape:"dot",text:"common.status.connected"});
+ node.status({fill:"green",shape:"dot",text:RED._("tcpin.status.connections",{count:Object.keys(clients).length})});
if (clients[connection_id] && clients[connection_id].client) {
clients[connection_id].connected = true;
clients[connection_id].connecting = false;
diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/network/31-tcpin.html b/packages/node_modules/@node-red/nodes/locales/en-US/network/31-tcpin.html
index dd42c6614..708df0449 100644
--- a/packages/node_modules/@node-red/nodes/locales/en-US/network/31-tcpin.html
+++ b/packages/node_modules/@node-red/nodes/locales/en-US/network/31-tcpin.html
@@ -30,6 +30,8 @@
before being sent.
If msg._session
is not present the payload is
sent to all connected clients.
+ In Reply-to mode, setting msg.reset = true
will reset the connection
+ specified by _session.id, or all connections if no _session.id is specified.
Note: On some systems you may need root or administrator access
to access ports below 1024.
@@ -40,7 +42,7 @@
returned characters into a fixed buffer, match a specified character before returning,
wait a fixed timeout from first reply and then return, sit and wait for data, or send then close the connection
immediately, without waiting for a reply.
- If in sit and wait mode (remain connected) you can send msg.reset = true;
to force a break in
+
If in sit and wait mode (remain connected) you can send msg.reset = true
or msg.reset = "host:port"
to force a break in
the connection and an automatic reconnection.
The response will be output in msg.payload
as a buffer, so you may want to .toString() it.
If you leave tcp host or port blank they must be set by using the msg.host
and msg.port
properties in every message sent to the node.