summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/mqtt.c
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2021-07-29 03:58:47 +0300
committerdartraiden <wowemuh@gmail.com>2021-07-29 04:00:29 +0300
commitfe19d22eaddb5383337114ab7a611d781de24b59 (patch)
tree618312785cafc338b2f3369184ef17364c20e6ec /libs/libcurl/src/mqtt.c
parentd60a8d0c45ea7903274c570f523b7775125f4e89 (diff)
libcurl: update to 7.78
Diffstat (limited to 'libs/libcurl/src/mqtt.c')
-rw-r--r--libs/libcurl/src/mqtt.c254
1 files changed, 203 insertions, 51 deletions
diff --git a/libs/libcurl/src/mqtt.c b/libs/libcurl/src/mqtt.c
index d88fa737df..f077e6c3dc 100644
--- a/libs/libcurl/src/mqtt.c
+++ b/libs/libcurl/src/mqtt.c
@@ -143,32 +143,197 @@ static int mqtt_getsock(struct Curl_easy *data,
return GETSOCK_READSOCK(FIRSTSOCKET);
}
+static int mqtt_encode_len(char *buf, size_t len)
+{
+ unsigned char encoded;
+ int i;
+
+ for(i = 0; (len > 0) && (i<4); i++) {
+ encoded = len % 0x80;
+ len /= 0x80;
+ if(len)
+ encoded |= 0x80;
+ buf[i] = encoded;
+ }
+
+ return i;
+}
+
+/* add the passwd to the CONNECT packet */
+static int add_passwd(const char *passwd, const size_t plen,
+ char *pkt, const size_t start, int remain_pos)
+{
+ /* magic number that need to be set properly */
+ const size_t conn_flags_pos = remain_pos + 8;
+ if(plen > 0xffff)
+ return 1;
+
+ /* set password flag */
+ pkt[conn_flags_pos] |= 0x40;
+
+ /* length of password provided */
+ pkt[start] = (char)((plen >> 8) & 0xFF);
+ pkt[start + 1] = (char)(plen & 0xFF);
+ memcpy(&pkt[start + 2], passwd, plen);
+ return 0;
+}
+
+/* add user to the CONN packet */
+static int add_user(const char *username, const size_t ulen,
+ unsigned char *pkt, const size_t start, int remain_pos)
+{
+ /* magic number that need to be set properly */
+ const size_t conn_flags_pos = remain_pos + 8;
+ if(ulen > 0xffff)
+ return 1;
+
+ /* set username flag */
+ pkt[conn_flags_pos] |= 0x80;
+ /* length of username provided */
+ pkt[start] = (unsigned char)((ulen >> 8) & 0xFF);
+ pkt[start + 1] = (unsigned char)(ulen & 0xFF);
+ memcpy(&pkt[start + 2], username, ulen);
+ return 0;
+}
+
+/* add client ID to the CONN packet */
+static int add_client_id(const char *client_id, const size_t client_id_len,
+ char *pkt, const size_t start)
+{
+ if(client_id_len != MQTT_CLIENTID_LEN)
+ return 1;
+ pkt[start] = 0x00;
+ pkt[start + 1] = MQTT_CLIENTID_LEN;
+ memcpy(&pkt[start + 2], client_id, MQTT_CLIENTID_LEN);
+ return 0;
+}
+
+/* Set initial values of CONN packet */
+static int init_connpack(char *packet, char *remain, int remain_pos)
+{
+ /* Fixed header starts */
+ /* packet type */
+ packet[0] = MQTT_MSG_CONNECT;
+ /* remaining length field */
+ memcpy(&packet[1], remain, remain_pos);
+ /* Fixed header ends */
+
+ /* Variable header starts */
+ /* protocol length */
+ packet[remain_pos + 1] = 0x00;
+ packet[remain_pos + 2] = 0x04;
+ /* protocol name */
+ packet[remain_pos + 3] = 'M';
+ packet[remain_pos + 4] = 'Q';
+ packet[remain_pos + 5] = 'T';
+ packet[remain_pos + 6] = 'T';
+ /* protocol level */
+ packet[remain_pos + 7] = 0x04;
+ /* CONNECT flag: CleanSession */
+ packet[remain_pos + 8] = 0x02;
+ /* keep-alive 0 = disabled */
+ packet[remain_pos + 9] = 0x00;
+ packet[remain_pos + 10] = 0x3c;
+ /*end of variable header*/
+ return remain_pos + 10;
+}
+
static CURLcode mqtt_connect(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- const size_t client_id_offset = 14;
- const size_t packetlen = client_id_offset + MQTT_CLIENTID_LEN;
+ int pos = 0;
+ int rc = 0;
+ /*remain length*/
+ int remain_pos = 0;
+ char remain[4] = {0};
+ size_t packetlen = 0;
+ size_t payloadlen = 0;
+ size_t start_user = 0;
+ size_t start_pwd = 0;
char client_id[MQTT_CLIENTID_LEN + 1] = "curl";
const size_t clen = strlen("curl");
- char packet[32] = {
- MQTT_MSG_CONNECT, /* packet type */
- 0x00, /* remaining length */
- 0x00, 0x04, /* protocol length */
- 'M','Q','T','T', /* protocol name */
- 0x04, /* protocol level */
- 0x02, /* CONNECT flag: CleanSession */
- 0x00, 0x3c, /* keep-alive 0 = disabled */
- 0x00, 0x00 /* payload1 length */
- };
- packet[1] = (packetlen - 2) & 0x7f;
- packet[client_id_offset - 1] = MQTT_CLIENTID_LEN;
+ char *packet = NULL;
+
+ /* extracting username from request */
+ const char *username = data->state.aptr.user ?
+ data->state.aptr.user : "";
+ const size_t ulen = strlen(username);
+ /* extracting password from request */
+ const char *passwd = data->state.aptr.passwd ?
+ data->state.aptr.passwd : "";
+ const size_t plen = strlen(passwd);
+
+ payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2;
+ /* The plus 2 are for the MSB and LSB describing the length of the string to
+ * be added on the payload. Refer to spec 1.5.2 and 1.5.4 */
+ if(ulen)
+ payloadlen += 2;
+ if(plen)
+ payloadlen += 2;
+
+ /* getting how much occupy the remain length */
+ remain_pos = mqtt_encode_len(remain, payloadlen + 10);
+
+ /* 10 length of variable header and 1 the first byte of the fixed header */
+ packetlen = payloadlen + 10 + remain_pos + 1;
+
+ /* allocating packet */
+ if(packetlen > 268435455)
+ return CURLE_WEIRD_SERVER_REPLY;
+ packet = malloc(packetlen);
+ if(!packet)
+ return CURLE_OUT_OF_MEMORY;
+ memset(packet, 0, packetlen);
+
+ /* set initial values for CONN pack */
+ pos = init_connpack(packet, remain, remain_pos);
result = Curl_rand_hex(data, (unsigned char *)&client_id[clen],
MQTT_CLIENTID_LEN - clen + 1);
- memcpy(&packet[client_id_offset], client_id, MQTT_CLIENTID_LEN);
- infof(data, "Using client id '%s'\n", client_id);
+ /* add client id */
+ rc = add_client_id(client_id, strlen(client_id), packet, pos + 1);
+ if(rc) {
+ failf(data, "Client ID length mismatched: [%lu]", strlen(client_id));
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto end;
+ }
+ infof(data, "Using client id '%s'", client_id);
+
+ /* position where starts the user payload */
+ start_user = pos + 3 + MQTT_CLIENTID_LEN;
+ /* position where starts the password payload */
+ start_pwd = start_user + ulen;
+ /* if user name was provided, add it to the packet */
+ if(ulen) {
+ start_pwd += 2;
+
+ rc = add_user(username, ulen,
+ (unsigned char *)packet, start_user, remain_pos);
+ if(rc) {
+ failf(data, "Username is too large: [%lu]", ulen);
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto end;
+ }
+ }
+
+ /* if passwd was provided, add it to the packet */
+ if(plen) {
+ rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos);
+ if(rc) {
+ failf(data, "Password is too large: [%lu]", plen);
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto end;
+ }
+ }
+
if(!result)
result = mqtt_send(data, packet, packetlen);
+
+end:
+ if(packet)
+ free(packet);
+ Curl_safefree(data->state.aptr.user);
+ Curl_safefree(data->state.aptr.passwd);
return result;
}
@@ -213,35 +378,12 @@ fail:
static CURLcode mqtt_get_topic(struct Curl_easy *data,
char **topic, size_t *topiclen)
{
- CURLcode result = CURLE_OK;
char *path = data->state.up.path;
-
- if(strlen(path) > 1) {
- result = Curl_urldecode(data, path + 1, 0, topic, topiclen,
- REJECT_NADA);
- }
- else {
- failf(data, "Error: No topic specified.");
- result = CURLE_URL_MALFORMAT;
- }
- return result;
-}
-
-
-static int mqtt_encode_len(char *buf, size_t len)
-{
- unsigned char encoded;
- int i;
-
- for(i = 0; (len > 0) && (i<4); i++) {
- encoded = len % 0x80;
- len /= 0x80;
- if(len)
- encoded |= 0x80;
- buf[i] = encoded;
- }
-
- return i;
+ if(strlen(path) > 1)
+ return Curl_urldecode(data, path + 1, 0, topic, topiclen,
+ REJECT_NADA);
+ failf(data, "No MQTT topic found. Forgot to URL encode it?");
+ return CURLE_URL_MALFORMAT;
}
static CURLcode mqtt_subscribe(struct Curl_easy *data)
@@ -418,7 +560,7 @@ static void mqstate(struct Curl_easy *data,
struct connectdata *conn = data->conn;
struct mqtt_conn *mqtt = &conn->proto.mqtt;
#ifdef CURLDEBUG
- infof(data, "%s (from %s) (next is %s)\n",
+ infof(data, "%s (from %s) (next is %s)",
statenames[state],
statenames[mqtt->state],
(state == MQTT_FIRST)? statenames[nextstate] : "");
@@ -465,7 +607,7 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
goto MQTT_SUBACK_COMING;
}
else if(packet == MQTT_MSG_DISCONNECT) {
- infof(data, "Got DISCONNECT\n");
+ infof(data, "Got DISCONNECT");
*done = TRUE;
goto end;
}
@@ -476,7 +618,13 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
/* -- switched state -- */
remlen = mq->remaining_length;
- infof(data, "Remaining length: %zd bytes\n", remlen);
+ infof(data, "Remaining length: %zd bytes", remlen);
+ if(data->set.max_filesize &&
+ (curl_off_t)remlen > data->set.max_filesize) {
+ failf(data, "Maximum file size exceeded");
+ result = CURLE_FILESIZE_EXCEEDED;
+ goto end;
+ }
Curl_pgrsSetDownloadSize(data, remlen);
data->req.bytecount = 0;
data->req.size = remlen;
@@ -491,12 +639,12 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
result = Curl_read(data, sockfd, (char *)pkt, rest, &nread);
if(result) {
if(CURLE_AGAIN == result) {
- infof(data, "EEEE AAAAGAIN\n");
+ infof(data, "EEEE AAAAGAIN");
}
goto end;
}
if(!nread) {
- infof(data, "server disconnected\n");
+ infof(data, "server disconnected");
result = CURLE_PARTIAL_FILE;
goto end;
}
@@ -562,7 +710,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
return result;
}
- infof(data, "mqtt_doing: state [%d]\n", (int) mqtt->state);
+ infof(data, "mqtt_doing: state [%d]", (int) mqtt->state);
switch(mqtt->state) {
case MQTT_FIRST:
/* Read the initial byte only */
@@ -582,6 +730,10 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
pkt[mq->npacket++] = byte;
} while((byte & 0x80) && (mq->npacket < 4));
+ if(nread && (byte & 0x80))
+ /* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
+ 127 * 128^3 bytes. server tried to send more */
+ result = CURLE_WEIRD_SERVER_REPLY;
if(result)
break;
mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL);
@@ -593,7 +745,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
mqstate(data, MQTT_FIRST, MQTT_FIRST);
if(mq->firstbyte == MQTT_MSG_DISCONNECT) {
- infof(data, "Got DISCONNECT\n");
+ infof(data, "Got DISCONNECT");
*done = TRUE;
}
break;