text: /*
   * Copyright (C) 2015-2018 Alibaba Group Holding Limited
   */
  
  #include <stddef.h>
  #include <string.h>
  
  #include "alcs_internal.h"
  #include "linkkit/alcs_api.h"
  #include "alcs_coap.h"
  #include "alcs_mqtt.h"
  #include "CoAPInternal.h"
  #include "CoAPExport.h"
  #include "CoAPServer.h"
  #include "alcs_adapter.h"
  #include "alcs_mqtt.h"
  #include "alcs_localsetup.h"
  #include "CoAPPlatform.h"
  
  static iotx_alcs_adapter_t g_alcs_adapter;
  
  static void alcs_heartbeat(void *handle);
  
  static iotx_alcs_adapter_t *__iotx_alcs_get_ctx(void)
  {
      return &g_alcs_adapter;
  }
  
  static char *iotx_alcs_topic_parse_pk(char *topic, uint16_t *length)
  {
      char *pos = NULL;
      uint8_t slash_count = 0;
      uint16_t idx = 0;
      uint16_t topic_len = 0;
  
      if (topic == NULL || length == NULL) {
          COAP_ERR("Invalid Parameter");
          return NULL;
      }
  
      topic_len = strlen(topic);
  
      while (idx < topic_len) {
          if (topic[idx] == '/') {
              slash_count++;
              if (slash_count == 2) {
                  pos = topic + idx + 1;
              }
              if (slash_count == 3) {
                  *length = topic + idx - pos;
              }
          }
          idx++;
      }
  
      return pos;
  }
  
  static char *iotx_alcs_topic_parse_dn(char *topic, uint16_t *length)
  {
      char *pos = NULL;
      uint8_t slash_count = 0;
      uint16_t idx = 0;
      uint16_t topic_len = 0;
  
      if (topic == NULL || length == NULL) {
          COAP_ERR("Invalid Parameter");
          return NULL;
      }
  
      topic_len = strlen(topic);
  
      while (idx < topic_len) {
          if (topic[idx] == '/') {
              slash_count++;
              if (slash_count == 3) {
                  pos = topic + idx + 1;
              }
              if (slash_count == 4) {
                  *length = topic + idx - pos;
              }
          }
          idx++;
      }
  
      return pos;
  }
  
  static int _iotx_alcs_send_list_search_and_remove(
      iotx_alcs_adapter_t *adapter, CoAPMessage *message,
      iotx_alcs_send_msg_t **send_msg)
  {
      iotx_alcs_send_msg_t *node = NULL;
      iotx_alcs_send_msg_t *next = NULL;
  
      list_for_each_entry_safe(node, next, &adapter->alcs_send_list, linked_list,
                               iotx_alcs_send_msg_t)
      {
          if (message->header.tokenlen == node->token_len &&
              memcmp(message->token, node->token, node->token_len) == 0) {
              *send_msg = node;
              list_del(&node->linked_list);
              return SUCCESS_RETURN;
          }
      }
  
      return FAIL_RETURN;
  }
  
  void iotx_alcs_coap_adapter_send_msg_handle(CoAPContext *context,
                                              CoAPReqResult result,
                                              void *userdata, NetworkAddr *remote,
                                              CoAPMessage *message)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)userdata;
      iotx_alcs_event_msg_t event;
      memset(&event, 0, sizeof(iotx_alcs_event_msg_t));
  
      switch (result) {
      case COAP_REQUEST_SUCCESS:
          {
              iotx_alcs_transfer_msg_t transfer_msg;
              iotx_alcs_send_msg_t *send_msg = NULL;
  
              memset(&transfer_msg, 0, sizeof(iotx_alcs_transfer_msg_t));
  
              transfer_msg.ip = (char *)remote->addr;
              transfer_msg.port = remote->port;
              HAL_MutexLock(adapter->mutex);
              res = _iotx_alcs_send_list_search_and_remove(adapter, message,
                                                           &send_msg);
              HAL_MutexUnlock(adapter->mutex);
  
              if (res < SUCCESS_RETURN) {
                  return;
              }
  
              transfer_msg.uri = send_msg->uri;
              transfer_msg.token_len = send_msg->token_len;
              transfer_msg.token = send_msg->token;
              transfer_msg.payload_len = message->payloadlen;
              transfer_msg.payload = message->payload;
  
              event.event_type = IOTX_ALCS_EVENT_MSG_SEND_MESSAGE_SUCCESS;
              event.msg = &transfer_msg;
  
              adapter->alcs_event_handle->h_fp(
                  adapter->alcs_event_handle->pcontext, (void *)adapter, &event);
  
              ALCS_free(send_msg->token);
              ALCS_free(send_msg->uri);
              ALCS_free(send_msg);
          }
          break;
      case COAP_RECV_RESP_TIMEOUT:
          {
              iotx_alcs_transfer_msg_t transfer_msg;
              iotx_alcs_send_msg_t *send_msg = NULL;
  
              memset(&transfer_msg, 0, sizeof(iotx_alcs_transfer_msg_t));
  
              transfer_msg.ip = (char *)remote->addr;
              transfer_msg.port = remote->port;
              HAL_MutexLock(adapter->mutex);
              res = _iotx_alcs_send_list_search_and_remove(adapter, message,
                                                           &send_msg);
              HAL_MutexUnlock(adapter->mutex);
  
              if (res < SUCCESS_RETURN) {
                  return;
              }
  
              transfer_msg.uri = send_msg->uri;
              transfer_msg.token_len = send_msg->token_len;
              transfer_msg.token = send_msg->token;
              transfer_msg.payload_len = 0;
              transfer_msg.payload = NULL;
  
              event.event_type = IOTX_ALCS_EVENT_MSG_SEND_MESSAGE_RESP_TIMEOUT;
              event.msg = &transfer_msg;
  
              adapter->alcs_event_handle->h_fp(
                  adapter->alcs_event_handle->pcontext, (void *)adapter, &event);
  
              ALCS_free(send_msg->token);
              ALCS_free(send_msg->uri);
              ALCS_free(send_msg);
          }
          break;
      default:
          COAP_WRN("Unknown Coap Request Result: %d", result);
          break;
      }
  }
  
  void iotx_alcs_coap_adapter_event_notifier(unsigned int event,
                                             NetworkAddr *remote, void *message)
  {
      COAP_INFO(
          "ALCS Coap Event: %d, Remote Device Address: %s, Remote Device Port: "
          "%d",
          event, remote->addr, remote->port);
  }
  
  int iotx_alcs_adapter_list_init(iotx_alcs_adapter_t *adapter)
  {
      /* initialze send list */
      INIT_LIST_HEAD(&adapter->alcs_send_list);
      INIT_LIST_HEAD(&adapter->alcs_subdev_list);
  
      return SUCCESS_RETURN;
  }
  
  static void _iotx_alcs_adapter_send_list_destroy(iotx_alcs_adapter_t *adapter)
  {
      iotx_alcs_send_msg_t *node = NULL;
      iotx_alcs_send_msg_t *next = NULL;
  
      list_for_each_entry_safe(node, next, &adapter->alcs_send_list, linked_list,
                               iotx_alcs_send_msg_t)
      {
          list_del(&node->linked_list);
          ALCS_free(node->token);
          ALCS_free(node->uri);
          ALCS_free(node);
      }
  }
  
  static void _iotx_alcs_adapter_subdev_list_destroy(iotx_alcs_adapter_t *adapter)
  {
      iotx_alcs_subdev_item_t *node = NULL;
      iotx_alcs_subdev_item_t *next = NULL;
  
      list_for_each_entry_safe(node, next, &adapter->alcs_subdev_list,
                               linked_list, iotx_alcs_subdev_item_t)
      {
          list_del(&node->linked_list);
          ALCS_free(node);
      }
  }
  
  int iotx_alcs_adapter_deinit(void)
  {
      char product_key[IOTX_PRODUCT_KEY_LEN + 1] = { 0 };
      char device_name[IOTX_DEVICE_NAME_LEN + 1] = { 0 };
      iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx();
  
      HAL_GetProductKey(product_key);
      HAL_GetDeviceName(device_name);
  
      HAL_MutexLock(adapter->mutex);
      _iotx_alcs_adapter_send_list_destroy(adapter);
      _iotx_alcs_adapter_subdev_list_destroy(adapter);
      HAL_MutexUnlock(adapter->mutex);
  
      if (adapter->alcs_event_handle) {
          ALCS_free(adapter->alcs_event_handle);
      }
  
      HAL_MutexDestroy(adapter->mutex);
  
      alcs_mqtt_deinit(adapter->coap_ctx, product_key, device_name);
  
      /* if (adapter->coap_ctx) CoAPContext_free(adapter->coap_ctx); */
  
      alcs_context_deinit();
      alcs_deinit();
      alcs_auth_deinit();
  
      return SUCCESS_RETURN;
  }
  
  int iotx_alcs_adapter_init(iotx_alcs_adapter_t *adapter,
                             iotx_alcs_param_t *param)
  {
      int res;
      CoAPInitParam coap_param;
      CoAPContext *coap_ctx = NULL;
      char product_key[IOTX_PRODUCT_KEY_LEN + 1] = { 0 };
      char device_name[IOTX_DEVICE_NAME_LEN + 1] = { 0 };
  
      COAP_INFO("iotx_alcs_adapter_init");
      memset(&coap_param, 0, sizeof(CoAPInitParam));
  
      adapter->mutex = HAL_MutexCreate();
      if (adapter->mutex == NULL) {
          COAP_ERR("Mutex Init Failed");
          return FAIL_RETURN;
      }
  
      coap_param.send_maxcount = param->send_maxcount;
      coap_param.obs_maxcount = param->obs_maxcount;
      coap_param.port = param->port;
      coap_param.group = param->group;
      coap_param.waittime = param->waittime;
      coap_param.res_maxcount = param->res_maxcount;
      coap_param.appdata = NULL;
      coap_param.notifier = iotx_alcs_coap_adapter_event_notifier;
  
      coap_ctx = alcs_context_init(&coap_param);
      if (coap_ctx == NULL) {
          COAP_ERR("Coap Context Init Failed");
          HAL_MutexDestroy(adapter->mutex);
          return FAIL_RETURN;
      }
      adapter->coap_ctx = coap_ctx;
  
      res = HAL_GetProductKey(product_key);
      if (res <= 0 || res > IOTX_PRODUCT_KEY_LEN + 1 - 1) {
          iotx_alcs_adapter_deinit();
          COAP_ERR("Get Product Key Failed");
          return FAIL_RETURN;
      }
  
      res = HAL_GetDeviceName(device_name);
      if (res <= 0 || res > IOTX_DEVICE_NAME_LEN + 1 - 1) {
          iotx_alcs_adapter_deinit();
          COAP_ERR("Get Device Name Failed");
          return FAIL_RETURN;
      }
  
      alcs_init();
  
      res = alcs_auth_init(coap_ctx, product_key, device_name, param->role);
      if (res != COAP_SUCCESS) {
          iotx_alcs_adapter_deinit();
          COAP_ERR("ALCS Auth Init Failed");
          return FAIL_RETURN;
      }
      adapter->role = param->role;
  #ifdef ALCS_SERVER_ENABLED
      {
          extern void on_svr_auth_timer(CoAPContext *);
          if (adapter->role & IOTX_ALCS_ROLE_SERVER) {
              adapter->alcs_server_auth_timer_func = on_svr_auth_timer;
          }
      }
  #endif
  
  #ifdef ALCS_CLIENT_ENABLED
      {
          extern void on_client_auth_timer(CoAPContext *);
          if (adapter->role & IOTX_ALCS_ROLE_CLIENT) {
              adapter->alcs_client_auth_timer_func = on_client_auth_timer;
          }
      }
  #endif
  
      adapter->alcs_event_handle =
          (iotx_alcs_event_handle_t *)ALCS_ADAPTER_malloc(
              sizeof(iotx_alcs_event_handle_t));
      if (adapter->alcs_event_handle == NULL) {
          iotx_alcs_adapter_deinit();
          COAP_ERR("ALCS Event Handle Init Failed");
          return FAIL_RETURN;
      }
      memcpy(adapter->alcs_event_handle, param->handle_event,
             sizeof(iotx_alcs_event_handle_t));
  
      if (iotx_alcs_adapter_list_init(adapter) != SUCCESS_RETURN) {
          iotx_alcs_adapter_deinit();
          COAP_ERR("ALCS Linked List Init Failed");
          return FAIL_RETURN;
      }
  
      alcs_localsetup_init(adapter, coap_ctx, product_key, device_name);
  
      return SUCCESS_RETURN;
  }
  
  static int _iotx_alcs_subdev_list_search(const char *pk, const char *dn,
                                           iotx_alcs_subdev_item_t **subdev_item)
  {
      iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx();
      iotx_alcs_subdev_item_t *node = NULL;
  
      if (pk == NULL || dn == NULL) {
          COAP_ERR("Invalid Parameter");
          return FAIL_RETURN;
      }
  
      list_for_each_entry(node, &adapter->alcs_subdev_list, linked_list,
                          iotx_alcs_subdev_item_t)
      {
          if (strlen(node->product_key) == strlen(pk) &&
              memcmp(node->product_key, pk, strlen(pk)) == 0 &&
              strlen(node->device_name) == strlen(dn) &&
              memcmp(node->device_name, dn, strlen(dn)) == 0) {
              *subdev_item = node;
              return SUCCESS_RETURN;
          }
      }
  
      return FAIL_RETURN;
  }
  
  int iotx_alcs_subdev_remove(const char *pk, const char *dn)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx();
      iotx_alcs_subdev_item_t *subdev_item = NULL;
  
      if (pk == NULL || dn == NULL) {
          COAP_ERR("Invalid Parameter");
          return FAIL_RETURN;
      }
  
      HAL_MutexLock(adapter->mutex);
      res = _iotx_alcs_subdev_list_search(pk, dn, &subdev_item);
      if (res < SUCCESS_RETURN) {
          COAP_ERR("No Matched Item");
          HAL_MutexUnlock(adapter->mutex);
          return FAIL_RETURN;
      }
  
      list_del(&subdev_item->linked_list);
      HAL_MutexUnlock(adapter->mutex);
  
      ALCS_free(subdev_item);
  
      return SUCCESS_RETURN;
  }
  
  int iotx_alcs_subdev_update_stage(iotx_alcs_subdev_item_t *item)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx();
      iotx_alcs_subdev_item_t *subdev_item = NULL;
  
      if (item == NULL) {
          COAP_ERR("Invalid Parameter");
          return FAIL_RETURN;
      }
  
      HAL_MutexLock(adapter->mutex);
      res = _iotx_alcs_subdev_list_search(item->product_key, item->device_name,
                                          &subdev_item);
  
      if (res < SUCCESS_RETURN) {
          COAP_WRN("No Matched Item");
          HAL_MutexUnlock(adapter->mutex);
          return FAIL_RETURN;
      }
  
      subdev_item->stage = item->stage;
  
      HAL_MutexUnlock(adapter->mutex);
      return SUCCESS_RETURN;
  }
  
  void iotx_alcs_subdev_stage_check(void)
  {
      iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx();
      iotx_alcs_subdev_item_t *node = NULL;
      uint64_t time_now = HAL_UptimeMs();
  
      HAL_MutexLock(adapter->mutex);
      list_for_each_entry(node, &adapter->alcs_subdev_list, linked_list,
                          iotx_alcs_subdev_item_t)
      {
          if (node->stage == IOTX_ALCS_SUBDEV_DISCONNCET_CLOUD) {
              if (((time_now > node->retry_ms) &&
                   (time_now - node->retry_ms >=
                    IOTX_ALCS_SUBDEV_RETRY_INTERVAL_MS)) ||
                  ((time_now <= node->retry_ms) &&
                   ((0xFFFFFFFFFFFFFFFF - node->retry_ms) + time_now >=
                    IOTX_ALCS_SUBDEV_RETRY_INTERVAL_MS))) {
                  /* Get Prefix And Secret From Cloud */
                  alcs_mqtt_subdev_prefix_get(node->product_key,
                                              node->device_name);
                  node->retry_ms = time_now;
              }
          }
      }
      HAL_MutexUnlock(adapter->mutex);
  }
  
  void *iotx_alcs_construct(iotx_alcs_param_t *params)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx();
  
      COAP_INFO("iotx_alcs_construct enter");
  
      if (params == NULL || params->group == NULL || strlen(params->group) == 0) {
          return NULL;
      }
  
      memset(adapter, 0, sizeof(iotx_alcs_adapter_t));
  
      res = iotx_alcs_adapter_init(adapter, params);
      if (res != SUCCESS_RETURN) {
          COAP_ERR("Adapter Init Failed");
          return NULL;
      }
  
      return (void *)adapter;
  }
  
  int iotx_alcs_cloud_init(void *handle)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = __iotx_alcs_get_ctx();
      char product_key[IOTX_PRODUCT_KEY_LEN + 1] = { 0 };
      char device_name[IOTX_DEVICE_NAME_LEN + 1] = { 0 };
  
      COAP_INFO("Start ALCS Cloud Init");
  
      if (adapter->local_cloud_inited == 1) {
          return SUCCESS_RETURN;
      }
  
      if (handle == NULL) {
          return FAIL_RETURN;
      }
  
      res = HAL_GetProductKey(product_key);
      if (res <= 0 || res > IOTX_PRODUCT_KEY_LEN + 1 - 1) {
          iotx_alcs_adapter_deinit();
          COAP_ERR("Get Product Key Failed");
          return FAIL_RETURN;
      }
  
      res = HAL_GetDeviceName(device_name);
      if (res <= 0 || res > IOTX_DEVICE_NAME_LEN + 1 - 1) {
          iotx_alcs_adapter_deinit();
          COAP_ERR("Get Device Name Failed");
          return FAIL_RETURN;
      }
  
      if (alcs_mqtt_init(adapter->coap_ctx, product_key, device_name) !=
          ALCS_MQTT_STATUS_SUCCESS) {
          /*solve the prpblem of hard fault when mqtt connection fails once*/
          COAP_ERR("ALCS MQTT Init Failed");
          return FAIL_RETURN;
      }
  
      adapter->local_cloud_inited = 1;
  
      return SUCCESS_RETURN;
  }
  
  int iotx_alcs_destroy(void **phandle)
  {
      if (phandle == NULL || *phandle == NULL) {
          return NULL_VALUE_ERROR;
      }
  
      iotx_alcs_adapter_deinit();
  
      return SUCCESS_RETURN;
  }
  
  static void alcs_heartbeat(void *handle)
  {
      iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle;
  
      if (adapter->role & IOTX_ALCS_ROLE_SERVER &&
          adapter->alcs_server_auth_timer_func != NULL) {
          adapter->alcs_server_auth_timer_func(adapter->coap_ctx);
      }
  
      if (adapter->role & IOTX_ALCS_ROLE_CLIENT &&
          adapter->alcs_client_auth_timer_func != NULL) {
          adapter->alcs_client_auth_timer_func(adapter->coap_ctx);
      }
  }
  int iotx_alcs_yield(void *handle)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle;
  
      if (adapter == NULL || adapter->coap_ctx == NULL) {
          return NULL_VALUE_ERROR;
      }
  
      alcs_heartbeat(handle);
  
      iotx_alcs_subdev_stage_check();
  
      return res;
  }
  
  int iotx_alcs_send(void *handle, iotx_alcs_msg_t *msg)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle;
      CoAPMessage coap_msg;
      CoAPLenString coap_payload;
      NetworkAddr network_addr;
  
      AlcsDeviceKey devKey;
      char productKey[IOTX_PRODUCT_KEY_LEN + 1] = { 0 };
      char deviceName[IOTX_DEVICE_NAME_LEN + 1] = { 0 };
      char *uri_pk = NULL;
      char *uri_dn = NULL;
      uint16_t uri_pk_len = 0;
      uint16_t uri_dn_len = 0;
      iotx_alcs_send_msg_t *alcs_send_msg = NULL;
  
      if (adapter == NULL || adapter->coap_ctx || msg == NULL ||
          msg->payload == NULL || msg->ip == NULL || strlen(msg->ip) == 0 ||
          msg->uri == NULL || strlen(msg->uri) == 0) {
          return NULL_VALUE_ERROR;
      }
  
      if (strlen(msg->ip) > NETWORK_ADDR_LEN) {
          COAP_ERR("Invalid Ip Address Length");
          return FAIL_RETURN;
      }
  
      memset(&coap_msg, 0, sizeof(CoAPMessage));
      memset(&coap_payload, 0, sizeof(CoAPLenString));
  
      coap_payload.len = msg->payload_len;
      coap_payload.data = msg->payload;
  
      alcs_msg_init(adapter->coap_ctx, &coap_msg, msg->msg_code, msg->msg_type, 0,
                    &coap_payload, (void *)adapter);
  
      res = alcs_msg_setAddr(&coap_msg, msg->uri, NULL);
      if (res != COAP_SUCCESS) {
          COAP_ERR("ALCS Message Set URI Failed");
          return FAIL_RETURN;
      }
  
      memset(&network_addr, 0, sizeof(NetworkAddr));
      memcpy(network_addr.addr, msg->ip, strlen(msg->ip));
      network_addr.port = msg->port;
  
      memset(&devKey, 0, sizeof(AlcsDeviceKey));
      memcpy(&devKey.addr, &network_addr, sizeof(NetworkAddr));
  
      uri_pk = iotx_alcs_topic_parse_pk(msg->uri, &uri_pk_len);
      uri_dn = iotx_alcs_topic_parse_dn(msg->uri, &uri_dn_len);
  
      if (uri_pk == NULL || uri_pk_len >= IOTX_PRODUCT_KEY_LEN + 1 ||
          uri_dn == NULL || uri_dn_len >= IOTX_DEVICE_NAME_LEN + 1) {
          COAP_ERR("Invalid Parameter");
          return FAIL_RETURN;
      }
      memcpy(productKey, uri_pk, uri_pk_len);
      memcpy(deviceName, uri_dn, uri_dn_len);
  
      devKey.pk = productKey;
      devKey.dn = deviceName;
  
      res = alcs_sendmsg_secure(adapter->coap_ctx, &devKey, &coap_msg, 2,
                                iotx_alcs_coap_adapter_send_msg_handle);
      alcs_msg_deinit(&coap_msg);
  
      if (res != COAP_SUCCESS) {
          COAP_ERR("ALCS Message Send Message Failed");
          return FAIL_RETURN;
      }
  
      alcs_send_msg = (iotx_alcs_send_msg_t *)ALCS_ADAPTER_malloc(
          sizeof(iotx_alcs_send_msg_t));
      if (alcs_send_msg == NULL) {
          COAP_WRN("Not Enough Memory");
          return FAIL_RETURN;
      }
      memset(alcs_send_msg, 0, sizeof(iotx_alcs_send_msg_t));
  
      alcs_send_msg->token =
          (uint8_t *)ALCS_ADAPTER_malloc(coap_msg.header.tokenlen + 1);
      if (alcs_send_msg->token == NULL) {
          ALCS_free(alcs_send_msg);
          COAP_WRN("Not Enough Memory");
          return FAIL_RETURN;
      }
      alcs_send_msg->token_len = coap_msg.header.tokenlen;
  
      memset(alcs_send_msg->token, 0, alcs_send_msg->token_len + 1);
      memcpy(alcs_send_msg->token, coap_msg.token, alcs_send_msg->token_len);
  
      alcs_send_msg->uri = (char *)ALCS_ADAPTER_malloc(strlen(msg->uri) + 1);
      if (alcs_send_msg->uri == NULL) {
          ALCS_free(alcs_send_msg->token);
          ALCS_free(alcs_send_msg);
          COAP_WRN("ALCS Message Buffer Failed");
          return FAIL_RETURN;
      }
      memset(alcs_send_msg->uri, 0, strlen(msg->uri) + 1);
      memcpy(alcs_send_msg->uri, msg->uri, strlen(msg->uri));
      INIT_LIST_HEAD(&alcs_send_msg->linked_list);
  
      HAL_MutexLock(adapter->mutex);
      list_add_tail(&alcs_send_msg->linked_list, &adapter->alcs_send_list);
      HAL_MutexUnlock(adapter->mutex);
  
      return SUCCESS_RETURN;
  }
  
  int iotx_alcs_send_Response(void *handle, iotx_alcs_msg_t *msg,
                              uint8_t token_len, uint8_t *token)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle;
      CoAPMessage coap_msg;
      CoAPLenString coap_payload;
      CoAPLenString token_payload;
      NetworkAddr network_addr;
  
      AlcsDeviceKey devKey;
      char productKey[IOTX_PRODUCT_KEY_LEN + 1] = { 0 };
      char deviceName[IOTX_DEVICE_NAME_LEN + 1] = { 0 };
      char *uri_pk = NULL;
      char *uri_dn = NULL;
      uint16_t uri_pk_len = 0;
      uint16_t uri_dn_len = 0;
  
      if (adapter == NULL || adapter->coap_ctx == NULL || msg == NULL ||
          msg->payload == NULL || msg->ip == NULL || strlen(msg->ip) == 0 ||
          msg->uri == NULL || strlen(msg->uri) == 0) {
          return NULL_VALUE_ERROR;
      }
  
      if (token_len == 0 || token == NULL) {
          return FAIL_RETURN;
      }
  
      if (strlen(msg->ip) > NETWORK_ADDR_LEN) {
          COAP_ERR("Invalid Ip Address Length");
          return FAIL_RETURN;
      }
  
      memset(&coap_msg, 0, sizeof(CoAPMessage));
      memset(&coap_payload, 0, sizeof(CoAPLenString));
      memset(&token_payload, 0, sizeof(CoAPLenString));
  
      coap_payload.len = msg->payload_len;
      coap_payload.data = msg->payload;
  
      alcs_msg_init(adapter->coap_ctx, &coap_msg, msg->msg_code, msg->msg_type, 0,
                    &coap_payload, (void *)adapter);
  
      res = alcs_msg_setAddr(&coap_msg, msg->uri, NULL);
      if (res != COAP_SUCCESS) {
          COAP_ERR("ALCS Message Set URI Failed");
          return FAIL_RETURN;
      }
  
      memset(&network_addr, 0, sizeof(NetworkAddr));
      memcpy(network_addr.addr, msg->ip, strlen(msg->ip));
      network_addr.port = msg->port;
  
      token_payload.len = token_len;
      token_payload.data = token;
  
      memset(&devKey, 0, sizeof(AlcsDeviceKey));
      memcpy(&devKey.addr, &network_addr, sizeof(NetworkAddr));
  
      uri_pk = iotx_alcs_topic_parse_pk(msg->uri, &uri_pk_len);
      uri_dn = iotx_alcs_topic_parse_dn(msg->uri, &uri_dn_len);
  
      if (uri_pk == NULL || uri_pk_len >= IOTX_PRODUCT_KEY_LEN + 1 ||
          uri_dn == NULL || uri_dn_len >= IOTX_DEVICE_NAME_LEN + 1) {
          COAP_ERR("Invalid Parameter");
          return FAIL_RETURN;
      }
      memcpy(productKey, uri_pk, uri_pk_len);
      memcpy(deviceName, uri_dn, uri_dn_len);
  
      devKey.pk = productKey;
      devKey.dn = deviceName;
  
      if (alcs_resource_need_auth(adapter->coap_ctx, msg->uri)) {
          res = alcs_sendrsp_secure(adapter->coap_ctx, &devKey, &coap_msg, 0, 0,
                                    &token_payload);
      } else {
          res = alcs_sendrsp(adapter->coap_ctx, &network_addr, &coap_msg, 0, 0,
                             &token_payload);
      }
  
      alcs_msg_deinit(&coap_msg);
  
      if (res != COAP_SUCCESS) {
          COAP_ERR("ALCS Message Send Message Failed");
          return FAIL_RETURN;
      }
  
      return SUCCESS_RETURN;
  }
  
  int iotx_alcs_register_resource(void *handle, iotx_alcs_res_t *resource)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle;
      char productKey[IOTX_PRODUCT_KEY_LEN + 1] = { 0 };
      char deviceName[IOTX_DEVICE_NAME_LEN + 1] = { 0 };
      char *uri_pk = NULL;
      char *uri_dn = NULL;
      uint16_t uri_pk_len = 0;
      uint16_t uri_dn_len = 0;
      int needAuth = 0;
  
      if (adapter == NULL || adapter->coap_ctx == NULL || resource->uri == NULL ||
          strlen(resource->uri) == 0) {
          return NULL_VALUE_ERROR;
      }
  
      uri_pk = iotx_alcs_topic_parse_pk(resource->uri, &uri_pk_len);
      uri_dn = iotx_alcs_topic_parse_dn(resource->uri, &uri_dn_len);
  
      if (uri_pk == NULL || uri_pk_len >= IOTX_PRODUCT_KEY_LEN + 1 ||
          uri_dn == NULL || uri_dn_len >= IOTX_DEVICE_NAME_LEN + 1) {
          COAP_ERR("Invalid Parameter");
          return FAIL_RETURN;
      }
      memcpy(productKey, uri_pk, uri_pk_len);
      memcpy(deviceName, uri_dn, uri_dn_len);
  
      COAP_INFO("alcs register resource, uri:%s", resource->uri);
      needAuth =
          resource
              ->need_auth; /* strcmp (resource->uri, "/dev/core/service/dev"); */
  
      res = alcs_resource_register(
          adapter->coap_ctx, productKey, deviceName, resource->uri,
          resource->msg_perm, resource->msg_ct, resource->maxage, needAuth,
          (void (*)(CoAPContext *context, const char *paths, NetworkAddr *remote,
                    CoAPMessage *message)) resource->callback);
  
      if (res != COAP_SUCCESS) {
          COAP_ERR("ALCS Register Resource Failed, Code: %d", res);
          return FAIL_RETURN;
      }
  
      return SUCCESS_RETURN;
  }
  
  int iotx_alcs_observe_notify(void *handle, const char *uri,
                               uint32_t payload_len, uint8_t *payload)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle;
      CoAPLenString coap_payload;
  
      coap_payload.len = (int32_t)payload_len;
      coap_payload.data = payload;
  
      res = alcs_observe_notify(adapter->coap_ctx, uri, &coap_payload);
      if (res != COAP_SUCCESS) {
          COAP_ERR("ALCS Observe Notify Failed, Code: %d", res);
          return FAIL_RETURN;
      }
  
      return SUCCESS_RETURN;
  }
  
  int iotx_alcs_unregister_resource(void *handle, char *uri)
  {
      return SUCCESS_RETURN;
  }
  
  int iotx_alcs_add_sub_device(void *handle, const char *pk, const char *dn)
  {
      int res = 0;
      iotx_alcs_adapter_t *adapter = (iotx_alcs_adapter_t *)handle;
      iotx_alcs_subdev_item_t *subdev_item = NULL;
      char prefix[ALCS_MQTT_PREFIX_MAX_LEN] = { 0 };
      char secret[ALCS_MQTT_SECRET_MAX_LEN] = { 0 };
  
      if (handle == NULL || pk == NULL ||
          strlen(pk) >= IOTX_PRODUCT_KEY_LEN + 1 || dn == NULL ||
          strlen(dn) >= IOTX_DEVICE_NAME_LEN + 1) {
          COAP_ERR("Invalid Argument");
          return FAIL_RETURN;
      }
  
      if (adapter->coap_ctx != NULL) {
          alcs_auth_subdev_init(adapter->coap_ctx, pk, dn);
      }
  
      /* Search Subdev In Linked List */
      HAL_MutexLock(adapter->mutex);
      res = _iotx_alcs_subdev_list_search(pk, dn, &subdev_item);
      if (res == SUCCESS_RETURN) {
          COAP_INFO("This Product Key And Device Name Have Been Added");
          HAL_MutexUnlock(adapter->mutex);
          return SUCCESS_RETURN;
      }
      HAL_MutexUnlock(adapter->mutex);
  
      /* Insert New Subdev Into Linked List */
      subdev_item = (iotx_alcs_subdev_item_t *)ALCS_ADAPTER_malloc(
          sizeof(iotx_alcs_subdev_item_t));
      if (subdev_item == NULL) {
          COAP_ERR("No Enough Memory");
          return FAIL_RETURN;
      }
      memset(subdev_item, 0, sizeof(iotx_alcs_subdev_item_t));
  
      /* Set Product Key And Device Name */
      memcpy(subdev_item->product_key, pk, strlen(pk));
      memcpy(subdev_item->device_name, dn, strlen(dn));
      subdev_item->stage = IOTX_ALCS_SUBDEV_DISCONNCET_CLOUD;
      subdev_item->retry_ms = HAL_UptimeMs();
      INIT_LIST_HEAD(&subdev_item->linked_list);
  
      HAL_MutexLock(adapter->mutex);
      list_add_tail(&subdev_item->linked_list, &adapter->alcs_subdev_list);
      HAL_MutexUnlock(adapter->mutex);
  
      alcs_localsetup_add_sub_device(adapter, subdev_item->product_key,
                                     subdev_item->device_name);
  
      /* Get Prefix And Secret From KV */
      res = alcs_mqtt_prefix_secret_load(pk, strlen(pk), dn, strlen(dn), prefix,
                                         secret);
      if (res == SUCCESS_RETURN) {
          memcpy(subdev_item->prefix, prefix, strlen(prefix));
          memcpy(subdev_item->secret, secret, strlen(secret));
          alcs_mqtt_add_srv_key(prefix, secret);
      }
  
      /* Get Prefix And Secret From Cloud */
      alcs_mqtt_subdev_prefix_get(pk, dn);
  
      return SUCCESS_RETURN;
  }
  
  int iotx_alcs_remove_sub_device(void *handle, const char *pk, const char *dn)
  {
      int res = 0;
  
      if (handle == NULL || pk == NULL ||
          strlen(pk) >= IOTX_PRODUCT_KEY_LEN + 1 || dn == NULL ||
          strlen(dn) >= IOTX_DEVICE_NAME_LEN + 1) {
          COAP_ERR("Invalid Parameter");
          return FAIL_RETURN;
      }
  
      res = iotx_alcs_subdev_remove(pk, dn);
      if (res != SUCCESS_RETURN) {
          return FAIL_RETURN;
      }
  
      /* Remove Subdev Item From KV */
      alcs_mqtt_prefix_secret_del(pk, strlen(pk), dn, strlen(dn));
      return SUCCESS_RETURN;
  }
  