EC600U_esp32_iap_uart/LinkSDK/components/dynreg-mqtt/aiot_dynregmq_api.c

504 lines
19 KiB
C
Raw Normal View History

2024-02-05 17:39:56 +08:00
/**
* @file aiot_dynregmq_api.c
* @brief dynregmq模块的API接口实现,
*
* @copyright Copyright (C) 2015-2020 Alibaba Group Holding Limited
*
*/
#include "dynregmq_private.h"
#include "core_string.h"
#include "core_log.h"
#include "core_auth.h"
static void _dynregmq_exec_inc(dynregmq_handle_t *dynregmq_handle)
{
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
dynregmq_handle->exec_count++;
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
}
static void _dynregmq_exec_dec(dynregmq_handle_t *dynregmq_handle)
{
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
dynregmq_handle->exec_count--;
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
}
static void _dynregmq_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata)
{
dynregmq_handle_t *dynregmq_handle = (dynregmq_handle_t *)userdata;
if (dynregmq_handle->recv_handler == NULL) {
return;
}
switch (packet->type) {
case AIOT_MQTTRECV_PUB: {
char *topic = packet->data.pub.topic;
uint32_t topic_len = packet->data.pub.topic_len;
char *payload = (char *)packet->data.pub.payload;
uint32_t payload_len = packet->data.pub.payload_len;
const char *topic_register = "/ext/register";
const char *topic_regnwl = "/ext/regnwl";
if (strlen(topic_register) == topic_len && !memcmp(topic_register, topic, topic_len)) {
const char *key_ds = "deviceSecret";
char *ds = NULL;
uint32_t ds_len = 0;
core_json_value(payload, payload_len, key_ds, strlen(key_ds),
&ds, &ds_len);
if (ds == NULL || ds_len == 0) {
break;
}
dynregmq_handle->flag_completed = 1;
if (dynregmq_handle->recv_handler) {
aiot_dynregmq_recv_t recv_data;
memset(&recv_data, 0, sizeof(aiot_dynregmq_recv_t));
*(ds + ds_len) = 0;
recv_data.type = AIOT_DYNREGMQRECV_DEVICEINFO_WL;
recv_data.data.deviceinfo_wl.device_secret = ds;
dynregmq_handle->recv_handler(dynregmq_handle, &recv_data, dynregmq_handle->userdata);
}
} else if (strlen(topic_regnwl) == topic_len && !memcmp(topic_regnwl, topic, topic_len)) {
const char *key_clientid = "clientId";
const char *key_devicetoken = "deviceToken";
char *client_id = NULL;
char *device_token = NULL;
uint32_t client_id_len = 0;
uint32_t device_token_len = 0;
core_json_value(payload, payload_len, key_clientid, strlen(key_clientid), &client_id, &client_id_len);
core_json_value(payload, payload_len, key_devicetoken, strlen(key_devicetoken), &device_token, &device_token_len);
if (client_id == NULL || device_token == NULL || client_id_len == 0 || device_token_len == 0) {
break;
}
dynregmq_handle->flag_completed = 1;
if (dynregmq_handle->recv_handler) {
aiot_dynregmq_recv_t recv_data;
char *conn_clientid = NULL;
char *conn_username = NULL;
char *conn_username_fmt[] = { dynregmq_handle->device_name, dynregmq_handle->product_key };
*(client_id + client_id_len) = 0;
*(device_token + device_token_len) = 0;
core_sprintf(dynregmq_handle->sysdep, &conn_clientid, "%s|authType=connwl,securemode=-2,_ss=1,ext=3,_v="CORE_AUTH_SDK_VERSION"|",
&client_id, 1, DYNREGMQ_MODULE_NAME);
core_sprintf(dynregmq_handle->sysdep, &conn_username, "%s&%s",
conn_username_fmt, sizeof(conn_username_fmt) / sizeof(char *), DYNREGMQ_MODULE_NAME);
memset(&recv_data, 0, sizeof(aiot_dynregmq_recv_t));
recv_data.type = AIOT_DYNREGMQRECV_DEVICEINFO_NWL;
recv_data.data.deviceinfo_nwl.clientid = conn_clientid;
recv_data.data.deviceinfo_nwl.username = conn_username;
recv_data.data.deviceinfo_nwl.password = device_token;
dynregmq_handle->recv_handler(dynregmq_handle, &recv_data, dynregmq_handle->userdata);
dynregmq_handle->sysdep->core_sysdep_free(conn_clientid);
dynregmq_handle->sysdep->core_sysdep_free(conn_username);
}
}
}
break;
default: break;
}
}
void *aiot_dynregmq_init(void)
{
dynregmq_handle_t *dynregmq_handle = NULL;
aiot_sysdep_portfile_t *sysdep = NULL;
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
sysdep = aiot_sysdep_get_portfile();
if (sysdep == NULL) {
return NULL;
}
dynregmq_handle = sysdep->core_sysdep_malloc(sizeof(dynregmq_handle_t), DYNREGMQ_MODULE_NAME);
if (dynregmq_handle == NULL) {
return NULL;
}
memset(dynregmq_handle, 0, sizeof(dynregmq_handle_t));
dynregmq_handle->sysdep = sysdep;
dynregmq_handle->timeout_ms = DYNREGMQ_DEFAULT_TIMEOUT_MS;
dynregmq_handle->deinit_timeout_ms = DYNREGMQ_DEFAULT_DEINIT_TIMEOUT_MS;
dynregmq_handle->send_timeout_ms = DYNREGMQ_DEFAULT_SEND_TIMEOUT;
dynregmq_handle->recv_timeout_ms = DYNREGMQ_DEFAULT_RECV_TIMEOUT;
dynregmq_handle->data_mutex = dynregmq_handle->sysdep->core_sysdep_mutex_init();
dynregmq_handle->exec_enabled = 1;
return dynregmq_handle;
}
int32_t aiot_dynregmq_setopt(void *handle, aiot_dynregmq_option_t option, void *data)
{
int32_t res = STATE_SUCCESS;
dynregmq_handle_t *dynregmq_handle = (dynregmq_handle_t *)handle;
if (dynregmq_handle == NULL || data == NULL) {
return STATE_USER_INPUT_NULL_POINTER;
}
if (option >= AIOT_DYNREGMQOPT_MAX) {
return STATE_USER_INPUT_OUT_RANGE;
}
if (dynregmq_handle->exec_enabled == 0) {
return STATE_USER_INPUT_EXEC_DISABLED;
}
_dynregmq_exec_inc(dynregmq_handle);
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
switch (option) {
case AIOT_DYNREGMQOPT_NETWORK_CRED: {
if (dynregmq_handle->cred != NULL) {
dynregmq_handle->sysdep->core_sysdep_free(dynregmq_handle->cred);
dynregmq_handle->cred = NULL;
}
dynregmq_handle->cred = dynregmq_handle->sysdep->core_sysdep_malloc(sizeof(aiot_sysdep_network_cred_t),
DYNREGMQ_MODULE_NAME);
if (dynregmq_handle->cred != NULL) {
memset(dynregmq_handle->cred, 0, sizeof(aiot_sysdep_network_cred_t));
memcpy(dynregmq_handle->cred, data, sizeof(aiot_sysdep_network_cred_t));
} else {
res = STATE_SYS_DEPEND_MALLOC_FAILED;
}
}
break;
case AIOT_DYNREGMQOPT_HOST: {
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->host, data, DYNREGMQ_MODULE_NAME);
}
break;
case AIOT_DYNREGMQOPT_PORT: {
dynregmq_handle->port = *(uint16_t *)data;
}
break;
case AIOT_DYNREGMQOPT_PROFILE_INDEX:{
dynregmq_handle->pdp = *(uint16_t *)data;
}
break;
case AIOT_DYNREGMQOPT_PRODUCT_KEY: {
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->product_key, data, DYNREGMQ_MODULE_NAME);
}
break;
case AIOT_DYNREGMQOPT_PRODUCT_SECRET: {
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->product_secret, data, DYNREGMQ_MODULE_NAME);
}
break;
case AIOT_DYNREGMQOPT_DEVICE_NAME: {
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->device_name, data, DYNREGMQ_MODULE_NAME);
}
break;
case AIOT_DYNREGMQOPT_CONNECT_TIMEOUT_MS:{
dynregmq_handle->connect_timeout_ms = *(uint32_t *)data;
}
break;
case AIOT_DYNREGMQOPT_SEND_TIMEOUT_MS: {
dynregmq_handle->send_timeout_ms = *(uint32_t *)data;
}
break;
case AIOT_DYNREGMQOPT_RECV_TIMEOUT_MS: {
dynregmq_handle->recv_timeout_ms = *(uint32_t *)data;
}
break;
case AIOT_DYNREGMQOPT_RECV_HANDLER: {
dynregmq_handle->recv_handler = (aiot_dynregmq_recv_handler_t)data;
}
break;
case AIOT_DYNREGMQOPT_USERDATA: {
dynregmq_handle->userdata = data;
}
break;
case AIOT_DYNREGMQOPT_TIMEOUT_MS: {
dynregmq_handle->timeout_ms = *(uint32_t *)data;
}
break;
case AIOT_DYNREGMQOPT_DEINIT_TIMEOUT_MS: {
dynregmq_handle->deinit_timeout_ms = *(uint32_t *)data;
}
break;
case AIOT_DYNREGMQOPT_NO_WHITELIST: {
dynregmq_handle->flag_nowhitelist = *(uint8_t *)data;
}
break;
case AIOT_DYNREGMQOPT_INSTANCE_ID: {
res = core_strdup(dynregmq_handle->sysdep, &dynregmq_handle->instance_id, data, DYNREGMQ_MODULE_NAME);
}
break;
default: {
res = STATE_USER_INPUT_UNKNOWN_OPTION;
}
break;
}
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
_dynregmq_exec_dec(dynregmq_handle);
return res;
}
int32_t aiot_dynregmq_deinit(void **handle)
{
uint32_t deinit_timeout_ms = 0;
dynregmq_handle_t *dynregmq_handle = NULL;
aiot_sysdep_portfile_t *sysdep = NULL;
if (handle == NULL || *handle == NULL) {
return STATE_USER_INPUT_NULL_POINTER;
}
dynregmq_handle = *(dynregmq_handle_t **)handle;
sysdep = dynregmq_handle->sysdep;
if (dynregmq_handle->exec_enabled == 0) {
return STATE_USER_INPUT_EXEC_DISABLED;
}
dynregmq_handle->exec_enabled = 0;
deinit_timeout_ms = dynregmq_handle->deinit_timeout_ms;
do {
if (dynregmq_handle->exec_count == 0) {
break;
}
dynregmq_handle->sysdep->core_sysdep_sleep(DYNREGMQ_DEINIT_INTERVAL_MS);
} while ((deinit_timeout_ms > DYNREGMQ_DEINIT_INTERVAL_MS) && (deinit_timeout_ms - DYNREGMQ_DEINIT_INTERVAL_MS > 0));
if (dynregmq_handle->exec_count != 0) {
return STATE_DYNREGMQ_DEINIT_TIMEOUT;
}
*handle = NULL;
if (dynregmq_handle->mqtt_handle != NULL) {
aiot_mqtt_deinit(&dynregmq_handle->mqtt_handle);
}
if (dynregmq_handle->host != NULL) {
sysdep->core_sysdep_free(dynregmq_handle->host);
}
if (dynregmq_handle->product_key != NULL) {
sysdep->core_sysdep_free(dynregmq_handle->product_key);
}
if (dynregmq_handle->product_secret != NULL) {
sysdep->core_sysdep_free(dynregmq_handle->product_secret);
}
if (dynregmq_handle->device_name != NULL) {
sysdep->core_sysdep_free(dynregmq_handle->device_name);
}
if (dynregmq_handle->cred != NULL) {
sysdep->core_sysdep_free(dynregmq_handle->cred);
}
if (dynregmq_handle->instance_id != NULL) {
sysdep->core_sysdep_free(dynregmq_handle->instance_id);
}
sysdep->core_sysdep_mutex_deinit(&dynregmq_handle->data_mutex);
sysdep->core_sysdep_free(dynregmq_handle);
return STATE_SUCCESS;
}
int32_t aiot_dynregmq_send_request(void *handle)
{
int32_t res = STATE_SUCCESS;
dynregmq_handle_t *dynregmq_handle = (dynregmq_handle_t *)handle;
char *auth_clientid = NULL;
char *auth_username = NULL;
char auth_password[65] = {0};
char *sign_input = NULL;
uint32_t random_num = 0;
char random[11] = {0};
char *auth_type = NULL;
uint8_t reconnect = 0;
if (dynregmq_handle == NULL) {
return STATE_USER_INPUT_NULL_POINTER;
}
if (dynregmq_handle->host == NULL) {
return STATE_USER_INPUT_MISSING_HOST;
}
if (dynregmq_handle->product_key == NULL) {
return STATE_USER_INPUT_MISSING_PRODUCT_KEY;
}
if (dynregmq_handle->product_secret == NULL) {
return STATE_USER_INPUT_MISSING_PRODUCT_SECRET;
}
if (dynregmq_handle->device_name == NULL) {
return STATE_USER_INPUT_MISSING_DEVICE_NAME;
}
if (dynregmq_handle->exec_enabled == 0) {
return STATE_USER_INPUT_EXEC_DISABLED;
}
_dynregmq_exec_inc(dynregmq_handle);
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
if (dynregmq_handle->mqtt_handle != NULL) {
aiot_mqtt_deinit(&dynregmq_handle->mqtt_handle);
}
dynregmq_handle->mqtt_handle = aiot_mqtt_init();
if (dynregmq_handle->mqtt_handle == NULL) {
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
_dynregmq_exec_dec(dynregmq_handle);
return STATE_SYS_DEPEND_MALLOC_FAILED;
}
/* setup auth_type */
auth_type = (dynregmq_handle->flag_nowhitelist) ? "regnwl" : "register";
/* generate random string */
dynregmq_handle->sysdep->core_sysdep_rand((uint8_t *)&random_num, 4);
core_uint2str(random_num, random, NULL);
/* assamble clientid, username and password */
{
uint8_t has_instance_id = (dynregmq_handle->flag_nowhitelist && dynregmq_handle->instance_id != NULL) ? 1 : 0;
char *client_fmt = (has_instance_id) ?
"%s.%s|random=%s,authType=%s,securemode=2,signmethod=hmacsha256,instanceId=%s|" :
"%s.%s|random=%s,authType=%s,securemode=2,signmethod=hmacsha256|";
char *client_src[] = { dynregmq_handle->device_name, dynregmq_handle->product_key,
random, auth_type, dynregmq_handle->instance_id
};
char *username_fmt = "%s&%s";
char *username_src[] = { dynregmq_handle->device_name, dynregmq_handle->product_key };
char *sign_input_fmt = "deviceName%sproductKey%srandom%s";
uint8_t sign_output[32] = {0};
core_sprintf(dynregmq_handle->sysdep, &auth_clientid, client_fmt, client_src,
has_instance_id ? 5 : 4, DYNREGMQ_MODULE_NAME);
core_sprintf(dynregmq_handle->sysdep, &auth_username, username_fmt, username_src,
sizeof(username_src) / sizeof(char *), DYNREGMQ_MODULE_NAME);
core_sprintf(dynregmq_handle->sysdep, &sign_input, sign_input_fmt, client_src,
3, DYNREGMQ_MODULE_NAME);
core_hmac_sha256((const uint8_t *)sign_input, (uint32_t)strlen(sign_input),
(const uint8_t *)dynregmq_handle->product_secret,
(uint32_t)strlen(dynregmq_handle->product_secret), sign_output);
core_hex2str(sign_output, sizeof(sign_output), auth_password, 0);
}
if (((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_HOST,
(void *)dynregmq_handle->host)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_PORT,
(void *)&dynregmq_handle->port)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_PROFILE_IDX,
(void *)&dynregmq_handle->pdp)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_CLIENTID,
(void *)auth_clientid)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_USERNAME,
(void *)auth_username)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_PASSWORD,
(void *)auth_password)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_NETWORK_CRED,
(void *)dynregmq_handle->cred)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_CONNECT_TIMEOUT_MS,
(void *)&dynregmq_handle->connect_timeout_ms)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_SEND_TIMEOUT_MS,
(void *)&dynregmq_handle->send_timeout_ms)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_RECV_TIMEOUT_MS,
(void *)&dynregmq_handle->recv_timeout_ms)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_RECV_HANDLER,
(void *)_dynregmq_recv_handler)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_USERDATA,
(void *)dynregmq_handle)) < STATE_SUCCESS) ||
((res = aiot_mqtt_setopt(dynregmq_handle->mqtt_handle, AIOT_MQTTOPT_RECONN_ENABLED,
(void *)&reconnect)) < STATE_SUCCESS)) {
aiot_mqtt_deinit(&dynregmq_handle->mqtt_handle);
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
_dynregmq_exec_dec(dynregmq_handle);
dynregmq_handle->sysdep->core_sysdep_free(auth_clientid);
dynregmq_handle->sysdep->core_sysdep_free(auth_username);
dynregmq_handle->sysdep->core_sysdep_free(sign_input);
return res;
}
res = aiot_mqtt_connect(dynregmq_handle->mqtt_handle);
if (res < STATE_SUCCESS) {
aiot_mqtt_deinit(&dynregmq_handle->mqtt_handle);
}
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
_dynregmq_exec_dec(dynregmq_handle);
dynregmq_handle->sysdep->core_sysdep_free(auth_clientid);
dynregmq_handle->sysdep->core_sysdep_free(auth_username);
dynregmq_handle->sysdep->core_sysdep_free(sign_input);
return res;
}
int32_t aiot_dynregmq_recv(void *handle)
{
int32_t res = STATE_SUCCESS;
uint64_t timenow_ms = 0;
dynregmq_handle_t *dynregmq_handle = (dynregmq_handle_t *)handle;
if (dynregmq_handle == NULL) {
return STATE_USER_INPUT_NULL_POINTER;
}
if (dynregmq_handle->mqtt_handle == NULL) {
return STATE_DYNREGMQ_NEED_SEND_REQUEST;
}
if (dynregmq_handle->exec_enabled == 0) {
return STATE_USER_INPUT_EXEC_DISABLED;
}
_dynregmq_exec_inc(dynregmq_handle);
dynregmq_handle->sysdep->core_sysdep_mutex_lock(dynregmq_handle->data_mutex);
timenow_ms = dynregmq_handle->sysdep->core_sysdep_time();
while (1) {
if (timenow_ms >= dynregmq_handle->sysdep->core_sysdep_time()) {
timenow_ms = dynregmq_handle->sysdep->core_sysdep_time();
}
if (dynregmq_handle->sysdep->core_sysdep_time() - timenow_ms >= dynregmq_handle->timeout_ms) {
res = STATE_DYNREGMQ_AUTH_TIMEOUT;
break;
}
res = aiot_mqtt_recv(dynregmq_handle->mqtt_handle);
if (res < 0) {
break;
}
if (dynregmq_handle->flag_completed == 1) {
dynregmq_handle->flag_completed = 0;
res = STATE_SUCCESS;
break;
}
}
dynregmq_handle->sysdep->core_sysdep_mutex_unlock(dynregmq_handle->data_mutex);
_dynregmq_exec_dec(dynregmq_handle);
return res;
}