Skip to main content

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

Is the TCP keepalive really solving a real use-case problem?

If so which one precisely? 

I understand how TCP keepalive works and how MQTT-PINGREQ/RESP works.

How can you prevent clients for sending MQTT-PING/RESP when keepalive on TCP level is already active? (if you do not disable the PING/RESP you are increasing traffic instead of decreasing it)
If the client does not have a reliable tcp channel, maybe it is better for the client to enable TCP-KeepAlive instead of the server (for every connection)

Just thinking aloud.
Gr,
Edwin van den Oetelaar

On Mon, Feb 19, 2018 at 3:35 PM, Raphael Lisicki <rlisicki@xxxxxxxxxxxxx> wrote:
Hello Karl,

I agree with you that no TCP keepalives will ever be sent if the MQTT keepalive is smaller than the TCP keepalive. On the other hand, if TCP keepalives are smaller than the MQTT keepalive timeout, both will be sent.

While a MQTT keepalive might be only 2 Bytes of plaintext traffic, things are different when SSL is being used:
I recorded 260Bytes of metered traffic for a MQTT PINGRQ/PINGRESP pair and only 136Bytes for a TCP keepalive pair. This is almost half the traffic.

I am aware of the different guarantees a TCP keep-alive gives you in comparison to the TCP keepalive. In this case, the TCP keepalives allow for a faster discovery of simple faults as compared to only using MQTT keepalives, provided having the same bandwidth budget.

The TCP keepalive is sufficient to discover that the client got disconnected from the network and to send out last-will messages, which is actually enough in this particular case.

It seems that the actual enabling of TCP keepalive also works on windows and MacOS. MacOS apparently also supports the setting of TCP_KEEPALIVE, TCP_KEEPINTVL, and TCP_KEEPCNT. I just preferred to not promise untested things. Are there any other supported platforms to care about?


Best regards

Raphael



On 19.02.2018 12:48, Karl Palsson wrote:
So, what's wrong with just turning down your mqtt keepalive?

TCP Keepalive shorter than MQTT keepalive -> never going to have
mqtt keeaplive timeouts. why bother? TCP keepalive longer than
MQTT keepalive -> never going to have tcp keepalive timeouts, why
bother?

MQTT keepalives are two bytes. Yes, this is bigger than a tcp
keepalive, but it covers more than a tcp keepalive does too. TCP
keepalive only tells you that the tcp connection is (probably)
still ok, not whether there's still a functional client at the
remote end.

I'm not sure I see any real motivation for this, and certainly
not something that's going to be platform specific!

Sincerely,
Karl Palsson


Raphael Lisicki <rlisicki@xxxxxxxxxxxxx> wrote:
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

_______________________________________________
mosquitto-dev mailing list
mosquitto-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or
unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/mosquitto-dev


_______________________________________________
mosquitto-dev mailing list
mosquitto-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/mosquitto-dev

--
---------------------------------------------------------------------
RADIODATA GmbH
Newtonstraße 18
12489 Berlin
Germany

Tel:                   +49 (0)30 756 81 -3
Fax:                   +49 (0)30 756 81 -599
e- Mail:               rlisicki@xxxxxxxxxxxxx
Homepage:              www.radiodata.biz

USt_IdNr.:             DE 195663499
WEEE-Reg.-Nr.:         DE 63967380


Sitz der Gesellschaft: Berlin
Registergericht:       Amtsgericht Charlottenburg HRB  Nr.: 67865
Geschäftsführer:       Hans-Joachim Langermann


_______________________________________________
mosquitto-dev mailing list
mosquitto-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/mosquitto-dev


Back to the top