From 08a10a8af5684409c815fea3867512565496a534 Mon Sep 17 00:00:00 2001
From: Deomid Ryabkov <rojer@cesanta.com>
Date: Mon, 10 Apr 2017 18:34:35 +0300
Subject: [PATCH] Handle multiple MQTT messages per RECV event

PUBLISHED_FROM=fc98c51254dd94d3f443fb66e49449da7d9e754c
---
 mongoose.c | 30 +++++++++++++++++++-----------
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/mongoose.c b/mongoose.c
index fcc508335..32fe0d70d 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -9740,21 +9740,27 @@ static const char *scanto(const char *p, struct mg_str *s) {
 
 MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) {
   uint8_t header;
-  size_t len = 0;
+  size_t len = 0, len_len = 0;
+  const char *p, *end;
+  unsigned char lc = 0;
   int cmd;
-  const char *p = &io->buf[1], *end;
 
   if (io->len < 2) return -1;
   header = io->buf[0];
   cmd = header >> 4;
 
   /* decode mqtt variable length */
-  do {
-    len += (*p & 127) << 7 * (p - &io->buf[1]);
-  } while ((*p++ & 128) != 0 && ((size_t)(p - io->buf) <= io->len));
+  len = len_len = 0;
+  p = io->buf + 1;
+  while ((size_t)(p - io->buf) < io->len) {
+    lc = *((const unsigned char *) p++);
+    len += (lc & 0x7f) << 7 * len_len;
+    len_len++;
+    if (!(lc & 0x80) || (len_len > sizeof(len))) break;
+  }
 
   end = p + len;
-  if (end > io->buf + io->len + 1) {
+  if (lc & 0x80 || end > io->buf + io->len) {
     return -1;
   }
 
@@ -9829,7 +9835,6 @@ MG_INTERNAL int parse_mqtt(struct mbuf *io, struct mg_mqtt_message *mm) {
 
 static void mqtt_handler(struct mg_connection *nc, int ev,
                          void *ev_data MG_UD_ARG(void *user_data)) {
-  int len;
   struct mbuf *io = &nc->recv_mbuf;
   struct mg_mqtt_message mm;
   memset(&mm, 0, sizeof(mm));
@@ -9838,10 +9843,13 @@ static void mqtt_handler(struct mg_connection *nc, int ev,
 
   switch (ev) {
     case MG_EV_RECV:
-      len = parse_mqtt(io, &mm);
-      if (len == -1) break; /* not fully buffered */
-      nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data));
-      mbuf_remove(io, len);
+      /* There can be multiple messages in the buffer, process them all. */
+      while (1) {
+        int len = parse_mqtt(io, &mm);
+        if (len == -1) break; /* not fully buffered */
+        nc->handler(nc, MG_MQTT_EVENT_BASE + mm.cmd, &mm MG_UD_ARG(user_data));
+        mbuf_remove(io, len);
+      }
       break;
   }
 }
-- 
GitLab