Files

3222 lines
100 KiB
C

/*
* Copyright (C) 2015-2018 Alibaba Group Holding Limited
*/
#include "mqtt_internal.h"
#ifdef LOG_REPORT_TO_CLOUD
#include "iotx_log_report.h"
#endif
static int _in_yield_cb;
#ifndef PLATFORM_HAS_DYNMEM
iotx_mc_client_t g_iotx_mc_client[IOTX_MC_CLIENT_MAX_COUNT] = {0};
#endif
static void iotx_mc_release(iotx_mc_client_t *pclient)
{
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(pclient);
#else
memset(pclient, 0, sizeof(iotx_mc_client_t));
#endif
}
#if !WITH_MQTT_ONLY_QOS0
static void iotx_mc_pub_wait_list_init(iotx_mc_client_t *pClient)
{
#ifdef PLATFORM_HAS_DYNMEM
INIT_LIST_HEAD(&pClient->list_pub_wait_ack);
#else
memset(pClient->list_pub_wait_ack, 0, sizeof(iotx_mc_pub_info_t) * IOTX_MC_REPUB_NUM_MAX);
#endif
}
static void iotx_mc_pub_wait_list_deinit(iotx_mc_client_t *pClient)
{
#ifdef PLATFORM_HAS_DYNMEM
iotx_mc_pub_info_t *node = NULL, *next_node = NULL;
list_for_each_entry_safe(node, next_node, &pClient->list_pub_wait_ack, linked_list, iotx_mc_pub_info_t) {
list_del(&node->linked_list);
mqtt_free(node);
}
#else
memset(pClient->list_pub_wait_ack, 0, sizeof(iotx_mc_pub_info_t) * IOTX_MC_REPUB_NUM_MAX);
#endif
}
#endif
/* set MQTT connection parameter */
static int iotx_mc_set_connect_params(iotx_mc_client_t *pClient, MQTTPacket_connectData *pConnectParams)
{
if (NULL == pClient || NULL == pConnectParams) {
return STATE_USER_INPUT_INVALID;
}
memcpy(pClient->connect_data.struct_id, pConnectParams->struct_id, 4);
pClient->connect_data.struct_version = pConnectParams->struct_version;
pClient->connect_data.MQTTVersion = pConnectParams->MQTTVersion;
pClient->connect_data.clientID = pConnectParams->clientID;
pClient->connect_data.cleansession = pConnectParams->cleansession;
pClient->connect_data.willFlag = pConnectParams->willFlag;
pClient->connect_data.username = pConnectParams->username;
pClient->connect_data.password = pConnectParams->password;
memcpy(pClient->connect_data.will.struct_id, pConnectParams->will.struct_id, 4);
pClient->connect_data.will.struct_version = pConnectParams->will.struct_version;
pClient->connect_data.will.topicName = pConnectParams->will.topicName;
pClient->connect_data.will.message = pConnectParams->will.message;
pClient->connect_data.will.qos = pConnectParams->will.qos;
pClient->connect_data.will.retained = pConnectParams->will.retained;
if (pConnectParams->keepAliveInterval < CONFIG_MQTT_KEEPALIVE_INTERVAL_MIN) {
mqtt_warning("Input heartbeat interval(%d ms) < Allowed minimum(%d ms)",
(pConnectParams->keepAliveInterval * 1000),
(CONFIG_MQTT_KEEPALIVE_INTERVAL_MIN * 1000)
);
mqtt_warning("Reset heartbeat interval => %d Millisecond",
(CONFIG_MQTT_KEEPALIVE_INTERVAL * 1000)
);
pClient->connect_data.keepAliveInterval = CONFIG_MQTT_KEEPALIVE_INTERVAL;
} else if (pConnectParams->keepAliveInterval > CONFIG_MQTT_KEEPALIVE_INTERVAL_MAX) {
mqtt_warning("Input heartbeat interval(%d ms) > Allowed maximum(%d ms)",
(pConnectParams->keepAliveInterval * 1000),
(CONFIG_MQTT_KEEPALIVE_INTERVAL_MAX * 1000)
);
mqtt_warning("Reset heartbeat interval => %d Millisecond",
(CONFIG_MQTT_KEEPALIVE_INTERVAL * 1000)
);
pClient->connect_data.keepAliveInterval = CONFIG_MQTT_KEEPALIVE_INTERVAL;
} else {
pClient->connect_data.keepAliveInterval = pConnectParams->keepAliveInterval;
}
return STATE_SUCCESS;
}
/* set state of MQTT client */
static void iotx_mc_set_client_state(iotx_mc_client_t *pClient, iotx_mc_state_t newState)
{
HAL_MutexLock(pClient->lock_generic);
pClient->client_state = newState;
HAL_MutexUnlock(pClient->lock_generic);
}
static iotx_mc_state_t iotx_mc_get_client_state(iotx_mc_client_t *pClient)
{
iotx_mc_state_t state;
HAL_MutexLock(pClient->lock_generic);
state = pClient->client_state;
HAL_MutexUnlock(pClient->lock_generic);
return state;
}
/* Initialize MQTT client */
static int iotx_mc_init(iotx_mc_client_t *pClient, iotx_mqtt_param_t *pInitParams)
{
int rc = -1;
iotx_mc_state_t mc_state = IOTX_MC_STATE_INVALID;
MQTTPacket_connectData connectdata = MQTTPacket_connectData_initializer;
if (pClient == NULL || pInitParams == NULL || pInitParams->write_buf_size == 0 || pInitParams->read_buf_size == 0) {
return STATE_USER_INPUT_INVALID;
}
pClient->lock_generic = HAL_MutexCreate();
if (!pClient->lock_generic) {
iotx_state_event(ITE_STATE_SYS_DEPEND, STATE_SYS_DEPEND_MUTEX_CREATE, "lock_generic create fail");
return STATE_SYS_DEPEND_MUTEX_CREATE;
}
pClient->lock_list_pub = HAL_MutexCreate();
if (!pClient->lock_list_pub) {
iotx_state_event(ITE_STATE_SYS_DEPEND, STATE_SYS_DEPEND_MUTEX_CREATE, "lock_list_pub create fail");
goto RETURN;
}
pClient->lock_yield = HAL_MutexCreate();
if (!pClient->lock_yield) {
iotx_state_event(ITE_STATE_SYS_DEPEND, STATE_SYS_DEPEND_MUTEX_CREATE, "lock_yield create fail");
goto RETURN;
}
pClient->lock_write_buf = HAL_MutexCreate();
if (!pClient->lock_write_buf) {
iotx_state_event(ITE_STATE_SYS_DEPEND, STATE_SYS_DEPEND_MUTEX_CREATE, "lock_write_buf create fail");
goto RETURN;
}
pClient->lock_read_buf = HAL_MutexCreate();
if (!pClient->lock_read_buf) {
iotx_state_event(ITE_STATE_SYS_DEPEND, STATE_SYS_DEPEND_MUTEX_CREATE, "lock_read_buf create fail");
goto RETURN;
}
connectdata.MQTTVersion = IOTX_MC_MQTT_VERSION;
connectdata.keepAliveInterval = pInitParams->keepalive_interval_ms / 1000;
connectdata.clientID.cstring = (char *)pInitParams->client_id;
connectdata.username.cstring = (char *)pInitParams->username;
connectdata.password.cstring = (char *)pInitParams->password;
connectdata.cleansession = pInitParams->clean_session;
if (pInitParams->request_timeout_ms < CONFIG_MQTT_REQ_TIMEOUT_MIN
|| pInitParams->request_timeout_ms > CONFIG_MQTT_REQ_TIMEOUT_MAX) {
pClient->request_timeout_ms = CONFIG_MQTT_REQUEST_TIMEOUT;
} else {
pClient->request_timeout_ms = pInitParams->request_timeout_ms;
}
#ifdef PLATFORM_HAS_DYNMEM
#if !( WITH_MQTT_DYN_BUF)
pClient->buf_send = mqtt_malloc(pInitParams->write_buf_size);
if (pClient->buf_send == NULL) {
iotx_state_event(ITE_STATE_SYS_DEPEND, STATE_SYS_DEPEND_MALLOC, "");
goto RETURN;
}
pClient->buf_size_send = pInitParams->write_buf_size;
pClient->buf_read = mqtt_malloc(pInitParams->read_buf_size);
if (pClient->buf_read == NULL) {
iotx_state_event(ITE_STATE_SYS_DEPEND, STATE_SYS_DEPEND_MALLOC, "");
goto RETURN;
}
pClient->buf_size_read = pInitParams->read_buf_size;
#else
pClient->buf_size_send_max = pInitParams->write_buf_size;
pClient->buf_size_read_max = pInitParams->read_buf_size;
#endif
#else
pClient->buf_size_send = IOTX_MC_TX_MAX_LEN;
pClient->buf_size_read = IOTX_MC_RX_MAX_LEN;
#endif
pClient->keepalive_probes = 0;
pClient->handle_event.h_fp = pInitParams->handle_event.h_fp;
pClient->handle_event.pcontext = pInitParams->handle_event.pcontext;
/* Initialize reconnect parameter */
pClient->reconnect_param.reconnect_time_interval_ms = IOTX_MC_RECONNECT_INTERVAL_MIN_MS;
#if !WITH_MQTT_ONLY_QOS0
iotx_mc_pub_wait_list_init(pClient);
#endif
#ifdef PLATFORM_HAS_DYNMEM
INIT_LIST_HEAD(&pClient->list_sub_handle);
INIT_LIST_HEAD(&pClient->list_sub_sync_ack);
#endif
/* Initialize MQTT connect parameter */
rc = iotx_mc_set_connect_params(pClient, &connectdata);
if (rc < STATE_SUCCESS) {
mc_state = IOTX_MC_STATE_INVALID;
iotx_state_event(ITE_STATE_MQTT_COMM, rc, "");
goto RETURN;
}
iotx_time_init(&pClient->next_ping_time);
iotx_time_init(&pClient->reconnect_param.reconnect_next_time);
memset(&pClient->ipstack, 0, sizeof(utils_network_t));
rc = iotx_net_init(&pClient->ipstack, pInitParams->host, pInitParams->port, pInitParams->pub_key);
if (STATE_SUCCESS != rc) {
mc_state = IOTX_MC_STATE_INVALID;
iotx_state_event(ITE_STATE_MQTT_COMM, rc, "");
goto RETURN;
}
mc_state = IOTX_MC_STATE_INITIALIZED;
rc = STATE_SUCCESS;
RETURN :
iotx_mc_set_client_state(pClient, mc_state);
if (rc < STATE_SUCCESS) {
#ifdef PLATFORM_HAS_DYNMEM
if (pClient->buf_send != NULL) {
mqtt_free(pClient->buf_send);
pClient->buf_send = NULL;
}
if (pClient->buf_read != NULL) {
mqtt_free(pClient->buf_read);
pClient->buf_read = NULL;
}
#endif
if (pClient->lock_list_pub) {
HAL_MutexDestroy(pClient->lock_list_pub);
pClient->lock_list_pub = NULL;
}
if (pClient->lock_write_buf) {
HAL_MutexDestroy(pClient->lock_write_buf);
pClient->lock_write_buf = NULL;
}
if (pClient->lock_read_buf) {
HAL_MutexDestroy(pClient->lock_read_buf);
pClient->lock_read_buf = NULL;
}
if (pClient->lock_yield) {
HAL_MutexDestroy(pClient->lock_yield);
pClient->lock_yield = NULL;
}
}
return rc;
}
#ifdef PLATFORM_HAS_DYNMEM
#if WITH_MQTT_DYN_BUF
extern int MQTTPacket_len(int rem_len);
extern int MQTTSerialize_connectLength(MQTTPacket_connectData *options);
#endif
#endif
static int _get_connect_length(MQTTPacket_connectData *options)
{
#ifdef PLATFORM_HAS_DYNMEM
#if WITH_MQTT_DYN_BUF
return MQTTPacket_len(MQTTSerialize_connectLength(options));
#else
return STATE_SUCCESS;
#endif
#else
return STATE_SUCCESS;
#endif
}
static int _reset_send_buffer(iotx_mc_client_t *c)
{
#ifdef PLATFORM_HAS_DYNMEM
#if WITH_MQTT_DYN_BUF
if (c == NULL || c->buf_send == NULL) {
return STATE_USER_INPUT_INVALID;
}
mqtt_free(c->buf_send);
c->buf_send = NULL;
c->buf_size_send = 0;
return STATE_SUCCESS;
#else
return STATE_SUCCESS;
#endif
#else
return STATE_SUCCESS;
#endif
}
static int _reset_recv_buffer(iotx_mc_client_t *c)
{
#ifdef PLATFORM_HAS_DYNMEM
#if WITH_MQTT_DYN_BUF
if (c == NULL || c->buf_read == NULL) {
return STATE_USER_INPUT_INVALID;
}
mqtt_free(c->buf_read);
c->buf_read = NULL;
c->buf_size_read = 0;
return STATE_SUCCESS;
#else
return STATE_SUCCESS;
#endif
#else
return STATE_SUCCESS;
#endif
}
static int _alloc_send_buffer(iotx_mc_client_t *c, int len)
{
#ifdef PLATFORM_HAS_DYNMEM
#if WITH_MQTT_DYN_BUF
int tmp_len;
if (c == NULL) {
return STATE_USER_INPUT_INVALID;
}
tmp_len = MQTT_DYNBUF_SEND_MARGIN + len;
if (tmp_len > c->buf_size_send_max) {
tmp_len = c->buf_size_send_max;
}
if (c->buf_send != NULL) {
mqtt_warning("c->buf_send is not null,free it first!");
mqtt_free(c->buf_send);
}
c->buf_send = mqtt_malloc(tmp_len);
if (c->buf_send == NULL) {
return STATE_SYS_DEPEND_MALLOC;
}
memset(c->buf_send, 0, tmp_len);
c->buf_size_send = tmp_len;
return STATE_SUCCESS;
#else
return STATE_SUCCESS;
#endif
#else
return STATE_SUCCESS;
#endif
}
static int _alloc_recv_buffer(iotx_mc_client_t *c, int len)
{
#ifdef PLATFORM_HAS_DYNMEM
#if WITH_MQTT_DYN_BUF
int tmp_len;
if (c == NULL) {
return STATE_USER_INPUT_INVALID;
}
tmp_len = MQTT_DYNBUF_RECV_MARGIN + len;
if (tmp_len > c->buf_size_read_max) {
tmp_len = c->buf_size_read_max;
}
if (c->buf_read != NULL) { /* do realloc */
char *temp = mqtt_malloc(tmp_len);
if (temp == NULL) {
return STATE_SYS_DEPEND_MALLOC;
}
memset(temp, 0, tmp_len);
memcpy(temp, c->buf_read, c->buf_size_read < tmp_len ? c->buf_size_read : tmp_len);
mqtt_free(c->buf_read);
c->buf_read = temp;
} else {
c->buf_read = mqtt_malloc(tmp_len);
if (c->buf_read == NULL) {
return STATE_SYS_DEPEND_MALLOC;
}
memset(c->buf_read, 0, tmp_len);
}
c->buf_size_read = tmp_len;
return STATE_SUCCESS;
#else
return STATE_SUCCESS;
#endif
#else
return STATE_SUCCESS;
#endif
}
static int iotx_mc_send_packet(iotx_mc_client_t *c, char *buf, int length, iotx_time_t *time)
{
int rc = STATE_SUCCESS;
int sent = 0;
unsigned int left_t = 0;
if (!c || !buf || !time) {
return STATE_USER_INPUT_INVALID;
}
while (sent < length && !utils_time_is_expired(time)) {
left_t = iotx_time_left(time);
left_t = (left_t == 0) ? 1 : left_t;
rc = c->ipstack.write(&c->ipstack, &buf[sent], length - sent, left_t);
if (rc < 0) { /* there was an error writing the data */
break;
}
sent += rc;
}
if (sent == length) {
rc = STATE_SUCCESS;
} else {
rc = STATE_SYS_DEPEND_NWK_CLOSE;
}
return rc;
}
int MQTTConnect(iotx_mc_client_t *pClient)
{
MQTTPacket_connectData *pConnectParams;
iotx_time_t connectTimer;
int len = 0, res = 0;
if (!pClient) {
return STATE_USER_INPUT_INVALID;
}
pConnectParams = &pClient->connect_data;
HAL_MutexLock(pClient->lock_write_buf);
len = _get_connect_length(pConnectParams);
res = _alloc_send_buffer(pClient, len);
if (res < STATE_SUCCESS) {
HAL_MutexUnlock(pClient->lock_write_buf);
return res;
}
if ((len = MQTTSerialize_connect((unsigned char *)pClient->buf_send, pClient->buf_size_send, pConnectParams)) <= 0) {
_reset_send_buffer(pClient);
HAL_MutexUnlock(pClient->lock_write_buf);
return STATE_MQTT_SERIALIZE_CONN_ERROR;
}
/* send the connect packet */
iotx_time_init(&connectTimer);
utils_time_countdown_ms(&connectTimer, pClient->request_timeout_ms);
res = iotx_mc_send_packet(pClient, pClient->buf_send, len, &connectTimer);
if (res < STATE_SUCCESS) {
_reset_send_buffer(pClient);
HAL_MutexUnlock(pClient->lock_write_buf);
return res;
}
_reset_send_buffer(pClient);
HAL_MutexUnlock(pClient->lock_write_buf);
return STATE_SUCCESS;
}
static int iotx_mc_decode_packet(iotx_mc_client_t *c, int *value, int timeout)
{
char i;
int multiplier = 1;
int len = 0;
const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
if (!c || !value) {
return STATE_USER_INPUT_INVALID;
}
*value = 0;
do {
int rc = MQTTPACKET_READ_ERROR;
if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES) {
return MQTTPACKET_READ_ERROR; /* bad data */
}
rc = c->ipstack.read(&c->ipstack, &i, 1, timeout == 0 ? 1 : timeout);
if (rc <= STATE_SUCCESS) {
return STATE_SYS_DEPEND_NWK_CLOSE;
}
*value += (i & 127) * multiplier;
multiplier *= 128;
} while ((i & 128) != 0);
return len;
}
static int _handle_event(iotx_mqtt_event_handle_pt handle, iotx_mc_client_t *c, iotx_mqtt_event_msg_pt msg)
{
if (handle == NULL || handle->h_fp == NULL) {
return STATE_USER_INPUT_INVALID;
}
_in_yield_cb = 1;
handle->h_fp(handle->pcontext, c, msg);
_in_yield_cb = 0;
return STATE_SUCCESS;
}
static int iotx_mc_read_packet(iotx_mc_client_t *c, iotx_time_t *timer, unsigned int *packet_type)
{
MQTTHeader header = {0};
int len = 0;
int rem_len = 0;
int rc = 0;
unsigned int left_t = 0;
if (!c || !timer || !packet_type) {
return STATE_USER_INPUT_INVALID;
}
HAL_MutexLock(c->lock_read_buf);
rc = _alloc_recv_buffer(c, 0);
if (rc < 0) {
HAL_MutexUnlock(c->lock_read_buf);
return rc;
}
/* 1. read the header byte. This has the packet type in it */
left_t = iotx_time_left(timer);
left_t = (left_t == 0) ? 1 : left_t;
rc = c->ipstack.read(&c->ipstack, c->buf_read, 1, left_t);
if (0 == rc) { /* timeout */
*packet_type = 0;
HAL_MutexUnlock(c->lock_read_buf);
return STATE_SUCCESS;
} else if (rc < STATE_SUCCESS) {
HAL_MutexUnlock(c->lock_read_buf);
return STATE_SYS_DEPEND_NWK_CLOSE;
}
len = 1;
/* 2. read the remaining length. This is variable in itself */
left_t = iotx_time_left(timer);
left_t = (left_t == 0) ? 1 : left_t;
if ((rc = iotx_mc_decode_packet(c, &rem_len, left_t)) < 0) {
HAL_MutexUnlock(c->lock_read_buf);
return rc;
}
len += MQTTPacket_encode((unsigned char *)c->buf_read + 1,
rem_len); /* put the original remaining length back into the buffer */
rc = _alloc_recv_buffer(c, rem_len + len);
if (rc < 0) {
HAL_MutexUnlock(c->lock_read_buf);
return rc;
}
/* Check if the received data length exceeds mqtt read buffer length */
if ((rem_len > 0) && ((rem_len + len) > c->buf_size_read)) {
int needReadLen;
iotx_state_event(ITE_STATE_MQTT_COMM, STATE_MQTT_RX_BUFFER_TOO_SHORT, "");
mqtt_err("mqtt read buffer is too short, mqttReadBufLen : %u, remainDataLen : %d", c->buf_size_read, rem_len);
*packet_type = 0;
left_t = iotx_time_left(timer);
left_t = (left_t == 0) ? 1 : left_t;
do {
needReadLen = (rem_len > c->buf_size_read) ? c->buf_size_read : rem_len;
mqtt_info("read len:%d\n", needReadLen);
if (c->ipstack.read(&c->ipstack, c->buf_read, needReadLen, left_t) != needReadLen) {
mqtt_err("mqtt read error");
HAL_MutexUnlock(c->lock_read_buf);
return STATE_SYS_DEPEND_NWK_READ_ERROR;
}
rem_len -= needReadLen;
} while (rem_len);
HAL_MutexUnlock(c->lock_read_buf);
if (NULL != c->handle_event.h_fp) {
iotx_mqtt_event_msg_t msg;
msg.event_type = IOTX_MQTT_EVENT_BUFFER_OVERFLOW;
msg.msg = "mqtt read buffer is too short";
_handle_event(&c->handle_event, c, &msg);
}
return STATE_SUCCESS;
}
/* 3. read the rest of the buffer using a callback to supply the rest of the data */
left_t = iotx_time_left(timer);
left_t = (left_t == 0) ? 1 : left_t;
rc = c->ipstack.read(&c->ipstack, c->buf_read + len, rem_len, left_t);
if (rem_len > 0) {
if (rc < 0) {
HAL_MutexUnlock(c->lock_read_buf);
return STATE_SYS_DEPEND_NWK_CLOSE;
} else if (rc != rem_len) {
HAL_MutexUnlock(c->lock_read_buf);
return STATE_MQTT_PACKET_READ_ERROR;
}
}
header.byte = c->buf_read[0];
*packet_type = MQTT_HEADER_GET_TYPE(header.byte);
if ((len + rem_len) < c->buf_size_read) {
c->buf_read[len + rem_len] = '\0';
}
HAL_MutexUnlock(c->lock_read_buf);
return STATE_SUCCESS;
}
static int iotx_mc_handle_recv_CONNACK(iotx_mc_client_t *c)
{
int rc = STATE_SUCCESS;
unsigned char connack_rc = 255;
char sessionPresent = 0;
if (!c) {
return STATE_USER_INPUT_INVALID;
}
if (MQTTDeserialize_connack((unsigned char *)&sessionPresent, &connack_rc, (unsigned char *)c->buf_read,
c->buf_size_read) != 1) {
return STATE_MQTT_DESERIALIZE_CONNACK_ERROR;
}
switch (connack_rc) {
case IOTX_MC_CONNECTION_ACCEPTED:
rc = STATE_SUCCESS;
break;
case IOTX_MC_CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION:
rc = STATE_MQTT_CONNACK_VERSION_UNACCEPT;
break;
case IOTX_MC_CONNECTION_REFUSED_IDENTIFIER_REJECTED:
rc = STATE_MQTT_CONNACK_IDENT_REJECT;
break;
case IOTX_MC_CONNECTION_REFUSED_SERVER_UNAVAILABLE:
rc = STATE_MQTT_CONNACK_SERVICE_NA;
break;
case IOTX_MC_CONNECTION_REFUSED_NOT_AUTHORIZED:
rc = STATE_MQTT_CONNACK_NOT_AUTHORIZED;
break;
case IOTX_MC_CONNECTION_REFUSED_BAD_USERDATA:
rc = STATE_MQTT_CONNACK_BAD_USERDATA;
break;
default:
rc = STATE_MQTT_CONNACK_UNKNOWN_ERROR;
break;
}
return rc;
}
static int iotx_mc_wait_CONNACK(iotx_mc_client_t *c)
{
#define WAIT_CONNACK_MAX (10)
unsigned char wait_connack = 0;
unsigned int packetType = 0;
int rc = 0;
iotx_time_t timer;
if (!c) {
return STATE_USER_INPUT_INVALID;
}
iotx_time_init(&timer);
utils_time_countdown_ms(&timer, c->request_timeout_ms);
do {
/* read the socket, see what work is due */
rc = iotx_mc_read_packet(c, &timer, &packetType);
if (rc < STATE_SUCCESS) {
HAL_MutexLock(c->lock_read_buf);
_reset_recv_buffer(c);
HAL_MutexUnlock(c->lock_read_buf);
return rc;
}
if (++wait_connack > WAIT_CONNACK_MAX) {
HAL_Printf("等待连接超时\n");
HAL_MutexLock(c->lock_read_buf);
_reset_recv_buffer(c);
HAL_MutexUnlock(c->lock_read_buf);
return STATE_SYS_DEPEND_NWK_CLOSE;
}
} while (packetType != CONNACK);
HAL_MutexLock(c->lock_read_buf);
HAL_Printf("接收到请求MQTT连接应答= %x\n",rc);
rc = iotx_mc_handle_recv_CONNACK(c); //收到应答后,将接收报文反序列号,并根据实际报文返回状态??
_reset_recv_buffer(c);
HAL_MutexUnlock(c->lock_read_buf);
return rc;
}
static int _mqtt_connect(void *client)
{
#define RETRY_TIME_LIMIT (8+1)
#define RETRY_INTV_PERIOD (2000)
int rc = STATE_SUCCESS;
int try_count = 1;
iotx_mc_client_t *pClient = (iotx_mc_client_t *)client;
int userKeepAliveInterval = 0;
if (NULL == pClient) {
return STATE_USER_INPUT_INVALID;
}
userKeepAliveInterval = pClient->connect_data.keepAliveInterval;
pClient->connect_data.keepAliveInterval = (userKeepAliveInterval * 2);
if(pClient->connect_data.keepAliveInterval > CONFIG_MQTT_KEEPALIVE_INTERVAL_MAX) {
pClient->connect_data.keepAliveInterval = CONFIG_MQTT_KEEPALIVE_INTERVAL_MAX;
}
mqtt_info("connect params: MQTTVersion=%d, clientID=%s, keepAliveInterval=%d, username=%s",
pClient->connect_data.MQTTVersion,
pClient->connect_data.clientID.cstring,
pClient->connect_data.keepAliveInterval,
pClient->connect_data.username.cstring);
/* Establish TCP or TLS connection */
do {
rc = MQTTConnect(pClient);
pClient->connect_data.keepAliveInterval = userKeepAliveInterval;
if (rc < STATE_SUCCESS) {
pClient->ipstack.disconnect(&pClient->ipstack);
mqtt_err("send connect packet failed, rc = %d", rc);
return rc;
}
rc = iotx_mc_wait_CONNACK(pClient);
if (rc <= STATE_MQTT_CONNACK_VERSION_UNACCEPT && rc >= STATE_MQTT_CONNACK_NOT_AUTHORIZED) {
mqtt_err("received reject ACK from MQTT server! rc = %d", rc);
pClient->ipstack.disconnect(&pClient->ipstack);
return rc;
}
if (STATE_SUCCESS != rc) {
mqtt_err("wait connect ACK timeout! rc = -0x%04X", -rc);
mqtt_warning("tried [%d/%d] times CONN, waiting for %d ms...", try_count, RETRY_TIME_LIMIT - 1, RETRY_INTV_PERIOD);
HAL_SleepMs(RETRY_INTV_PERIOD);
pClient->ipstack.disconnect(&pClient->ipstack);
pClient->ipstack.connect(&pClient->ipstack);
continue;
} else {
break;
}
} while (++try_count < RETRY_TIME_LIMIT);
if (try_count == RETRY_TIME_LIMIT) {
HAL_Printf("_mqtt_connect()连接超时\n");
return STATE_MQTT_CONN_RETRY_EXCEED_MAX;
}
pClient->keepalive_probes = 0;
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_CONNECTED);
utils_time_countdown_ms(&pClient->next_ping_time, pClient->connect_data.keepAliveInterval * 1000);
mqtt_info("mqtt connect success!");
return STATE_SUCCESS;
}
#if !WITH_MQTT_ONLY_QOS0
static int iotx_mc_push_pubInfo_to(iotx_mc_client_t *c, int len, unsigned short msgId, iotx_mc_pub_info_t **node)
{
#ifdef PLATFORM_HAS_DYNMEM
int list_number;
iotx_mc_pub_info_t *repubInfo;
#else
int idx;
#endif
if (!c || !node) {
return STATE_USER_INPUT_INVALID;
}
if ((len < 0) || (len > c->buf_size_send)) {
#ifndef PLATFORM_HAS_DYNMEM
if (len >= c->buf_size_send) {
mqtt_err("IOTX_MC_TX_MAX_LEN is too short, len: %d, IOTX_MC_TX_MAX_LEN: %d", len, IOTX_MC_TX_MAX_LEN);
}
#endif
return STATE_MQTT_TX_BUFFER_TOO_SHORT;
}
#ifdef PLATFORM_HAS_DYNMEM
list_number = list_entry_number(&c->list_pub_wait_ack);
if (list_number >= IOTX_MC_REPUB_NUM_MAX) {
mqtt_err("more than %u elements in republish list. List overflow!", list_number);
return STATE_MQTT_QOS1_REPUB_EXCEED_MAX;
}
repubInfo = (iotx_mc_pub_info_t *)mqtt_malloc(sizeof(iotx_mc_pub_info_t) + len);
if (NULL == repubInfo) {
mqtt_err("run iotx_memory_malloc is error!");
return STATE_SYS_DEPEND_MALLOC;
}
repubInfo->node_state = IOTX_MC_NODE_STATE_NORMANL;
repubInfo->msg_id = msgId;
repubInfo->len = len;
iotx_time_start(&repubInfo->pub_start_time);
repubInfo->buf = (unsigned char *)repubInfo + sizeof(iotx_mc_pub_info_t);
memcpy(repubInfo->buf, c->buf_send, len);
INIT_LIST_HEAD(&repubInfo->linked_list);
list_add_tail(&repubInfo->linked_list, &c->list_pub_wait_ack);
*node = repubInfo;
return STATE_SUCCESS;
#else
for (idx = 0; idx < IOTX_MC_REPUB_NUM_MAX; idx++) {
if (c->list_pub_wait_ack[idx].used == 0) {
c->list_pub_wait_ack[idx].node_state = IOTX_MC_NODE_STATE_NORMANL;
c->list_pub_wait_ack[idx].msg_id = msgId;
c->list_pub_wait_ack[idx].len = len;
iotx_time_start(&c->list_pub_wait_ack[idx].pub_start_time);
memcpy(c->list_pub_wait_ack[idx].buf, c->buf_send, len);
c->list_pub_wait_ack[idx].used = 1;
*node = &c->list_pub_wait_ack[idx];
return STATE_SUCCESS;
}
}
mqtt_err("IOTX_MC_REPUB_NUM_MAX is too short");
return STATE_MQTT_QOS1_REPUB_EXCEED_MAX;
#endif
}
static int iotx_mc_mask_pubInfo_from(iotx_mc_client_t *c, uint16_t msgId)
{
#ifdef PLATFORM_HAS_DYNMEM
iotx_mc_pub_info_t *node = NULL;
if (!c) {
return STATE_USER_INPUT_INVALID;
}
HAL_MutexLock(c->lock_list_pub);
list_for_each_entry(node, &c->list_pub_wait_ack, linked_list, iotx_mc_pub_info_t) {
if (node->msg_id == msgId) {
node->node_state = IOTX_MC_NODE_STATE_INVALID; /* mark as invalid node */
}
}
HAL_MutexUnlock(c->lock_list_pub);
#else
int idx;
for (idx = 0; idx < IOTX_MC_REPUB_NUM_MAX; idx++) {
if (c->list_pub_wait_ack[idx].used &&
c->list_pub_wait_ack[idx].msg_id == msgId) {
c->list_pub_wait_ack[idx].node_state = IOTX_MC_NODE_STATE_INVALID; /* mark as invalid node */
}
}
#endif
return STATE_SUCCESS;
}
static int MQTTRePublish(iotx_mc_client_t *c, char *buf, int len)
{
iotx_time_t timer;
iotx_time_init(&timer);
utils_time_countdown_ms(&timer, c->request_timeout_ms);
HAL_MutexLock(c->lock_write_buf);
if (iotx_mc_send_packet(c, buf, len, &timer) != STATE_SUCCESS) {
HAL_MutexUnlock(c->lock_write_buf);
return STATE_SYS_DEPEND_NWK_CLOSE;
}
HAL_MutexUnlock(c->lock_write_buf);
return STATE_SUCCESS;
}
static int MQTTPubInfoProc(iotx_mc_client_t *pClient)
{
int rc = 0;
iotx_mc_state_t state = IOTX_MC_STATE_INVALID;
#ifdef PLATFORM_HAS_DYNMEM
iotx_mc_pub_info_t *node = NULL, *next_node = NULL;
#else
int idx;
#endif
if (!pClient) {
return STATE_USER_INPUT_INVALID;
}
HAL_MutexLock(pClient->lock_list_pub);
#ifdef PLATFORM_HAS_DYNMEM
list_for_each_entry_safe(node, next_node, &pClient->list_pub_wait_ack, linked_list, iotx_mc_pub_info_t) {
/* remove invalid node */
if (IOTX_MC_NODE_STATE_INVALID == node->node_state) {
list_del(&node->linked_list);
mqtt_free(node);
continue;
}
state = iotx_mc_get_client_state(pClient);
if (state != IOTX_MC_STATE_CONNECTED) {
continue;
}
/* check the request if timeout or not */
if (utils_time_spend(&node->pub_start_time) <= (pClient->request_timeout_ms * 2)) {
continue;
}
/* If wait ACK timeout, republish */
rc = MQTTRePublish(pClient, (char *)node->buf, node->len);
iotx_time_start(&node->pub_start_time);
if (STATE_SYS_DEPEND_NWK_CLOSE == rc) {
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED);
break;
}
}
#else
for (idx = 0; idx < IOTX_MC_REPUB_NUM_MAX; idx++) {
if (pClient->list_pub_wait_ack[idx].used == 0) {
continue;
}
if (IOTX_MC_NODE_STATE_INVALID == pClient->list_pub_wait_ack[idx].node_state) {
memset(&pClient->list_pub_wait_ack[idx], 0, sizeof(iotx_mc_pub_info_t));
continue;
}
state = iotx_mc_get_client_state(pClient);
if (state != IOTX_MC_STATE_CONNECTED) {
continue;
}
/* check the request if timeout or not */
if (utils_time_spend(&pClient->list_pub_wait_ack[idx].pub_start_time) <= (pClient->request_timeout_ms * 2)) {
continue;
}
/* If wait ACK timeout, republish */
rc = MQTTRePublish(pClient, (char *)pClient->list_pub_wait_ack[idx].buf, pClient->list_pub_wait_ack[idx].len);
iotx_time_start(&pClient->list_pub_wait_ack[idx].pub_start_time);
if (STATE_SYS_DEPEND_NWK_CLOSE == rc) {
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED);
break;
}
}
#endif
HAL_MutexUnlock(pClient->lock_list_pub);
return STATE_SUCCESS;
}
/* handle PUBACK packet received from remote MQTT broker */
static int iotx_mc_handle_recv_PUBACK(iotx_mc_client_t *c)
{
unsigned short mypacketid;
unsigned char dup = 0;
unsigned char type = 0;
if (!c) {
return STATE_USER_INPUT_INVALID;
}
if (MQTTDeserialize_ack(&type, &dup, &mypacketid, (unsigned char *)c->buf_read, c->buf_size_read) != 1) {
return MQTT_PUBLISH_ACK_PACKET_ERROR;
}
(void)iotx_mc_mask_pubInfo_from(c, mypacketid);
/* call callback function to notify that PUBLISH is successful */
if (NULL != c->handle_event.h_fp) {
iotx_mqtt_event_msg_t msg;
msg.event_type = IOTX_MQTT_EVENT_PUBLISH_SUCCESS;
msg.msg = (void *)(uintptr_t)mypacketid;
_handle_event(&c->handle_event, c, &msg);
}
return STATE_SUCCESS;
}
#endif
static void _iotx_mqtt_event_handle_sub(void *pcontext, void *pclient, iotx_mqtt_event_msg_pt msg)
{
iotx_mc_client_t *client;
uintptr_t packet_id;
#ifdef PLATFORM_HAS_DYNMEM
mqtt_sub_sync_node_t *node = NULL;
mqtt_sub_sync_node_t *next = NULL;
#else
int idx;
#endif
if (pclient == NULL || msg == NULL) {
return;
}
client = (iotx_mc_client_t *)pclient;
packet_id = (uintptr_t) msg->msg;
mqtt_debug("packet_id = %lu, event_type=%d", packet_id, msg->event_type);
HAL_MutexLock(client->lock_generic);
#ifdef PLATFORM_HAS_DYNMEM
list_for_each_entry_safe(node, next, &client->list_sub_sync_ack, linked_list, mqtt_sub_sync_node_t) {
if (node->packet_id == packet_id) {
node->ack_type = msg->event_type;
}
}
#else
for (idx = 0; idx < IOTX_MC_SUBSYNC_LIST_MAX_LEN; idx++) {
if (client->list_sub_sync_ack[idx].used &&
client->list_sub_sync_ack[idx].packet_id == packet_id) {
client->list_sub_sync_ack[idx].ack_type = msg->event_type;
}
}
#endif
HAL_MutexUnlock(client->lock_generic);
}
static int iotx_mc_handle_recv_SUBACK(iotx_mc_client_t *c)
{
unsigned short mypacketid;
iotx_mqtt_event_msg_t msg;
int i = 0, count = 0, fail_flag = -1, j = 0;
int grantedQoS[MUTLI_SUBSCIRBE_MAX];
int rc;
if (!c) {
return STATE_USER_INPUT_INVALID;
}
rc = MQTTDeserialize_suback(&mypacketid, MUTLI_SUBSCIRBE_MAX, &count, grantedQoS, (unsigned char *)c->buf_read,
c->buf_size_read);
if (rc < 0) {
mqtt_err("Sub ack packet error, rc = MQTTDeserialize_suback() = %d", rc);
return STATE_MQTT_DESERIALIZE_SUBACK_ERROR;
}
mqtt_debug("%20s : %d", "Return Value", rc);
mqtt_debug("%20s : %d", "Packet ID", mypacketid);
mqtt_debug("%20s : %d", "Count", count);
for (i = 0; i < count; ++i) {
mqtt_debug("%16s[%02d] : %d", "Granted QoS", i, grantedQoS[i]);
}
for (j = 0; j < count; j++) {
fail_flag = 0;
/* In negative case, grantedQoS will be 0xFFFF FF80, which means -128 */
if ((uint8_t)grantedQoS[j] == 0x80) {
fail_flag = 1;
mqtt_err("MQTT SUBSCRIBE failed, ack code is 0x80");
}
}
/* call callback function to notify that SUBSCRIBE is successful */
msg.msg = (void *)(uintptr_t)mypacketid;
if (fail_flag == 1) {
msg.event_type = IOTX_MQTT_EVENT_SUBCRIBE_NACK;
} else {
msg.event_type = IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS;
}
_iotx_mqtt_event_handle_sub(c->handle_event.pcontext, c, &msg);
if (NULL != c->handle_event.h_fp) {
_handle_event(&c->handle_event, c, &msg);
}
return STATE_SUCCESS;
}
#if WITH_MQTT_ZIP_TOPIC
#define MQTT_ZIP_PATH_DEFAULT_LEN (32)
static int iotx_mc_get_zip_topic(const char *path, int len, char outbuf[], int outlen)
{
unsigned char comp_data[MQTT_ZIP_PATH_DEFAULT_LEN] = {0};
if (!path || !len || !outbuf || !outlen) {
return STATE_USER_INPUT_INVALID;
}
utils_sha256((unsigned char *)path, (size_t)len, comp_data);
memcpy(outbuf, comp_data, outlen > MQTT_ZIP_PATH_DEFAULT_LEN ? MQTT_ZIP_PATH_DEFAULT_LEN : outlen);
return STATE_SUCCESS;
}
#endif
static char iotx_mc_is_topic_matched(char *topicFilter, MQTTString *topicName)
{
char *curf;
char *curn;
char *curn_end;
if (!topicFilter || !topicName) {
return STATE_SUCCESS;
}
curf = topicFilter;
curn = topicName->lenstring.data;
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');
}
/* /ext/auth/identity/response, payload: {"productKey":"","deviceName":""} */
static void iotx_mc_parse_identity_response(iotx_mqtt_topic_info_pt topic_msg)
{
char *identify_topic = "/ext/auth/identity/response";
void *callback = NULL;
if (topic_msg->topic_len == strlen(identify_topic) &&
(memcmp(topic_msg->ptopic, identify_topic, strlen(identify_topic)) == 0)) {
char *payload = NULL;
payload = HAL_Malloc(topic_msg->payload_len + 1);
if (payload == NULL) {
iotx_state_event(ITE_STATE_MQTT_COMM, STATE_SYS_DEPEND_MALLOC, "identify response fail");
return;
}
memset(payload, 0, topic_msg->payload_len + 1);
memcpy(payload, topic_msg->payload, topic_msg->payload_len);
callback = iotx_event_callback(ITE_IDENTITY_RESPONSE);
if (callback) {
((int (*)(const char*))callback)(payload);
}
HAL_Free(payload);
/* parse payload then set product key and device name */
{
char *product_key = NULL, *device_name = NULL, *str_product_key = NULL, *str_device_name = NULL;
uint32_t product_key_len = 0, device_name_len = 0;
if (infra_json_value(topic_msg->payload, topic_msg->payload_len, "productKey", strlen("productKey"), &product_key, &product_key_len) != STATE_SUCCESS ||
infra_json_value(topic_msg->payload, topic_msg->payload_len, "deviceName", strlen("deviceName"), &device_name, &device_name_len) != STATE_SUCCESS) {
return;
}
str_product_key = HAL_Malloc(product_key_len - 2 + 1);
if (str_product_key == NULL) {
iotx_state_event(ITE_STATE_MQTT_COMM, STATE_SYS_DEPEND_MALLOC, "identify response fail");
return;
}
memset(str_product_key, 0, product_key_len - 2 + 1);
memcpy(str_product_key, product_key + 1, product_key_len - 2);
str_device_name = HAL_Malloc(device_name_len - 2 + 1);
if (str_device_name == NULL) {
HAL_Free(str_product_key);
iotx_state_event(ITE_STATE_MQTT_COMM, STATE_SYS_DEPEND_MALLOC, "identify response fail");
return;
}
memset(str_device_name, 0, device_name_len - 2 + 1);
memcpy(str_device_name, device_name + 1, device_name_len - 2);
IOT_Ioctl(IOTX_IOCTL_SET_PRODUCT_KEY, str_product_key);
IOT_Ioctl(IOTX_IOCTL_SET_DEVICE_NAME, str_device_name);
HAL_Free(str_product_key);
HAL_Free(str_device_name);
}
}
}
static void iotx_mc_deliver_message(iotx_mc_client_t *c, MQTTString *topicName, iotx_mqtt_topic_info_pt topic_msg)
{
int flag_matched = 0;
MQTTString *compare_topic = NULL;
#ifdef PLATFORM_HAS_DYNMEM
iotx_mc_topic_handle_t *node = NULL;
#else
int idx = 0;
#endif
#if WITH_MQTT_ZIP_TOPIC
MQTTString md5_topic;
char md5_topic_data[MQTT_ZIP_PATH_DEFAULT_LEN] = {0};
char *net_topic;
uint32_t net_topic_len;
#endif
if (!c || !topicName || !topic_msg) {
return;
}
topic_msg->ptopic = topicName->lenstring.data;
topic_msg->topic_len = topicName->lenstring.len;
iotx_mc_parse_identity_response(topic_msg);
#if WITH_MQTT_ZIP_TOPIC
if (topicName->cstring) {
net_topic = topicName->cstring;
net_topic_len = strlen(topicName->cstring);
} else {
net_topic = topicName->lenstring.data;
net_topic_len = topicName->lenstring.len;
}
md5_topic.cstring = NULL;
md5_topic.lenstring.data = md5_topic_data;
md5_topic.lenstring.len = MQTT_ZIP_PATH_DEFAULT_LEN;
iotx_mc_get_zip_topic(net_topic, net_topic_len, md5_topic_data, MQTT_ZIP_PATH_DEFAULT_LEN);
compare_topic = &md5_topic;
#else
compare_topic = topicName;
#endif
/* we have to find the right message handler - indexed by topic */
HAL_MutexLock(c->lock_generic);
#ifdef PLATFORM_HAS_DYNMEM
list_for_each_entry(node, &c->list_sub_handle, linked_list, iotx_mc_topic_handle_t) {
if (MQTTPacket_equals(compare_topic, (char *)node->topic_filter)
|| iotx_mc_is_topic_matched((char *)node->topic_filter, topicName)) {
mqtt_debug("topic be matched");
HAL_MutexUnlock(c->lock_generic);
if (NULL != node->handle.h_fp) {
iotx_mqtt_event_msg_t msg;
msg.event_type = IOTX_MQTT_EVENT_PUBLISH_RECEIVED;
msg.msg = (void *)topic_msg;
_handle_event(&node->handle, c, &msg);
flag_matched = 1;
}
HAL_MutexLock(c->lock_generic);
}
}
#else
for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) {
if ((c->list_sub_handle[idx].used == 1) &&
(MQTTPacket_equals(compare_topic, (char *)c->list_sub_handle[idx].topic_filter)
|| iotx_mc_is_topic_matched((char *)c->list_sub_handle[idx].topic_filter, topicName))) {
mqtt_debug("topic be matched");
HAL_MutexUnlock(c->lock_generic);
if (NULL != c->list_sub_handle[idx].handle.h_fp) {
iotx_mqtt_event_msg_t msg;
msg.event_type = IOTX_MQTT_EVENT_PUBLISH_RECEIVED;
msg.msg = (void *)topic_msg;
_handle_event(&c->list_sub_handle[idx].handle, c, &msg);
flag_matched = 1;
}
HAL_MutexLock(c->lock_generic);
}
}
#endif
HAL_MutexUnlock(c->lock_generic);
if (0 == flag_matched) {
mqtt_info("NO matching any topic, call default handle function");
if (NULL != c->handle_event.h_fp) {
iotx_mqtt_event_msg_t msg;
msg.event_type = IOTX_MQTT_EVENT_PUBLISH_RECEIVED;
msg.msg = topic_msg;
_handle_event(&c->handle_event, c, &msg);
}
}
}
static int MQTTPuback(iotx_mc_client_t *c, unsigned int msgId, enum msgTypes type)
{
int rc = 0;
int len = 0;
iotx_time_t timer;
if (!c) {
return STATE_USER_INPUT_INVALID;
}
iotx_time_init(&timer);
utils_time_countdown_ms(&timer, c->request_timeout_ms);
HAL_MutexLock(c->lock_write_buf);
if (type == PUBACK) {
rc = _alloc_send_buffer(c, 0);
if (rc < STATE_SUCCESS) {
HAL_MutexUnlock(c->lock_write_buf);
return rc;
}
len = MQTTSerialize_ack((unsigned char *)c->buf_send, c->buf_size_send, PUBACK, 0, msgId);
#if WITH_MQTT_QOS2_PACKET
} else if (type == PUBREC) {
rc = _alloc_send_buffer(c, 0);
if (rc < STATE_SUCCESS) {
HAL_MutexUnlock(c->lock_write_buf);
return rc;
}
len = MQTTSerialize_ack((unsigned char *)c->buf_send, c->buf_size_send, PUBREC, 0, msgId);
} else if (type == PUBREL) {
rc = _alloc_send_buffer(c, 0);
if (rc < STATE_SUCCESS) {
HAL_MutexUnlock(c->lock_write_buf);
return rc;
}
len = MQTTSerialize_ack((unsigned char *)c->buf_send, c->buf_size_send, PUBREL, 0, msgId);
#endif /* #if WITH_MQTT_QOS2_PACKET */
} else {
HAL_MutexUnlock(c->lock_write_buf);
return STATE_MQTT_SERIALIZE_PUBACK_ERROR;
}
if (len <= 0) {
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
return STATE_MQTT_SERIALIZE_PUBACK_ERROR;
}
rc = iotx_mc_send_packet(c, c->buf_send, len, &timer);
if (rc < STATE_SUCCESS) {
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
return rc;
}
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
return STATE_SUCCESS;
}
static int iotx_mc_handle_recv_PUBLISH(iotx_mc_client_t *c)
{
int result = 0;
MQTTString topicName;
iotx_mqtt_topic_info_t topic_msg;
int qos = 0;
uint32_t payload_len = 0;
#ifdef INFRA_LOG_NETWORK_PAYLOAD
const char *json_payload = NULL;
#endif
if (!c) {
return STATE_USER_INPUT_INVALID;
}
memset(&topic_msg, 0x0, sizeof(iotx_mqtt_topic_info_t));
memset(&topicName, 0x0, sizeof(MQTTString));
if (1 != MQTTDeserialize_publish((unsigned char *)&topic_msg.dup,
(int *)&qos,
(unsigned char *)&topic_msg.retain,
(unsigned short *)&topic_msg.packet_id,
&topicName,
(unsigned char **)&topic_msg.payload,
(int *)&payload_len,
(unsigned char *)c->buf_read,
c->buf_size_read)) {
return MQTT_PUBLISH_PACKET_ERROR;
}
topic_msg.qos = (unsigned char)qos;
topic_msg.payload_len = payload_len;
if (topicName.lenstring.len == 0 || topicName.lenstring.data == NULL) {
mqtt_err("Null topicName");
return STATE_MQTT_DESERIALIZE_PUB_ERROR;
}
#ifdef INFRA_LOG_NETWORK_PAYLOAD
json_payload = (const char *)topic_msg.payload;
mqtt_info("Downstream Topic: '%.*s'", topicName.lenstring.len, topicName.lenstring.data);
mqtt_info("Downstream Payload:");
iotx_facility_json_print(json_payload, LOG_INFO_LEVEL, '<');
#endif /* #ifdef INFRA_LOG */
mqtt_debug("%20s : %08d", "Packet Ident", topic_msg.packet_id);
mqtt_debug("%20s : %d", "Topic Length", topicName.lenstring.len);
mqtt_debug("%20s : %.*s",
"Topic Name",
topicName.lenstring.len,
topicName.lenstring.data);
mqtt_debug("%20s : %u / %d", "Payload Len/Room",
(unsigned int)topic_msg.payload_len,
(int)(c->buf_read + c->buf_size_read - topic_msg.payload));
mqtt_debug("%20s : %lu", "Receive Buflen", c->buf_size_read);
#if defined(INSPECT_MQTT_FLOW)
mqtt_debug("%20s : %p", "Payload Buffer", topic_msg.payload);
mqtt_debug("%20s : %p", "Receive Buffer", c->buf_read);
#ifdef INFRA_LOG
HEXDUMP_DEBUG(topic_msg.payload, topic_msg.payload_len);
#endif
#endif
#if defined(LOG_REPORT_TO_CLOUD) && !defined(DEVICE_MODEL_RAWDATA_SOLO)
get_msgid(topicName.lenstring.data, 1);
#endif
topic_msg.ptopic = NULL;
topic_msg.topic_len = 0;
mqtt_debug("delivering msg ...");
#if WITH_MQTT_FLOW_CTRL
/* flowControl for specific topic */
static uint64_t time_prev = 0;
uint64_t time_curr = 0;
char *filterStr = "{\"method\":\"thing.service.property.set\"";
int filterLen = strlen(filterStr);
if (0 == memcmp(topic_msg.payload, filterStr, filterLen)) {
time_curr = HAL_UptimeMs();
if (time_curr < time_prev) {
time_curr = time_prev;
}
if ((time_curr - time_prev) <= (uint64_t)50) {
mqtt_info("MQTT over threshould");
return STATE_SUCCESS;
} else {
time_prev = time_curr;
}
}
#endif
iotx_mc_deliver_message(c, &topicName, &topic_msg);
if (topic_msg.qos == IOTX_MQTT_QOS0) {
return STATE_SUCCESS;
} else if (topic_msg.qos == IOTX_MQTT_QOS1) {
result = MQTTPuback(c, topic_msg.packet_id, PUBACK);
} else if (topic_msg.qos == IOTX_MQTT_QOS2) {
result = MQTTPuback(c, topic_msg.packet_id, PUBREC);
} else {
mqtt_err("Invalid QOS, QOSvalue = %d", topic_msg.qos);
return STATE_MQTT_PUB_QOS_INVALID;
}
return result;
}
static int iotx_mc_handle_recv_UNSUBACK(iotx_mc_client_t *c)
{
unsigned short mypacketid = 0; /* should be the same as the packetid above */
if (!c) {
return STATE_USER_INPUT_INVALID;
}
if (MQTTDeserialize_unsuback(&mypacketid, (unsigned char *)c->buf_read, c->buf_size_read) != 1) {
return STATE_MQTT_DESERIALIZE_UNSUBACK_ERROR;
}
if (NULL != c->handle_event.h_fp) {
iotx_mqtt_event_msg_t msg;
msg.event_type = IOTX_MQTT_EVENT_UNSUBCRIBE_SUCCESS;
msg.msg = (void *)(uintptr_t)mypacketid;
_handle_event(&c->handle_event, c, &msg);
}
return STATE_SUCCESS;
}
static int iotx_mc_cycle(iotx_mc_client_t *c, iotx_time_t *timer)
{
unsigned int packetType;
iotx_mc_state_t state;
int rc = STATE_SUCCESS;
if (!c) {
return STATE_USER_INPUT_INVALID;
}
state = iotx_mc_get_client_state(c);
if (state != IOTX_MC_STATE_CONNECTED) {
return STATE_MQTT_IN_OFFLINE_STATUS;
}
if (IOTX_MC_KEEPALIVE_PROBE_MAX < c->keepalive_probes) {
iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED);
c->keepalive_probes = 0;
mqtt_debug("keepalive_probes more than %u, disconnected\n", IOTX_MC_KEEPALIVE_PROBE_MAX);
return STATE_MQTT_IN_OFFLINE_STATUS;
}
/* read the socket, see what work is due */
rc = iotx_mc_read_packet(c, timer, &packetType);
if (rc != STATE_SUCCESS) {
HAL_MutexLock(c->lock_read_buf);
_reset_recv_buffer(c);
HAL_MutexUnlock(c->lock_read_buf);
if (rc == STATE_SYS_DEPEND_NWK_CLOSE) {
iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED);
}
mqtt_err("readPacket error, result = -0x%04X", -rc);
return STATE_SYS_DEPEND_NWK_CLOSE;
}
if (MQTT_CPT_RESERVED == packetType) {
/* mqtt_debug("wait data timeout"); */
HAL_MutexLock(c->lock_read_buf);
_reset_recv_buffer(c);
HAL_MutexUnlock(c->lock_read_buf);
return STATE_SUCCESS;
}
/* clear ping mark when any data received from MQTT broker */
c->keepalive_probes = 0;
HAL_MutexLock(c->lock_read_buf);
switch (packetType) {
case CONNACK: {
mqtt_debug("CONNACK");
break;
}
#if !WITH_MQTT_ONLY_QOS0
case PUBACK: {
mqtt_debug("PUBACK");
rc = iotx_mc_handle_recv_PUBACK(c);
if (rc < STATE_SUCCESS) {
mqtt_err("recvPubackProc error,result = %d", rc);
}
break;
}
#endif
case SUBACK: {
mqtt_debug("SUBACK");
rc = iotx_mc_handle_recv_SUBACK(c);
if (rc < STATE_SUCCESS) {
mqtt_err("recvSubAckProc error,result = %d", rc);
}
break;
}
case PUBLISH: {
mqtt_debug("PUBLISH");
/* HEXDUMP_DEBUG(c->buf_read, 32); */
rc = iotx_mc_handle_recv_PUBLISH(c);
if (rc < STATE_SUCCESS) {
mqtt_err("recvPublishProc error,result = %d", rc);
}
break;
}
case UNSUBACK: {
mqtt_debug("UNSUBACK");
rc = iotx_mc_handle_recv_UNSUBACK(c);
if (rc < STATE_SUCCESS) {
mqtt_err("recvUnsubAckProc error,result = %d", rc);
}
break;
}
case PINGRESP: {
rc = STATE_SUCCESS;
mqtt_info("receive ping response!");
break;
}
default:
mqtt_err("INVALID TYPE");
_reset_recv_buffer(c);
HAL_MutexUnlock(c->lock_read_buf);
return STATE_MQTT_RECV_UNKNOWN_PACKET;
}
_reset_recv_buffer(c);
HAL_MutexUnlock(c->lock_read_buf);
return rc;
}
void _mqtt_cycle(void *client)
{
int rc = STATE_SUCCESS;
iotx_time_t time;
iotx_mc_client_t *pClient = (iotx_mc_client_t *)client;
iotx_time_init(&time);
utils_time_countdown_ms(&time, pClient->cycle_timeout_ms);
do {
unsigned int left_t;
if (rc < STATE_SUCCESS) {
/*mqtt_err("error occur rc=%d", rc);*/
}
HAL_MutexLock(pClient->lock_yield);
/* acquire package in cycle, such as PINGRESP or PUBLISH */
rc = iotx_mc_cycle(pClient, &time);
if (rc == STATE_SUCCESS) {
#ifndef ASYNC_PROTOCOL_STACK
#if !WITH_MQTT_ONLY_QOS0
/* check list of wait publish ACK to remove node that is ACKED or timeout */
MQTTPubInfoProc(pClient);
#endif
#endif
}
HAL_MutexUnlock(pClient->lock_yield);
left_t = iotx_time_left(&time);
if (left_t < 10) {
HAL_SleepMs(left_t);
} else {
HAL_SleepMs(10);
}
} while (!utils_time_is_expired(&time));
}
static int MQTTKeepalive(iotx_mc_client_t *pClient)
{
int len = 0;
int rc = 0;
/* there is no ping outstanding - send ping packet */
iotx_time_t timer;
if (!pClient) {
return STATE_USER_INPUT_INVALID;
}
iotx_time_init(&timer);
utils_time_countdown_ms(&timer, 1000);
HAL_MutexLock(pClient->lock_write_buf);
rc = _alloc_send_buffer(pClient, 0);
if (rc < STATE_SUCCESS) {
HAL_MutexUnlock(pClient->lock_write_buf);
return rc;
}
len = MQTTSerialize_pingreq((unsigned char *)pClient->buf_send, pClient->buf_size_send);
mqtt_debug("len = MQTTSerialize_pingreq() = %d", len);
if (len <= 0) {
mqtt_err("Serialize ping request is error");
_reset_send_buffer(pClient);
HAL_MutexUnlock(pClient->lock_write_buf);
return STATE_MQTT_SERIALIZE_PINGREQ_ERROR;
}
rc = iotx_mc_send_packet(pClient, pClient->buf_send, len, &timer);
if (rc < STATE_SUCCESS) {
/* ping outstanding, then close socket unsubscribe topic and handle callback function */
mqtt_err("ping outstanding is error,result = %d", rc);
_reset_send_buffer(pClient);
HAL_MutexUnlock(pClient->lock_write_buf);
return STATE_SYS_DEPEND_NWK_CLOSE;
}
_reset_send_buffer(pClient);
HAL_MutexUnlock(pClient->lock_write_buf);
return STATE_SUCCESS;
}
static int iotx_mc_keepalive_sub(iotx_mc_client_t *pClient)
{
int rc = STATE_SUCCESS;
if (NULL == pClient) {
return STATE_USER_INPUT_INVALID;
}
/* if in disabled state, without having to send ping packets */
if (!wrapper_mqtt_check_state(pClient)) {
return STATE_SUCCESS;
}
/* if there is no ping_timer timeout, then return success */
if (!utils_time_is_expired(&pClient->next_ping_time)) {
return STATE_SUCCESS;
}
/* update to next time sending MQTT keep-alive */
utils_time_countdown_ms(&pClient->next_ping_time, pClient->connect_data.keepAliveInterval * 1000);
rc = MQTTKeepalive(pClient);
if (rc < STATE_SUCCESS) {
if (rc == STATE_SYS_DEPEND_NWK_CLOSE) {
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED);
}
mqtt_err("ping outstanding is error,result = %d", rc);
return rc;
}
mqtt_info("send MQTT ping...");
pClient->keepalive_probes++;
return STATE_SUCCESS;
}
int _mqtt_nwk_connect(void *client);
static int iotx_mc_attempt_reconnect(iotx_mc_client_t *pClient)
{
int rc;
if (pClient == NULL) {
return STATE_USER_INPUT_INVALID;
}
pClient->ipstack.disconnect(&pClient->ipstack);
mqtt_info("reconnect params: MQTTVersion=%d, clientID=%s, keepAliveInterval=%d, username=%s",
pClient->connect_data.MQTTVersion,
pClient->connect_data.clientID.cstring,
pClient->connect_data.keepAliveInterval,
pClient->connect_data.username.cstring);
/* Ignoring return code. failures expected if network is disconnected */
rc = _mqtt_nwk_connect(pClient);
if (rc < STATE_SUCCESS) {
mqtt_err("run _mqtt_nwk_connect() error!");
}
rc = _mqtt_connect(pClient);
if (rc < STATE_SUCCESS && rc != STATE_MQTT_ASYNC_STACK_CONN_IN_PROG) {
mqtt_err("run _mqtt_connect() error!");
}
return rc;
}
static int iotx_mc_handle_reconnect(iotx_mc_client_t *pClient)
{
int rc = STATE_SUCCESS;
uint32_t interval_ms = 0;
if (NULL == pClient) {
return STATE_USER_INPUT_INVALID;
}
if (!utils_time_is_expired(&(pClient->reconnect_param.reconnect_next_time))) {
/* Timer has not expired. Not time to attempt reconnect yet. Return attempting reconnect */
HAL_SleepMs(100);
return STATE_MQTT_WAIT_RECONN_TIMER;
}
mqtt_info("start to reconnect");
/*
rc = _conn_info_dynamic_reload(pClient);
if (STATE_SUCCESS != rc) {
mqtt_err("update connect info err");
return -1;
}
*/
rc = iotx_mc_attempt_reconnect(pClient);
if (rc == STATE_SUCCESS) {
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_CONNECTED);
/*
_conn_info_dynamic_reload_clear(pClient);
*/
return STATE_SUCCESS;
} else if (STATE_MQTT_ASYNC_STACK_CONN_IN_PROG == rc) {
return rc;
} else {
/* if reconnect network failed, then increase currentReconnectWaitInterval */
/* e.g. init currentReconnectWaitInterval=1s, reconnect failed, then 2s..4s..8s */
if (IOTX_MC_RECONNECT_INTERVAL_MAX_MS > pClient->reconnect_param.reconnect_time_interval_ms) {
pClient->reconnect_param.reconnect_time_interval_ms *= 2;
} else {
pClient->reconnect_param.reconnect_time_interval_ms = IOTX_MC_RECONNECT_INTERVAL_MAX_MS;
}
}
/*
_conn_info_dynamic_reload_clear(pClient);
*/
interval_ms = pClient->reconnect_param.reconnect_time_interval_ms;
if (IOTX_MC_RECONNECT_INTERVAL_MAX_MS < interval_ms) {
interval_ms = IOTX_MC_RECONNECT_INTERVAL_MAX_MS;
}
utils_time_countdown_ms(&(pClient->reconnect_param.reconnect_next_time), interval_ms);
mqtt_err("mqtt reconnect failed rc = %d", rc);
return rc;
}
static void iotx_mc_reconnect_callback(iotx_mc_client_t *pClient)
{
/* handle callback function */
if (NULL != pClient->handle_event.h_fp) {
iotx_mqtt_event_msg_t msg;
msg.event_type = IOTX_MQTT_EVENT_RECONNECT;
msg.msg = NULL;
pClient->handle_event.h_fp(pClient->handle_event.pcontext,
pClient,
&msg);
}
}
static void iotx_mc_disconnect_callback(iotx_mc_client_t *pClient)
{
if (NULL != pClient->handle_event.h_fp) {
iotx_mqtt_event_msg_t msg;
msg.event_type = IOTX_MQTT_EVENT_DISCONNECT;
msg.msg = NULL;
pClient->handle_event.h_fp(pClient->handle_event.pcontext,
pClient,
&msg);
}
}
static void iotx_mc_keepalive(iotx_mc_client_t *pClient)
{
int rc = 0;
iotx_mc_state_t currentState;
if (!pClient) {
return;
}
/* Periodic sending ping packet to detect whether the network is connected */
iotx_mc_keepalive_sub(pClient);
currentState = iotx_mc_get_client_state(pClient);
do {
/* if Exceeds the maximum delay time, then return reconnect timeout */
if (IOTX_MC_STATE_DISCONNECTED_RECONNECTING == currentState ||
IOTX_MC_STATE_CONNECT_BLOCK == currentState) {
/* Reconnection is successful, Resume regularly ping packets */
rc = iotx_mc_handle_reconnect(pClient);
if (rc < STATE_SUCCESS) {
if (rc == STATE_MQTT_ASYNC_STACK_CONN_IN_PROG) {
mqtt_debug("now using async protocol stack, wait network connected...");
}
} else {
mqtt_info("network is reconnected!");
iotx_mc_reconnect_callback(pClient);
pClient->reconnect_param.reconnect_time_interval_ms = IOTX_MC_RECONNECT_INTERVAL_MIN_MS;
}
break;
}
/* If network suddenly interrupted, stop pinging packet, try to reconnect network immediately */
if (currentState == IOTX_MC_STATE_DISCONNECTED) {
mqtt_err("network is disconnected!");
iotx_mc_disconnect_callback(pClient);
pClient->reconnect_param.reconnect_time_interval_ms = IOTX_MC_RECONNECT_INTERVAL_MIN_MS;
utils_time_countdown_ms(&(pClient->reconnect_param.reconnect_next_time),
pClient->reconnect_param.reconnect_time_interval_ms);
pClient->ipstack.disconnect(&pClient->ipstack);
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED_RECONNECTING);
break;
}
} while (0);
}
static int iotx_mc_check_handle_is_identical_ex(iotx_mc_topic_handle_t *messageHandlers1,
iotx_mc_topic_handle_t *messageHandler2)
{
int topicNameLen = 0;
if (!messageHandlers1 || !messageHandler2) {
return 1;
}
if (!(messageHandlers1->topic_filter) || !(messageHandler2->topic_filter)) {
return 1;
}
#if !(WITH_MQTT_ZIP_TOPIC)
topicNameLen = strlen(messageHandlers1->topic_filter);
if (topicNameLen != strlen(messageHandler2->topic_filter)) {
return 1;
}
if (0 != strncmp(messageHandlers1->topic_filter, messageHandler2->topic_filter, topicNameLen)) {
return 1;
}
#else
if (messageHandlers1->topic_type != messageHandler2->topic_type) {
return 1;
}
if (messageHandlers1->topic_type == TOPIC_NAME_TYPE) {
int i;
for (i = 0; i < MQTT_ZIP_PATH_DEFAULT_LEN; i++) {
if (messageHandler2->topic_filter[i] != messageHandlers1->topic_filter[i]) {
return 1;
}
}
} else {
topicNameLen = strlen(messageHandlers1->topic_filter);
if (topicNameLen != strlen(messageHandler2->topic_filter)) {
return 1;
}
if (0 != strncmp(messageHandlers1->topic_filter, messageHandler2->topic_filter, topicNameLen)) {
return 1;
}
}
#endif
return 0;
}
static int iotx_mc_check_handle_is_identical(iotx_mc_topic_handle_t *messageHandlers1,
iotx_mc_topic_handle_t *messageHandler2)
{
if (iotx_mc_check_handle_is_identical_ex(messageHandlers1, messageHandler2) != 0) {
return 1;
}
if (messageHandlers1->handle.h_fp != messageHandler2->handle.h_fp) {
return 1;
}
/* context must be identical also */
if (messageHandlers1->handle.pcontext != messageHandler2->handle.pcontext) {
return 1;
}
return 0;
}
static int MQTTSubscribe(iotx_mc_client_t *c, const char *topicFilter, iotx_mqtt_qos_t qos, unsigned int msgId,
iotx_mqtt_event_handle_func_fpt messageHandler, void *pcontext)
{
int len = 0, res = 0;
int tmpqos = (int)qos;
iotx_time_t timer;
MQTTString topic = MQTTString_initializer;
/*iotx_mc_topic_handle_t handler = {topicFilter, {messageHandler, pcontext}};*/
iotx_mc_topic_handle_t *handler = NULL;
#ifndef PLATFORM_HAS_DYNMEM
int idx = 0;
#endif
if (!c || !topicFilter || !messageHandler) {
return STATE_USER_INPUT_INVALID;
}
#if !( WITH_MQTT_DYN_BUF)
if (!c->buf_send) {
return STATE_USER_INPUT_INVALID;
}
#endif
topic.cstring = (char *)topicFilter;
iotx_time_init(&timer);
utils_time_countdown_ms(&timer, c->request_timeout_ms);
#ifdef PLATFORM_HAS_DYNMEM
handler = mqtt_malloc(sizeof(iotx_mc_topic_handle_t));
if (NULL == handler) {
return STATE_SYS_DEPEND_MALLOC;
}
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
INIT_LIST_HEAD(&handler->linked_list);
#else
for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) {
if (c->list_sub_handle[idx].used == 0) {
handler = &c->list_sub_handle[idx];
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
c->list_sub_handle[idx].used = 1;
break;
}
}
if (handler == NULL) {
return STATE_MQTT_SUB_EXCEED_MAX;
}
#endif
#if !(WITH_MQTT_ZIP_TOPIC)
#ifdef PLATFORM_HAS_DYNMEM
handler->topic_filter = mqtt_malloc(strlen(topicFilter) + 1);
if (NULL == handler->topic_filter) {
mqtt_free(handler);
return STATE_SYS_DEPEND_MALLOC;
}
memset((char *)handler->topic_filter, 0, strlen(topicFilter) + 1);
#else
if (strlen(topicFilter) >= CONFIG_MQTT_TOPIC_MAXLEN) {
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
return STATE_MQTT_TOPIC_BUF_TOO_SHORT;
}
memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN);
#endif
memcpy((char *)handler->topic_filter, topicFilter, strlen(topicFilter) + 1);
#else
if (strstr(topicFilter, "/+") != NULL || strstr(topicFilter, "/#") != NULL) {
#ifdef PLATFORM_HAS_DYNMEM
handler->topic_filter = mqtt_malloc(strlen(topicFilter) + 1);
if (NULL == handler->topic_filter) {
mqtt_free(handler);
return STATE_SYS_DEPEND_MALLOC;
}
memset((char *)handler->topic_filter, 0, strlen(topicFilter) + 1);
#else
if (strlen(topicFilter) >= CONFIG_MQTT_TOPIC_MAXLEN) {
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
return STATE_MQTT_TOPIC_BUF_TOO_SHORT;
}
memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN);
#endif
handler->topic_type = TOPIC_FILTER_TYPE;
memcpy((char *)handler->topic_filter, topicFilter, strlen(topicFilter) + 1);
} else {
#ifdef PLATFORM_HAS_DYNMEM
handler->topic_filter = mqtt_malloc(MQTT_ZIP_PATH_DEFAULT_LEN);
if (NULL == handler->topic_filter) {
mqtt_free(handler);
return STATE_SYS_DEPEND_MALLOC;
}
memset((char *)handler->topic_filter, 0, MQTT_ZIP_PATH_DEFAULT_LEN);
#else
if (MQTT_ZIP_PATH_DEFAULT_LEN >= CONFIG_MQTT_TOPIC_MAXLEN) {
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
return MQTT_TOPIC_LEN_TOO_SHORT;
}
memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN);
#endif
handler->topic_type = TOPIC_NAME_TYPE;
res = iotx_mc_get_zip_topic(topicFilter, strlen(topicFilter), (char *)handler->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN);
if (res < STATE_SUCCESS) {
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#else
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
#endif
return res;
}
}
#endif
handler->handle.h_fp = messageHandler;
handler->handle.pcontext = pcontext;
if (qos == IOTX_MQTT_QOS3_SUB_LOCAL) {
uint8_t dup = 0;
#ifdef PLATFORM_HAS_DYNMEM
iotx_mc_topic_handle_t *node;
#endif
HAL_MutexLock(c->lock_generic);
#ifdef PLATFORM_HAS_DYNMEM
#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG)
#if WITH_MQTT_ZIP_TOPIC
HEXDUMP_DEBUG(handler->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN);
#else
mqtt_warning("handler->topic: %s", handler->topic_filter);
#endif
#endif
list_for_each_entry(node, &c->list_sub_handle, linked_list, iotx_mc_topic_handle_t) {
/* If subscribe the same topic and callback function, then ignore */
#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG)
#if WITH_MQTT_ZIP_TOPIC
HEXDUMP_DEBUG(node->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN);
#else
mqtt_warning("node->topic: %s", node->topic_filter);
#endif
#endif
if (0 == iotx_mc_check_handle_is_identical(node, handler)) {
mqtt_warning("dup sub,topic = %s", topicFilter);
dup = 1;
}
}
#else
for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) {
/* If subscribe the same topic and callback function, then ignore */
if (&c->list_sub_handle[idx] != handler &&
0 == iotx_mc_check_handle_is_identical(&c->list_sub_handle[idx], handler)) {
mqtt_warning("dup sub,topic = %s", topicFilter);
dup = 1;
}
}
#endif
if (dup == 0) {
#ifdef PLATFORM_HAS_DYNMEM
list_add_tail(&handler->linked_list, &c->list_sub_handle);
#endif
} else {
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#else
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
#endif
}
HAL_MutexUnlock(c->lock_generic);
return STATE_SUCCESS;
}
HAL_MutexLock(c->lock_write_buf);
res = _alloc_send_buffer(c, strlen(topicFilter));
if (res < STATE_SUCCESS) {
HAL_MutexUnlock(c->lock_write_buf);
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#else
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
#endif
return res;
}
len = MQTTSerialize_subscribe((unsigned char *)c->buf_send, c->buf_size_send, 0, (unsigned short)msgId, 1, &topic,
&tmpqos);
if (len <= 0) {
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#else
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
#endif
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
return STATE_MQTT_SERIALIZE_SUB_ERROR;
}
mqtt_debug("%20s : %08d", "Packet Ident", msgId);
mqtt_debug("%20s : %s", "Topic", topicFilter);
mqtt_debug("%20s : %d", "QoS", tmpqos);
mqtt_debug("%20s : %d", "Packet Length", len);
#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG)
HEXDUMP_DEBUG(c->buf_send, len);
#endif
if ((iotx_mc_send_packet(c, c->buf_send, len, &timer)) != STATE_SUCCESS) { /* send the subscribe packet */
/* If send failed, remove it */
mqtt_err("run sendPacket error!");
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#else
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
#endif
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
return STATE_SYS_DEPEND_NWK_CLOSE;
}
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
{
uint8_t dup = 0;
#ifdef PLATFORM_HAS_DYNMEM
iotx_mc_topic_handle_t *node;
#endif
HAL_MutexLock(c->lock_generic);
#ifdef PLATFORM_HAS_DYNMEM
#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG)
#if WITH_MQTT_ZIP_TOPIC
HEXDUMP_DEBUG(handler->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN);
#else
mqtt_warning("handler->topic: %s", handler->topic_filter);
#endif
#endif
list_for_each_entry(node, &c->list_sub_handle, linked_list, iotx_mc_topic_handle_t) {
/* If subscribe the same topic and callback function, then ignore */
#if defined(INSPECT_MQTT_FLOW) && defined (INFRA_LOG)
#if WITH_MQTT_ZIP_TOPIC
HEXDUMP_DEBUG(node->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN);
#else
mqtt_warning("node->topic: %s", node->topic_filter);
#endif
#endif
if (0 == iotx_mc_check_handle_is_identical(node, handler)) {
mqtt_warning("dup sub,topic = %s", topicFilter);
dup = 1;
}
}
#else
for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) {
/* If subscribe the same topic and callback function, then ignore */
if (&c->list_sub_handle[idx] != handler &&
0 == iotx_mc_check_handle_is_identical(&c->list_sub_handle[idx], handler)) {
mqtt_warning("dup sub,topic = %s", topicFilter);
dup = 1;
}
}
#endif
if (dup == 0) {
#ifdef PLATFORM_HAS_DYNMEM
list_add_tail(&handler->linked_list, &c->list_sub_handle);
#endif
} else {
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#else
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
#endif
}
HAL_MutexUnlock(c->lock_generic);
}
return STATE_SUCCESS;
}
static int iotx_mc_get_next_packetid(iotx_mc_client_t *c)
{
unsigned int id = 0;
if (!c) {
return STATE_USER_INPUT_INVALID;
}
HAL_MutexLock(c->lock_generic);
c->packet_id = (c->packet_id == IOTX_MC_PACKET_ID_MAX) ? 1 : c->packet_id + 1;
id = c->packet_id;
HAL_MutexUnlock(c->lock_generic);
return id;
}
static int iotx_mc_check_rule(char *iterm, iotx_mc_topic_type_t type)
{
int i = 0;
int len = 0;
if (NULL == iterm) {
mqtt_err("iterm is NULL");
return STATE_USER_INPUT_INVALID;
}
len = strlen(iterm);
for (i = 0; i < len; i++) {
if (TOPIC_FILTER_TYPE == type) {
if ('+' == iterm[i] || '#' == iterm[i]) {
if (1 != len) {
mqtt_err("the character # and + is error");
return STATE_MQTT_UNEXP_TOPIC_FORMAT;
}
}
} else {
if ('+' == iterm[i] || '#' == iterm[i]) {
mqtt_err("has character # and + is error");
return STATE_MQTT_UNEXP_TOPIC_FORMAT;
}
}
if (iterm[i] < 32 || iterm[i] >= 127) {
return STATE_MQTT_UNEXP_TOPIC_FORMAT;
}
}
return STATE_SUCCESS;
}
static int iotx_mc_check_topic(const char *topicName, iotx_mc_topic_type_t type)
{
int mask = 0, res = 0;
char *delim = "/";
char *iterm = NULL;
char topicString[CONFIG_MQTT_TOPIC_MAXLEN];
if (NULL == topicName || '/' != topicName[0]) {
return STATE_MQTT_UNEXP_TOPIC_FORMAT;
}
if (strlen(topicName) > CONFIG_MQTT_TOPIC_MAXLEN) {
mqtt_err("len of topicName exceeds %d", CONFIG_MQTT_TOPIC_MAXLEN);
return STATE_MQTT_TOPIC_BUF_TOO_SHORT;
}
memset(topicString, 0x0, CONFIG_MQTT_TOPIC_MAXLEN);
strncpy(topicString, topicName, CONFIG_MQTT_TOPIC_MAXLEN - 1);
iterm = infra_strtok(topicString, delim);
res = iotx_mc_check_rule(iterm, type);
if (res < STATE_SUCCESS) {
mqtt_err("run iotx_check_rule error");
return res;
}
for (;;) {
iterm = infra_strtok(NULL, delim);
if (iterm == NULL) {
break;
}
/* The character '#' is not in the last */
if (1 == mask) {
mqtt_err("the character # is error");
return STATE_MQTT_UNEXP_TOPIC_FORMAT;
}
res = iotx_mc_check_rule(iterm, type);
if (res < STATE_SUCCESS) {
mqtt_err("run iotx_check_rule error");
return res;
}
if (iterm[0] == '#') {
mask = 1;
}
}
return STATE_SUCCESS;
}
static inline int _is_in_yield_cb()
{
return _in_yield_cb;
}
static int MQTTUnsubscribe(iotx_mc_client_t *c, const char *topicFilter, unsigned int msgId)
{
MQTTString cur_topic;
iotx_time_t timer;
MQTTString topic = MQTTString_initializer;
int len = 0, res = 0;
/*iotx_mc_topic_handle_t handler = {topicFilter, {NULL, NULL}};*/
iotx_mc_topic_handle_t *handler = NULL;
#ifdef PLATFORM_HAS_DYNMEM
iotx_mc_topic_handle_t *node = NULL;
iotx_mc_topic_handle_t *next = NULL;
#else
int idx = 0;
iotx_mc_topic_handle_t s_handler;
#endif
if (!c || !topicFilter) {
return STATE_USER_INPUT_INVALID;
}
topic.cstring = (char *)topicFilter;
iotx_time_init(&timer);
utils_time_countdown_ms(&timer, c->request_timeout_ms);
#ifdef PLATFORM_HAS_DYNMEM
handler = mqtt_malloc(sizeof(iotx_mc_topic_handle_t));
if (NULL == handler) {
return STATE_SYS_DEPEND_MALLOC;
}
#else
handler = &s_handler;
#endif
memset(handler, 0, sizeof(iotx_mc_topic_handle_t));
#if !(WITH_MQTT_ZIP_TOPIC)
#ifdef PLATFORM_HAS_DYNMEM
handler->topic_filter = mqtt_malloc(strlen(topicFilter) + 1);
if (NULL == handler->topic_filter) {
mqtt_free(handler);
return STATE_SYS_DEPEND_MALLOC;
}
memset((char *)handler->topic_filter, 0, strlen(topicFilter) + 1);
#else
if (strlen(topicFilter) >= CONFIG_MQTT_TOPIC_MAXLEN) {
return MQTT_TOPIC_LEN_TOO_SHORT;
}
memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN);
#endif
memcpy((char *)handler->topic_filter, topicFilter, strlen(topicFilter) + 1);
#else
if (strstr(topicFilter, "/+") != NULL || strstr(topicFilter, "/#") != NULL) {
#ifdef PLATFORM_HAS_DYNMEM
handler->topic_filter = mqtt_malloc(strlen(topicFilter) + 1);
if (NULL == handler->topic_filter) {
mqtt_free(handler);
return STATE_SYS_DEPEND_MALLOC;
}
memset((char *)handler->topic_filter, 0, strlen(topicFilter) + 1);
#else
if (strlen(topicFilter) >= CONFIG_MQTT_TOPIC_MAXLEN) {
return MQTT_TOPIC_LEN_TOO_SHORT;
}
memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN);
#endif
handler->topic_type = TOPIC_FILTER_TYPE;
memcpy((char *)handler->topic_filter, topicFilter, strlen(topicFilter) + 1);
} else {
#ifdef PLATFORM_HAS_DYNMEM
handler->topic_filter = mqtt_malloc(MQTT_ZIP_PATH_DEFAULT_LEN);
if (NULL == handler->topic_filter) {
mqtt_free(handler);
return STATE_SYS_DEPEND_MALLOC;
}
memset((char *)handler->topic_filter, 0, MQTT_ZIP_PATH_DEFAULT_LEN);
#else
if (MQTT_ZIP_PATH_DEFAULT_LEN >= CONFIG_MQTT_TOPIC_MAXLEN) {
return MQTT_TOPIC_LEN_TOO_SHORT;
}
memset((char *)handler->topic_filter, 0, CONFIG_MQTT_TOPIC_MAXLEN);
#endif
handler->topic_type = TOPIC_NAME_TYPE;
res = iotx_mc_get_zip_topic(topicFilter, strlen(topicFilter), (char *)handler->topic_filter, MQTT_ZIP_PATH_DEFAULT_LEN);
if (res < STATE_SUCCESS) {
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#endif
return res;
}
}
#endif
HAL_MutexLock(c->lock_write_buf);
res = _alloc_send_buffer(c, strlen(topicFilter));
if (res < STATE_SUCCESS) {
HAL_MutexUnlock(c->lock_write_buf);
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#endif
return res;
}
if ((len = MQTTSerialize_unsubscribe((unsigned char *)c->buf_send, c->buf_size_send, 0, (unsigned short)msgId, 1,
&topic)) <= 0) {
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#endif
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
return STATE_MQTT_SERIALIZE_UNSUB_ERROR;
}
if ((iotx_mc_send_packet(c, c->buf_send, len, &timer)) != STATE_SUCCESS) { /* send the subscribe packet */
#ifdef PLATFORM_HAS_DYNMEM
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#endif
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
return STATE_SYS_DEPEND_NWK_CLOSE;
}
cur_topic.cstring = NULL;
cur_topic.lenstring.data = (char *)handler->topic_filter;
#if !(WITH_MQTT_ZIP_TOPIC)
cur_topic.lenstring.len = strlen(handler->topic_filter) + 1;
#else
if (handler->topic_type == TOPIC_FILTER_TYPE) {
cur_topic.lenstring.len = strlen(handler->topic_filter) + 1;
} else {
cur_topic.lenstring.len = MQTT_ZIP_PATH_DEFAULT_LEN;
}
#endif
/* we have to find the right message handler - indexed by topic */
HAL_MutexLock(c->lock_generic);
#ifdef PLATFORM_HAS_DYNMEM
list_for_each_entry_safe(node, next, &c->list_sub_handle, linked_list, iotx_mc_topic_handle_t) {
if (MQTTPacket_equals(&cur_topic, (char *)node->topic_filter)
|| iotx_mc_is_topic_matched((char *)node->topic_filter, &cur_topic)) {
mqtt_debug("topic be matched");
list_del(&node->linked_list);
mqtt_free(node->topic_filter);
mqtt_free(node);
}
}
mqtt_free(handler->topic_filter);
mqtt_free(handler);
#else
for (idx = 0; idx < IOTX_MC_SUBHANDLE_LIST_MAX_LEN; idx++) {
if ((c->list_sub_handle[idx].used == 1) &&
(MQTTPacket_equals(&cur_topic, (char *)c->list_sub_handle[idx].topic_filter) ||
iotx_mc_is_topic_matched((char *)c->list_sub_handle[idx].topic_filter, &cur_topic))) {
mqtt_debug("topic be matched");
memset(&c->list_sub_handle[idx], 0, sizeof(iotx_mc_topic_handle_t));
}
}
#endif
HAL_MutexUnlock(c->lock_generic);
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
return STATE_SUCCESS;
}
int MQTTPublish(iotx_mc_client_t *c, const char *topicName, iotx_mqtt_topic_info_pt topic_msg)
{
int res = 0;
iotx_time_t timer;
MQTTString topic = MQTTString_initializer;
int len = 0;
#if !WITH_MQTT_ONLY_QOS0
iotx_mc_pub_info_t *node = NULL;
#endif
#ifdef INFRA_LOG_NETWORK_PAYLOAD
const char *json_payload = NULL;
#endif
if (!c || !topicName || !topic_msg) {
return STATE_USER_INPUT_INVALID;
}
topic.cstring = (char *)topicName;
iotx_time_init(&timer);
utils_time_countdown_ms(&timer, c->request_timeout_ms);
HAL_MutexLock(c->lock_list_pub);
HAL_MutexLock(c->lock_write_buf);
res = _alloc_send_buffer(c, strlen(topicName) + topic_msg->payload_len);
if (res < STATE_SUCCESS) {
HAL_MutexUnlock(c->lock_write_buf);
HAL_MutexUnlock(c->lock_list_pub);
return res;
}
len = MQTTSerialize_publish((unsigned char *)c->buf_send,
c->buf_size_send,
0,
topic_msg->qos,
topic_msg->retain,
topic_msg->packet_id,
topic,
(unsigned char *)topic_msg->payload,
topic_msg->payload_len);
if (len <= 0) {
mqtt_err("MQTTSerialize_publish is error, len=%d, buf_size_send=%u, payloadlen=%u",
len,
c->buf_size_send,
topic_msg->payload_len);
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
HAL_MutexUnlock(c->lock_list_pub);
return STATE_MQTT_SERIALIZE_PUB_ERROR;
}
#if !WITH_MQTT_ONLY_QOS0
node = NULL;
/* If the QOS >1, push the information into list of wait publish ACK */
if (topic_msg->qos > IOTX_MQTT_QOS0) {
/* push into list */
res = iotx_mc_push_pubInfo_to(c, len, topic_msg->packet_id, &node);
if (res < STATE_SUCCESS) {
mqtt_err("push publish into to pubInfolist failed!");
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
HAL_MutexUnlock(c->lock_list_pub);
return res;
}
}
#endif
/* send the publish packet */
if (iotx_mc_send_packet(c, c->buf_send, len, &timer) != STATE_SUCCESS) {
#if !WITH_MQTT_ONLY_QOS0
if (topic_msg->qos > IOTX_MQTT_QOS0) {
/* If not even successfully sent to IP stack, meaningless to wait QOS1 ack, give up waiting */
#ifdef PLATFORM_HAS_DYNMEM
list_del(&node->linked_list);
mqtt_free(node);
#else
memset(node, 0, sizeof(iotx_mc_pub_info_t));
#endif
}
#endif
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
HAL_MutexUnlock(c->lock_list_pub);
return STATE_SYS_DEPEND_NWK_CLOSE;
}
#ifdef INFRA_LOG_NETWORK_PAYLOAD
json_payload = (const char *)topic_msg->payload;
mqtt_info("Upstream Topic: '%s'", topicName);
mqtt_info("Upstream Payload:");
iotx_facility_json_print(json_payload, LOG_INFO_LEVEL, '>');
#endif /* #ifdef INFRA_LOG */
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
HAL_MutexUnlock(c->lock_list_pub);
return STATE_SUCCESS;
}
static int MQTTDisconnect(iotx_mc_client_t *c)
{
int rc = STATE_SUCCESS;
int len = 0, res = 0;
iotx_time_t timer; /* we might wait for incomplete incoming publishes to complete */
if (!c) {
return STATE_USER_INPUT_INVALID;
}
HAL_MutexLock(c->lock_write_buf);
res = _alloc_send_buffer(c, 0);
if (res < STATE_SUCCESS) {
HAL_MutexUnlock(c->lock_write_buf);
return res;
}
len = MQTTSerialize_disconnect((unsigned char *)c->buf_send, c->buf_size_send);
iotx_time_init(&timer);
utils_time_countdown_ms(&timer, c->request_timeout_ms);
if (len > 0) {
rc = iotx_mc_send_packet(c, c->buf_send, len, &timer); /* send the disconnect packet */
}
_reset_send_buffer(c);
HAL_MutexUnlock(c->lock_write_buf);
return rc;
}
static int iotx_mc_disconnect(iotx_mc_client_t *pClient)
{
int rc = -1;
if (NULL == pClient) {
return STATE_USER_INPUT_INVALID;
}
if (wrapper_mqtt_check_state(pClient)) {
rc = MQTTDisconnect(pClient);
mqtt_debug("rc = MQTTDisconnect() = %d", rc);
rc = rc;
}
/* close tcp/ip socket or free tls resources */
pClient->ipstack.disconnect(&pClient->ipstack);
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_INITIALIZED);
mqtt_info("mqtt disconnect!");
return STATE_SUCCESS;
}
/************************ Public Interface ************************/
void *wrapper_mqtt_init(iotx_mqtt_param_t *mqtt_params)
{
int err;
iotx_mc_client_t *pclient = NULL;
#ifndef PLATFORM_HAS_DYNMEM
int idx;
#endif
#ifdef PLATFORM_HAS_DYNMEM
pclient = (iotx_mc_client_t *)mqtt_malloc(sizeof(iotx_mc_client_t));
if (NULL == pclient) {
iotx_state_event(ITE_STATE_MQTT_COMM, STATE_SYS_DEPEND_MALLOC, "");
return NULL;
}
memset(pclient, 0, sizeof(iotx_mc_client_t));
#else
for (idx = 0; idx < IOTX_MC_CLIENT_MAX_COUNT; idx++) {
if (g_iotx_mc_client[idx].used == 0) {
g_iotx_mc_client[idx].used = 1;
pclient = &g_iotx_mc_client[idx];
break;
}
}
if (NULL == pclient) {
iotx_state_event(ITE_STATE_MQTT_COMM, STATE_MQTT_CLI_EXCEED_MAX, "");
return NULL;
}
#endif
err = iotx_mc_init(pclient, mqtt_params);
if (err < STATE_SUCCESS) {
iotx_state_event(ITE_STATE_MQTT_COMM, err, "iotx_mc_init fail");
iotx_mc_release(pclient);
return NULL;
}
return pclient;
}
int _mqtt_nwk_connect(void *client)
{
int rc = STATE_SUCCESS;
int retry_max = 3;
int retry_cnt = 1;
int retry_interval = 1000;
iotx_mc_client_t *pClient = (iotx_mc_client_t *)client;
/* Establish TCP or TLS connection */
do {
mqtt_debug("calling TCP or TLS connect HAL for [%d/%d] iteration", retry_cnt, retry_max);
rc = pClient->ipstack.connect(&pClient->ipstack);
if (STATE_SUCCESS != rc) {
pClient->ipstack.disconnect(&pClient->ipstack);
mqtt_err("TCP or TLS Connection failed");
if (ERROR_CERTIFICATE_EXPIRED == rc) {
mqtt_err("certificate is expired! rc = %d", rc);
rc = ERROR_CERT_VERIFY_FAIL;
HAL_SleepMs(retry_interval);
continue;
} else {
rc = STATE_SYS_DEPEND_NWK_CLOSE;
HAL_SleepMs(retry_interval);
continue;
}
} else {
mqtt_debug("rc = pClient->ipstack.connect() = %d, success @ [%d/%d] iteration", rc, retry_cnt, retry_max);
break;
}
} while (++retry_cnt <= retry_max);
return rc;
}
int wrapper_mqtt_connect(void *client)
{
int rc = STATE_SUCCESS;
#ifndef ASYNC_PROTOCOL_STACK
int try_count = 0;
char product_key[IOTX_PRODUCT_KEY_LEN + 1] = {0};
char device_name[IOTX_DEVICE_NAME_LEN + 1] = {0};
#endif
iotx_mc_client_t *pClient = (iotx_mc_client_t *)client;
if (NULL == pClient) {
return STATE_USER_INPUT_INVALID;
}
rc = _mqtt_nwk_connect(client);
if (rc != STATE_SUCCESS) {
return rc;
}
#ifdef ASYNC_PROTOCOL_STACK
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_CONNECT_BLOCK);
rc = STATE_MQTT_ASYNC_STACK_CONN_IN_PROG;
#else
rc = _mqtt_connect(pClient);
do {
HAL_MutexLock(pClient->lock_yield);
pClient->cycle_timeout_ms = 500;
HAL_MutexUnlock(pClient->lock_yield);
IOT_Ioctl(IOTX_IOCTL_GET_PRODUCT_KEY, product_key);
IOT_Ioctl(IOTX_IOCTL_GET_DEVICE_NAME, device_name);
if (strlen(product_key) != 0 && strlen(device_name) != 0) {
break;
}
_mqtt_cycle(client);
} while (++try_count < RETRY_TIME_LIMIT);
#endif
return rc;
}
int wrapper_mqtt_release(void **c)
{
iotx_mc_client_t *pClient;
#ifdef PLATFORM_HAS_DYNMEM
iotx_mc_topic_handle_t *node = NULL, *next = NULL;
#endif
if (NULL == c) {
return STATE_USER_INPUT_INVALID;
}
pClient = (iotx_mc_client_t *)*c;
if (NULL == pClient) {
return STATE_USER_INPUT_INVALID;
}
/* iotx_delete_thread(pClient); */
HAL_SleepMs(100);
iotx_mc_disconnect(pClient);
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_INVALID);
HAL_SleepMs(100);
#ifdef PLATFORM_HAS_DYNMEM
list_for_each_entry_safe(node, next, &pClient->list_sub_handle, linked_list, iotx_mc_topic_handle_t) {
list_del(&node->linked_list);
mqtt_free(node->topic_filter);
mqtt_free(node);
}
#else
memset(pClient->list_sub_handle, 0, sizeof(iotx_mc_topic_handle_t) * IOTX_MC_SUBHANDLE_LIST_MAX_LEN);
#endif
HAL_MutexDestroy(pClient->lock_generic);
HAL_MutexDestroy(pClient->lock_list_pub);
HAL_MutexDestroy(pClient->lock_write_buf);
HAL_MutexDestroy(pClient->lock_yield);
HAL_MutexDestroy(pClient->lock_read_buf);
#if !WITH_MQTT_ONLY_QOS0
iotx_mc_pub_wait_list_deinit(pClient);
#endif
#ifdef PLATFORM_HAS_DYNMEM
if (pClient->buf_send != NULL) {
mqtt_free(pClient->buf_send);
pClient->buf_send = NULL;
}
if (pClient->buf_read != NULL) {
mqtt_free(pClient->buf_read);
pClient->buf_read = NULL;
}
mqtt_free(pClient);
#else
memset(pClient, 0, sizeof(iotx_mc_client_t));
#endif
*c = NULL;
mqtt_info("mqtt release!");
return STATE_SUCCESS;
}
int wrapper_mqtt_yield(void *client, int timeout_ms)
{
iotx_mc_client_t *pClient = (iotx_mc_client_t *)client;
if (pClient == NULL) {
return STATE_USER_INPUT_INVALID;
}
if (timeout_ms < 0) {
mqtt_err("Invalid argument, timeout_ms = %d", timeout_ms);
return STATE_USER_INPUT_INVALID;
}
if (timeout_ms == 0) {
timeout_ms = 10;
}
HAL_MutexLock(pClient->lock_yield);
pClient->cycle_timeout_ms = timeout_ms;
/* Keep MQTT alive or reconnect if connection abort */
iotx_mc_keepalive(pClient);
HAL_MutexUnlock(pClient->lock_yield);
#ifndef ASYNC_PROTOCOL_STACK
_mqtt_cycle(client);
#else
if (pClient->client_state == IOTX_MC_STATE_CONNECTED) {
#if !WITH_MQTT_ONLY_QOS0
/* check list of wait publish ACK to remove node that is ACKED or timeout */
MQTTPubInfoProc(pClient);
#endif
}
HAL_SleepMs(timeout_ms);
#endif
return STATE_SUCCESS;
}
/* check MQTT client is in normal state */
/* 0, in abnormal state; 1, in normal state */
int wrapper_mqtt_check_state(void *client)
{
if (!client) {
return 0;
}
if (iotx_mc_get_client_state((iotx_mc_client_t *)client) == IOTX_MC_STATE_CONNECTED) {
return 1;
}
return 0;
}
int wrapper_mqtt_subscribe(void *client,
const char *topicFilter,
iotx_mqtt_qos_t qos,
iotx_mqtt_event_handle_func_fpt topic_handle_func,
void *pcontext)
{
int rc = STATE_SUCCESS;
unsigned int msgId;
iotx_mc_client_t *c;
if (NULL == client || NULL == topicFilter || strlen(topicFilter) == 0 || !topic_handle_func) {
mqtt_err(" paras error");
return STATE_USER_INPUT_INVALID;
}
c = (iotx_mc_client_t *)client;
msgId = iotx_mc_get_next_packetid(c);
if (!wrapper_mqtt_check_state(c)) {
mqtt_err("mqtt client state is error,state = %d", iotx_mc_get_client_state(c));
return STATE_MQTT_IN_OFFLINE_STATUS;
}
rc = iotx_mc_check_topic(topicFilter, TOPIC_FILTER_TYPE);
if (rc < STATE_SUCCESS) {
mqtt_err("topic format is error,topicFilter = %s", topicFilter);
return rc;
}
mqtt_debug("PERFORM subscribe to '%s' (msgId=%d)", topicFilter, msgId);
rc = MQTTSubscribe(c, topicFilter, qos, msgId, topic_handle_func, pcontext);
if (rc < STATE_SUCCESS) {
if (rc == STATE_SYS_DEPEND_NWK_CLOSE) {
iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED);
}
mqtt_err("run MQTTSubscribe error, rc = %d", rc);
return rc;
}
mqtt_info("mqtt subscribe packet sent,topic = %s!", topicFilter);
return msgId;
}
int wrapper_mqtt_subscribe_sync(void *c,
const char *topic_filter,
iotx_mqtt_qos_t qos,
iotx_mqtt_event_handle_func_fpt topic_handle_func,
void *pcontext,
int timeout_ms)
{
int subed;
int ret;
iotx_time_t timer;
iotx_mc_client_t *client = (iotx_mc_client_t *)c;
int cnt = 0;
mqtt_sub_sync_node_t *node = NULL;
#ifdef PLATFORM_HAS_DYNMEM
mqtt_sub_sync_node_t *next = NULL;
#else
int idx = 0;
#endif
if (client == NULL) {
return STATE_USER_INPUT_INVALID;
}
if (qos > IOTX_MQTT_QOS3_SUB_LOCAL) {
mqtt_warning("Invalid qos(%d) out of [%d, %d], using %d",
qos,
IOTX_MQTT_QOS0, IOTX_MQTT_QOS3_SUB_LOCAL, IOTX_MQTT_QOS0);
qos = IOTX_MQTT_QOS0;
}
iotx_time_init(&timer);
utils_time_countdown_ms(&timer, timeout_ms);
ret = -1;
subed = 0;
cnt = 0;
cnt = cnt;
do {
#ifdef PLATFORM_HAS_DYNMEM
mqtt_sub_sync_node_t *node = NULL;
mqtt_sub_sync_node_t *next = NULL;
#else
int idx = 0;
#endif
if (ret < 0) {
ret = wrapper_mqtt_subscribe(client, topic_filter, qos, topic_handle_func, pcontext);
if (_is_in_yield_cb() != 0 || qos == IOTX_MQTT_QOS3_SUB_LOCAL) {
return ret;
}
}
if (!subed && ret >= 0) {
mqtt_sub_sync_node_t *node = NULL;
#ifndef PLATFORM_HAS_DYNMEM
int idx = 0;
#endif
#ifdef PLATFORM_HAS_DYNMEM
node = (mqtt_sub_sync_node_t *)mqtt_malloc(sizeof(mqtt_sub_sync_node_t));
#else
for (idx = 0; idx < IOTX_MC_SUBSYNC_LIST_MAX_LEN; idx++) {
if (client->list_sub_sync_ack[idx].used == 0) {
memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t));
client->list_sub_sync_ack[idx].used = 1;
node = &client->list_sub_sync_ack[idx];
break;
}
}
#endif
if (node != NULL) {
mqtt_debug("packet_id = %d", ret);
node->packet_id = ret;
node->ack_type = IOTX_MQTT_EVENT_UNDEF;
#ifdef PLATFORM_HAS_DYNMEM
HAL_MutexLock(client->lock_generic);
list_add_tail(&node->linked_list, &client->list_sub_sync_ack);
HAL_MutexUnlock(client->lock_generic);
#endif
subed = 1;
}
}
wrapper_mqtt_yield(client, 100);
HAL_MutexLock(client->lock_generic);
#ifdef PLATFORM_HAS_DYNMEM
list_for_each_entry_safe(node, next, &client->list_sub_sync_ack, linked_list, mqtt_sub_sync_node_t) {
if (node->packet_id == ret) {
mqtt_debug("node->ack_type=%d cnt=%d", node->ack_type, cnt++);
if (node->ack_type == IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS) {
list_del(&node->linked_list);
mqtt_free(node);
mqtt_debug("success!!");
HAL_MutexUnlock(client->lock_generic);
return ret;
} else if (node->ack_type == IOTX_MQTT_EVENT_SUBCRIBE_NACK) {
list_del(&node->linked_list);
mqtt_free(node);
ret = -1; /* resub */
subed = 0;
} else if (node->ack_type == IOTX_MQTT_EVENT_SUBCRIBE_TIMEOUT) {
list_del(&node->linked_list);
mqtt_free(node);
ret = -1; /* resub */
subed = 0;
}
}
break;
}
#else
for (idx = 0; idx < IOTX_MC_SUBSYNC_LIST_MAX_LEN; idx++) {
if (client->list_sub_sync_ack[idx].used == 0) {
continue;
}
if (client->list_sub_sync_ack[idx].packet_id == ret) {
mqtt_debug("client->list_sub_sync_ack[%d].ack_type=%d cnt=%d", idx, client->list_sub_sync_ack[idx].ack_type, cnt++);
if (client->list_sub_sync_ack[idx].ack_type == IOTX_MQTT_EVENT_SUBCRIBE_SUCCESS) {
memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t));
mqtt_debug("success!!");
HAL_MutexUnlock(client->lock_generic);
return ret;
} else if (client->list_sub_sync_ack[idx].ack_type == IOTX_MQTT_EVENT_SUBCRIBE_NACK) {
memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t));
ret = -1; /* resub */
subed = 0;
} else if (client->list_sub_sync_ack[idx].ack_type == IOTX_MQTT_EVENT_SUBCRIBE_TIMEOUT) {
memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t));
ret = -1; /* resub */
subed = 0;
}
}
break;
}
#endif
HAL_MutexUnlock(client->lock_generic);
} while (!utils_time_is_expired(&timer));
mqtt_warning("sync subscribe time out!!");
HAL_MutexLock(client->lock_generic);
#ifdef PLATFORM_HAS_DYNMEM
list_for_each_entry_safe(node, next, &client->list_sub_sync_ack, linked_list, mqtt_sub_sync_node_t) {
if (node->packet_id == ret) {
list_del(&node->linked_list);
mqtt_free(node);
}
}
#else
for (idx = 0; idx < IOTX_MC_SUBSYNC_LIST_MAX_LEN; idx++) {
if (client->list_sub_sync_ack[idx].used && node->packet_id == ret) {
memset(&client->list_sub_sync_ack[idx], 0, sizeof(mqtt_sub_sync_node_t));
}
}
#endif
HAL_MutexUnlock(client->lock_generic);
return STATE_MQTT_SYNC_SUB_TIMEOUT;
}
int wrapper_mqtt_unsubscribe(void *client, const char *topicFilter)
{
int rc = STATE_SUCCESS;
iotx_mc_client_t *c = (iotx_mc_client_t *)client;
unsigned int msgId;
if (NULL == c || NULL == topicFilter) {
return STATE_USER_INPUT_INVALID;
}
msgId = iotx_mc_get_next_packetid(c);
rc = iotx_mc_check_topic(topicFilter, TOPIC_FILTER_TYPE);
if (rc < STATE_SUCCESS) {
mqtt_err("topic format is error,topicFilter = %s", topicFilter);
return rc;
}
if (!wrapper_mqtt_check_state(c)) {
mqtt_err("mqtt client state is error,state = %d", iotx_mc_get_client_state(c));
return STATE_MQTT_IN_OFFLINE_STATUS;
}
rc = MQTTUnsubscribe(c, topicFilter, msgId);
if (rc < STATE_SUCCESS) {
if (rc == STATE_SYS_DEPEND_NWK_CLOSE) { /* send the subscribe packet */
iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED);
}
mqtt_err("run MQTTUnsubscribe error!, rc = %d", rc);
return rc;
}
mqtt_info("mqtt unsubscribe packet sent,topic = %s!", topicFilter);
return (int)msgId;
}
int wrapper_mqtt_publish(void *client, const char *topicName, iotx_mqtt_topic_info_pt topic_msg)
{
uint16_t msg_id = 0;
int rc = STATE_SUCCESS;
iotx_mc_client_t *c = (iotx_mc_client_t *)client;
if (c == NULL || topicName == NULL || topic_msg == NULL || topic_msg->payload == NULL) {
return STATE_USER_INPUT_INVALID;
}
rc = iotx_mc_check_topic(topicName, TOPIC_NAME_TYPE);
if (rc < STATE_SUCCESS) {
mqtt_err("topic format is error,topicFilter = %s", topicName);
return rc;
}
if (!wrapper_mqtt_check_state(c)) {
mqtt_err("mqtt client state is error,state = %d", iotx_mc_get_client_state(c));
return STATE_MQTT_IN_OFFLINE_STATUS;
}
#if !WITH_MQTT_ONLY_QOS0
if (topic_msg->qos == IOTX_MQTT_QOS1 || topic_msg->qos == IOTX_MQTT_QOS2) {
msg_id = iotx_mc_get_next_packetid(c);
topic_msg->packet_id = msg_id;
}
if (topic_msg->qos == IOTX_MQTT_QOS2) {
mqtt_err("MQTTPublish return error,MQTT_QOS2 is now not supported.");
return STATE_MQTT_PUB_QOS_INVALID;
}
#else
topic_msg->qos = IOTX_MQTT_QOS0;
#endif
#if defined(INSPECT_MQTT_FLOW) && defined(INFRA_LOG)
HEXDUMP_DEBUG(topicName, strlen(topicName));
HEXDUMP_DEBUG(topic_msg->payload, topic_msg->payload_len);
#endif
rc = MQTTPublish(c, topicName, topic_msg);
if (rc < STATE_SUCCESS) { /* send the subscribe packet */
if (rc == STATE_SYS_DEPEND_NWK_CLOSE) {
iotx_mc_set_client_state(c, IOTX_MC_STATE_DISCONNECTED);
}
mqtt_err("MQTTPublish is error, rc = %d", rc);
return rc;
}
return (int)msg_id;
}
#ifdef ASYNC_PROTOCOL_STACK
int wrapper_mqtt_nwk_event_handler(void *client, iotx_mqtt_nwk_event_t event, iotx_mqtt_nwk_param_t *param)
{
int rc = STATE_SUCCESS;
iotx_mc_client_t *pClient = (iotx_mc_client_t *)client;
if (client == NULL || event >= IOTX_MQTT_SOC_MAX) {
return STATE_USER_INPUT_INVALID;
}
switch (event) {
case IOTX_MQTT_SOC_CONNECTED: {
rc = _mqtt_connect(pClient);
if (rc == STATE_SUCCESS) {
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_CONNECTED);
}
}
break;
case IOTX_MQTT_SOC_CLOSE: {
iotx_mc_set_client_state(pClient, IOTX_MC_STATE_DISCONNECTED);
}
break;
case IOTX_MQTT_SOC_READ: {
HAL_MutexLock(pClient->lock_yield);
_mqtt_cycle(pClient);
HAL_MutexUnlock(pClient->lock_yield);
rc = STATE_SUCCESS;
}
break;
case IOTX_MQTT_SOC_WRITE: {
}
break;
default: {
mqtt_err("unknown event: %d", event);
rc = STATE_MQTT_ASYNC_STACK_UNKNOWN_EVENT;
}
break;
}
return rc;
}
#endif