#include "sock_api/sock_api.h" #include "mqtt/MQTTClient.h" #include "echo_random.h" #include "echo_cloud.h" #include #define MQTT_DEBUG_EN 1 #if MQTT_DEBUG_EN #define MQTT_DEBUG log_d #define MQTT_LOGV log_v #define MQTT_LOGD log_d #define MQTT_LOGI log_i #define MQTT_LOGW log_w #define MQTT_LOGE log_e #define MQTT_LOGWTF log_i #else #define MQTT_DEBUG(_l,...) #define MQTT_LOGV(...) #define MQTT_LOGD(...) #define MQTT_LOGI(...) #define MQTT_LOGW(...) #define MQTT_LOGE(...) #define MQTT_LOGWTF(...) #endif #undef MAX_MESSAGE_HANDLERS #define MAX_MESSAGE_HANDLERS 1 #define DEV_MQTT_QOS QOS2 #define MQTT_SEND_BUF_LEN 1024 #define MQTT_READ_BUF_LEN (1024 * 2) #define DEV_ENT_RECV_TIMEOUT 1000 #define DEV_ENT_SEND_TIMEOUT 1000 #define DEV_MQTT_KEEPALIVE_TIME (30 * 1000) #define MQTT_PUT_TO_MS (2*100) #define MQTT_SERVER_HOST "mqtt.echocloud.com" #define MQTT_SERVER_PORT 1883 enum { ECHO_CLOUD_MQTT_ERR_MALLOC, ECHO_CLOUD_MQTT_ERR_PTR, ECHO_CLOUD_MQTT_ERR_STU, ECHO_CLOUD_MQTT_ERR_CLOSE, ECHO_CLOUD_MQTT_ERR_SEND, ECHO_CLOUD_MQTT_ERR_USER, ECHO_CLOUD_MQTT_ERR_JSON, }; struct dev_mqtt_msg_hdl { char topicFilter[UUID_LEN + DEVICE_ID_LEN + 5 + 1]; void (*fp)(MessageData *); }; struct dev_mqtt_hdl { Client c; Network n; MQTTPacket_connectData data; struct echo_cloud_auth_parm *auth; unsigned char sendbuf[MQTT_SEND_BUF_LEN]; unsigned char recvbuf[MQTT_READ_BUF_LEN]; u8 ready; u8 stu; u16 port; char host[19]; char password[PASSWORD_LEN + 1]; char username[USERNAME_LEN + 1]; struct dev_mqtt_msg_hdl msg[MAX_MESSAGE_HANDLERS]; }; static const MQTTPacket_connectData MQTTPacket_default = MQTTPacket_connectData_initializer; static int echo_mqtt_task_pid; static u8 volatile echo_mqtt_exit_flag = 0; static void dev_mqtt_user_msg(MessageData *md) { MQTTMessage *message = md->message; u8 *msg = (u8 *)malloc(message->payloadlen + 1); if (!msg) { return; } memcpy(msg, message->payload, message->payloadlen); msg[message->payloadlen] = 0; //消息全放在同一线程里处理 if (OS_NO_ERR != os_taskq_post("echo_cloud_app_task", 2, ECHO_CLOUD_MQTT_MSG_DEAL, msg)) { free(msg); } } static int sock_cb_func(enum sock_api_msg_type type, void *priv) { if (echo_mqtt_exit_flag) { return -1; } return 0; } static int dev_net_read(Network *n, unsigned char *buffer, int len, unsigned long timeout_ms) { int bytes; bytes = sock_recv(n->my_socket, buffer, len, 0); if (bytes <= 0) { if (bytes == 0 || !sock_would_block(n->my_socket)) { n->state = -1; MQTT_LOGE("Socket %d recv ret %d, error %d \n", *(int *)n->my_socket, bytes, sock_get_error(n->my_socket)); } bytes = -1; } return bytes; } static int dev_net_write(Network *n, unsigned char *buffer, int len, unsigned long timeout_ms) { int bytes; bytes = sock_send(n->my_socket, buffer, len, 0); if (bytes <= 0) { if (bytes == 0 || !sock_would_block(n->my_socket)) { n->state = -1; MQTT_LOGE("Socket %d send ret %d, error %d \n", *(int *)n->my_socket, bytes, sock_get_error(n->my_socket)); } bytes = -1; } return bytes; } static void dev_net_disconnect(Network *n) { sock_unreg(n->my_socket); n->my_socket = NULL; } static void newNetwork(Network *n) { n->my_socket = NULL; n->mqttread = dev_net_read; n->mqttwrite = dev_net_write; n->disconnect = dev_net_disconnect; } static int connectNetwork(Network *n, char *addr, u16 port) { struct sockaddr_in address; int rc = -1; struct addrinfo *result = NULL; struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; if ((rc = getaddrinfo(addr, NULL, &hints, &result)) == 0) { struct addrinfo *res = result; /* prefer ip4 addresses */ while (res) { if (res->ai_family == AF_INET) { result = res; break; } res = res->ai_next; } if (result->ai_family == AF_INET) { address.sin_port = htons(port); address.sin_family = AF_INET; address.sin_addr = ((struct sockaddr_in *)(result->ai_addr))->sin_addr; } else { rc = -1; } freeaddrinfo(result); } if (rc == 0) { n->state = 0; n->my_socket = sock_reg(AF_INET, SOCK_STREAM, 0, sock_cb_func, n); if (n->my_socket) { sock_set_recv_timeout(n->my_socket, DEV_ENT_RECV_TIMEOUT); rc = sock_connect(n->my_socket, (struct sockaddr *)&address, sizeof(address)); if (rc) { MQTT_LOGE("mqtt_sock connect err = %d \r\n", rc); } } else { rc = -1; } } return rc; } static int dev_mqtt_start(struct dev_mqtt_hdl *mqtt) { int i, ret; if (mqtt->stu) { return ECHO_CLOUD_MQTT_ERR_STU; } mqtt->n.priv = &mqtt->c; newNetwork(&mqtt->n); ret = connectNetwork(&mqtt->n, mqtt->host, mqtt->port); if (ret) { MQTT_LOGE("connectNetwork error :%d \n", ret); goto __mqtt_start_err1; } MQTTClient(&mqtt->c, &mqtt->n, 1000, mqtt->sendbuf, MQTT_SEND_BUF_LEN, mqtt->recvbuf, MQTT_READ_BUF_LEN); memcpy(&mqtt->data, &MQTTPacket_default, sizeof(MQTTPacket_connectData)); mqtt->data.willFlag = 0; mqtt->data.MQTTVersion = 4; mqtt->data.clientID.cstring = mqtt->auth->device_id; mqtt->data.username.cstring = mqtt->username; mqtt->data.password.cstring = mqtt->password; mqtt->data.keepAliveInterval = DEV_MQTT_KEEPALIVE_TIME / 1000; mqtt->data.cleansession = 1; ret = MQTTConnect(&mqtt->c, &mqtt->data); if (ret) { MQTT_LOGE("MQTTConnect error :%d \n", ret); goto __mqtt_start_err1; } for (i = 0; i < MAX_MESSAGE_HANDLERS; i++) { if (!mqtt->msg[i].topicFilter[0]) { break; } /* printf("sub fp:0x%x , topic: %s \n", g_jl_mqtt->msg[i].fp, g_jl_mqtt->msg[i].topicFilter); */ ret = MQTTSubscribe(&mqtt->c, mqtt->msg[i].topicFilter, DEV_MQTT_QOS, mqtt->msg[i].fp); if (ret) { MQTT_LOGE("MQTTSubscribe error :%d \n", ret); goto __mqtt_start_err; } } mqtt->stu = 1; MQTT_LOGI("mqtt start ok \n"); return 0; __mqtt_start_err: MQTTDisconnect(&mqtt->c); __mqtt_start_err1: mqtt->n.disconnect(&mqtt->n); mqtt->stu = 0; return ret; } static void dev_mqtt_stop(struct dev_mqtt_hdl *mqtt) { MQTT_LOGI("dev_mqtt_stop_1\n"); if (!mqtt->stu) { return; } MQTTDisconnect(&mqtt->c); mqtt->n.disconnect(&mqtt->n); mqtt->stu = 0; MQTT_LOGI("dev_mqtt_stop_2\n"); } static int dev_mqtt_opr(struct dev_mqtt_hdl *mqtt) { if (!mqtt->stu) { return ECHO_CLOUD_MQTT_ERR_STU; } return MQTTYield(&mqtt->c, MQTT_PUT_TO_MS); } static void dev_mqtt_update_user_info(struct dev_mqtt_hdl *mqtt) { char nonce[33]; avGenRand(nonce, 32); nonce[32] = 0; echo_cloud_get_hmac_sha256(mqtt->auth->device_id, mqtt->auth->channel_uuid, nonce, mqtt->password, mqtt->auth->hash); mqtt->password[PASSWORD_LEN] = 0; snprintf(mqtt->username, USERNAME_LEN + 1, "%s.%s.%s", mqtt->auth->channel_uuid, mqtt->auth->device_id, nonce); } static void dev_mqtt_set_server(struct dev_mqtt_hdl *mqtt, const char *host, u16 port) { strcpy(mqtt->host, host); mqtt->port = port; for (u8 i = 0; i < MAX_MESSAGE_HANDLERS; i++) { sprintf(mqtt->msg[i].topicFilter, "%s/%s/sub", mqtt->auth->channel_uuid, mqtt->auth->device_id); mqtt->msg[i].fp = dev_mqtt_user_msg; } } static void echo_cloud_mqtt_task(void *priv) { u32 delay_cnt = 200; struct dev_mqtt_hdl __mqtt; struct dev_mqtt_hdl *mqtt = &__mqtt; memset(mqtt, 0, sizeof(struct dev_mqtt_hdl)); mqtt->auth = (struct echo_cloud_auth_parm *)priv; dev_mqtt_set_server(mqtt, MQTT_SERVER_HOST, MQTT_SERVER_PORT); while (1) { if (mqtt->ready) { delay_cnt = 200; } else { delay_cnt <<= 1; if (delay_cnt > 30 * 1000) { delay_cnt = 200; } } if (echo_mqtt_exit_flag) { mqtt->ready = 0; dev_mqtt_stop(mqtt); return; } if (!mqtt->ready) { os_time_dly(delay_cnt / 10); // mqtt每次连接都要重新生成username和password MQTT_LOGI("dev get mqtt user...\n"); dev_mqtt_update_user_info(mqtt); MQTT_LOGI("username:%s password:%s device_id:%s channel_uuid:%s topic:%s host:%s port:%d\n" , mqtt->username , mqtt->password , mqtt->auth->device_id , mqtt->auth->channel_uuid , mqtt->msg[0].topicFilter , mqtt->host , mqtt->port); if (0 == dev_mqtt_start(mqtt)) { mqtt->ready = 1; } } if (dev_mqtt_opr(mqtt)) { // mqtt 有错误,重新连接 dev_mqtt_stop(mqtt); mqtt->ready = 0; } } } int echo_cloud_mqtt_init(struct echo_cloud_auth_parm *auth) { echo_mqtt_exit_flag = 0; return thread_fork("echo_cloud_mqtt_task", 15, 1536, 0, &echo_mqtt_task_pid, echo_cloud_mqtt_task, auth); } void echo_cloud_mqtt_uninit(void) { echo_mqtt_exit_flag = 1; thread_kill(&echo_mqtt_task_pid, KILL_WAIT); echo_mqtt_exit_flag = 0; }