mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-21 17:16:29 +08:00
feat(mqtt): remove ibm-mqtt component and example
This commit is contained in:
@ -1,17 +1,3 @@
|
||||
if(CONFIG_MQTT_USING_IBM)
|
||||
set(COMPONENT_ADD_INCLUDEDIRS
|
||||
"ibm-mqtt/MQTTClient-C/src"
|
||||
"ibm-mqtt/MQTTClient-C/src/FreeRTOS"
|
||||
"ibm-mqtt/MQTTPacket/src")
|
||||
|
||||
set(COMPONENT_SRCDIRS
|
||||
"ibm-mqtt/MQTTClient-C/src"
|
||||
"ibm-mqtt/MQTTClient-C/src/FreeRTOS"
|
||||
"ibm-mqtt/MQTTPacket/src")
|
||||
|
||||
endif()
|
||||
|
||||
if (CONFIG_MQTT_USING_ESP)
|
||||
set(COMPONENT_ADD_INCLUDEDIRS "esp-mqtt/include")
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS "esp-mqtt/lib/include")
|
||||
set(COMPONENT_SRCS "esp-mqtt/mqtt_client.c"
|
||||
@ -19,12 +5,6 @@ set(COMPONENT_SRCS "esp-mqtt/mqtt_client.c"
|
||||
"esp-mqtt/lib/mqtt_outbox.c"
|
||||
"esp-mqtt/lib/platform_idf.c")
|
||||
|
||||
endif()
|
||||
|
||||
set(COMPONENT_REQUIRES lwip http_parser tcp_transport freertos lwip mbedtls openssl)
|
||||
|
||||
register_component()
|
||||
|
||||
if(CONFIG_MQTT_USING_IBM)
|
||||
target_compile_options(${COMPONENT_LIB} PUBLIC -DMQTT_TASK -DMQTTCLIENT_PLATFORM_HEADER=MQTTFreeRTOS.h)
|
||||
endif()
|
||||
|
@ -1,160 +1,5 @@
|
||||
menu "MQTT"
|
||||
|
||||
choice MQTT_LIBRARY_CHOOSE
|
||||
prompt "Choose MQTT library"
|
||||
default MQTT_USING_ESP
|
||||
help
|
||||
Choose the MQTT library which you want to use.
|
||||
|
||||
Currently we support ESP-MQTT and IBM-MQTT(paho).
|
||||
|
||||
config MQTT_USING_ESP
|
||||
bool "ESP-MQTT(Recommended)"
|
||||
config MQTT_USING_IBM
|
||||
bool "IBM-MQTT(not recommended and will be removed at v3.4)"
|
||||
endchoice
|
||||
|
||||
menu "IBM-MQTT(paho)"
|
||||
depends on MQTT_USING_IBM
|
||||
|
||||
choice MQTT_VERSION
|
||||
prompt "MQTT version"
|
||||
default V3_1
|
||||
help
|
||||
Current supported MQTT version.
|
||||
|
||||
config V3_1
|
||||
bool "V3.1"
|
||||
config V3_1_1
|
||||
bool "V3.1.1"
|
||||
endchoice
|
||||
|
||||
config DEFAULT_MQTT_VERSION
|
||||
int
|
||||
default 3 if V3_1
|
||||
default 4 if V3_1_1
|
||||
|
||||
config MQTT_CLIENT_ID
|
||||
string "MQTT client ID"
|
||||
default "espressif_sample"
|
||||
help
|
||||
MQTT client ID for MQTT broker to identify ESP device.
|
||||
|
||||
config MQTT_KEEP_ALIVE
|
||||
int "MQTT keep-alive(seconds)"
|
||||
default 30
|
||||
help
|
||||
MQTT keep alive interval, Recommended value: 30s - 60s.
|
||||
The last MQTT packet timestamp will be recorded,
|
||||
a PING request will be sent if (current_timestamp - last_mqtt_packet_timestamp) > MQTT_KEEP_ALIVE.
|
||||
|
||||
config MQTT_USERNAME
|
||||
string "MQTT username"
|
||||
default "espressif"
|
||||
help
|
||||
Username used for logging to MQTT broker.
|
||||
Generally, you should use a valid MQTT_USERNAME if MQTT broker does not allow an anonymous login.
|
||||
|
||||
config MQTT_PASSWORD
|
||||
string "MQTT password"
|
||||
default "admin"
|
||||
help
|
||||
Password used for logging to MQTT broker.
|
||||
Generally, you should use a valid MQTT_PASSWORD if MQTT broker does not allow an anonymous login.
|
||||
|
||||
choice MQTT_SESSION
|
||||
prompt "MQTT Session"
|
||||
default CLEAN_SESSION
|
||||
help
|
||||
Clean session to start a new session.
|
||||
If clean-seesion is set, it will discard any previous session and start a new one.
|
||||
If keep-session is set, it will store session state and the communication can resume.
|
||||
|
||||
config CLEAN_SESSION
|
||||
bool "Clean Session"
|
||||
config KEEP_SESSION
|
||||
bool "Keep Session"
|
||||
endchoice
|
||||
|
||||
config DEFAULT_MQTT_SESSION
|
||||
int
|
||||
default 0 if KEEP_SESSION
|
||||
default 1 if CLEAN_SESSION
|
||||
|
||||
choice MQTT_SECURITY
|
||||
prompt "MQTT over TCP/SSL/TLS feature"
|
||||
default NO_TLS
|
||||
help
|
||||
MQTT over TCP/SSL/TLS.
|
||||
MQTT_SECURITY=0: MQTT over TCP
|
||||
MQTT_SECURITY=1: MQTT over TLS with no verify
|
||||
MQTT_SECURITY=2: MQTT over TLS with verify peer
|
||||
MQTT_SECURITY=3: MQTT over TLS with verify client
|
||||
|
||||
config NO_TLS
|
||||
bool "TCP"
|
||||
config TLS_VERIFY_NONE
|
||||
bool "TLS Verify None"
|
||||
config TLS_VERIFY_PEER
|
||||
bool "TLS Verify Peer"
|
||||
config TLS_VERIFY_CLIENT
|
||||
bool "TLS Verify Client"
|
||||
endchoice
|
||||
|
||||
config DEFAULT_MQTT_SECURITY
|
||||
int
|
||||
default 0 if NO_TLS
|
||||
default 1 if TLS_VERIFY_NONE
|
||||
default 2 if TLS_VERIFY_PEER
|
||||
default 3 if TLS_VERIFY_CLIENT
|
||||
|
||||
config MQTT_SEND_BUFFER
|
||||
int "MQTT send buffer"
|
||||
default 2048
|
||||
help
|
||||
Recommended value: 1460 - 2048.
|
||||
Buffer used for sending MQTT messages, including MQTT header, MQTT topic, payload and etc.
|
||||
|
||||
config MQTT_RECV_BUFFER
|
||||
int "MQTT recv buffer"
|
||||
default 2048
|
||||
help
|
||||
Recommended value: 1460 - 2048.
|
||||
Buffer used for receiving MQTT messages, including MQTT header, MQTT topic, payload and etc.
|
||||
|
||||
config MQTT_SEND_CYCLE
|
||||
int "MQTT send cycle(ms)"
|
||||
default 30000
|
||||
help
|
||||
Recommended value: 30000 - 60000.
|
||||
MQTT send interval in every cycle.
|
||||
A MQTT packet should be sent out in MQTT_SEND_CYCLE,
|
||||
will block for MQTT_SEND_CYCLE if weak network, and return timeout.
|
||||
|
||||
config MQTT_RECV_CYCLE
|
||||
int "MQTT recv cycle(ms)"
|
||||
default 0
|
||||
help
|
||||
Recommended value: 0ms - 500ms.
|
||||
MQTT receive interval in every cycle.
|
||||
a MQTT packet should be received in MQTT_RECV_CYCLE,
|
||||
will block for MQTT_RECV_CYCLE if weak network , and return timeout.
|
||||
|
||||
config MQTT_PING_TIMEOUT
|
||||
int "MQTT ping timeout(ms)"
|
||||
default 3000
|
||||
help
|
||||
Recommended value: 3000ms - 10000ms.
|
||||
MQTT ping timeout.
|
||||
When MQTT_KEEP_ALIVE expired, it will start sending ping request.
|
||||
If the ESP device does not receive any ping response within MQTT_PING_TIMEOUT,
|
||||
it will terminate the MQTT connection.
|
||||
|
||||
endmenu # IBM-MQTT(paho)
|
||||
|
||||
menu "ESP-MQTT"
|
||||
depends on MQTT_USING_ESP
|
||||
|
||||
config MQTT_PROTOCOL_311
|
||||
bool "Enable MQTT protocol 3.1.1"
|
||||
default y
|
||||
@ -254,6 +99,5 @@ config MQTT_CUSTOM_OUTBOX
|
||||
help
|
||||
Set to true if a specific implementation of message outbox is needed (e.g. persistant outbox in NVM or similar).
|
||||
|
||||
endmenu # ESP-MQTT
|
||||
|
||||
endmenu
|
||||
|
@ -1,3 +0,0 @@
|
||||
ifdef CONFIG_MQTT_USING_IBM
|
||||
CPPFLAGS += -DMQTT_TASK -DMQTTCLIENT_PLATFORM_HEADER=MQTTFreeRTOS.h
|
||||
endif
|
@ -1,19 +1,3 @@
|
||||
|
||||
ifdef CONFIG_MQTT_USING_IBM
|
||||
COMPONENT_ADD_INCLUDEDIRS += ibm-mqtt/MQTTClient-C/src \
|
||||
ibm-mqtt/MQTTClient-C/src/FreeRTOS \
|
||||
ibm-mqtt/MQTTPacket/src
|
||||
|
||||
COMPONENT_SRCDIRS += ibm-mqtt/MQTTClient-C/src \
|
||||
ibm-mqtt/MQTTClient-C/src/FreeRTOS \
|
||||
ibm-mqtt/MQTTPacket/src
|
||||
|
||||
CFLAGS += -DMQTT_TASK
|
||||
else
|
||||
ifdef CONFIG_MQTT_USING_ESP
|
||||
COMPONENT_ADD_INCLUDEDIRS := esp-mqtt/include
|
||||
COMPONENT_SRCDIRS := esp-mqtt esp-mqtt/lib
|
||||
COMPONENT_PRIV_INCLUDEDIRS := esp-mqtt/lib/include
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -1,440 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2015 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Allan Stockdill-Mander - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - convert to FreeRTOS
|
||||
*******************************************************************************/
|
||||
#include <string.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "MQTTFreeRTOS.h"
|
||||
|
||||
int ThreadStart(Thread *thread, void (*fn)(void *), void *arg)
|
||||
{
|
||||
int rc = 0;
|
||||
uint16_t usTaskStackSize = (configMINIMAL_STACK_SIZE * 5);
|
||||
UBaseType_t uxTaskPriority = uxTaskPriorityGet(NULL); /* set the priority as the same as the calling task*/
|
||||
|
||||
rc = xTaskCreate(fn, /* The function that implements the task. */
|
||||
"MQTTTask", /* Just a text name for the task to aid debugging. */
|
||||
usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */
|
||||
arg, /* The task parameter, not used in this case. */
|
||||
uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */
|
||||
&thread->task); /* The task handle is not used. */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void MutexInit(Mutex *mutex)
|
||||
{
|
||||
mutex->sem = xSemaphoreCreateMutex();
|
||||
}
|
||||
|
||||
int MutexLock(Mutex *mutex)
|
||||
{
|
||||
return xSemaphoreTake(mutex->sem, portMAX_DELAY);
|
||||
}
|
||||
|
||||
int MutexUnlock(Mutex *mutex)
|
||||
{
|
||||
return xSemaphoreGive(mutex->sem);
|
||||
}
|
||||
|
||||
|
||||
void TimerCountdownMS(Timer *timer, unsigned int timeout_ms)
|
||||
{
|
||||
timer->xTicksToWait = timeout_ms / portTICK_PERIOD_MS; /* convert milliseconds to ticks */
|
||||
vTaskSetTimeOutState(&timer->xTimeOut); /* Record the time at which this function was entered. */
|
||||
}
|
||||
|
||||
|
||||
void TimerCountdown(Timer *timer, unsigned int timeout)
|
||||
{
|
||||
TimerCountdownMS(timer, timeout * 1000);
|
||||
}
|
||||
|
||||
|
||||
int TimerLeftMS(Timer *timer)
|
||||
{
|
||||
xTaskCheckForTimeOut(&timer->xTimeOut, &timer->xTicksToWait); /* updates xTicksToWait to the number left */
|
||||
return (timer->xTicksToWait <= 0) ? 0 : (timer->xTicksToWait * portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
|
||||
char TimerIsExpired(Timer *timer)
|
||||
{
|
||||
return xTaskCheckForTimeOut(&timer->xTimeOut, &timer->xTicksToWait) == pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
void TimerInit(Timer *timer)
|
||||
{
|
||||
timer->xTicksToWait = 0;
|
||||
memset(&timer->xTimeOut, '\0', sizeof(timer->xTimeOut));
|
||||
}
|
||||
|
||||
|
||||
static int esp_read(Network *n, unsigned char *buffer, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
portTickType xTicksToWait = timeout_ms / portTICK_RATE_MS; /* convert milliseconds to ticks */
|
||||
xTimeOutType xTimeOut;
|
||||
int recvLen = 0, rc = 0, ret = 0;
|
||||
|
||||
struct timeval timeout;
|
||||
fd_set fdset;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(n->my_socket, &fdset);
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = timeout_ms * 1000;
|
||||
|
||||
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
|
||||
|
||||
ret = select(n->my_socket + 1, &fdset, NULL, NULL, &timeout);
|
||||
|
||||
if (ret <= 0) {
|
||||
// ret == 0: timeout
|
||||
// ret < 0: socket err
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (FD_ISSET(n->my_socket, &fdset)) {
|
||||
do {
|
||||
rc = recv(n->my_socket, buffer + recvLen, len - recvLen, MSG_DONTWAIT);
|
||||
|
||||
if (rc > 0) {
|
||||
recvLen += rc;
|
||||
} else if (rc < 0) {
|
||||
recvLen = rc;
|
||||
break;
|
||||
}
|
||||
} while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
|
||||
}
|
||||
|
||||
return recvLen;
|
||||
}
|
||||
|
||||
|
||||
static int esp_write(Network *n, unsigned char *buffer, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
portTickType xTicksToWait = timeout_ms / portTICK_RATE_MS; /* convert milliseconds to ticks */
|
||||
xTimeOutType xTimeOut;
|
||||
int sentLen = 0, rc = 0, ret = 0;
|
||||
|
||||
struct timeval timeout;
|
||||
fd_set fdset;
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(n->my_socket, &fdset);
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = timeout_ms * 1000;
|
||||
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
|
||||
|
||||
ret = select(n->my_socket + 1, NULL, &fdset, NULL, &timeout);
|
||||
|
||||
if (ret <= 0) {
|
||||
// ret == 0: timeout
|
||||
// ret < 0: socket err
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (FD_ISSET(n->my_socket, &fdset)) {
|
||||
do {
|
||||
rc = send(n->my_socket, buffer + sentLen, len - sentLen, 0);
|
||||
|
||||
if (rc > 0) {
|
||||
sentLen += rc;
|
||||
} else if (rc < 0) {
|
||||
sentLen = rc;
|
||||
break;
|
||||
}
|
||||
} while (sentLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
|
||||
}
|
||||
|
||||
return sentLen;
|
||||
}
|
||||
|
||||
|
||||
static void esp_disconnect(Network *n)
|
||||
{
|
||||
close(n->my_socket);
|
||||
}
|
||||
|
||||
|
||||
void NetworkInit(Network *n)
|
||||
{
|
||||
n->my_socket = 0;
|
||||
n->mqttread = esp_read;
|
||||
n->mqttwrite = esp_write;
|
||||
n->disconnect = esp_disconnect;
|
||||
}
|
||||
|
||||
|
||||
int NetworkConnect(Network *n, char *addr, int port)
|
||||
{
|
||||
struct sockaddr_in sAddr;
|
||||
int retVal = -1;
|
||||
struct hostent *ipAddress;
|
||||
|
||||
if ((ipAddress = gethostbyname(addr)) == 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sAddr.sin_family = AF_INET;
|
||||
sAddr.sin_addr.s_addr = ((struct in_addr *)(ipAddress->h_addr))->s_addr;
|
||||
sAddr.sin_port = htons(port);
|
||||
|
||||
if ((n->my_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((retVal = connect(n->my_socket, (struct sockaddr *)&sAddr, sizeof(sAddr))) < 0) {
|
||||
close(n->my_socket);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return retVal;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SSL_USING_MBEDTLS
|
||||
static int esp_ssl_read(Network *n, unsigned char *buffer, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
portTickType xTicksToWait = timeout_ms / portTICK_RATE_MS; /* convert milliseconds to ticks */
|
||||
xTimeOutType xTimeOut;
|
||||
int recvLen = 0;
|
||||
int rc = 0;
|
||||
static unsigned char *read_buffer;
|
||||
|
||||
struct timeval timeout;
|
||||
fd_set readset;
|
||||
fd_set errset;
|
||||
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&errset);
|
||||
FD_SET(n->my_socket, &readset);
|
||||
FD_SET(n->my_socket, &errset);
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = timeout_ms * 1000;
|
||||
|
||||
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
|
||||
|
||||
if (!n->read_count) { /* read mqtt packet for the first time */
|
||||
if (select(n->my_socket + 1, &readset, NULL, &errset, &timeout) > 0) {
|
||||
if (FD_ISSET(n->my_socket, &errset)) {
|
||||
return recvLen;
|
||||
} else if (FD_ISSET(n->my_socket, &readset)) {
|
||||
read_buffer = buffer;
|
||||
len = 2; /* len: msg_type(1 octet) + msg_len(1 octet) */
|
||||
|
||||
do {
|
||||
rc = SSL_read(n->ssl, read_buffer, len);
|
||||
|
||||
if (rc > 0) {
|
||||
recvLen += rc;
|
||||
} else if (rc < 0) {
|
||||
recvLen = rc;
|
||||
return recvLen;
|
||||
}
|
||||
} while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
|
||||
|
||||
recvLen = 0;
|
||||
len = *(read_buffer + 1); /* len: remaining msg */
|
||||
|
||||
if (len > 0) {
|
||||
do {
|
||||
rc = SSL_read(n->ssl, read_buffer + 2, len);
|
||||
|
||||
if (rc > 0) {
|
||||
recvLen += rc;
|
||||
} else if (rc < 0) {
|
||||
recvLen = rc;
|
||||
return recvLen;
|
||||
}
|
||||
} while (recvLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
|
||||
}
|
||||
|
||||
n->read_count++;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else if (n->read_count == 1) { /* read same mqtt packet for the second time */
|
||||
if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdTRUE) {
|
||||
n->read_count = 0;
|
||||
read_buffer[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
n->read_count++;
|
||||
*buffer = *(read_buffer + 1);
|
||||
return 1;
|
||||
} else if (n->read_count == 2) { /* read same mqtt packet for the third time */
|
||||
n->read_count = 0;
|
||||
|
||||
if (xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdTRUE) {
|
||||
read_buffer[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(buffer, read_buffer + 2, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
return recvLen;
|
||||
}
|
||||
|
||||
|
||||
static int esp_ssl_write(Network *n, unsigned char *buffer, unsigned int len, unsigned int timeout_ms)
|
||||
{
|
||||
portTickType xTicksToWait = timeout_ms / portTICK_RATE_MS; /* convert milliseconds to ticks */
|
||||
xTimeOutType xTimeOut;
|
||||
int sentLen = 0;
|
||||
int rc = 0;
|
||||
int readysock;
|
||||
|
||||
struct timeval timeout;
|
||||
fd_set writeset;
|
||||
fd_set errset;
|
||||
|
||||
FD_ZERO(&writeset);
|
||||
FD_ZERO(&errset);
|
||||
FD_SET(n->my_socket, &writeset);
|
||||
FD_SET(n->my_socket, &errset);
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = timeout_ms * 1000;
|
||||
|
||||
vTaskSetTimeOutState(&xTimeOut); /* Record the time at which this function was entered. */
|
||||
|
||||
do {
|
||||
readysock = select(n->my_socket + 1, NULL, &writeset, &errset, &timeout);
|
||||
} while (readysock <= 0);
|
||||
|
||||
if (FD_ISSET(n->my_socket, &errset)) {
|
||||
return sentLen;
|
||||
} else if (FD_ISSET(n->my_socket, &writeset)) {
|
||||
do {
|
||||
rc = SSL_write(n->ssl, buffer + sentLen, len - sentLen);
|
||||
|
||||
if (rc > 0) {
|
||||
sentLen += rc;
|
||||
} else if (rc < 0) {
|
||||
sentLen = rc;
|
||||
break;
|
||||
}
|
||||
} while (sentLen < len && xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE);
|
||||
}
|
||||
|
||||
return sentLen;
|
||||
}
|
||||
|
||||
|
||||
static void esp_ssl_disconnect(Network *n)
|
||||
{
|
||||
close(n->my_socket);
|
||||
SSL_free(n->ssl);
|
||||
SSL_CTX_free(n->ctx);
|
||||
n->read_count = 0;
|
||||
}
|
||||
|
||||
|
||||
void NetworkInitSSL(Network *n)
|
||||
{
|
||||
n->my_socket = 0;
|
||||
n->mqttread = esp_ssl_read;
|
||||
n->mqttwrite = esp_ssl_write;
|
||||
n->disconnect = esp_ssl_disconnect;
|
||||
n->read_count = 0;
|
||||
n->ctx = NULL;
|
||||
n->ssl = NULL;
|
||||
}
|
||||
|
||||
|
||||
int NetworkConnectSSL(Network *n, char *addr, int port, ssl_ca_crt_key_t *ssl_cck, const SSL_METHOD *method, int verify_mode, size_t frag_len)
|
||||
{
|
||||
struct sockaddr_in sAddr;
|
||||
int retVal = -1;
|
||||
struct hostent *ipAddress;
|
||||
|
||||
if ((ipAddress = gethostbyname(addr)) == 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
n->ctx = SSL_CTX_new((SSL_METHOD *)method);
|
||||
|
||||
if (!n->ctx) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ssl_cck->cert && ssl_cck->key) {
|
||||
retVal = SSL_CTX_use_certificate_ASN1(n->ctx, ssl_cck->cert_len, ssl_cck->cert);
|
||||
|
||||
if (!retVal) {
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
retVal = SSL_CTX_use_PrivateKey_ASN1(0, n->ctx, ssl_cck->key, ssl_cck->key_len);
|
||||
|
||||
if (!retVal) {
|
||||
goto exit1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ssl_cck->cacrt) {
|
||||
SSL_CTX_set_verify(n->ctx, verify_mode, NULL);
|
||||
} else {
|
||||
SSL_CTX_set_verify(n->ctx, SSL_VERIFY_NONE, NULL);
|
||||
}
|
||||
|
||||
sAddr.sin_family = AF_INET;
|
||||
sAddr.sin_addr.s_addr = ((struct in_addr *)(ipAddress->h_addr))->s_addr;
|
||||
sAddr.sin_port = htons(port);
|
||||
|
||||
if ((n->my_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
if ((retVal = connect(n->my_socket, (struct sockaddr *)&sAddr, sizeof(sAddr))) < 0) {
|
||||
goto exit2;
|
||||
}
|
||||
|
||||
n->ssl = SSL_new(n->ctx);
|
||||
|
||||
if (!n->ssl) {
|
||||
goto exit2;
|
||||
}
|
||||
|
||||
SSL_set_fd(n->ssl, n->my_socket);
|
||||
|
||||
if ((retVal = SSL_connect(n->ssl)) <= 0) {
|
||||
goto exit3;
|
||||
} else {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit3:
|
||||
SSL_free(n->ssl);
|
||||
exit2:
|
||||
close(n->my_socket);
|
||||
exit1:
|
||||
SSL_CTX_free(n->ctx);
|
||||
exit:
|
||||
return retVal;
|
||||
}
|
||||
#endif
|
@ -1,131 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2015 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Allan Stockdill-Mander - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTFreeRTOS_H
|
||||
#define MQTTFreeRTOS_H
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#ifdef CONFIG_SSL_USING_MBEDTLS
|
||||
#include "openssl/ssl.h"
|
||||
#endif
|
||||
|
||||
#define OVER_TCP 0 // 0: MQTT over TCP
|
||||
#define TLS_VERIFY_NONE 1 // 1: enable SSL/TLS, but there is no a certificate verify
|
||||
#define TLS_VERIFY_PEER 2 // 2: enable SSL/TLS, and verify the MQTT broker certificate
|
||||
#define TLS_VERIFY_CLIENT 3 // 3: enable SSL/TLS, and verify the MQTT broker certificate, and enable certificate for MQTT broker
|
||||
|
||||
typedef struct Timer {
|
||||
TickType_t xTicksToWait;
|
||||
TimeOut_t xTimeOut;
|
||||
} Timer;
|
||||
|
||||
typedef struct Network Network;
|
||||
|
||||
struct Network {
|
||||
int my_socket;
|
||||
int (*mqttread)(Network *, unsigned char *, unsigned int, unsigned int);
|
||||
int (*mqttwrite)(Network *, unsigned char *, unsigned int, unsigned int);
|
||||
void (*disconnect)(Network *);
|
||||
|
||||
int read_count;
|
||||
#ifdef CONFIG_SSL_USING_MBEDTLS
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
#endif
|
||||
};
|
||||
|
||||
void TimerInit(Timer *);
|
||||
char TimerIsExpired(Timer *);
|
||||
void TimerCountdownMS(Timer *, unsigned int);
|
||||
void TimerCountdown(Timer *, unsigned int);
|
||||
int TimerLeftMS(Timer *);
|
||||
|
||||
typedef struct Mutex {
|
||||
SemaphoreHandle_t sem;
|
||||
} Mutex;
|
||||
|
||||
void MutexInit(Mutex *);
|
||||
int MutexLock(Mutex *);
|
||||
int MutexUnlock(Mutex *);
|
||||
|
||||
typedef struct Thread {
|
||||
TaskHandle_t task;
|
||||
} Thread;
|
||||
|
||||
int ThreadStart(Thread *, void (*fn)(void *), void *arg);
|
||||
|
||||
/**
|
||||
* @brief Initialize the network structure
|
||||
*
|
||||
* @param m - network structure
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void NetworkInit(Network *);
|
||||
|
||||
/**
|
||||
* @brief connect with mqtt broker
|
||||
*
|
||||
* @param n - mqtt network struct
|
||||
* @param addr - mqtt broker address
|
||||
* @param port - mqtt broker port
|
||||
*
|
||||
* @return connect status
|
||||
*/
|
||||
int NetworkConnect(Network *n, char *addr, int port);
|
||||
|
||||
#ifdef CONFIG_SSL_USING_MBEDTLS
|
||||
typedef struct ssl_ca_crt_key {
|
||||
unsigned char *cacrt;
|
||||
unsigned int cacrt_len;
|
||||
unsigned char *cert;
|
||||
unsigned int cert_len;
|
||||
unsigned char *key;
|
||||
unsigned int key_len;
|
||||
} ssl_ca_crt_key_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the network structure for SSL connection
|
||||
*
|
||||
* @param m - network structure
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void NetworkInitSSL(Network *n);
|
||||
|
||||
/**
|
||||
* @brief Use SSL to connect with mqtt broker
|
||||
*
|
||||
* @param n - mqtt network struct
|
||||
* @param addr - mqtt broker address
|
||||
* @param port - mqtt broker port
|
||||
* @param ssl_cck - client CA, certificate and private key
|
||||
* @param method - SSL context client method
|
||||
* @param verify_mode - SSL verifying mode
|
||||
* @param frag_len - SSL read buffer length
|
||||
*
|
||||
* @return connect status
|
||||
*/
|
||||
int NetworkConnectSSL(Network *n, char *addr, int port, ssl_ca_crt_key_t *ssl_cck, const SSL_METHOD *method, int verify_mode, unsigned int frag_len);
|
||||
|
||||
/*int NetworkConnectTLS(Network*, char*, int, SlSockSecureFiles_t*, unsigned char, unsigned int, char);*/
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,810 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2017 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - fix for #96 - check rem_len in readPacket
|
||||
* Ian Craggs - add ability to set message handler separately #6
|
||||
*******************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "MQTTClient.h"
|
||||
|
||||
static const char *TAG = "mc";
|
||||
|
||||
static void NewMessageData(MessageData *md, MQTTString *aTopicName, MQTTMessage *aMessage)
|
||||
{
|
||||
md->topicName = aTopicName;
|
||||
md->message = aMessage;
|
||||
}
|
||||
|
||||
|
||||
static int getNextPacketId(MQTTClient *c)
|
||||
{
|
||||
return c->next_packetid = (c->next_packetid == MAX_PACKET_ID) ? 1 : c->next_packetid + 1;
|
||||
}
|
||||
|
||||
|
||||
static int sendPacket(MQTTClient *c, int length, Timer *timer)
|
||||
{
|
||||
int rc = FAILURE,
|
||||
sent = 0;
|
||||
|
||||
while (sent < length && !TimerIsExpired(timer)) {
|
||||
rc = c->ipstack->mqttwrite(c->ipstack, &c->buf[sent], length, TimerLeftMS(timer));
|
||||
|
||||
if (rc < 0) { // there was an error writing the data
|
||||
break;
|
||||
}
|
||||
|
||||
sent += rc;
|
||||
}
|
||||
|
||||
if (sent == length) {
|
||||
TimerCountdown(&c->last_sent, c->keepAliveInterval); // record the fact that we have successfully sent the packet
|
||||
rc = SUCCESS;
|
||||
} else {
|
||||
rc = FAILURE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool MQTTClientInit(MQTTClient *c, Network *network, unsigned int command_timeout_ms,
|
||||
unsigned char *sendbuf, size_t sendbuf_size, unsigned char *readbuf, size_t readbuf_size)
|
||||
{
|
||||
int i;
|
||||
c->ipstack = network;
|
||||
|
||||
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
|
||||
c->messageHandlers[i].topicFilter = 0;
|
||||
}
|
||||
|
||||
if (command_timeout_ms != 0) {
|
||||
c->command_timeout_ms = command_timeout_ms;
|
||||
} else {
|
||||
c->command_timeout_ms = CONFIG_MQTT_SEND_CYCLE;
|
||||
}
|
||||
|
||||
if (sendbuf) {
|
||||
c->buf = sendbuf;
|
||||
c->buf_size = sendbuf_size;
|
||||
} else {
|
||||
c->buf = (unsigned char *)malloc(CONFIG_MQTT_SEND_BUFFER);
|
||||
|
||||
if (c->buf) {
|
||||
c->buf_size = CONFIG_MQTT_SEND_BUFFER;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (readbuf) {
|
||||
c->readbuf = readbuf;
|
||||
c->readbuf_size = readbuf_size;
|
||||
} else {
|
||||
c->readbuf = (unsigned char *)malloc(CONFIG_MQTT_RECV_BUFFER);
|
||||
|
||||
if (c->readbuf) {
|
||||
c->readbuf_size = CONFIG_MQTT_RECV_BUFFER;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
c->isconnected = 0;
|
||||
c->cleansession = 0;
|
||||
c->ping_outstanding = 0;
|
||||
c->defaultMessageHandler = NULL;
|
||||
c->next_packetid = 1;
|
||||
TimerInit(&c->last_sent);
|
||||
TimerInit(&c->last_received);
|
||||
TimerInit(&c->ping_wait);
|
||||
#if defined(MQTT_TASK)
|
||||
MutexInit(&c->mutex);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static int decodePacket(MQTTClient *c, int *value, int timeout)
|
||||
{
|
||||
unsigned char i;
|
||||
int multiplier = 1;
|
||||
int len = 0;
|
||||
const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
|
||||
|
||||
*value = 0;
|
||||
|
||||
do {
|
||||
int rc = MQTTPACKET_READ_ERROR;
|
||||
|
||||
if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
|
||||
rc = MQTTPACKET_READ_ERROR; /* bad data */
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = c->ipstack->mqttread(c->ipstack, &i, 1, timeout);
|
||||
|
||||
if (rc != 1) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*value += (i & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
} while ((i & 128) != 0);
|
||||
|
||||
exit:
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int readPacket(MQTTClient *c, Timer *timer)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
int len = 0;
|
||||
int rem_len = 0;
|
||||
|
||||
/* 1. read the header byte. This has the packet type in it */
|
||||
int rc = c->ipstack->mqttread(c->ipstack, c->readbuf, 1, TimerLeftMS(timer));
|
||||
|
||||
if (rc != 1) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
len = 1;
|
||||
/* 2. read the remaining length. This is variable in itself */
|
||||
decodePacket(c, &rem_len, TimerLeftMS(timer));
|
||||
len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */
|
||||
|
||||
if (rem_len > (c->readbuf_size - len)) {
|
||||
rc = BUFFER_OVERFLOW;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 3. read the rest of the buffer using a callback to supply the rest of the data */
|
||||
if (rem_len > 0 && (rc = c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, TimerLeftMS(timer)) != rem_len)) {
|
||||
rc = 0;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
header.byte = c->readbuf[0];
|
||||
rc = header.bits.type;
|
||||
|
||||
if (c->keepAliveInterval > 0) {
|
||||
TimerCountdown(&c->last_received, c->keepAliveInterval); // record the fact that we have successfully received a packet
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
// assume topic filter and name is in correct format
|
||||
// # can only be at end
|
||||
// + and # can only be next to separator
|
||||
static char isTopicMatched(char *topicFilter, MQTTString *topicName)
|
||||
{
|
||||
char *curf = topicFilter;
|
||||
char *curn = topicName->lenstring.data;
|
||||
char *curn_end = curn + topicName->lenstring.len;
|
||||
|
||||
while (*curf && curn < curn_end) {
|
||||
if (*curn == '/' && *curf != '/') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*curf != '+' && *curf != '#' && *curf != *curn) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*curf == '+') {
|
||||
// skip until we meet the next separator, or end of string
|
||||
char *nextpos = curn + 1;
|
||||
|
||||
while (nextpos < curn_end && *nextpos != '/') {
|
||||
nextpos = ++curn + 1;
|
||||
}
|
||||
} else if (*curf == '#') {
|
||||
curn = curn_end - 1; // skip until end of string
|
||||
}
|
||||
|
||||
curf++;
|
||||
curn++;
|
||||
};
|
||||
|
||||
return (curn == curn_end) && (*curf == '\0');
|
||||
}
|
||||
|
||||
|
||||
int deliverMessage(MQTTClient *c, MQTTString *topicName, MQTTMessage *message)
|
||||
{
|
||||
int i;
|
||||
int rc = FAILURE;
|
||||
|
||||
// we have to find the right message handler - indexed by topic
|
||||
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
|
||||
if (c->messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(topicName, (char *)c->messageHandlers[i].topicFilter) ||
|
||||
isTopicMatched((char *)c->messageHandlers[i].topicFilter, topicName))) {
|
||||
if (c->messageHandlers[i].fp != NULL) {
|
||||
MessageData md;
|
||||
NewMessageData(&md, topicName, message);
|
||||
c->messageHandlers[i].fp(&md);
|
||||
rc = SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == FAILURE && c->defaultMessageHandler != NULL) {
|
||||
MessageData md;
|
||||
NewMessageData(&md, topicName, message);
|
||||
c->defaultMessageHandler(&md);
|
||||
rc = SUCCESS;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int keepalive(MQTTClient *c)
|
||||
{
|
||||
int rc = SUCCESS;
|
||||
|
||||
if (c->keepAliveInterval == 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (TimerIsExpired(&c->last_sent) || TimerIsExpired(&c->last_received)) {
|
||||
if (c->ping_outstanding && TimerIsExpired(&c->ping_wait)) {
|
||||
rc = FAILURE; /* PINGRESP not received in keepalive interval */
|
||||
} else {
|
||||
Timer timer;
|
||||
TimerInit(&timer);
|
||||
TimerCountdownMS(&timer, 1000);
|
||||
int len = MQTTSerialize_pingreq(c->buf, c->buf_size);
|
||||
|
||||
if (len > 0 && (rc = sendPacket(c, len, &timer)) == SUCCESS) { // send the ping packet
|
||||
c->ping_outstanding = 1;
|
||||
TimerCountdownMS(&c->ping_wait, CONFIG_MQTT_PING_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void MQTTCleanSession(MQTTClient *c)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
|
||||
c->messageHandlers[i].topicFilter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MQTTCloseSession(MQTTClient *c)
|
||||
{
|
||||
ESP_LOGW(TAG, "mqtt close session");
|
||||
c->ping_outstanding = 0;
|
||||
c->isconnected = 0;
|
||||
|
||||
if (c->cleansession) {
|
||||
MQTTCleanSession(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int cycle(MQTTClient *c, Timer *timer)
|
||||
{
|
||||
int len = 0,
|
||||
rc = SUCCESS;
|
||||
|
||||
int packet_type = readPacket(c, timer); /* read the socket, see what work is due */
|
||||
|
||||
switch (packet_type) {
|
||||
default:
|
||||
/* no more data to read, unrecoverable. Or read packet fails due to unexpected network error */
|
||||
rc = packet_type;
|
||||
goto exit;
|
||||
|
||||
case 0: /* timed out reading packet */
|
||||
break;
|
||||
|
||||
case CONNACK:
|
||||
case PUBACK:
|
||||
case SUBACK:
|
||||
case UNSUBACK:
|
||||
break;
|
||||
|
||||
case PUBLISH: {
|
||||
MQTTString topicName;
|
||||
MQTTMessage msg;
|
||||
int intQoS;
|
||||
msg.payloadlen = 0; /* this is a size_t, but deserialize publish sets this as int */
|
||||
|
||||
if (MQTTDeserialize_publish(&msg.dup, &intQoS, &msg.retained, &msg.id, &topicName,
|
||||
(unsigned char **)&msg.payload, (int *)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
msg.qos = (enum QoS)intQoS;
|
||||
deliverMessage(c, &topicName, &msg);
|
||||
|
||||
if (msg.qos != QOS0) {
|
||||
if (msg.qos == QOS1) {
|
||||
len = MQTTSerialize_ack(c->buf, c->buf_size, PUBACK, 0, msg.id);
|
||||
} else if (msg.qos == QOS2) {
|
||||
len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREC, 0, msg.id);
|
||||
}
|
||||
|
||||
if (len <= 0) {
|
||||
rc = FAILURE;
|
||||
} else {
|
||||
rc = sendPacket(c, len, timer);
|
||||
}
|
||||
|
||||
if (rc == FAILURE) {
|
||||
goto exit; // there was a problem
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PUBREC:
|
||||
case PUBREL: {
|
||||
unsigned short mypacketid;
|
||||
unsigned char dup, type;
|
||||
|
||||
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1) {
|
||||
rc = FAILURE;
|
||||
} else if ((len = MQTTSerialize_ack(c->buf, c->buf_size,
|
||||
(packet_type == PUBREC) ? PUBREL : PUBCOMP, 0, mypacketid)) <= 0) {
|
||||
rc = FAILURE;
|
||||
} else if ((rc = sendPacket(c, len, timer)) != SUCCESS) { // send the PUBREL packet
|
||||
rc = FAILURE; // there was a problem
|
||||
}
|
||||
|
||||
if (rc == FAILURE) {
|
||||
goto exit; // there was a problem
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PUBCOMP:
|
||||
break;
|
||||
|
||||
case PINGRESP:
|
||||
c->ping_outstanding = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (keepalive(c) != SUCCESS) {
|
||||
//check only keepalive FAILURE status so that previous FAILURE status can be considered as FAULT
|
||||
rc = FAILURE;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (rc == SUCCESS) {
|
||||
rc = packet_type;
|
||||
} else if (c->isconnected) {
|
||||
MQTTCloseSession(c);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTYield(MQTTClient *c, int timeout_ms)
|
||||
{
|
||||
int rc = SUCCESS;
|
||||
Timer timer;
|
||||
|
||||
TimerInit(&timer);
|
||||
TimerCountdownMS(&timer, timeout_ms);
|
||||
|
||||
do {
|
||||
if (cycle(c, &timer) < 0) {
|
||||
rc = FAILURE;
|
||||
break;
|
||||
}
|
||||
} while (!TimerIsExpired(&timer));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void MQTTRun(void *parm)
|
||||
{
|
||||
Timer timer;
|
||||
MQTTClient *c = (MQTTClient *)parm;
|
||||
|
||||
TimerInit(&timer);
|
||||
|
||||
while (1) {
|
||||
TimerCountdownMS(&timer, CONFIG_MQTT_RECV_CYCLE); /* Don't wait too long if no traffic is incoming */
|
||||
|
||||
#if CONFIG_MQTT_RECV_CYCLE == 0 /* The smaller cycle, the greater throughput */
|
||||
esp_task_wdt_reset();
|
||||
#endif
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexLock(&c->mutex);
|
||||
#endif
|
||||
|
||||
int rc = cycle(c, &timer);
|
||||
|
||||
if (rc == FAILURE) {
|
||||
ESP_LOGE(TAG, "MQTTRun cycle failed");
|
||||
#if defined(MQTT_TASK)
|
||||
MutexUnlock(&c->mutex);
|
||||
#endif
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexUnlock(&c->mutex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
int MQTTStartTask(MQTTClient *client)
|
||||
{
|
||||
return ThreadStart(&client->thread, &MQTTRun, client);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int waitfor(MQTTClient *c, int packet_type, Timer *timer)
|
||||
{
|
||||
int rc = FAILURE;
|
||||
|
||||
do {
|
||||
if (TimerIsExpired(timer)) {
|
||||
break; // we timed out
|
||||
}
|
||||
|
||||
rc = cycle(c, timer);
|
||||
} while (rc != packet_type && rc >= 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int MQTTConnectWithResults(MQTTClient *c, MQTTPacket_connectData *options, MQTTConnackData *data)
|
||||
{
|
||||
Timer connect_timer;
|
||||
int rc = FAILURE;
|
||||
MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
|
||||
int len = 0;
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexLock(&c->mutex);
|
||||
#endif
|
||||
|
||||
if (c->isconnected) { /* don't send connect packet again if we are already connected */
|
||||
goto exit;
|
||||
}
|
||||
|
||||
TimerInit(&connect_timer);
|
||||
TimerCountdownMS(&connect_timer, c->command_timeout_ms);
|
||||
|
||||
if (options == 0) {
|
||||
options = &default_options; /* set default options if none were supplied */
|
||||
}
|
||||
|
||||
c->keepAliveInterval = options->keepAliveInterval;
|
||||
c->cleansession = options->cleansession;
|
||||
TimerCountdown(&c->last_received, c->keepAliveInterval);
|
||||
|
||||
if ((len = MQTTSerialize_connect(c->buf, c->buf_size, options)) <= 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((rc = sendPacket(c, len, &connect_timer)) != SUCCESS) { // send the connect packet
|
||||
goto exit; // there was a problem
|
||||
}
|
||||
|
||||
// this will be a blocking call, wait for the connack
|
||||
if (waitfor(c, CONNACK, &connect_timer) == CONNACK) {
|
||||
data->rc = 0;
|
||||
data->sessionPresent = 0;
|
||||
|
||||
if (MQTTDeserialize_connack(&data->sessionPresent, &data->rc, c->readbuf, c->readbuf_size) == 1) {
|
||||
rc = data->rc;
|
||||
} else {
|
||||
rc = FAILURE;
|
||||
}
|
||||
} else {
|
||||
rc = FAILURE;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (rc == SUCCESS) {
|
||||
c->isconnected = 1;
|
||||
c->ping_outstanding = 0;
|
||||
}
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexUnlock(&c->mutex);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTConnect(MQTTClient *c, MQTTPacket_connectData *options)
|
||||
{
|
||||
MQTTConnackData data;
|
||||
return MQTTConnectWithResults(c, options, &data);
|
||||
}
|
||||
|
||||
|
||||
int MQTTSetMessageHandler(MQTTClient *c, const char *topicFilter, messageHandler messageHandler)
|
||||
{
|
||||
int rc = FAILURE;
|
||||
int i = -1;
|
||||
|
||||
/* first check for an existing matching slot */
|
||||
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
|
||||
if (c->messageHandlers[i].topicFilter != NULL && strcmp(c->messageHandlers[i].topicFilter, topicFilter) == 0) {
|
||||
if (messageHandler == NULL) { /* remove existing */
|
||||
c->messageHandlers[i].topicFilter = NULL;
|
||||
c->messageHandlers[i].fp = NULL;
|
||||
}
|
||||
|
||||
rc = SUCCESS; /* return i when adding new subscription */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if no existing, look for empty slot (unless we are removing) */
|
||||
if (messageHandler != NULL) {
|
||||
if (rc == FAILURE) {
|
||||
for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
|
||||
if (c->messageHandlers[i].topicFilter == NULL) {
|
||||
rc = SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i < MAX_MESSAGE_HANDLERS) {
|
||||
c->messageHandlers[i].topicFilter = topicFilter;
|
||||
c->messageHandlers[i].fp = messageHandler;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTSubscribeWithResults(MQTTClient *c, const char *topicFilter, enum QoS qos,
|
||||
messageHandler messageHandler, MQTTSubackData *data)
|
||||
{
|
||||
int rc = FAILURE;
|
||||
Timer timer;
|
||||
int len = 0;
|
||||
MQTTString topic = MQTTString_initializer;
|
||||
topic.cstring = (char *)topicFilter;
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexLock(&c->mutex);
|
||||
#endif
|
||||
|
||||
if (!c->isconnected) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
TimerInit(&timer);
|
||||
TimerCountdownMS(&timer, c->command_timeout_ms);
|
||||
|
||||
len = MQTTSerialize_subscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic, (int *)&qos);
|
||||
|
||||
if (len <= 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((rc = sendPacket(c, len, &timer)) != SUCCESS) { // send the subscribe packet
|
||||
goto exit; // there was a problem
|
||||
}
|
||||
|
||||
if (waitfor(c, SUBACK, &timer) == SUBACK) { // wait for suback
|
||||
int count = 0;
|
||||
unsigned short mypacketid;
|
||||
data->grantedQoS = QOS0;
|
||||
|
||||
if (MQTTDeserialize_suback(&mypacketid, 1, &count, (int *)&data->grantedQoS, c->readbuf, c->readbuf_size) == 1) {
|
||||
if (data->grantedQoS != 0x80) {
|
||||
rc = MQTTSetMessageHandler(c, topicFilter, messageHandler);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = FAILURE;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (rc == FAILURE) {
|
||||
MQTTCloseSession(c);
|
||||
}
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexUnlock(&c->mutex);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTSubscribe(MQTTClient *c, const char *topicFilter, enum QoS qos,
|
||||
messageHandler messageHandler)
|
||||
{
|
||||
MQTTSubackData data;
|
||||
return MQTTSubscribeWithResults(c, topicFilter, qos, messageHandler, &data);
|
||||
}
|
||||
|
||||
|
||||
int MQTTUnsubscribe(MQTTClient *c, const char *topicFilter)
|
||||
{
|
||||
int rc = FAILURE;
|
||||
Timer timer;
|
||||
MQTTString topic = MQTTString_initializer;
|
||||
topic.cstring = (char *)topicFilter;
|
||||
int len = 0;
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexLock(&c->mutex);
|
||||
#endif
|
||||
|
||||
if (!c->isconnected) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
TimerInit(&timer);
|
||||
TimerCountdownMS(&timer, c->command_timeout_ms);
|
||||
|
||||
if ((len = MQTTSerialize_unsubscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic)) <= 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((rc = sendPacket(c, len, &timer)) != SUCCESS) { // send the subscribe packet
|
||||
goto exit; // there was a problem
|
||||
}
|
||||
|
||||
if (waitfor(c, UNSUBACK, &timer) == UNSUBACK) {
|
||||
unsigned short mypacketid; // should be the same as the packetid above
|
||||
|
||||
if (MQTTDeserialize_unsuback(&mypacketid, c->readbuf, c->readbuf_size) == 1) {
|
||||
/* remove the subscription message handler associated with this topic, if there is one */
|
||||
MQTTSetMessageHandler(c, topicFilter, NULL);
|
||||
}
|
||||
} else {
|
||||
rc = FAILURE;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (rc == FAILURE) {
|
||||
MQTTCloseSession(c);
|
||||
}
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexUnlock(&c->mutex);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTPublish(MQTTClient *c, const char *topicName, MQTTMessage *message)
|
||||
{
|
||||
int rc = FAILURE;
|
||||
Timer timer;
|
||||
MQTTString topic = MQTTString_initializer;
|
||||
topic.cstring = (char *)topicName;
|
||||
int len = 0;
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexLock(&c->mutex);
|
||||
#endif
|
||||
|
||||
if (!c->isconnected) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
TimerInit(&timer);
|
||||
TimerCountdownMS(&timer, c->command_timeout_ms);
|
||||
|
||||
if (message->qos == QOS1 || message->qos == QOS2) {
|
||||
message->id = getNextPacketId(c);
|
||||
}
|
||||
|
||||
len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id,
|
||||
topic, (unsigned char *)message->payload, message->payloadlen);
|
||||
|
||||
if (len <= 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((rc = sendPacket(c, len, &timer)) != SUCCESS) { // send the subscribe packet
|
||||
goto exit; // there was a problem
|
||||
}
|
||||
|
||||
if (message->qos == QOS1) {
|
||||
if (waitfor(c, PUBACK, &timer) == PUBACK) {
|
||||
unsigned short mypacketid;
|
||||
unsigned char dup, type;
|
||||
|
||||
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1) {
|
||||
rc = FAILURE;
|
||||
}
|
||||
} else {
|
||||
rc = FAILURE;
|
||||
}
|
||||
} else if (message->qos == QOS2) {
|
||||
if (waitfor(c, PUBCOMP, &timer) == PUBCOMP) {
|
||||
unsigned short mypacketid;
|
||||
unsigned char dup, type;
|
||||
|
||||
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1) {
|
||||
rc = FAILURE;
|
||||
}
|
||||
} else {
|
||||
rc = FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (rc == FAILURE) {
|
||||
MQTTCloseSession(c);
|
||||
}
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexUnlock(&c->mutex);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int MQTTDisconnect(MQTTClient *c)
|
||||
{
|
||||
int rc = FAILURE;
|
||||
Timer timer; // we might wait for incomplete incoming publishes to complete
|
||||
int len = 0;
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexLock(&c->mutex);
|
||||
#endif
|
||||
TimerInit(&timer);
|
||||
TimerCountdownMS(&timer, c->command_timeout_ms);
|
||||
|
||||
len = MQTTSerialize_disconnect(c->buf, c->buf_size);
|
||||
|
||||
if (len > 0) {
|
||||
rc = sendPacket(c, len, &timer); // send the disconnect packet
|
||||
}
|
||||
|
||||
MQTTCloseSession(c);
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
MutexUnlock(&c->mutex);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
@ -1,230 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2017 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - documentation and platform specific header
|
||||
* Ian Craggs - add setMessageHandler function
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTT_CLIENT_H)
|
||||
#define MQTT_CLIENT_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(WIN32_DLL) || defined(WIN64_DLL)
|
||||
#define DLLImport __declspec(dllimport)
|
||||
#define DLLExport __declspec(dllexport)
|
||||
#elif defined(LINUX_SO)
|
||||
#define DLLImport extern
|
||||
#define DLLExport __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define DLLImport
|
||||
#define DLLExport
|
||||
#endif
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
|
||||
#if defined(MQTTCLIENT_PLATFORM_HEADER)
|
||||
/* The following sequence of macros converts the MQTTCLIENT_PLATFORM_HEADER value
|
||||
* into a string constant suitable for use with include.
|
||||
*/
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
#include xstr(MQTTCLIENT_PLATFORM_HEADER)
|
||||
#endif
|
||||
|
||||
#define MAX_PACKET_ID 65535 /* according to the MQTT specification - do not change! */
|
||||
|
||||
#if !defined(MAX_MESSAGE_HANDLERS)
|
||||
#define MAX_MESSAGE_HANDLERS 5 /* redefinable - how many subscriptions do you want? */
|
||||
#endif
|
||||
|
||||
enum QoS { QOS0, QOS1, QOS2, SUBFAIL = 0x80 };
|
||||
|
||||
/* all failure return codes must be negative */
|
||||
enum returnCode { BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };
|
||||
|
||||
/* The Platform specific header must define the Network and Timer structures and functions
|
||||
* which operate on them.
|
||||
*
|
||||
typedef struct Network
|
||||
{
|
||||
int (*mqttread)(Network*, unsigned char* read_buffer, int, int);
|
||||
int (*mqttwrite)(Network*, unsigned char* send_buffer, int, int);
|
||||
} Network;*/
|
||||
|
||||
/* The Timer structure must be defined in the platform specific header,
|
||||
* and have the following functions to operate on it. */
|
||||
extern void TimerInit(Timer *);
|
||||
extern char TimerIsExpired(Timer *);
|
||||
extern void TimerCountdownMS(Timer *, unsigned int);
|
||||
extern void TimerCountdown(Timer *, unsigned int);
|
||||
extern int TimerLeftMS(Timer *);
|
||||
|
||||
typedef struct MQTTMessage {
|
||||
enum QoS qos;
|
||||
unsigned char retained;
|
||||
unsigned char dup;
|
||||
unsigned short id;
|
||||
void *payload;
|
||||
size_t payloadlen;
|
||||
} MQTTMessage;
|
||||
|
||||
typedef struct MessageData {
|
||||
MQTTMessage *message;
|
||||
MQTTString *topicName;
|
||||
} MessageData;
|
||||
|
||||
typedef struct MQTTConnackData {
|
||||
unsigned char rc;
|
||||
unsigned char sessionPresent;
|
||||
} MQTTConnackData;
|
||||
|
||||
typedef struct MQTTSubackData {
|
||||
enum QoS grantedQoS;
|
||||
} MQTTSubackData;
|
||||
|
||||
typedef void (*messageHandler)(MessageData *);
|
||||
|
||||
typedef struct MQTTClient {
|
||||
unsigned int next_packetid,
|
||||
command_timeout_ms;
|
||||
size_t buf_size,
|
||||
readbuf_size;
|
||||
unsigned char *buf,
|
||||
*readbuf;
|
||||
unsigned int keepAliveInterval;
|
||||
char ping_outstanding;
|
||||
int isconnected;
|
||||
int cleansession;
|
||||
|
||||
struct MessageHandlers {
|
||||
const char *topicFilter;
|
||||
void (*fp)(MessageData *);
|
||||
} messageHandlers[MAX_MESSAGE_HANDLERS]; /* Message handlers are indexed by subscription topic */
|
||||
|
||||
void (*defaultMessageHandler)(MessageData *);
|
||||
|
||||
Network *ipstack;
|
||||
Timer last_sent, last_received, ping_wait;
|
||||
#if defined(MQTT_TASK)
|
||||
Mutex mutex;
|
||||
Thread thread;
|
||||
#endif
|
||||
} MQTTClient;
|
||||
|
||||
#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}
|
||||
|
||||
|
||||
/**
|
||||
* Create an MQTT client object
|
||||
* @param client
|
||||
* @param network
|
||||
* @param command_timeout_ms
|
||||
* @param
|
||||
*/
|
||||
DLLExport bool MQTTClientInit(MQTTClient *client, Network *network, unsigned int command_timeout_ms,
|
||||
unsigned char *sendbuf, size_t sendbuf_size, unsigned char *readbuf, size_t readbuf_size);
|
||||
|
||||
/** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
|
||||
* The nework object must be connected to the network endpoint before calling this
|
||||
* @param options - connect options
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTConnectWithResults(MQTTClient *client, MQTTPacket_connectData *options,
|
||||
MQTTConnackData *data);
|
||||
|
||||
/** MQTT Connect - send an MQTT connect packet down the network and wait for a Connack
|
||||
* The nework object must be connected to the network endpoint before calling this
|
||||
* @param options - connect options
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTConnect(MQTTClient *client, MQTTPacket_connectData *options);
|
||||
|
||||
/** MQTT Publish - send an MQTT publish packet and wait for all acks to complete for all QoSs
|
||||
* @param client - the client object to use
|
||||
* @param topic - the topic to publish to
|
||||
* @param message - the message to send
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTPublish(MQTTClient *client, const char *, MQTTMessage *);
|
||||
|
||||
/** MQTT SetMessageHandler - set or remove a per topic message handler
|
||||
* @param client - the client object to use
|
||||
* @param topicFilter - the topic filter set the message handler for
|
||||
* @param messageHandler - pointer to the message handler function or NULL to remove
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTSetMessageHandler(MQTTClient *c, const char *topicFilter, messageHandler messageHandler);
|
||||
|
||||
/** MQTT Subscribe - send an MQTT subscribe packet and wait for suback before returning.
|
||||
* @param client - the client object to use
|
||||
* @param topicFilter - the topic filter to subscribe to
|
||||
* @param message - the message to send
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTSubscribe(MQTTClient *client, const char *topicFilter, enum QoS, messageHandler);
|
||||
|
||||
/** MQTT Subscribe - send an MQTT subscribe packet and wait for suback before returning.
|
||||
* @param client - the client object to use
|
||||
* @param topicFilter - the topic filter to subscribe to
|
||||
* @param message - the message to send
|
||||
* @param data - suback granted QoS returned
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTSubscribeWithResults(MQTTClient *client, const char *topicFilter, enum QoS, messageHandler, MQTTSubackData *data);
|
||||
|
||||
/** MQTT Subscribe - send an MQTT unsubscribe packet and wait for unsuback before returning.
|
||||
* @param client - the client object to use
|
||||
* @param topicFilter - the topic filter to unsubscribe from
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTUnsubscribe(MQTTClient *client, const char *topicFilter);
|
||||
|
||||
/** MQTT Disconnect - send an MQTT disconnect packet and close the connection
|
||||
* @param client - the client object to use
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTDisconnect(MQTTClient *client);
|
||||
|
||||
/** MQTT Yield - MQTT background
|
||||
* @param client - the client object to use
|
||||
* @param time - the time, in milliseconds, to yield for
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTYield(MQTTClient *client, int time);
|
||||
|
||||
/** MQTT isConnected
|
||||
* @param client - the client object to use
|
||||
* @return truth value indicating whether the client is connected to the server
|
||||
*/
|
||||
static inline DLLExport int MQTTIsConnected(MQTTClient *client)
|
||||
{
|
||||
return client->isconnected;
|
||||
}
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
/** MQTT start background thread for a client. After this, MQTTYield should not be called.
|
||||
* @param client - the client object to use
|
||||
* @return success code
|
||||
*/
|
||||
DLLExport int MQTTStartTask(MQTTClient *client);
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,148 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2017 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - add connack return code definitions
|
||||
* Xiang Rong - 442039 Add makefile to Embedded C client
|
||||
* Ian Craggs - fix for issue #64, bit order in connack response
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTCONNECT_H_
|
||||
#define MQTTCONNECT_H_
|
||||
|
||||
enum connack_return_codes
|
||||
{
|
||||
MQTT_CONNECTION_ACCEPTED = 0,
|
||||
MQTT_UNNACCEPTABLE_PROTOCOL = 1,
|
||||
MQTT_CLIENTID_REJECTED = 2,
|
||||
MQTT_SERVER_UNAVAILABLE = 3,
|
||||
MQTT_BAD_USERNAME_OR_PASSWORD = 4,
|
||||
MQTT_NOT_AUTHORIZED = 5,
|
||||
};
|
||||
|
||||
#if !defined(DLLImport)
|
||||
#define DLLImport
|
||||
#endif
|
||||
#if !defined(DLLExport)
|
||||
#define DLLExport
|
||||
#endif
|
||||
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned char all; /**< all connect flags */
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
unsigned int username : 1; /**< 3.1 user name */
|
||||
unsigned int password : 1; /**< 3.1 password */
|
||||
unsigned int willRetain : 1; /**< will retain setting */
|
||||
unsigned int willQoS : 2; /**< will QoS value */
|
||||
unsigned int will : 1; /**< will flag */
|
||||
unsigned int cleansession : 1; /**< clean session flag */
|
||||
unsigned int : 1; /**< unused */
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
unsigned int : 1; /**< unused */
|
||||
unsigned int cleansession : 1; /**< cleansession flag */
|
||||
unsigned int will : 1; /**< will flag */
|
||||
unsigned int willQoS : 2; /**< will QoS value */
|
||||
unsigned int willRetain : 1; /**< will retain setting */
|
||||
unsigned int password : 1; /**< 3.1 password */
|
||||
unsigned int username : 1; /**< 3.1 user name */
|
||||
} bits;
|
||||
#endif
|
||||
} MQTTConnectFlags; /**< connect flags byte */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Defines the MQTT "Last Will and Testament" (LWT) settings for
|
||||
* the connect packet.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
/** The eyecatcher for this structure. must be MQTW. */
|
||||
char struct_id[4];
|
||||
/** The version number of this structure. Must be 0 */
|
||||
int struct_version;
|
||||
/** The LWT topic to which the LWT message will be published. */
|
||||
MQTTString topicName;
|
||||
/** The LWT payload. */
|
||||
MQTTString message;
|
||||
/**
|
||||
* The retained flag for the LWT message (see MQTTAsync_message.retained).
|
||||
*/
|
||||
unsigned char retained;
|
||||
/**
|
||||
* The quality of service setting for the LWT message (see
|
||||
* MQTTAsync_message.qos and @ref qos).
|
||||
*/
|
||||
char qos;
|
||||
} MQTTPacket_willOptions;
|
||||
|
||||
|
||||
#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/** The eyecatcher for this structure. must be MQTC. */
|
||||
char struct_id[4];
|
||||
/** The version number of this structure. Must be 0 */
|
||||
int struct_version;
|
||||
/** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1
|
||||
*/
|
||||
unsigned char MQTTVersion;
|
||||
MQTTString clientID;
|
||||
unsigned short keepAliveInterval;
|
||||
unsigned char cleansession;
|
||||
unsigned char willFlag;
|
||||
MQTTPacket_willOptions will;
|
||||
MQTTString username;
|
||||
MQTTString password;
|
||||
} MQTTPacket_connectData;
|
||||
|
||||
typedef union
|
||||
{
|
||||
unsigned char all; /**< all connack flags */
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
unsigned int reserved : 7; /**< unused */
|
||||
unsigned int sessionpresent : 1; /**< session present flag */
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
unsigned int sessionpresent : 1; /**< session present flag */
|
||||
unsigned int reserved: 7; /**< unused */
|
||||
} bits;
|
||||
#endif
|
||||
} MQTTConnackFlags; /**< connack flags byte */
|
||||
|
||||
#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
|
||||
MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
|
||||
|
||||
DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);
|
||||
DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);
|
||||
|
||||
DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);
|
||||
DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);
|
||||
|
||||
DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);
|
||||
DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);
|
||||
|
||||
#endif /* MQTTCONNECT_H_ */
|
@ -1,214 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
|
||||
* @param options the options to be used to build the connect packet
|
||||
* @return the length of buffer needed to contain the serialized version of the packet
|
||||
*/
|
||||
int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
|
||||
if (options->MQTTVersion == 3)
|
||||
len = 12; /* variable depending on MQTT or MQIsdp */
|
||||
else if (options->MQTTVersion == 4)
|
||||
len = 10;
|
||||
|
||||
len += MQTTstrlen(options->clientID)+2;
|
||||
if (options->willFlag)
|
||||
len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
|
||||
if (options->username.cstring || options->username.lenstring.data)
|
||||
len += MQTTstrlen(options->username)+2;
|
||||
if (options->password.cstring || options->password.lenstring.data)
|
||||
len += MQTTstrlen(options->password)+2;
|
||||
|
||||
FUNC_EXIT_RC(len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the connect options into the buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param len the length in bytes of the supplied buffer
|
||||
* @param options the options to be used to build the connect packet
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
|
||||
{
|
||||
unsigned char *ptr = buf;
|
||||
MQTTHeader header = {0};
|
||||
MQTTConnectFlags flags = {0};
|
||||
int len = 0;
|
||||
int rc = -1;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
header.byte = 0;
|
||||
header.bits.type = CONNECT;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
|
||||
|
||||
if (options->MQTTVersion == 4)
|
||||
{
|
||||
writeCString(&ptr, "MQTT");
|
||||
writeChar(&ptr, (char) 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeCString(&ptr, "MQIsdp");
|
||||
writeChar(&ptr, (char) 3);
|
||||
}
|
||||
|
||||
flags.all = 0;
|
||||
flags.bits.cleansession = options->cleansession;
|
||||
flags.bits.will = (options->willFlag) ? 1 : 0;
|
||||
if (flags.bits.will)
|
||||
{
|
||||
flags.bits.willQoS = options->will.qos;
|
||||
flags.bits.willRetain = options->will.retained;
|
||||
}
|
||||
|
||||
if (options->username.cstring || options->username.lenstring.data)
|
||||
flags.bits.username = 1;
|
||||
if (options->password.cstring || options->password.lenstring.data)
|
||||
flags.bits.password = 1;
|
||||
|
||||
writeChar(&ptr, flags.all);
|
||||
writeInt(&ptr, options->keepAliveInterval);
|
||||
writeMQTTString(&ptr, options->clientID);
|
||||
if (options->willFlag)
|
||||
{
|
||||
writeMQTTString(&ptr, options->will.topicName);
|
||||
writeMQTTString(&ptr, options->will.message);
|
||||
}
|
||||
if (flags.bits.username)
|
||||
writeMQTTString(&ptr, options->username);
|
||||
if (flags.bits.password)
|
||||
writeMQTTString(&ptr, options->password);
|
||||
|
||||
rc = ptr - buf;
|
||||
|
||||
exit: FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into connack data - return code
|
||||
* @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
|
||||
* @param connack_rc returned integer value of the connack return code
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param len the length in bytes of the data in the supplied buffer
|
||||
* @return error code. 1 is success, 0 is failure
|
||||
*/
|
||||
int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = NULL;
|
||||
int rc = 0;
|
||||
int mylen;
|
||||
MQTTConnackFlags flags = {0};
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = readChar(&curdata);
|
||||
if (header.bits.type != CONNACK)
|
||||
goto exit;
|
||||
|
||||
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
|
||||
enddata = curdata + mylen;
|
||||
if (enddata - curdata < 2)
|
||||
goto exit;
|
||||
|
||||
flags.all = readChar(&curdata);
|
||||
*sessionPresent = flags.bits.sessionpresent;
|
||||
*connack_rc = readChar(&curdata);
|
||||
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
|
||||
* @param packettype the message type
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
int rc = -1;
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (buflen < 2)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
header.byte = 0;
|
||||
header.bits.type = packettype;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
|
||||
{
|
||||
return MQTTSerialize_zero(buf, buflen, DISCONNECT);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer, to avoid overruns
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
|
||||
{
|
||||
return MQTTSerialize_zero(buf, buflen, PINGREQ);
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "StackTrace.h"
|
||||
#include "MQTTPacket.h"
|
||||
#include <string.h>
|
||||
|
||||
#define min(a, b) ((a < b) ? a : b)
|
||||
|
||||
|
||||
/**
|
||||
* Validates MQTT protocol name and version combinations
|
||||
* @param protocol the MQTT protocol name as an MQTTString
|
||||
* @param version the MQTT protocol version number, as in the connect packet
|
||||
* @return correct MQTT combination? 1 is true, 0 is false
|
||||
*/
|
||||
int MQTTPacket_checkVersion(MQTTString* protocol, int version)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",
|
||||
min(6, protocol->lenstring.len)) == 0)
|
||||
rc = 1;
|
||||
else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",
|
||||
min(4, protocol->lenstring.len)) == 0)
|
||||
rc = 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into connect data structure
|
||||
* @param data the connect data structure to be filled out
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param len the length in bytes of the data in the supplied buffer
|
||||
* @return error code. 1 is success, 0 is failure
|
||||
*/
|
||||
int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
MQTTConnectFlags flags = {0};
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = &buf[len];
|
||||
int rc = 0;
|
||||
MQTTString Protocol;
|
||||
int version;
|
||||
int mylen = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = readChar(&curdata);
|
||||
if (header.bits.type != CONNECT)
|
||||
goto exit;
|
||||
|
||||
curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
|
||||
|
||||
if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
|
||||
enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
|
||||
goto exit;
|
||||
|
||||
version = (int)readChar(&curdata); /* Protocol version */
|
||||
/* If we don't recognize the protocol version, we don't parse the connect packet on the
|
||||
* basis that we don't know what the format will be.
|
||||
*/
|
||||
if (MQTTPacket_checkVersion(&Protocol, version))
|
||||
{
|
||||
flags.all = readChar(&curdata);
|
||||
data->cleansession = flags.bits.cleansession;
|
||||
data->keepAliveInterval = readInt(&curdata);
|
||||
if (!readMQTTLenString(&data->clientID, &curdata, enddata))
|
||||
goto exit;
|
||||
data->willFlag = flags.bits.will;
|
||||
if (flags.bits.will)
|
||||
{
|
||||
data->will.qos = flags.bits.willQoS;
|
||||
data->will.retained = flags.bits.willRetain;
|
||||
if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
|
||||
!readMQTTLenString(&data->will.message, &curdata, enddata))
|
||||
goto exit;
|
||||
}
|
||||
if (flags.bits.username)
|
||||
{
|
||||
if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
|
||||
goto exit; /* username flag set, but no username supplied - invalid */
|
||||
if (flags.bits.password &&
|
||||
(enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
|
||||
goto exit; /* password flag set, but no password supplied - invalid */
|
||||
}
|
||||
else if (flags.bits.password)
|
||||
goto exit; /* password flag set without username - invalid */
|
||||
rc = 1;
|
||||
}
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the connack packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param connack_rc the integer connack return code to be used
|
||||
* @param sessionPresent the MQTT 3.1.1 sessionPresent flag
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
int rc = 0;
|
||||
unsigned char *ptr = buf;
|
||||
MQTTConnackFlags flags = {0};
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (buflen < 2)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
header.byte = 0;
|
||||
header.bits.type = CONNACK;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
|
||||
|
||||
flags.all = 0;
|
||||
flags.bits.sessionpresent = sessionPresent;
|
||||
writeChar(&ptr, flags.all);
|
||||
writeChar(&ptr, connack_rc);
|
||||
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1,107 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "StackTrace.h"
|
||||
#include "MQTTPacket.h"
|
||||
#include <string.h>
|
||||
|
||||
#define min(a, b) ((a < b) ? 1 : 0)
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into publish data
|
||||
* @param dup returned integer - the MQTT dup flag
|
||||
* @param qos returned integer - the MQTT QoS value
|
||||
* @param retained returned integer - the MQTT retained flag
|
||||
* @param packetid returned integer - the MQTT packet identifier
|
||||
* @param topicName returned MQTTString - the MQTT topic in the publish
|
||||
* @param payload returned byte buffer - the MQTT publish payload
|
||||
* @param payloadlen returned integer - the length of the MQTT payload
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param buflen the length in bytes of the data in the supplied buffer
|
||||
* @return error code. 1 is success
|
||||
*/
|
||||
int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
|
||||
unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = NULL;
|
||||
int rc = 0;
|
||||
int mylen = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = readChar(&curdata);
|
||||
if (header.bits.type != PUBLISH)
|
||||
goto exit;
|
||||
*dup = header.bits.dup;
|
||||
*qos = header.bits.qos;
|
||||
*retained = header.bits.retain;
|
||||
|
||||
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
|
||||
enddata = curdata + mylen;
|
||||
|
||||
if (!readMQTTLenString(topicName, &curdata, enddata) ||
|
||||
enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
|
||||
goto exit;
|
||||
|
||||
if (*qos > 0)
|
||||
*packetid = readInt(&curdata);
|
||||
|
||||
*payloadlen = enddata - curdata;
|
||||
*payload = curdata;
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into an ack
|
||||
* @param packettype returned integer - the MQTT packet type
|
||||
* @param dup returned integer - the MQTT dup flag
|
||||
* @param packetid returned integer - the MQTT packet identifier
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param buflen the length in bytes of the data in the supplied buffer
|
||||
* @return error code. 1 is success, 0 is failure
|
||||
*/
|
||||
int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = NULL;
|
||||
int rc = 0;
|
||||
int mylen;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = readChar(&curdata);
|
||||
*dup = header.bits.dup;
|
||||
*packettype = header.bits.type;
|
||||
|
||||
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
|
||||
enddata = curdata + mylen;
|
||||
|
||||
if (enddata - curdata < 2)
|
||||
goto exit;
|
||||
*packetid = readInt(&curdata);
|
||||
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
@ -1,262 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "StackTrace.h"
|
||||
#include "MQTTPacket.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
const char* MQTTPacket_names[] =
|
||||
{
|
||||
"RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL",
|
||||
"PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK",
|
||||
"PINGREQ", "PINGRESP", "DISCONNECT"
|
||||
};
|
||||
|
||||
|
||||
const char* MQTTPacket_getName(unsigned short packetid)
|
||||
{
|
||||
return MQTTPacket_names[packetid];
|
||||
}
|
||||
|
||||
|
||||
int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data)
|
||||
{
|
||||
int strindex = 0;
|
||||
|
||||
strindex = snprintf(strbuf, strbuflen,
|
||||
"CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %d",
|
||||
(int)data->MQTTVersion, data->clientID.lenstring.len, data->clientID.lenstring.data,
|
||||
(int)data->cleansession, data->keepAliveInterval);
|
||||
if (data->willFlag)
|
||||
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
|
||||
", will QoS %d, will retain %d, will topic %.*s, will message %.*s",
|
||||
data->will.qos, data->will.retained,
|
||||
data->will.topicName.lenstring.len, data->will.topicName.lenstring.data,
|
||||
data->will.message.lenstring.len, data->will.message.lenstring.data);
|
||||
if (data->username.lenstring.data && data->username.lenstring.len > 0)
|
||||
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
|
||||
", user name %.*s", data->username.lenstring.len, data->username.lenstring.data);
|
||||
if (data->password.lenstring.data && data->password.lenstring.len > 0)
|
||||
strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
|
||||
", password %.*s", data->password.lenstring.len, data->password.lenstring.data);
|
||||
return strindex;
|
||||
}
|
||||
|
||||
|
||||
int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent)
|
||||
{
|
||||
int strindex = snprintf(strbuf, strbuflen, "CONNACK session present %d, rc %d", sessionPresent, connack_rc);
|
||||
return strindex;
|
||||
}
|
||||
|
||||
|
||||
int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
|
||||
unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen)
|
||||
{
|
||||
int strindex = snprintf(strbuf, strbuflen,
|
||||
"PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s",
|
||||
dup, qos, retained, packetid,
|
||||
(topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data,
|
||||
payloadlen, (payloadlen < 20) ? payloadlen : 20, payload);
|
||||
return strindex;
|
||||
}
|
||||
|
||||
|
||||
int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
|
||||
{
|
||||
int strindex = snprintf(strbuf, strbuflen, "%s, packet id %d", MQTTPacket_names[packettype], packetid);
|
||||
if (dup)
|
||||
strindex += snprintf(strbuf + strindex, strbuflen - strindex, ", dup %d", dup);
|
||||
return strindex;
|
||||
}
|
||||
|
||||
|
||||
int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
|
||||
MQTTString topicFilters[], int requestedQoSs[])
|
||||
{
|
||||
return snprintf(strbuf, strbuflen,
|
||||
"SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d",
|
||||
dup, packetid, count,
|
||||
topicFilters[0].lenstring.len, topicFilters[0].lenstring.data,
|
||||
requestedQoSs[0]);
|
||||
}
|
||||
|
||||
|
||||
int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs)
|
||||
{
|
||||
return snprintf(strbuf, strbuflen,
|
||||
"SUBACK packet id %d count %d granted qos %d", packetid, count, grantedQoSs[0]);
|
||||
}
|
||||
|
||||
|
||||
int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
|
||||
int count, MQTTString topicFilters[])
|
||||
{
|
||||
return snprintf(strbuf, strbuflen,
|
||||
"UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s",
|
||||
dup, packetid, count,
|
||||
topicFilters[0].lenstring.len, topicFilters[0].lenstring.data);
|
||||
}
|
||||
|
||||
|
||||
#if defined(MQTT_CLIENT)
|
||||
char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
|
||||
{
|
||||
int index = 0;
|
||||
int rem_length = 0;
|
||||
MQTTHeader header = {0};
|
||||
int strindex = 0;
|
||||
|
||||
header.byte = buf[index++];
|
||||
index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
|
||||
|
||||
switch (header.bits.type)
|
||||
{
|
||||
|
||||
case CONNACK:
|
||||
{
|
||||
unsigned char sessionPresent, connack_rc;
|
||||
if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1)
|
||||
strindex = MQTTStringFormat_connack(strbuf, strbuflen, connack_rc, sessionPresent);
|
||||
}
|
||||
break;
|
||||
case PUBLISH:
|
||||
{
|
||||
unsigned char dup, retained, *payload;
|
||||
unsigned short packetid;
|
||||
int qos, payloadlen;
|
||||
MQTTString topicName = MQTTString_initializer;
|
||||
if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
|
||||
&payload, &payloadlen, buf, buflen) == 1)
|
||||
strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
|
||||
topicName, payload, payloadlen);
|
||||
}
|
||||
break;
|
||||
case PUBACK:
|
||||
case PUBREC:
|
||||
case PUBREL:
|
||||
case PUBCOMP:
|
||||
{
|
||||
unsigned char packettype, dup;
|
||||
unsigned short packetid;
|
||||
if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
|
||||
strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
|
||||
}
|
||||
break;
|
||||
case SUBACK:
|
||||
{
|
||||
unsigned short packetid;
|
||||
int maxcount = 1, count = 0;
|
||||
int grantedQoSs[1];
|
||||
if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1)
|
||||
strindex = MQTTStringFormat_suback(strbuf, strbuflen, packetid, count, grantedQoSs);
|
||||
}
|
||||
break;
|
||||
case UNSUBACK:
|
||||
{
|
||||
unsigned short packetid;
|
||||
if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1)
|
||||
strindex = MQTTStringFormat_ack(strbuf, strbuflen, UNSUBACK, 0, packetid);
|
||||
}
|
||||
break;
|
||||
case PINGREQ:
|
||||
case PINGRESP:
|
||||
case DISCONNECT:
|
||||
strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
|
||||
break;
|
||||
}
|
||||
return strbuf;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MQTT_SERVER)
|
||||
char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
|
||||
{
|
||||
int index = 0;
|
||||
int rem_length = 0;
|
||||
MQTTHeader header = {0};
|
||||
int strindex = 0;
|
||||
|
||||
header.byte = buf[index++];
|
||||
index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
|
||||
|
||||
switch (header.bits.type)
|
||||
{
|
||||
case CONNECT:
|
||||
{
|
||||
MQTTPacket_connectData data;
|
||||
int rc;
|
||||
if ((rc = MQTTDeserialize_connect(&data, buf, buflen)) == 1)
|
||||
strindex = MQTTStringFormat_connect(strbuf, strbuflen, &data);
|
||||
}
|
||||
break;
|
||||
case PUBLISH:
|
||||
{
|
||||
unsigned char dup, retained, *payload;
|
||||
unsigned short packetid;
|
||||
int qos, payloadlen;
|
||||
MQTTString topicName = MQTTString_initializer;
|
||||
if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
|
||||
&payload, &payloadlen, buf, buflen) == 1)
|
||||
strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
|
||||
topicName, payload, payloadlen);
|
||||
}
|
||||
break;
|
||||
case PUBACK:
|
||||
case PUBREC:
|
||||
case PUBREL:
|
||||
case PUBCOMP:
|
||||
{
|
||||
unsigned char packettype, dup;
|
||||
unsigned short packetid;
|
||||
if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
|
||||
strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
|
||||
}
|
||||
break;
|
||||
case SUBSCRIBE:
|
||||
{
|
||||
unsigned char dup;
|
||||
unsigned short packetid;
|
||||
int maxcount = 1, count = 0;
|
||||
MQTTString topicFilters[1];
|
||||
int requestedQoSs[1];
|
||||
if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count,
|
||||
topicFilters, requestedQoSs, buf, buflen) == 1)
|
||||
strindex = MQTTStringFormat_subscribe(strbuf, strbuflen, dup, packetid, count, topicFilters, requestedQoSs);;
|
||||
}
|
||||
break;
|
||||
case UNSUBSCRIBE:
|
||||
{
|
||||
unsigned char dup;
|
||||
unsigned short packetid;
|
||||
int maxcount = 1, count = 0;
|
||||
MQTTString topicFilters[1];
|
||||
if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1)
|
||||
strindex = MQTTStringFormat_unsubscribe(strbuf, strbuflen, dup, packetid, count, topicFilters);
|
||||
}
|
||||
break;
|
||||
case PINGREQ:
|
||||
case PINGRESP:
|
||||
case DISCONNECT:
|
||||
strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
|
||||
break;
|
||||
}
|
||||
strbuf[strbuflen] = '\0';
|
||||
return strbuf;
|
||||
}
|
||||
#endif
|
@ -1,37 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(MQTTFORMAT_H)
|
||||
#define MQTTFORMAT_H
|
||||
|
||||
#include "StackTrace.h"
|
||||
#include "MQTTPacket.h"
|
||||
|
||||
const char* MQTTPacket_getName(unsigned short packetid);
|
||||
int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);
|
||||
int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);
|
||||
int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
|
||||
unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);
|
||||
int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);
|
||||
int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
|
||||
MQTTString topicFilters[], int requestedQoSs[]);
|
||||
int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);
|
||||
int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
|
||||
int count, MQTTString topicFilters[]);
|
||||
char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
|
||||
char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
|
||||
|
||||
#endif
|
@ -1,433 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Sergio R. Caprile - non-blocking packet read functions for stream transport
|
||||
*******************************************************************************/
|
||||
|
||||
#include "StackTrace.h"
|
||||
#include "MQTTPacket.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Encodes the message length according to the MQTT algorithm
|
||||
* @param buf the buffer into which the encoded data is written
|
||||
* @param length the length to be encoded
|
||||
* @return the number of bytes written to buffer
|
||||
*/
|
||||
int MQTTPacket_encode(unsigned char* buf, int length)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
do
|
||||
{
|
||||
char d = length % 128;
|
||||
length /= 128;
|
||||
/* if there are more digits to encode, set the top bit of this digit */
|
||||
if (length > 0)
|
||||
d |= 0x80;
|
||||
buf[rc++] = d;
|
||||
} while (length > 0);
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decodes the message length according to the MQTT algorithm
|
||||
* @param getcharfn pointer to function to read the next character from the data source
|
||||
* @param value the decoded length returned
|
||||
* @return the number of bytes read from the socket
|
||||
*/
|
||||
int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
|
||||
{
|
||||
unsigned char c;
|
||||
int multiplier = 1;
|
||||
int len = 0;
|
||||
#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
|
||||
|
||||
FUNC_ENTRY;
|
||||
*value = 0;
|
||||
do
|
||||
{
|
||||
int rc = MQTTPACKET_READ_ERROR;
|
||||
|
||||
if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
|
||||
{
|
||||
rc = MQTTPACKET_READ_ERROR; /* bad data */
|
||||
goto exit;
|
||||
}
|
||||
rc = (*getcharfn)(&c, 1);
|
||||
if (rc != 1)
|
||||
goto exit;
|
||||
*value += (c & 127) * multiplier;
|
||||
multiplier *= 128;
|
||||
} while ((c & 128) != 0);
|
||||
exit:
|
||||
FUNC_EXIT_RC(len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
int MQTTPacket_len(int rem_len)
|
||||
{
|
||||
rem_len += 1; /* header byte */
|
||||
|
||||
/* now remaining_length field */
|
||||
if (rem_len < 128)
|
||||
rem_len += 1;
|
||||
else if (rem_len < 16384)
|
||||
rem_len += 2;
|
||||
else if (rem_len < 2097151)
|
||||
rem_len += 3;
|
||||
else
|
||||
rem_len += 4;
|
||||
return rem_len;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char* bufptr;
|
||||
|
||||
int bufchar(unsigned char* c, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
*c = *bufptr++;
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int MQTTPacket_decodeBuf(unsigned char* buf, int* value)
|
||||
{
|
||||
bufptr = buf;
|
||||
return MQTTPacket_decode(bufchar, value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates an integer from two bytes read from the input buffer
|
||||
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return the integer value calculated
|
||||
*/
|
||||
int readInt(unsigned char** pptr)
|
||||
{
|
||||
unsigned char* ptr = *pptr;
|
||||
int len = 256*(*ptr) + (*(ptr+1));
|
||||
*pptr += 2;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads one character from the input buffer.
|
||||
* @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
|
||||
* @return the character read
|
||||
*/
|
||||
char readChar(unsigned char** pptr)
|
||||
{
|
||||
char c = **pptr;
|
||||
(*pptr)++;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes one character to an output buffer.
|
||||
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
* @param c the character to write
|
||||
*/
|
||||
void writeChar(unsigned char** pptr, char c)
|
||||
{
|
||||
**pptr = c;
|
||||
(*pptr)++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes an integer as 2 bytes to an output buffer.
|
||||
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
* @param anInt the integer to write
|
||||
*/
|
||||
void writeInt(unsigned char** pptr, int anInt)
|
||||
{
|
||||
**pptr = (unsigned char)(anInt / 256);
|
||||
(*pptr)++;
|
||||
**pptr = (unsigned char)(anInt % 256);
|
||||
(*pptr)++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes a "UTF" string to an output buffer. Converts C string to length-delimited.
|
||||
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
* @param string the C string to write
|
||||
*/
|
||||
void writeCString(unsigned char** pptr, const char* string)
|
||||
{
|
||||
int len = strlen(string);
|
||||
writeInt(pptr, len);
|
||||
memcpy(*pptr, string, len);
|
||||
*pptr += len;
|
||||
}
|
||||
|
||||
|
||||
int getLenStringLen(char* ptr)
|
||||
{
|
||||
int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void writeMQTTString(unsigned char** pptr, MQTTString mqttstring)
|
||||
{
|
||||
if (mqttstring.lenstring.len > 0)
|
||||
{
|
||||
writeInt(pptr, mqttstring.lenstring.len);
|
||||
memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
|
||||
*pptr += mqttstring.lenstring.len;
|
||||
}
|
||||
else if (mqttstring.cstring)
|
||||
writeCString(pptr, mqttstring.cstring);
|
||||
else
|
||||
writeInt(pptr, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param mqttstring the MQTTString structure into which the data is to be read
|
||||
* @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
|
||||
* @param enddata pointer to the end of the data: do not read beyond
|
||||
* @return 1 if successful, 0 if not
|
||||
*/
|
||||
int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
/* the first two bytes are the length of the string */
|
||||
if (enddata - (*pptr) > 1) /* enough length to read the integer? */
|
||||
{
|
||||
mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
|
||||
if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
|
||||
{
|
||||
mqttstring->lenstring.data = (char*)*pptr;
|
||||
*pptr += mqttstring->lenstring.len;
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
mqttstring->cstring = NULL;
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
|
||||
* @param mqttstring the string to return the length of
|
||||
* @return the length of the string
|
||||
*/
|
||||
int MQTTstrlen(MQTTString mqttstring)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (mqttstring.cstring)
|
||||
rc = strlen(mqttstring.cstring);
|
||||
else
|
||||
rc = mqttstring.lenstring.len;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compares an MQTTString to a C string
|
||||
* @param a the MQTTString to compare
|
||||
* @param bptr the C string to compare
|
||||
* @return boolean - equal or not
|
||||
*/
|
||||
int MQTTPacket_equals(MQTTString* a, char* bptr)
|
||||
{
|
||||
int alen = 0,
|
||||
blen = 0;
|
||||
char *aptr;
|
||||
|
||||
if (a->cstring)
|
||||
{
|
||||
aptr = a->cstring;
|
||||
alen = strlen(a->cstring);
|
||||
}
|
||||
else
|
||||
{
|
||||
aptr = a->lenstring.data;
|
||||
alen = a->lenstring.len;
|
||||
}
|
||||
blen = strlen(bptr);
|
||||
|
||||
return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to read packet data from some source into a buffer
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param getfn pointer to a function which will read any number of bytes from the needed source
|
||||
* @return integer MQTT packet type, or -1 on error
|
||||
* @note the whole message must fit into the caller's buffer
|
||||
*/
|
||||
int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
|
||||
{
|
||||
int rc = -1;
|
||||
MQTTHeader header = {0};
|
||||
int len = 0;
|
||||
int rem_len = 0;
|
||||
|
||||
/* 1. read the header byte. This has the packet type in it */
|
||||
if ((*getfn)(buf, 1) != 1)
|
||||
goto exit;
|
||||
|
||||
len = 1;
|
||||
/* 2. read the remaining length. This is variable in itself */
|
||||
MQTTPacket_decode(getfn, &rem_len);
|
||||
len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
|
||||
|
||||
/* 3. read the rest of the buffer using a callback to supply the rest of the data */
|
||||
if((rem_len + len) > buflen)
|
||||
goto exit;
|
||||
if (rem_len && ((*getfn)(buf + len, rem_len) != rem_len))
|
||||
goto exit;
|
||||
|
||||
header.byte = buf[0];
|
||||
rc = header.bits.type;
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the message length according to the MQTT algorithm, non-blocking
|
||||
* @param trp pointer to a transport structure holding what is needed to solve getting data from it
|
||||
* @param value the decoded length returned
|
||||
* @return integer the number of bytes read from the socket, 0 for call again, or -1 on error
|
||||
*/
|
||||
static int MQTTPacket_decodenb(MQTTTransport *trp)
|
||||
{
|
||||
unsigned char c;
|
||||
int rc = MQTTPACKET_READ_ERROR;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if(trp->len == 0){ /* initialize on first call */
|
||||
trp->multiplier = 1;
|
||||
trp->rem_len = 0;
|
||||
}
|
||||
do {
|
||||
int frc;
|
||||
if (trp->len >= MAX_NO_OF_REMAINING_LENGTH_BYTES)
|
||||
goto exit;
|
||||
if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)
|
||||
goto exit;
|
||||
if (frc == 0){
|
||||
rc = 0;
|
||||
goto exit;
|
||||
}
|
||||
++(trp->len);
|
||||
trp->rem_len += (c & 127) * trp->multiplier;
|
||||
trp->multiplier *= 128;
|
||||
} while ((c & 128) != 0);
|
||||
rc = trp->len;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to read packet data from some source into a buffer, non-blocking
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param trp pointer to a transport structure holding what is needed to solve getting data from it
|
||||
* @return integer MQTT packet type, 0 for call again, or -1 on error
|
||||
* @note the whole message must fit into the caller's buffer
|
||||
*/
|
||||
int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)
|
||||
{
|
||||
int rc = -1, frc;
|
||||
MQTTHeader header = {0};
|
||||
|
||||
switch(trp->state){
|
||||
default:
|
||||
trp->state = 0;
|
||||
/*FALLTHROUGH*/
|
||||
case 0:
|
||||
/* read the header byte. This has the packet type in it */
|
||||
if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)
|
||||
goto exit;
|
||||
if (frc == 0)
|
||||
return 0;
|
||||
trp->len = 0;
|
||||
++trp->state;
|
||||
/*FALLTHROUGH*/
|
||||
/* read the remaining length. This is variable in itself */
|
||||
case 1:
|
||||
if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)
|
||||
goto exit;
|
||||
if(frc == 0)
|
||||
return 0;
|
||||
trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */
|
||||
if((trp->rem_len + trp->len) > buflen)
|
||||
goto exit;
|
||||
++trp->state;
|
||||
/*FALLTHROUGH*/
|
||||
case 2:
|
||||
if(trp->rem_len){
|
||||
/* read the rest of the buffer using a callback to supply the rest of the data */
|
||||
if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)
|
||||
goto exit;
|
||||
if (frc == 0)
|
||||
return 0;
|
||||
trp->rem_len -= frc;
|
||||
trp->len += frc;
|
||||
if(trp->rem_len)
|
||||
return 0;
|
||||
}
|
||||
header.byte = buf[0];
|
||||
rc = header.bits.type;
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
trp->state = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
const char* MQTTPacket_msgTypesToString(enum msgTypes msgType)
|
||||
{
|
||||
switch (msgType)
|
||||
{
|
||||
case CONNECT: return "CONNECT";
|
||||
case CONNACK: return "CONNACK";
|
||||
case PUBLISH: return "PUBLISH";
|
||||
case PUBACK: return "PUBACK";
|
||||
case PUBREC: return "PUBREC";
|
||||
case PUBREL: return "PUBREL";
|
||||
case PUBCOMP: return "PUBCOMP";
|
||||
case SUBSCRIBE: return "SUBSCRIBE";
|
||||
case SUBACK: return "SUBACK";
|
||||
case UNSUBSCRIBE: return "UNSUBSCRIBE";
|
||||
case UNSUBACK: return "UNSUBACK";
|
||||
case PINGREQ: return "PINGREQ";
|
||||
case PINGRESP: return "PINGRESP";
|
||||
case DISCONNECT: return "DISCONNECT";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Xiang Rong - 442039 Add makefile to Embedded C client
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTPACKET_H_
|
||||
#define MQTTPACKET_H_
|
||||
|
||||
#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(WIN32_DLL) || defined(WIN64_DLL)
|
||||
#define DLLImport __declspec(dllimport)
|
||||
#define DLLExport __declspec(dllexport)
|
||||
#elif defined(LINUX_SO)
|
||||
#define DLLImport extern
|
||||
#define DLLExport __attribute__ ((visibility ("default")))
|
||||
#else
|
||||
#define DLLImport
|
||||
#define DLLExport
|
||||
#endif
|
||||
|
||||
enum errors
|
||||
{
|
||||
MQTTPACKET_BUFFER_TOO_SHORT = -2,
|
||||
MQTTPACKET_READ_ERROR = -1,
|
||||
MQTTPACKET_READ_COMPLETE
|
||||
};
|
||||
|
||||
enum msgTypes
|
||||
{
|
||||
CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
|
||||
PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
|
||||
PINGREQ, PINGRESP, DISCONNECT
|
||||
};
|
||||
|
||||
/**
|
||||
* Bitfields for the MQTT header byte.
|
||||
*/
|
||||
typedef union
|
||||
{
|
||||
unsigned char byte; /**< the whole byte */
|
||||
#if defined(REVERSED)
|
||||
struct
|
||||
{
|
||||
unsigned int type : 4; /**< message type nibble */
|
||||
unsigned int dup : 1; /**< DUP flag bit */
|
||||
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
|
||||
unsigned int retain : 1; /**< retained flag bit */
|
||||
} bits;
|
||||
#else
|
||||
struct
|
||||
{
|
||||
unsigned int retain : 1; /**< retained flag bit */
|
||||
unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
|
||||
unsigned int dup : 1; /**< DUP flag bit */
|
||||
unsigned int type : 4; /**< message type nibble */
|
||||
} bits;
|
||||
#endif
|
||||
} MQTTHeader;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
char* data;
|
||||
} MQTTLenString;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* cstring;
|
||||
MQTTLenString lenstring;
|
||||
} MQTTString;
|
||||
|
||||
#define MQTTString_initializer {NULL, {0, NULL}}
|
||||
|
||||
int MQTTstrlen(MQTTString mqttstring);
|
||||
|
||||
#include "MQTTConnect.h"
|
||||
#include "MQTTPublish.h"
|
||||
#include "MQTTSubscribe.h"
|
||||
#include "MQTTUnsubscribe.h"
|
||||
#include "MQTTFormat.h"
|
||||
|
||||
DLLExport int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);
|
||||
DLLExport int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);
|
||||
|
||||
int MQTTPacket_len(int rem_len);
|
||||
DLLExport int MQTTPacket_equals(MQTTString* a, char* b);
|
||||
|
||||
DLLExport int MQTTPacket_encode(unsigned char* buf, int length);
|
||||
int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
|
||||
int MQTTPacket_decodeBuf(unsigned char* buf, int* value);
|
||||
|
||||
int readInt(unsigned char** pptr);
|
||||
char readChar(unsigned char** pptr);
|
||||
void writeChar(unsigned char** pptr, char c);
|
||||
void writeInt(unsigned char** pptr, int anInt);
|
||||
int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
|
||||
void writeCString(unsigned char** pptr, const char* string);
|
||||
void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);
|
||||
|
||||
DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
|
||||
|
||||
typedef struct {
|
||||
int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */
|
||||
void *sck; /* pointer to whatever the system may use to identify the transport */
|
||||
int multiplier;
|
||||
int rem_len;
|
||||
int len;
|
||||
char state;
|
||||
}MQTTTransport;
|
||||
|
||||
int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);
|
||||
|
||||
const char* MQTTPacket_msgTypesToString(enum msgTypes);
|
||||
|
||||
#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* MQTTPACKET_H_ */
|
@ -1,38 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Xiang Rong - 442039 Add makefile to Embedded C client
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTPUBLISH_H_
|
||||
#define MQTTPUBLISH_H_
|
||||
|
||||
#if !defined(DLLImport)
|
||||
#define DLLImport
|
||||
#endif
|
||||
#if !defined(DLLExport)
|
||||
#define DLLExport
|
||||
#endif
|
||||
|
||||
DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
|
||||
MQTTString topicName, unsigned char* payload, int payloadlen);
|
||||
|
||||
DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
|
||||
unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
|
||||
|
||||
DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);
|
||||
DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);
|
||||
DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
|
||||
|
||||
#endif /* MQTTPUBLISH_H_ */
|
@ -1,169 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* Determines the length of the MQTT publish packet that would be produced using the supplied parameters
|
||||
* @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
|
||||
* @param topicName the topic name to be used in the publish
|
||||
* @param payloadlen the length of the payload to be sent
|
||||
* @return the length of buffer needed to contain the serialized version of the packet
|
||||
*/
|
||||
int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
len += 2 + MQTTstrlen(topicName) + payloadlen;
|
||||
if (qos > 0)
|
||||
len += 2; /* packetid */
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the supplied publish data into the supplied buffer, ready for sending
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param dup integer - the MQTT dup flag
|
||||
* @param qos integer - the MQTT QoS value
|
||||
* @param retained integer - the MQTT retained flag
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @param topicName MQTTString - the MQTT topic in the publish
|
||||
* @param payload byte buffer - the MQTT publish payload
|
||||
* @param payloadlen integer - the length of the MQTT payload
|
||||
* @return the length of the serialized data. <= 0 indicates error
|
||||
*/
|
||||
int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
|
||||
MQTTString topicName, unsigned char* payload, int payloadlen)
|
||||
{
|
||||
unsigned char *ptr = buf;
|
||||
MQTTHeader header = {0};
|
||||
int rem_len = 0;
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
header.bits.type = PUBLISH;
|
||||
header.bits.dup = dup;
|
||||
header.bits.qos = qos;
|
||||
header.bits.retain = retained;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
|
||||
|
||||
writeMQTTString(&ptr, topicName);
|
||||
|
||||
if (qos > 0)
|
||||
writeInt(&ptr, packetid);
|
||||
|
||||
memcpy(ptr, payload, payloadlen);
|
||||
ptr += payloadlen;
|
||||
|
||||
rc = ptr - buf;
|
||||
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the ack packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param type the MQTT packet type
|
||||
* @param dup the MQTT dup flag
|
||||
* @param packetid the MQTT packet identifier
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
int rc = 0;
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (buflen < 4)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
header.bits.type = packettype;
|
||||
header.bits.dup = dup;
|
||||
header.bits.qos = (packettype == PUBREL) ? 1 : 0;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
|
||||
writeInt(&ptr, packetid);
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a puback packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
|
||||
{
|
||||
return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a pubrel packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param dup integer - the MQTT dup flag
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
|
||||
{
|
||||
return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a pubrel packet into the supplied buffer.
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @return serialized length, or error if 0
|
||||
*/
|
||||
int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
|
||||
{
|
||||
return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
|
||||
}
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Xiang Rong - 442039 Add makefile to Embedded C client
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTSUBSCRIBE_H_
|
||||
#define MQTTSUBSCRIBE_H_
|
||||
|
||||
#if !defined(DLLImport)
|
||||
#define DLLImport
|
||||
#endif
|
||||
#if !defined(DLLExport)
|
||||
#define DLLExport
|
||||
#endif
|
||||
|
||||
DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
|
||||
int count, MQTTString topicFilters[], int requestedQoSs[]);
|
||||
|
||||
DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,
|
||||
int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);
|
||||
|
||||
DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);
|
||||
|
||||
DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);
|
||||
|
||||
|
||||
#endif /* MQTTSUBSCRIBE_H_ */
|
@ -1,137 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
|
||||
* @param count the number of topic filter strings in topicFilters
|
||||
* @param topicFilters the array of topic filter strings to be used in the publish
|
||||
* @return the length of buffer needed to contain the serialized version of the packet
|
||||
*/
|
||||
int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
|
||||
{
|
||||
int i;
|
||||
int len = 2; /* packetid */
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the supplied subscribe data into the supplied buffer, ready for sending
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied bufferr
|
||||
* @param dup integer - the MQTT dup flag
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @param count - number of members in the topicFilters and reqQos arrays
|
||||
* @param topicFilters - array of topic filter names
|
||||
* @param requestedQoSs - array of requested QoS
|
||||
* @return the length of the serialized data. <= 0 indicates error
|
||||
*/
|
||||
int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,
|
||||
MQTTString topicFilters[], int requestedQoSs[])
|
||||
{
|
||||
unsigned char *ptr = buf;
|
||||
MQTTHeader header = {0};
|
||||
int rem_len = 0;
|
||||
int rc = 0;
|
||||
int i = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
header.byte = 0;
|
||||
header.bits.type = SUBSCRIBE;
|
||||
header.bits.dup = dup;
|
||||
header.bits.qos = 1;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
|
||||
|
||||
writeInt(&ptr, packetid);
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
writeMQTTString(&ptr, topicFilters[i]);
|
||||
writeChar(&ptr, requestedQoSs[i]);
|
||||
}
|
||||
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into suback data
|
||||
* @param packetid returned integer - the MQTT packet identifier
|
||||
* @param maxcount - the maximum number of members allowed in the grantedQoSs array
|
||||
* @param count returned integer - number of members in the grantedQoSs array
|
||||
* @param grantedQoSs returned array of integers - the granted qualities of service
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param buflen the length in bytes of the data in the supplied buffer
|
||||
* @return error code. 1 is success, 0 is failure
|
||||
*/
|
||||
int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = NULL;
|
||||
int rc = 0;
|
||||
int mylen;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = readChar(&curdata);
|
||||
if (header.bits.type != SUBACK)
|
||||
goto exit;
|
||||
|
||||
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
|
||||
enddata = curdata + mylen;
|
||||
if (enddata - curdata < 2)
|
||||
goto exit;
|
||||
|
||||
*packetid = readInt(&curdata);
|
||||
|
||||
*count = 0;
|
||||
while (curdata < enddata)
|
||||
{
|
||||
if (*count > maxcount)
|
||||
{
|
||||
rc = -1;
|
||||
goto exit;
|
||||
}
|
||||
grantedQoSs[(*count)++] = readChar(&curdata);
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1,112 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into subscribe data
|
||||
* @param dup integer returned - the MQTT dup flag
|
||||
* @param packetid integer returned - the MQTT packet identifier
|
||||
* @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
|
||||
* @param count - number of members in the topicFilters and requestedQoSs arrays
|
||||
* @param topicFilters - array of topic filter names
|
||||
* @param requestedQoSs - array of requested QoS
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param buflen the length in bytes of the data in the supplied buffer
|
||||
* @return the length of the serialized data. <= 0 indicates error
|
||||
*/
|
||||
int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
|
||||
int requestedQoSs[], unsigned char* buf, int buflen)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = NULL;
|
||||
int rc = -1;
|
||||
int mylen = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = readChar(&curdata);
|
||||
if (header.bits.type != SUBSCRIBE)
|
||||
goto exit;
|
||||
*dup = header.bits.dup;
|
||||
|
||||
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
|
||||
enddata = curdata + mylen;
|
||||
|
||||
*packetid = readInt(&curdata);
|
||||
|
||||
*count = 0;
|
||||
while (curdata < enddata)
|
||||
{
|
||||
if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
|
||||
goto exit;
|
||||
if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */
|
||||
goto exit;
|
||||
requestedQoSs[*count] = readChar(&curdata);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the supplied suback data into the supplied buffer, ready for sending
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @param count - number of members in the grantedQoSs array
|
||||
* @param grantedQoSs - array of granted QoS
|
||||
* @return the length of the serialized data. <= 0 indicates error
|
||||
*/
|
||||
int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
int rc = -1;
|
||||
unsigned char *ptr = buf;
|
||||
int i;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (buflen < 2 + count)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
header.byte = 0;
|
||||
header.bits.type = SUBACK;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */
|
||||
|
||||
writeInt(&ptr, packetid);
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
writeChar(&ptr, grantedQoSs[i]);
|
||||
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1,38 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Xiang Rong - 442039 Add makefile to Embedded C client
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef MQTTUNSUBSCRIBE_H_
|
||||
#define MQTTUNSUBSCRIBE_H_
|
||||
|
||||
#if !defined(DLLImport)
|
||||
#define DLLImport
|
||||
#endif
|
||||
#if !defined(DLLExport)
|
||||
#define DLLExport
|
||||
#endif
|
||||
|
||||
DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
|
||||
int count, MQTTString topicFilters[]);
|
||||
|
||||
DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],
|
||||
unsigned char* buf, int len);
|
||||
|
||||
DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
|
||||
|
||||
DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);
|
||||
|
||||
#endif /* MQTTUNSUBSCRIBE_H_ */
|
@ -1,106 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
|
||||
* @param count the number of topic filter strings in topicFilters
|
||||
* @param topicFilters the array of topic filter strings to be used in the publish
|
||||
* @return the length of buffer needed to contain the serialized version of the packet
|
||||
*/
|
||||
int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
|
||||
{
|
||||
int i;
|
||||
int len = 2; /* packetid */
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param buflen the length in bytes of the data in the supplied buffer
|
||||
* @param dup integer - the MQTT dup flag
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @param count - number of members in the topicFilters array
|
||||
* @param topicFilters - array of topic filter names
|
||||
* @return the length of the serialized data. <= 0 indicates error
|
||||
*/
|
||||
int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
|
||||
int count, MQTTString topicFilters[])
|
||||
{
|
||||
unsigned char *ptr = buf;
|
||||
MQTTHeader header = {0};
|
||||
int rem_len = 0;
|
||||
int rc = -1;
|
||||
int i = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
header.byte = 0;
|
||||
header.bits.type = UNSUBSCRIBE;
|
||||
header.bits.dup = dup;
|
||||
header.bits.qos = 1;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
|
||||
|
||||
writeInt(&ptr, packetid);
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
writeMQTTString(&ptr, topicFilters[i]);
|
||||
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into unsuback data
|
||||
* @param packetid returned integer - the MQTT packet identifier
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param buflen the length in bytes of the data in the supplied buffer
|
||||
* @return error code. 1 is success, 0 is failure
|
||||
*/
|
||||
int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
|
||||
{
|
||||
unsigned char type = 0;
|
||||
unsigned char dup = 0;
|
||||
int rc = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
|
||||
if (type == UNSUBACK)
|
||||
rc = 1;
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1,102 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include "MQTTPacket.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes the supplied (wire) buffer into unsubscribe data
|
||||
* @param dup integer returned - the MQTT dup flag
|
||||
* @param packetid integer returned - the MQTT packet identifier
|
||||
* @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
|
||||
* @param count - number of members in the topicFilters and requestedQoSs arrays
|
||||
* @param topicFilters - array of topic filter names
|
||||
* @param buf the raw buffer data, of the correct length determined by the remaining length field
|
||||
* @param buflen the length in bytes of the data in the supplied buffer
|
||||
* @return the length of the serialized data. <= 0 indicates error
|
||||
*/
|
||||
int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
|
||||
unsigned char* buf, int len)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
unsigned char* curdata = buf;
|
||||
unsigned char* enddata = NULL;
|
||||
int rc = 0;
|
||||
int mylen = 0;
|
||||
|
||||
FUNC_ENTRY;
|
||||
header.byte = readChar(&curdata);
|
||||
if (header.bits.type != UNSUBSCRIBE)
|
||||
goto exit;
|
||||
*dup = header.bits.dup;
|
||||
|
||||
curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
|
||||
enddata = curdata + mylen;
|
||||
|
||||
*packetid = readInt(&curdata);
|
||||
|
||||
*count = 0;
|
||||
while (curdata < enddata)
|
||||
{
|
||||
if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
|
||||
goto exit;
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
rc = 1;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the supplied unsuback data into the supplied buffer, ready for sending
|
||||
* @param buf the buffer into which the packet will be serialized
|
||||
* @param buflen the length in bytes of the supplied buffer
|
||||
* @param packetid integer - the MQTT packet identifier
|
||||
* @return the length of the serialized data. <= 0 indicates error
|
||||
*/
|
||||
int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
|
||||
{
|
||||
MQTTHeader header = {0};
|
||||
int rc = 0;
|
||||
unsigned char *ptr = buf;
|
||||
|
||||
FUNC_ENTRY;
|
||||
if (buflen < 2)
|
||||
{
|
||||
rc = MQTTPACKET_BUFFER_TOO_SHORT;
|
||||
goto exit;
|
||||
}
|
||||
header.byte = 0;
|
||||
header.bits.type = UNSUBACK;
|
||||
writeChar(&ptr, header.byte); /* write header */
|
||||
|
||||
ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
|
||||
|
||||
writeInt(&ptr, packetid);
|
||||
|
||||
rc = ptr - buf;
|
||||
exit:
|
||||
FUNC_EXIT_RC(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1,78 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
* Ian Craggs - fix for bug #434081
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef STACKTRACE_H_
|
||||
#define STACKTRACE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#define NOSTACKTRACE 1
|
||||
|
||||
#if defined(NOSTACKTRACE)
|
||||
#define FUNC_ENTRY
|
||||
#define FUNC_ENTRY_NOLOG
|
||||
#define FUNC_ENTRY_MED
|
||||
#define FUNC_ENTRY_MAX
|
||||
#define FUNC_EXIT
|
||||
#define FUNC_EXIT_NOLOG
|
||||
#define FUNC_EXIT_MED
|
||||
#define FUNC_EXIT_MAX
|
||||
#define FUNC_EXIT_RC(x)
|
||||
#define FUNC_EXIT_MED_RC(x)
|
||||
#define FUNC_EXIT_MAX_RC(x)
|
||||
|
||||
#else
|
||||
|
||||
#if defined(WIN32)
|
||||
#define inline __inline
|
||||
#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
|
||||
#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
|
||||
#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
|
||||
#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
|
||||
#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
|
||||
#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
|
||||
#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
|
||||
#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
|
||||
#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
|
||||
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
|
||||
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
|
||||
#else
|
||||
#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
|
||||
#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
|
||||
#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
|
||||
#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
|
||||
#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
|
||||
#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
|
||||
#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
|
||||
#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
|
||||
#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
|
||||
#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
|
||||
#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
|
||||
|
||||
void StackTrace_entry(const char* name, int line, int trace);
|
||||
void StackTrace_exit(const char* name, int line, void* return_value, int trace);
|
||||
|
||||
void StackTrace_printStack(FILE* dest);
|
||||
char* StackTrace_get(unsigned long);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* STACKTRACE_H_ */
|
@ -1,3 +1,2 @@
|
||||
CONFIG_BROKER_URI="mqtts://${EXAMPLE_MQTT_BROKER_SSL}"
|
||||
CONFIG_BROKER_CERTIFICATE_OVERRIDE="${EXAMPLE_MQTT_BROKER_CERTIFICATE}"
|
||||
CONFIG_MQTT_USING_ESP=y
|
||||
|
@ -1 +0,0 @@
|
||||
CONFIG_MQTT_USING_ESP=y
|
@ -1 +0,0 @@
|
||||
CONFIG_MQTT_USING_ESP=y
|
@ -1,3 +1,2 @@
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
CONFIG_BROKER_URL="FROM_STDIN"
|
||||
CONFIG_MQTT_USING_ESP=y
|
||||
|
@ -1 +0,0 @@
|
||||
CONFIG_MQTT_USING_ESP=y
|
@ -1,2 +1 @@
|
||||
CONFIG_BROKER_URI="ws://${EXAMPLE_MQTT_BROKER_WS}/ws"
|
||||
CONFIG_MQTT_USING_ESP=y
|
||||
|
@ -1 +0,0 @@
|
||||
CONFIG_MQTT_USING_ESP=y
|
@ -1,3 +1,2 @@
|
||||
CONFIG_BROKER_URI="wss://${EXAMPLE_MQTT_BROKER_WSS}/ws"
|
||||
CONFIG_BROKER_CERTIFICATE_OVERRIDE="${EXAMPLE_MQTT_BROKER_CERTIFICATE}"
|
||||
CONFIG_MQTT_USING_ESP=y
|
||||
|
@ -1 +0,0 @@
|
||||
CONFIG_MQTT_USING_ESP=y
|
@ -1,6 +0,0 @@
|
||||
# The following four lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ibm-mqtt)
|
@ -1,9 +0,0 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := mqtt_demo
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@ -1,21 +0,0 @@
|
||||
# ESP8266 MQTT Client Demo
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
This MQTT demo is based on the Eclipse Paho MQTT library, and demonstrates a working MQTT client actions(subscribe, publish, ping). Using this MQTT demo, you can connect to the MQTT broker, subscribe to a topic and publish messages to the predefined topic.
|
||||
|
||||
Also, this demo will ping the MQTT broker in the defined interval if no sending or receiving action happens. And we add some APIs to realize the SSL functionality, these SSL APIs provide the one-way certification and two-way certification.
|
||||
|
||||
## 2. Configuration
|
||||
* export `IDF_PATH`
|
||||
* `make menuconfig` -> `Example Configuration` to config your example
|
||||
* `make menuconfig` -> `Component config` -> `MQTT(Paho)` -> to config your MQTT parameters
|
||||
|
||||
## 3. Compiling & Execution
|
||||
|
||||
Once all the aforementioned works are done, the MQTT client demo will:
|
||||
|
||||
* Connect to the MQTT Broker
|
||||
* Subscribe to the topic "/espressif/sub"
|
||||
* Publish messages to the topic "/espressif/pub"
|
||||
* MQTT keep alive interval is 30s, so if no sending and receiving actions happended during this interval, ping request will be sent and ping response is expected to be received.
|
@ -1,4 +0,0 @@
|
||||
set(COMPONENT_SRCS "MQTTEcho.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
@ -1,93 +0,0 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
Can be left blank if the network has no security set.
|
||||
|
||||
config MQTT_BROKER
|
||||
string "MQTT broker"
|
||||
default "mosquitto.org"
|
||||
help
|
||||
MQTT broker which you want to login, either IP address or domain name is OK.
|
||||
|
||||
config MQTT_PORT
|
||||
int "Default MQTT port"
|
||||
default 1883
|
||||
help
|
||||
MQTT port.
|
||||
|
||||
config MQTT_SUB_TOPIC
|
||||
string "MQTT subscribe topic"
|
||||
default "/espressif/sub"
|
||||
help
|
||||
MQTT subscribe topic to MQTT broker.
|
||||
|
||||
choice MQTT_SUB_QOS
|
||||
prompt "MQTT Subscribe QoS"
|
||||
default SUB_QOS1
|
||||
help
|
||||
MQTT subcribe QoS level.
|
||||
|
||||
config SUB_QOS0
|
||||
bool "QOS0"
|
||||
config SUB_QOS1
|
||||
bool "QOS1"
|
||||
config SUB_QOS2
|
||||
bool "QOS2"
|
||||
endchoice
|
||||
|
||||
config DEFAULT_MQTT_SUB_QOS
|
||||
int
|
||||
default 0 if SUB_QOS0
|
||||
default 1 if SUB_QOS1
|
||||
default 2 if SUB_QOS2
|
||||
|
||||
config MQTT_PUB_TOPIC
|
||||
string "MQTT publish topic"
|
||||
default "/espressif/pub"
|
||||
help
|
||||
MQTT publish topic to MQTT broker.
|
||||
|
||||
choice MQTT_PUB_QOS
|
||||
prompt "MQTT publish QoS"
|
||||
default PUB_QOS1
|
||||
help
|
||||
MQTT publish QoS level.
|
||||
|
||||
config PUB_QOS0
|
||||
bool "QOS0"
|
||||
config PUB_QOS1
|
||||
bool "QOS1"
|
||||
config PUB_QOS2
|
||||
bool "QOS2"
|
||||
endchoice
|
||||
|
||||
config DEFAULT_MQTT_PUB_QOS
|
||||
int
|
||||
default 0 if PUB_QOS0
|
||||
default 1 if PUB_QOS1
|
||||
default 2 if PUB_QOS2
|
||||
|
||||
config MQTT_PUBLISH_INTERVAL
|
||||
int "MQTT publish interval(ms)"
|
||||
default 0
|
||||
help
|
||||
Default MQTT publish message interval.
|
||||
|
||||
config MQTT_PAYLOAD_BUFFER
|
||||
int "MQTT payload size(Bytes)"
|
||||
default 1460
|
||||
help
|
||||
1460~2048 is recommended.
|
||||
MQTT payload size.
|
||||
|
||||
endmenu
|
@ -1,249 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2014 IBM Corp.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
||||
*
|
||||
* The Eclipse Public License is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
* and the Eclipse Distribution License is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* Contributors:
|
||||
* Ian Craggs - initial API and implementation and/or initial documentation
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event_loop.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#include "MQTTClient.h"
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected & ready to make a request */
|
||||
static EventGroupHandle_t wifi_event_group;
|
||||
|
||||
/* The event group allows multiple bits for each event,
|
||||
but we only care about one event - are we connected
|
||||
to the AP with an IP? */
|
||||
const int CONNECTED_BIT = BIT0;
|
||||
|
||||
#define MQTT_CLIENT_THREAD_NAME "mqtt_client_thread"
|
||||
#define MQTT_CLIENT_THREAD_STACK_WORDS 4096
|
||||
#define MQTT_CLIENT_THREAD_PRIO 8
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
||||
{
|
||||
/* For accessing reason codes in case of disconnection */
|
||||
system_event_info_t *info = &event->event_info;
|
||||
|
||||
switch (event->event_id) {
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
esp_wifi_connect();
|
||||
break;
|
||||
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
|
||||
break;
|
||||
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
ESP_LOGE(TAG, "Disconnect reason : %d", info->disconnected.reason);
|
||||
if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||
/*Switch to 802.11 bgn mode */
|
||||
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCAL_11B | WIFI_PROTOCAL_11G | WIFI_PROTOCAL_11N);
|
||||
}
|
||||
esp_wifi_connect();
|
||||
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void initialise_wifi(void)
|
||||
{
|
||||
tcpip_adapter_init();
|
||||
wifi_event_group = xEventGroupCreate();
|
||||
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = CONFIG_WIFI_SSID,
|
||||
.password = CONFIG_WIFI_PASSWORD,
|
||||
},
|
||||
};
|
||||
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
}
|
||||
|
||||
static void messageArrived(MessageData *data)
|
||||
{
|
||||
ESP_LOGI(TAG, "Message arrived[len:%u]: %.*s", \
|
||||
data->message->payloadlen, data->message->payloadlen, (char *)data->message->payload);
|
||||
}
|
||||
|
||||
static void mqtt_client_thread(void *pvParameters)
|
||||
{
|
||||
char *payload = NULL;
|
||||
MQTTClient client;
|
||||
Network network;
|
||||
int rc = 0;
|
||||
char clientID[32] = {0};
|
||||
uint32_t count = 0;
|
||||
|
||||
ESP_LOGI(TAG, "ssid:%s passwd:%s sub:%s qos:%u pub:%s qos:%u pubinterval:%u payloadsize:%u",
|
||||
CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD, CONFIG_MQTT_SUB_TOPIC,
|
||||
CONFIG_DEFAULT_MQTT_SUB_QOS, CONFIG_MQTT_PUB_TOPIC, CONFIG_DEFAULT_MQTT_PUB_QOS,
|
||||
CONFIG_MQTT_PUBLISH_INTERVAL, CONFIG_MQTT_PAYLOAD_BUFFER);
|
||||
|
||||
ESP_LOGI(TAG, "ver:%u clientID:%s keepalive:%d username:%s passwd:%s session:%d level:%u",
|
||||
CONFIG_DEFAULT_MQTT_VERSION, CONFIG_MQTT_CLIENT_ID,
|
||||
CONFIG_MQTT_KEEP_ALIVE, CONFIG_MQTT_USERNAME, CONFIG_MQTT_PASSWORD,
|
||||
CONFIG_DEFAULT_MQTT_SESSION, CONFIG_DEFAULT_MQTT_SECURITY);
|
||||
|
||||
ESP_LOGI(TAG, "broker:%s port:%u", CONFIG_MQTT_BROKER, CONFIG_MQTT_PORT);
|
||||
|
||||
ESP_LOGI(TAG, "sendbuf:%u recvbuf:%u sendcycle:%u recvcycle:%u",
|
||||
CONFIG_MQTT_SEND_BUFFER, CONFIG_MQTT_RECV_BUFFER,
|
||||
CONFIG_MQTT_SEND_CYCLE, CONFIG_MQTT_RECV_CYCLE);
|
||||
|
||||
MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
|
||||
|
||||
NetworkInit(&network);
|
||||
|
||||
if (MQTTClientInit(&client, &network, 0, NULL, 0, NULL, 0) == false) {
|
||||
ESP_LOGE(TAG, "mqtt init err");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
payload = malloc(CONFIG_MQTT_PAYLOAD_BUFFER);
|
||||
|
||||
if (!payload) {
|
||||
ESP_LOGE(TAG, "mqtt malloc err");
|
||||
} else {
|
||||
memset(payload, 0x0, CONFIG_MQTT_PAYLOAD_BUFFER);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ESP_LOGI(TAG, "wait wifi connect...");
|
||||
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
|
||||
|
||||
if ((rc = NetworkConnect(&network, CONFIG_MQTT_BROKER, CONFIG_MQTT_PORT)) != 0) {
|
||||
ESP_LOGE(TAG, "Return code from network connect is %d", rc);
|
||||
continue;
|
||||
}
|
||||
|
||||
connectData.MQTTVersion = CONFIG_DEFAULT_MQTT_VERSION;
|
||||
|
||||
sprintf(clientID, "%s_%u", CONFIG_MQTT_CLIENT_ID, esp_random());
|
||||
|
||||
connectData.clientID.cstring = clientID;
|
||||
connectData.keepAliveInterval = CONFIG_MQTT_KEEP_ALIVE;
|
||||
|
||||
connectData.username.cstring = CONFIG_MQTT_USERNAME;
|
||||
connectData.password.cstring = CONFIG_MQTT_PASSWORD;
|
||||
|
||||
connectData.cleansession = CONFIG_DEFAULT_MQTT_SESSION;
|
||||
|
||||
ESP_LOGI(TAG, "MQTT Connecting");
|
||||
|
||||
if ((rc = MQTTConnect(&client, &connectData)) != 0) {
|
||||
ESP_LOGE(TAG, "Return code from MQTT connect is %d", rc);
|
||||
network.disconnect(&network);
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "MQTT Connected");
|
||||
|
||||
#if defined(MQTT_TASK)
|
||||
|
||||
if ((rc = MQTTStartTask(&client)) != pdPASS) {
|
||||
ESP_LOGE(TAG, "Return code from start tasks is %d", rc);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Use MQTTStartTask");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ((rc = MQTTSubscribe(&client, CONFIG_MQTT_SUB_TOPIC, CONFIG_DEFAULT_MQTT_SUB_QOS, messageArrived)) != 0) {
|
||||
ESP_LOGE(TAG, "Return code from MQTT subscribe is %d", rc);
|
||||
network.disconnect(&network);
|
||||
continue;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "MQTT subscribe to topic %s OK", CONFIG_MQTT_SUB_TOPIC);
|
||||
|
||||
for (;;) {
|
||||
MQTTMessage message;
|
||||
|
||||
message.qos = CONFIG_DEFAULT_MQTT_PUB_QOS;
|
||||
message.retained = 0;
|
||||
message.payload = payload;
|
||||
sprintf(payload, "message number %d", ++count);
|
||||
message.payloadlen = strlen(payload);
|
||||
|
||||
if ((rc = MQTTPublish(&client, CONFIG_MQTT_PUB_TOPIC, &message)) != 0) {
|
||||
ESP_LOGE(TAG, "Return code from MQTT publish is %d", rc);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "MQTT published topic %s, len:%u heap:%u", CONFIG_MQTT_PUB_TOPIC, message.payloadlen, esp_get_free_heap_size());
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay(CONFIG_MQTT_PUBLISH_INTERVAL / portTICK_RATE_MS);
|
||||
}
|
||||
|
||||
network.disconnect(&network);
|
||||
}
|
||||
|
||||
ESP_LOGW(TAG, "mqtt_client_thread going to be deleted");
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// Initialize NVS
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
initialise_wifi();
|
||||
|
||||
ret = xTaskCreate(&mqtt_client_thread,
|
||||
MQTT_CLIENT_THREAD_NAME,
|
||||
MQTT_CLIENT_THREAD_STACK_WORDS,
|
||||
NULL,
|
||||
MQTT_CLIENT_THREAD_PRIO,
|
||||
NULL);
|
||||
|
||||
if (ret != pdPASS) {
|
||||
ESP_LOGE(TAG, "mqtt create client thread %s failed", MQTT_CLIENT_THREAD_NAME);
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
Reference in New Issue
Block a user