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);
+ /* 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'\n", 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;
}
}
-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;
-}
static CURLcode mqtt_subscribe(struct Curl_easy *data)
{
static curl_socket_t mqttit(curl_socket_t fd)
{
- unsigned char buffer[10*1024];
+ size_t buff_size = 10*1024;
+ unsigned char *buffer = NULL;
ssize_t rc;
unsigned char byte;
unsigned short packet_id;
size_t payload_len;
+ size_t client_id_length;
unsigned int topic_len;
size_t remaining_length = 0;
size_t bytes = 0; /* remaining length field size in bytes */
long testno;
FILE *stream = NULL;
+
static const char protocol[7] = {
0x00, 0x04, /* protocol length */
'M','Q','T','T', /* protocol name */
if(testno)
logmsg("Found test number %ld", testno);
+ buffer = malloc(buff_size);
+ if(!buffer) {
+ logmsg("Out of memory, unable to allocate buffer");
+ goto end;
+ }
+
do {
+ unsigned char usr_flag = 0x80;
+ unsigned char passwd_flag = 0x40;
+ unsigned char conn_flags;
+ const size_t client_id_offset = 12;
+ size_t start_usr;
+ size_t start_passwd;
+
/* get the fixed header */
rc = fixedheader(fd, &byte, &remaining_length, &bytes);
if(rc)
break;
+
+ if(remaining_length >= buff_size) {
+ buff_size = remaining_length;
+ buffer = realloc(buffer, buff_size);
+ if(!buffer) {
+ logmsg("Failed realloc of size %lu", buff_size);
+ goto end;
+ }
+ }
+
if(remaining_length) {
+ /* reading variable header and payload into buffer */
rc = sread(fd, (char *)buffer, remaining_length);
if(rc > 0) {
logmsg("READ %d bytes", rc);
goto end;
}
/* ignore the connect flag byte and two keepalive bytes */
-
payload_len = (buffer[10] << 8) | buffer[11];
+ /* first part of the payload is the client ID */
+ client_id_length = payload_len;
+
+ /* checking if user and password flags were set */
+ conn_flags = buffer[7];
+
+ start_usr = client_id_offset + payload_len;
+ if(usr_flag == (unsigned char)(conn_flags & usr_flag)) {
+ logmsg("User flag is present in CONN flag");
+ payload_len += (buffer[start_usr] << 8) | buffer[start_usr + 1];
+ payload_len += 2; /* MSB and LSB for user length */
+ }
+
+ start_passwd = client_id_offset + payload_len;
+ if(passwd_flag == (char)(conn_flags & passwd_flag)) {
+ logmsg("Password flag is present in CONN flags");
+ payload_len += (buffer[start_passwd] << 8) | buffer[start_passwd + 1];
+ payload_len += 2; /* MSB and LSB for password length */
+ }
+
+ /* check the length of the payload */
if((ssize_t)payload_len != (rc - 12)) {
logmsg("Payload length mismatch, expected %x got %x",
rc - 12, payload_len);
goto end;
}
- else if((payload_len + 1) > MAX_CLIENT_ID_LENGTH) {
+ /* check the length of the client ID */
+ else if((client_id_length + 1) > MAX_CLIENT_ID_LENGTH) {
logmsg("Too large client id");
goto end;
}
- memcpy(client_id, &buffer[12], payload_len);
- client_id[payload_len] = 0;
+ memcpy(client_id, &buffer[12], client_id_length);
+ client_id[client_id_length] = 0;
logmsg("MQTT client connect accepted: %s", client_id);
} while(1);
end:
+ if(buffer)
+ free(buffer);
if(dump)
fclose(dump);
if(stream)