diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml
index 5734b485..820b6bce 100644
--- a/man/mosquitto.conf.5.xml
+++ b/man/mosquitto.conf.5.xml
@@ -1697,23 +1697,45 @@ openssl dhparam -out dhparam.pem 2048
mqttv311.
-
idleintervalcounter
-
- Set TCP keepalive parameters for this bridge connection.
- Use this option to allow you to set a long MQTT
- keepalive value, whilst still being able to detect the
- connection dropping in a reasonable time.
+
+ Set TCP keepalive parameters for this bridge connection.
+ Use this option to allow you to set a long MQTT
+ keepalive value, whilst still being able to detect the
+ connection dropping in a reasonable time.
- This may be useful when bridging to services that bill
- for PINGREQ messages.
+ This may be useful when bridging to services that bill
+ for PINGREQ messages.
Disabled by default.
+
+ timeout
+
+
+ It specifies the maximum amount of time (in milliseconds) that
+ transmitted data may remain unacknowledged at TCP level.
+ Popular Linux distributions seem to set this time to "up to 20
+ minutes with system defaults" (from Linux tcp man page).
+ The default time is related to tcp_retries2.
+ Reducing this value helps detecting dropped connections faster.
+
+
+ Be aware that when used in combination with TCP Keepalive, it might
+ change the latter's behavior.
+
+
+ You can find more details about this setting at:
+
+
+ Only available on Linux.
+
+
+ [ true | false ]
diff --git a/mosquitto.conf b/mosquitto.conf
index 99282299..93814433 100644
--- a/mosquitto.conf
+++ b/mosquitto.conf
@@ -723,6 +723,16 @@
# Disabled by default.
#bridge_tcp_keepalive
+# Change the maximum amount of time (in milliseconds) that transmitted data
+# may remain unacknowledged at TCP level.
+# Popular Linux distributions seem to set this time to "up to 20 minutes with
+# system defaults" (from Linux tcp man page). Reducing this value helps
+# detecting dropped connections faster.
+# When used together with TCP Keepalive, it might change it's behavior.
+# More details at: https://blog.cloudflare.com/when-tcp-sockets-refuse-to-die/
+# Only available on Linux.
+#bridge_tcp_user_timeout
+
# Set the clientid to use on the local broker. If not defined, this defaults to
# 'local.'. If you are bridging a broker to itself, it is important
# that local_clientid and clientid do not match.
diff --git a/src/bridge.c b/src/bridge.c
index 3cfd7cc2..a6cd3fb1 100644
--- a/src/bridge.c
+++ b/src/bridge.c
@@ -177,7 +177,7 @@ static int bridge__set_tcp_keepalive(struct mosquitto *context)
unsigned int enabled = 1;
bool ret;
- if (idle == 0 || interval == 0 || counter == 0) return MOSQ_ERR_SUCCESS;
+ if(idle == 0 || interval == 0 || counter == 0) return MOSQ_ERR_SUCCESS;
#ifdef WIN32
ret =
@@ -193,11 +193,24 @@ static int bridge__set_tcp_keepalive(struct mosquitto *context)
setsockopt(context->sock, IPPROTO_TCP, TCP_KEEPCNT, (const void*)&counter, sizeof(counter));
#endif
- if (ret) return MOSQ_ERR_UNKNOWN;
+ if(ret) return MOSQ_ERR_UNKNOWN;
return MOSQ_ERR_SUCCESS;
}
+#ifdef WITH_TCP_USER_TIMEOUT
+static int bridge__set_tcp_user_timeout(struct mosquitto *context) {
+ int timeout = context->bridge->tcp_user_timeout;
+ if(timeout >= 0) {
+ if(setsockopt(context->sock, IPPROTO_TCP, TCP_USER_TIMEOUT, (char *)&timeout, sizeof(timeout))) {
+ return MOSQ_ERR_UNKNOWN;
+ }
+ }
+
+ return MOSQ_ERR_SUCCESS;
+}
+#endif
+
#if defined(__GLIBC__) && defined(WITH_ADNS)
static int bridge__connect_step1(struct mosquitto *context)
{
@@ -373,6 +386,9 @@ int bridge__connect_step3(struct mosquitto *context)
}
if (bridge__set_tcp_keepalive(context) != MOSQ_ERR_SUCCESS) return MOSQ_ERR_UNKNOWN;
+#ifdef WITH_TCP_USER_TIMEOUT
+ if(bridge__set_tcp_user_timeout(context)) return MOSQ_ERR_UNKNOWN;
+#endif
if(context->bridge->max_topic_alias != 0){
topic_alias_max.next = NULL;
@@ -526,6 +542,9 @@ int bridge__connect(struct mosquitto *context)
HASH_ADD(hh_sock, db.contexts_by_sock, sock, sizeof(context->sock), context);
if (bridge__set_tcp_keepalive(context) != MOSQ_ERR_SUCCESS) return MOSQ_ERR_UNKNOWN;
+#ifdef WITH_TCP_USER_TIMEOUT
+ if(bridge__set_tcp_user_timeout(context)) return MOSQ_ERR_UNKNOWN;
+#endif
if(context->bridge->max_topic_alias){
topic_alias_max.next = NULL;
diff --git a/src/conf.c b/src/conf.c
index 307922ff..7bf23c9a 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -1273,6 +1273,22 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload,
cur_bridge->tcp_keepalive_counter = (unsigned int)tmp_int;
#else
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available.");
+#endif
+ }else if(!strcmp(token, "bridge_tcp_user_timeout")){
+#if defined(WITH_BRIDGE) && defined(WITH_TCP_USER_TIMEOUT)
+ if(!cur_bridge){
+ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration.");
+ return MOSQ_ERR_INVAL;
+ }
+
+ if(conf__parse_int(&token, "bridge_tcp_user_timeout", &tmp_int, &saveptr)) return MOSQ_ERR_INVAL;
+ if(tmp_int < 0) {
+ log__printf(NULL, MOSQ_LOG_ERR, "Error: invalid TCP user timeout value.");
+ return MOSQ_ERR_INVAL;
+ }
+ cur_bridge->tcp_user_timeout = (unsigned int) tmp_int;
+#else
+ log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge and/or TCP user timeout support not available.");
#endif
}else if(!strcmp(token, "bridge_tls_version")){
#if defined(WITH_BRIDGE) && defined(WITH_TLS)
@@ -1416,6 +1432,9 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload,
cur_bridge->clean_start_local = -1;
cur_bridge->reload_type = brt_lazy;
cur_bridge->max_topic_alias = 10;
+#ifdef WITH_TCP_USER_TIMEOUT
+ cur_bridge->tcp_user_timeout = -1;
+#endif
}else{
log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty connection value in configuration.");
return MOSQ_ERR_INVAL;
diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h
index 3194a104..a40ade57 100644
--- a/src/mosquitto_broker_internal.h
+++ b/src/mosquitto_broker_internal.h
@@ -30,6 +30,10 @@ Contributors:
# endif
#endif
+#ifdef __linux__
+#define WITH_TCP_USER_TIMEOUT
+#endif
+
#include "mosquitto_internal.h"
#include "mosquitto_broker.h"
#include "mosquitto_plugin.h"
@@ -533,6 +537,9 @@ struct mosquitto__bridge{
unsigned int tcp_keepalive_idle;
unsigned int tcp_keepalive_interval;
unsigned int tcp_keepalive_counter;
+#ifdef WITH_TCP_USER_TIMEOUT
+ unsigned int tcp_user_timeout;
+#endif
struct mosquitto__bridge_topic *topics;
int topic_count;
bool topic_remapping;