From 023b55f2e53ae07018921bbbc1ff1bd8a0e482d8 Mon Sep 17 00:00:00 2001
From: Deomid Ryabkov <rojer@cesanta.com>
Date: Sun, 4 Jun 2017 15:10:52 +0100
Subject: [PATCH] MQTT client keep alive fixes

 - Move keep alive management up to the Mongoose library
 - Only outgoing control messgaes should reset keepalive timer
 - Add unit test

https://forum.mongoose-os.com/discussion/1155/mqtt-keep-alive-compliance-issue

PUBLISHED_FROM=f86e30744ded53a6f7f96afec066b4ff3b4372c0
---
 docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md |  1 +
 mongoose.c                                     | 17 +++++++++++++++--
 mongoose.h                                     |  1 +
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md b/docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md
index 8ae54fcfc..f095589d2 100644
--- a/docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md
+++ b/docs/c-api/mqtt.h/struct_mg_mqtt_proto_data.md
@@ -5,6 +5,7 @@ symbol_kind: "struct"
 signature: |
   struct mg_mqtt_proto_data {
     uint16_t keep_alive;
+    double last_control_time;
   };
 ---
 
diff --git a/mongoose.c b/mongoose.c
index 1424e929c..f69d00105 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -2079,7 +2079,7 @@ void mg_if_poll(struct mg_connection *nc, time_t now) {
   }
 }
 
-static void mg_destroy_conn(struct mg_connection *conn, int destroy_if) {
+void mg_destroy_conn(struct mg_connection *conn, int destroy_if) {
   if (destroy_if) conn->iface->vtable->destroy_conn(conn);
   if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
     conn->proto_data_destructor(conn->proto_data);
@@ -9957,7 +9957,7 @@ static void mqtt_handler(struct mg_connection *nc, int ev,
   nc->handler(nc, ev, ev_data MG_UD_ARG(user_data));
 
   switch (ev) {
-    case MG_EV_RECV:
+    case MG_EV_RECV: {
       /* There can be multiple messages in the buffer, process them all. */
       while (1) {
         int len = parse_mqtt(io, &mm);
@@ -9966,6 +9966,17 @@ static void mqtt_handler(struct mg_connection *nc, int ev,
         mbuf_remove(io, len);
       }
       break;
+    }
+    case MG_EV_POLL: {
+      struct mg_mqtt_proto_data *pd =
+          (struct mg_mqtt_proto_data *) nc->proto_data;
+      double now = mg_time();
+      if (pd->keep_alive > 0 && pd->last_control_time > 0 &&
+          (now - pd->last_control_time) > pd->keep_alive) {
+        LOG(LL_DEBUG, ("Send PINGREQ"));
+        mg_mqtt_ping(nc);
+      }
+    }
   }
 }
 
@@ -10007,6 +10018,7 @@ void mg_set_protocol_mqtt(struct mg_connection *nc) {
 
 static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd,
                                    uint8_t flags, size_t len) {
+  struct mg_mqtt_proto_data *pd = (struct mg_mqtt_proto_data *) nc->proto_data;
   size_t off = nc->send_mbuf.len - len;
   uint8_t header = cmd << 4 | (uint8_t) flags;
 
@@ -10026,6 +10038,7 @@ static void mg_mqtt_prepend_header(struct mg_connection *nc, uint8_t cmd,
   } while (len > 0);
 
   mbuf_insert(&nc->send_mbuf, off, buf, vlen - buf);
+  pd->last_control_time = mg_time();
 }
 
 void mg_send_mqtt_handshake(struct mg_connection *nc, const char *client_id) {
diff --git a/mongoose.h b/mongoose.h
index a8e30c3f3..209614cb6 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -5105,6 +5105,7 @@ struct mg_send_mqtt_handshake_opts {
 /* mg_mqtt_proto_data should be in header to allow external access to it */
 struct mg_mqtt_proto_data {
   uint16_t keep_alive;
+  double last_control_time;
 };
 
 /* Message types */
-- 
GitLab