Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[mosquitto-dev] [PATCH] Add option to use tcp keepalive

This commit adds new configuration options to use TCP keepalives.
They can be useful when using a bandwidth-constrained connection.
The broker can realize earlier that a client has disconnected before
the next MQTT ping takes place
---
 config.mk                       |  7 +++++++
 mosquitto.conf                  |  9 +++++++++
 src/conf.c                      | 30 ++++++++++++++++++++++++++++++
 src/mosquitto_broker_internal.h |  6 ++++++
 src/net.c                       | 25 +++++++++++++++++++++++++
 5 files changed, 77 insertions(+)

diff --git a/config.mk b/config.mk
index 0185027..297abfa 100644
--- a/config.mk
+++ b/config.mk
@@ -92,6 +92,9 @@ WITH_STATIC_LIBRARIES:=no
 # Build with epoll support.
 WITH_EPOLL:=yes
 
+# Build with support for TCP keepalives. Requires Linux
+WITH_TCPKEEPALIVE:=yes
+
 # =============================================================================
 # End of user configuration
 # =============================================================================
@@ -255,6 +258,10 @@ ifeq ($(WITH_EC),yes)
 	BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_EC
 endif
 
+ifeq ($(WITH_TCPKEEPALIVE),yes)
+	BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_TCPKEEPALIVE
+endif
+
 ifeq ($(WITH_ADNS),yes)
 	BROKER_LIBS:=$(BROKER_LIBS) -lanl
 	BROKER_CFLAGS:=$(BROKER_CFLAGS) -DWITH_ADNS
diff --git a/mosquitto.conf b/mosquitto.conf
index b383c0a..31cf71a 100644
--- a/mosquitto.conf
+++ b/mosquitto.conf
@@ -136,6 +136,15 @@
 # of packets being sent.
 #set_tcp_nodelay false
 
+# Additionally use TCP keepalive as a lower-overhead way to check if a session
+# is still alive. Might allow to set a bigger ping rate.
+# The properties are directly passed to setsockopt.
+# See http://man7.org/linux/man-pages/man7/tcp.7.html for explanation
+#use_tcp_keepalive true
+#tcp_keepcnt 5
+#tcp_keepidle 900
+#tcp_keepintvl 180
+
 # =================================================================
 # Default listener
 # =================================================================
diff --git a/src/conf.c b/src/conf.c
index 44207d4..3b8aa7e 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -251,6 +251,12 @@ void config__init(struct mosquitto__config *config)
 	config->auth_plugins = NULL;
 	config->verbose = false;
 	config->message_size_limit = 0;
+#ifdef WITH_TCPKEEPALIVE
+	config->use_tcp_keepalive = false;
+	config->tcp_keepcnt = 5;
+	config->tcp_keepidle = 900;
+	config->tcp_keepintvl = 180;
+#endif
 }
 
 void config__cleanup(struct mosquitto__config *config)
@@ -1854,6 +1860,30 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, const
 						|| !strcmp(token, "max_log_entries")
 						|| !strcmp(token, "trace_output")){
 					log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Unsupported rsmb configuration option \"%s\".", token);
+				}else if(!strcmp(token, "use_tcp_keepalive")){
+#ifdef WITH_TCPKEEPALIVE
+					if(conf__parse_bool(&token, "use_tcp_keepalive", &config->use_tcp_keepalive, saveptr)) return MOSQ_ERR_INVAL;
+#else
+					log__printf(NULL, MOSQ_LOG_WARNING, "Warning: TCPKEEPALIVE support not available.");
+#endif
+				}else if(!strcmp(token, "tcp_keepcnt")){
+#ifdef WITH_TCPKEEPALIVE
+					if(conf__parse_int(&token, "tcp_keepcnt", &config->tcp_keepcnt, saveptr)) return MOSQ_ERR_INVAL;
+#else
+					log__printf(NULL, MOSQ_LOG_WARNING, "Warning: TCPKEEPALIVE support not available.");
+#endif
+				}else if(!strcmp(token, "tcp_keepidle")){
+#ifdef WITH_TCPKEEPALIVE
+					if(conf__parse_int(&token, "tcp_keepidle", &config->tcp_keepidle, saveptr)) return MOSQ_ERR_INVAL;
+#else
+					log__printf(NULL, MOSQ_LOG_WARNING, "Warning: TCPKEEPALIVE support not available.");
+#endif
+				}else if(!strcmp(token, "tcp_keepintvl")){
+#ifdef WITH_TCPKEEPALIVE
+					if(conf__parse_int(&token, "tcp_keepintvl", &config->tcp_keepintvl, saveptr)) return MOSQ_ERR_INVAL;
+#else
+					log__printf(NULL, MOSQ_LOG_WARNING, "Warning: TCPKEEPALIVE support not available.");
+#endif
 				}else{
 					log__printf(NULL, MOSQ_LOG_ERR, "Error: Unknown configuration variable \"%s\".", token);
 					return MOSQ_ERR_INVAL;
diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h
index 92fac93..85b9cbf 100644
--- a/src/mosquitto_broker_internal.h
+++ b/src/mosquitto_broker_internal.h
@@ -223,6 +223,12 @@ struct mosquitto__config {
 	struct mosquitto__bridge *bridges;
 	int bridge_count;
 #endif
+#ifdef WITH_TCPKEEPALIVE
+	bool use_tcp_keepalive;
+	int tcp_keepcnt;
+	int tcp_keepidle;
+	int tcp_keepintvl;
+#endif
 	struct mosquitto__auth_plugin_config *auth_plugins;
 	int auth_plugin_count;
 };
diff --git a/src/net.c b/src/net.c
index a0f90b8..ae9c5bc 100644
--- a/src/net.c
+++ b/src/net.c
@@ -27,6 +27,11 @@ Contributors:
 #include <ws2tcpip.h>
 #endif
 
+#ifdef WITH_TCPKEEPALIVE
+#	include <sys/socket.h>
+#	include <netinet/tcp.h>
+#endif
+
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -127,6 +132,26 @@ int net__socket_accept(struct mosquitto_db *db, mosq_sock_t listensock)
 		setsockopt(new_sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
 	}
 
+#ifdef WITH_TCPKEEPALIVE
+	if (db->config->use_tcp_keepalive){
+		int optval = 1;
+		if (setsockopt(new_sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) {
+			log__printf(NULL, MOSQ_LOG_WARNING, "TCP keepalive could not be enabled");
+		}
+		else {
+			int keepcnt  =  db->config->tcp_keepcnt;
+			int keepidle =  db->config->tcp_keepidle;
+			int keepintvl = db->config->tcp_keepintvl;
+
+			setsockopt(new_sock, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
+			setsockopt(new_sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
+			setsockopt(new_sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof(keepintvl));
+
+			log__printf(NULL, MOSQ_LOG_DEBUG, "TCP keepalive enabled with %d, %d, %d", keepcnt, keepidle, keepintvl);
+		}
+	}
+#endif
+
 	new_context = context__init(db, new_sock);
 	if(!new_context){
 		COMPAT_CLOSE(new_sock);
-- 
2.7.4



Back to the top