]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
mqtt: convert sendleftovers to dynbuf
authorDaniel Stenberg <daniel@haxx.se>
Mon, 24 Mar 2025 10:46:34 +0000 (11:46 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 25 Mar 2025 07:22:05 +0000 (08:22 +0100)
Avoid frequent strdups/free calls, including the double-free risk.

Reported-by: Ronald Crane
Closes #16823

lib/dynbuf.h
lib/mqtt.c
lib/mqtt.h

index 71b0cc239db6151a8bc5a659d327de41cea70c05..cc7e5a12ed248cc816a216309bdb97c53f3e8dc5 100644 (file)
@@ -97,5 +97,6 @@ char *Curl_dyn_take(struct dynbuf *s, size_t *plen);
 #define DYN_PINGPPONG_CMD   (64*1024)
 #define DYN_IMAP_CMD        (64*1024)
 #define DYN_MQTT_RECV       (64*1024)
+#define DYN_MQTT_SEND       0xFFFFFFF
 #define DYN_CRLFILE_SIZE    (400*1024*1024) /* 400mb */
 #endif
index 69bbf658f892b1e294ae3310986e5133e533f67d..287037d483ce0e1cc8ff1d5d4f2a8ee0e1021e2a 100644 (file)
@@ -112,6 +112,7 @@ static CURLcode mqtt_setup_conn(struct Curl_easy *data,
   if(!mq)
     return CURLE_OUT_OF_MEMORY;
   Curl_dyn_init(&mq->recvbuf, DYN_MQTT_RECV);
+  Curl_dyn_init(&mq->sendbuf, DYN_MQTT_SEND);
   data->req.p.mqtt = mq;
   return CURLE_OK;
 }
@@ -119,25 +120,24 @@ static CURLcode mqtt_setup_conn(struct Curl_easy *data,
 static CURLcode mqtt_send(struct Curl_easy *data,
                           const char *buf, size_t len)
 {
-  CURLcode result = CURLE_OK;
   struct MQTT *mq = data->req.p.mqtt;
   size_t n;
-  result = Curl_xfer_send(data, buf, len, FALSE, &n);
+  CURLcode result = Curl_xfer_send(data, buf, len, FALSE, &n);
   if(result)
     return result;
   Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
   if(len != n) {
     size_t nsend = len - n;
-    char *sendleftovers = Curl_memdup(&buf[n], nsend);
-    if(!sendleftovers)
-      return CURLE_OUT_OF_MEMORY;
-    mq->sendleftovers = sendleftovers;
-    mq->nsend = nsend;
-  }
-  else {
-    mq->sendleftovers = NULL;
-    mq->nsend = 0;
+    if(Curl_dyn_len(&mq->sendbuf)) {
+      DEBUGASSERT(Curl_dyn_len(&mq->sendbuf) >= nsend);
+      result = Curl_dyn_tail(&mq->sendbuf, nsend); /* keep this much */
+    }
+    else {
+      result = Curl_dyn_addn(&mq->sendbuf, &buf[n], nsend);
+    }
   }
+  else
+    Curl_dyn_reset(&mq->sendbuf);
   return result;
 }
 
@@ -352,7 +352,7 @@ static CURLcode mqtt_disconnect(struct Curl_easy *data)
   CURLcode result = CURLE_OK;
   struct MQTT *mq = data->req.p.mqtt;
   result = mqtt_send(data, "\xe0\x00", 2);
-  Curl_safefree(mq->sendleftovers);
+  Curl_dyn_free(&mq->sendbuf);
   Curl_dyn_free(&mq->recvbuf);
   return result;
 }
@@ -732,7 +732,7 @@ static CURLcode mqtt_done(struct Curl_easy *data,
   struct MQTT *mq = data->req.p.mqtt;
   (void)status;
   (void)premature;
-  Curl_safefree(mq->sendleftovers);
+  Curl_dyn_free(&mq->sendbuf);
   Curl_dyn_free(&mq->recvbuf);
   return CURLE_OK;
 }
@@ -740,19 +740,17 @@ static CURLcode mqtt_done(struct Curl_easy *data,
 static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
-  struct connectdata *conn = data->conn;
-  struct mqtt_conn *mqtt = &conn->proto.mqtt;
+  struct mqtt_conn *mqtt = &data->conn->proto.mqtt;
   struct MQTT *mq = data->req.p.mqtt;
   ssize_t nread;
   unsigned char recvbyte;
 
   *done = FALSE;
 
-  if(mq->nsend) {
+  if(Curl_dyn_len(&mq->sendbuf)) {
     /* send the remainder of an outgoing packet */
-    char *ptr = mq->sendleftovers;
-    result = mqtt_send(data, mq->sendleftovers, mq->nsend);
-    free(ptr);
+    result = mqtt_send(data, Curl_dyn_ptr(&mq->sendbuf),
+                       Curl_dyn_len(&mq->sendbuf));
     if(result)
       return result;
   }
index 99ab12a98a40577889db0f155a9ad56a2b11bcb6..b181e3c16df592eeaf59d92953549152db152111 100644 (file)
@@ -49,15 +49,13 @@ struct mqtt_conn {
 
 /* protocol-specific transfer-related data */
 struct MQTT {
-  char *sendleftovers;
-  size_t nsend; /* size of sendleftovers */
-
+  struct dynbuf sendbuf;
   /* when receiving */
+  struct dynbuf recvbuf;
   size_t npacket; /* byte counter */
-  unsigned char firstbyte;
   size_t remaining_length;
-  struct dynbuf recvbuf;
   unsigned char pkt_hd[4]; /* for decoding the arriving packet length */
+  unsigned char firstbyte;
 };
 
 #endif /* HEADER_CURL_MQTT_H */