123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- /*
- * Tencent is pleased to support the open source community by making IoT Hub
- available.
- * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights
- reserved.
- * Licensed under the MIT License (the "License"); you may not use this file
- except in
- * compliance with the License. You may obtain a copy of the License at
- * http://opensource.org/licenses/MIT
- * Unless required by applicable law or agreed to in writing, software
- distributed under the License is
- * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND,
- * either express or implied. See the License for the specific language
- governing permissions and
- * limitations under the License.
- *
- */
- #include "gateway_common.h"
- #include "lite-utils.h"
- #include "mqtt_client.h"
- #include "utils_base64.h"
- #include "utils_md5.h"
- #include "utils_hmac.h"
- #include "ql_fs.h"
- #define QUECTEL_OPEN_CPU
- static char cloud_rcv_buf[GATEWAY_RECEIVE_BUFFER_LEN];
- static bool get_json_type(char *json, char **v)
- {
- *v = LITE_json_value_of("type", json);
- return *v == NULL ? false : true;
- }
- static bool get_json_devices(char *json, char **v)
- {
- *v = LITE_json_value_of("payload.devices", json);
- return *v == NULL ? false : true;
- }
- static bool get_json_result(char *json, int32_t *res)
- {
- char *v = LITE_json_value_of("result", json);
- if (v == NULL) {
- return false;
- }
- if (LITE_get_int32(res, v) != QCLOUD_RET_SUCCESS) {
- HAL_Free(v);
- return false;
- }
- HAL_Free(v);
- return true;
- }
- static bool get_json_product_id(char *json, char **v)
- {
- *v = LITE_json_value_of("product_id", json);
- return *v == NULL ? false : true;
- }
- static bool get_json_device_name(char *json, char **v)
- {
- *v = LITE_json_value_of("device_name", json);
- return *v == NULL ? false : true;
- }
- static void _gateway_message_handler(void *client, MQTTMessage *message, void *user_data)
- {
- Qcloud_IoT_Client *mqtt = NULL;
- Gateway * gateway = NULL;
- char * topic = NULL;
- size_t topic_len = 0;
- int cloud_rcv_len = 0;
- char * type = NULL;
- char * devices = NULL, *devices_strip = NULL;
- char * product_id = NULL;
- char * device_name = NULL;
- int32_t result = 0;
- char client_id[MAX_SIZE_OF_CLIENT_ID + 1] = {0};
- int size = 0;
- POINTER_SANITY_CHECK_RTN(client);
- POINTER_SANITY_CHECK_RTN(message);
- mqtt = (Qcloud_IoT_Client *)client;
- gateway = (Gateway *)mqtt->event_handle.context;
- POINTER_SANITY_CHECK_RTN(gateway);
- topic = (char *)message->ptopic;
- topic_len = message->topic_len;
- if (NULL == topic || topic_len <= 0) {
- Log_e("topic == NULL or topic_len <= 0.");
- return;
- }
- if (message->payload_len > GATEWAY_RECEIVE_BUFFER_LEN) {
- Log_e("message->payload_len > GATEWAY_RECEIVE_BUFFER_LEN.");
- return;
- }
- cloud_rcv_len = Min(GATEWAY_RECEIVE_BUFFER_LEN - 1, message->payload_len);
- memcpy(cloud_rcv_buf, message->payload, cloud_rcv_len + 1);
- cloud_rcv_buf[cloud_rcv_len] = '\0'; // jsmn_parse relies on a string
- // Log_d("recv:%s", cloud_rcv_buf);
- if (!get_json_type(cloud_rcv_buf, &type)) {
- Log_e("Fail to parse type from msg: %s", cloud_rcv_buf);
- return;
- }
- if (!get_json_devices(cloud_rcv_buf, &devices)) {
- Log_e("Fail to parse devices from msg: %s", cloud_rcv_buf);
- HAL_Free(type);
- return;
- }
- if (devices[0] == '[') {
- devices_strip = devices + 1;
- } else {
- devices_strip = devices;
- }
- if (!get_json_result(devices_strip, &result)) {
- Log_e("Fail to parse result from msg: %s", cloud_rcv_buf);
- HAL_Free(type);
- HAL_Free(devices);
- return;
- }
- if (!get_json_product_id(devices_strip, &product_id)) {
- Log_e("Fail to parse product_id from msg: %s", cloud_rcv_buf);
- HAL_Free(type);
- HAL_Free(devices);
- return;
- }
- if (!get_json_device_name(devices_strip, &device_name)) {
- Log_e("Fail to parse device_name from msg: %s", cloud_rcv_buf);
- HAL_Free(type);
- HAL_Free(devices);
- HAL_Free(product_id);
- return;
- }
- size = HAL_Snprintf(client_id, MAX_SIZE_OF_CLIENT_ID + 1, GATEWAY_CLIENT_ID_FMT, product_id, device_name);
- if (size < 0 || size > MAX_SIZE_OF_CLIENT_ID) {
- Log_e("generate client_id fail.");
- HAL_Free(type);
- HAL_Free(devices);
- HAL_Free(product_id);
- HAL_Free(device_name);
- return;
- }
- if (strncmp(type, GATEWAY_ONLINE_OP_STR, sizeof(GATEWAY_ONLINE_OP_STR) - 1) == 0) {
- if (strncmp(client_id, gateway->gateway_data.online.client_id, size) == 0) {
- Log_i("client_id(%s), online result %d", client_id, result);
- gateway->gateway_data.online.result = result;
- }
- } else if (strncmp(type, GATEWAY_OFFLIN_OP_STR, sizeof(GATEWAY_OFFLIN_OP_STR) - 1) == 0) {
- if (strncmp(client_id, gateway->gateway_data.offline.client_id, size) == 0) {
- Log_i("client_id(%s), offline result %d", client_id, result);
- gateway->gateway_data.offline.result = result;
- }
- } else if(strncmp(type, GATEWAY_BIND_OP_STR, sizeof(GATEWAY_BIND_OP_STR) - 1) == 0) {
- if (strncmp(client_id, gateway->gateway_data.bind.client_id, size) == 0) {
- gateway->gateway_data.bind.result = (result > 0)? -result: result;
- Log_i("client_id(%s), bind result %d", client_id, gateway->gateway_data.bind.result);
- }
- } else if(strncmp(type, GATEWAY_UNBIND_OP_STR, sizeof(GATEWAY_UNBIND_OP_STR) - 1) == 0) {
- if (strncmp(client_id, gateway->gateway_data.unbind.client_id, size) == 0) {
- gateway->gateway_data.unbind.result = (result > 0)? -result: result;
- Log_i("client_id(%s), unbind result %d", client_id, gateway->gateway_data.unbind.result);
- }
- }
- HAL_Free(type);
- HAL_Free(devices);
- HAL_Free(product_id);
- HAL_Free(device_name);
- return;
- }
- int gateway_subscribe_unsubscribe_topic(Gateway *gateway, char *topic_filter, SubscribeParams *params, int is_subscribe)
- {
- int rc = 0;
- int loop_count = 0;
- uint32_t status = -1;
- POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
- POINTER_SANITY_CHECK(params, QCLOUD_ERR_INVAL);
- STRING_PTR_SANITY_CHECK(topic_filter, QCLOUD_ERR_INVAL);
- params->qos = QOS1;
- gateway->gateway_data.sync_status = status;
- if (is_subscribe) {
- /* subscribe */
- rc = IOT_MQTT_Subscribe(gateway->mqtt, topic_filter, params);
- } else {
- /* unsubscribe */
- rc = IOT_MQTT_Unsubscribe(gateway->mqtt, topic_filter);
- }
- if (rc < 0) {
- Log_e("subscribe or un(%d), result(%d)", is_subscribe, rc);
- IOT_FUNC_EXIT_RC(rc);
- }
- gateway->gateway_data.sync_status = status = rc;
- while (status == gateway->gateway_data.sync_status) {
- if (loop_count > GATEWAY_LOOP_MAX_COUNT) {
- Log_i("loop max count, time out");
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
- }
- IOT_Gateway_Yield(gateway, 200);
- loop_count++;
- }
- if (gateway->gateway_data.sync_status != 0) {
- Log_e("gateway->gateway_data.sync_status(%u) != 0", gateway->gateway_data.sync_status);
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
- }
- IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
- }
- int gateway_subscribe_unsubscribe_default(Gateway *gateway, GatewayParam *param)
- {
- int rc = 0;
- int size = 0;
- char topic_filter[MAX_SIZE_OF_CLOUD_TOPIC + 1] = {0};
- SubscribeParams subscribe_params = DEFAULT_SUB_PARAMS;
- POINTER_SANITY_CHECK(param, QCLOUD_ERR_INVAL);
- STRING_PTR_SANITY_CHECK(param->product_id, QCLOUD_ERR_INVAL);
- STRING_PTR_SANITY_CHECK(param->device_name, QCLOUD_ERR_INVAL);
- // subscribe online/offline operation reslut
- size = HAL_Snprintf(topic_filter, MAX_SIZE_OF_CLOUD_TOPIC + 1, GATEWAY_TOPIC_OPERATION_RESULT_FMT,
- param->product_id, param->device_name);
- if (size < 0 || size > MAX_SIZE_OF_CLOUD_TOPIC) {
- Log_e("buf size < topic length!");
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
- }
- subscribe_params.on_message_handler = _gateway_message_handler;
- rc = gateway_subscribe_unsubscribe_topic(gateway, topic_filter, &subscribe_params, IOT_TRUE);
- if (QCLOUD_RET_SUCCESS != rc) {
- IOT_FUNC_EXIT_RC(rc);
- }
- IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
- }
- SubdevSession *subdev_find_session(Gateway *gateway, char *product_id, char *device_name)
- {
- SubdevSession *session = NULL;
- POINTER_SANITY_CHECK(gateway, NULL);
- STRING_PTR_SANITY_CHECK(product_id, NULL);
- STRING_PTR_SANITY_CHECK(device_name, NULL);
- session = gateway->session_list;
- /* session is exist */
- while (session) {
- if (0 == strcmp(session->product_id, product_id) && 0 == strcmp(session->device_name, device_name)) {
- IOT_FUNC_EXIT_RC(session);
- }
- session = session->next;
- }
- IOT_FUNC_EXIT_RC(NULL);
- }
- SubdevSession *subdev_add_session(Gateway *gateway, char *product_id, char *device_name)
- {
- SubdevSession *session = NULL;
- POINTER_SANITY_CHECK(gateway, NULL);
- STRING_PTR_SANITY_CHECK(product_id, NULL);
- STRING_PTR_SANITY_CHECK(device_name, NULL);
- session = HAL_Malloc(sizeof(SubdevSession));
- if (session == NULL) {
- Log_e("Not enough memory");
- IOT_FUNC_EXIT_RC(NULL);
- }
- /* add session to list */
- session->next = gateway->session_list;
- gateway->session_list = session;
- int size = strlen(product_id);
- strncpy(session->product_id, product_id, size);
- session->product_id[size] = '\0';
- size = strlen(device_name);
- strncpy(session->device_name, device_name, size);
- session->device_name[size] = '\0';
- session->session_status = SUBDEV_SEESION_STATUS_INIT;
- IOT_FUNC_EXIT_RC(session);
- }
- int subdev_remove_session(Gateway *gateway, char *product_id, char *device_name)
- {
- SubdevSession *cur_session = NULL;
- SubdevSession *pre_session = NULL;
- POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_FAILURE);
- STRING_PTR_SANITY_CHECK(product_id, QCLOUD_ERR_FAILURE);
- STRING_PTR_SANITY_CHECK(device_name, QCLOUD_ERR_FAILURE);
- pre_session = cur_session = gateway->session_list;
- if (NULL == cur_session) {
- Log_e("session list is empty");
- IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
- }
- /* session is exist */
- while (cur_session) {
- if (0 == strcmp(cur_session->product_id, product_id) && 0 == strcmp(cur_session->device_name, device_name)) {
- if (cur_session == gateway->session_list) {
- gateway->session_list = cur_session->next;
- } else {
- pre_session->next = cur_session->next;
- }
- HAL_Free(cur_session);
- IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
- }
- pre_session = cur_session;
- cur_session = cur_session->next;
- }
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
- }
- int gateway_publish_sync(Gateway *gateway, char *topic, PublishParams *params, int32_t *result)
- {
- int rc = 0;
- int loop_count = 0;
- int32_t res = *result;
- POINTER_SANITY_CHECK(gateway, QCLOUD_ERR_INVAL);
- rc = IOT_Gateway_Publish(gateway, topic, params);
- if (rc < 0) {
- Log_e("publish fail.");
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
- }
- /* wait for response */
- while (res == *result) {
- if (loop_count > GATEWAY_LOOP_MAX_COUNT) {
- Log_i("loop max count, time out.");
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_GATEWAY_SESSION_TIMEOUT);
- }
- #ifdef MULTITHREAD_ENABLED
- if((gateway->yield_thread_running)) {
- HAL_SleepMs(200);
- } else
- #endif
- {
- IOT_Gateway_Yield(gateway, 200);
- }
- loop_count++;
- }
- if (*result != 0) {
- IOT_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
- }
- IOT_FUNC_EXIT_RC(QCLOUD_RET_SUCCESS);
- }
- #ifdef AUTH_MODE_CERT
- static int gen_key_from_cert_file(const char *file_path, char *keybuff, int buff_len)
- {
- QFILE fp;
- uint32_t length;
- int ret = QCLOUD_RET_SUCCESS;
-
- fp = ql_fopen(file_path, "r");
- if (fp <0) {
- Log_e("fail to open cert file %s", file_path);
- return QCLOUD_ERR_FAILURE;
- }
- #ifdef QUECTEL_OPEN_CPU
- ql_fseek(fp, 0L, SEEK_END);
- length = ql_ftell(fp);
- #else
- fseek(fp, 0L, SEEK_END);
- length = ftell(fp);
- #endif
- uint8_t *data = HAL_Malloc(length + 1);
- if(!data) {
- Log_e("malloc mem err");
- return QCLOUD_ERR_MALLOC;
- }
- ql_fseek(fp, 0, SEEK_SET);
- if(length != ql_fread(data, 1, length, fp)) {
- Log_e("read data len fail");
- ret = QCLOUD_ERR_FAILURE;
- goto exit;
- }
- utils_md5_str(data, length, (uint8_t *)keybuff);
- Log_d("sign key: %s", keybuff);
- exit:
- HAL_Free(data);
- #ifdef QUECTEL_OPEN_CPU
- ql_fclose(fp);
- #else
- fclose(fp);
- #endif
- return ret;
- }
- #endif
- int subdev_bind_hmac_sha1_cal(DeviceInfo *pDevInfo, char *signout, int max_signlen, int nonce, long timestamp)
- {
- int text_len,ret;
- size_t olen = 0;
- char * pSignText = NULL;
- const char *sign_fmt = "%s%s;%d;%d"; //${product_id}${device_name};${random};${expiration_time}
- /*format sign data*/
- text_len = strlen(sign_fmt) + strlen(pDevInfo->device_name) + strlen(pDevInfo->product_id) + sizeof(int) + sizeof(long) + 10;
- pSignText = HAL_Malloc(text_len);
- if (pSignText == NULL) {
- Log_e("malloc sign source buff fail");
- return QCLOUD_ERR_FAILURE;
- }
- memset(pSignText, 0, text_len);
- HAL_Snprintf((char *)pSignText, text_len, sign_fmt, pDevInfo->product_id, pDevInfo->device_name, nonce, timestamp);
- //gen digest key
- char key[BIND_SIGN_KEY_SIZE + 1] = {0};
- #ifdef AUTH_MODE_CERT
- ret = gen_key_from_cert_file(pDevInfo->dev_cert_file_name, key, BIND_SIGN_KEY_SIZE);
- if(QCLOUD_RET_SUCCESS != ret) {
- Log_e("gen key from cert file fail, ret:%d",ret);
- HAL_Free(pSignText);
- return ret;
- }
- #else
- strncpy(key, pDevInfo->device_secret, strlen(pDevInfo->device_secret));
- #endif
- /*cal hmac sha1*/
- char sign[SUBDEV_BIND_SIGN_LEN] = {0};
- int sign_len = utils_hmac_sha1_hex(pSignText, strlen(pSignText), sign, key, strlen(key));
- /*base64 encode*/
- ret = qcloud_iot_utils_base64encode((uint8_t *)signout, max_signlen, &olen, (const uint8_t *)sign, sign_len);
- HAL_Free(pSignText);
- return (olen > max_signlen) ? QCLOUD_ERR_FAILURE : ret;
- }
|