/** * Copyright (2017) Baidu Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. */ // Author: Su Hao (suhao@baidu.com) // // Description: Provide the API for external applications. #include "lightduer_ca.h" #include "lightduer_timestamp.h" #include "lightduer_lib.h" #include "lightduer_coap_trace.h" #include "lightduer_coap.h" #include "lightduer_ca_conf.h" #include "lightduer_mutex.h" #include "lightduer_memory.h" #include "lightduer_log.h" #include "lightduer_ds_log_ca.h" #include "lightduer_timestamp.h" #include "baidu_json.h" #define DUER_CONF_KEY_UUID "uuid" #define DUER_CONF_KEY_TOKEN "token" #define DUER_CONF_KEY_BINDTOKEN "bindToken" #define DUER_CONF_KEY_HOST "serverAddr" #define DUER_CONF_KEY_PORT_REG "lwm2mPort" #define DUER_CONF_KEY_PORT_RPT "coapPort" #define DUER_CONF_KEY_CERT "rsaCaCrt" #define DUER_CONF_KEY_CUID "cuid" #define DUER_CONF_KEY_BDUSS "bduss" #define DUER_CONF_KEY_CLIENT_ID "clientId" #define DUER_CONF_KEY_USER_AGENT "userAgent" #define DUER_COAP_LIFETIME "3600" #define DUER_SR_REG_PATH "reg_for_control" #define DUER_REPORT_PATH "v1/device/data" #define DUER_RPT_QUERY_UUID "deviceUuid=" #define DUER_RPT_QUERY_TOKEN "token=" #define SR_TAG_UUID "deviceUUID" #define SR_TAG_TOKEN "token" #define SR_TAG_CUID "cuid" #define SR_TAG_BDUSS "bduss" #define SR_TAG_CLIENT_ID "clientId" #define SR_TAG_USER_AGENT "userAgent" #if defined(DUER_UDP_REPORTER) #define SR_HOST "117.185.17.43" #define SR_PORT 8899 #endif #define DUER_READ_TIMEOUT (0) #define DUER_RES_INC_COUNT (5) typedef enum _baidu_ca_start_state_enum { DUER_ST_STOPED, DUER_ST_UNREGISTERED, DUER_ST_REGISTER_CONNECTED, DUER_ST_REGISTERED, DUER_ST_SR_CONNECTING, DUER_ST_SR_DATA_SENDING, DUER_ST_SR_DATA_RECEIVING, DUER_ST_SR_INITIALIZED, DUER_ST_RPT_CONNECTED, DUER_ST_RPT_INITIALIZED, DUER_ST_STARTED, DUER_ST_REPORTING, DUER_ST_REPORTED, DUER_ST_REGISTER_FAIL } duer_state_e; typedef struct _baidu_ca_s { // Start state volatile duer_u8_t state; // register message id #if defined(DUER_LWM2M_REGISTER) duer_u16_t msg_id_reg; duer_u16_t msg_id_unreg; #endif // Configuation duer_conf_handler conf; // mutex duer_mutex_t mutex; // Configuration char *uuid; char *token; char *bindToken; // If cuid is not null, deviceUuid will be binded to cuid on IoT cloud char *cuid; // If bduss is not null, auth by bduss on IoT cloud char *bduss; char *client_id; char *user_agent; char *serverAddr; char *report_query; duer_size_t report_query_len; const char *cert; duer_size_t cert_length; // Token generator duer_u16_t gen_token; // Coap handler #if defined(DUER_LWM2M_REGISTER) duer_coap_handler reg; #endif duer_coap_handler sr; #if defined(DUER_UDP_REPORTER) duer_coap_handler rpt; #endif // Resource list duer_res_t *res_list; duer_u32_t res_size; duer_u32_t res_capa; // Response callback duer_notify_f f_response; duer_context ctx_response; // Response callback duer_transmit_f f_transmit; // Socket context duer_transevt_func ctx_socket; // Remote address #if defined(DUER_LWM2M_REGISTER) duer_addr_t addr_reg; #endif duer_addr_t addr_sr; #if defined(DUER_UDP_REPORTER) duer_addr_t addr_rpt; #endif duer_u32_t start_connect_time; } baidu_ca_t; static volatile duer_u32_t s_max_connect_time_ms = 0; static volatile duer_u32_t s_count_connect = 0; static volatile duer_u32_t s_total_connect_time_ms = 0; void baidu_ca_get_statistic(duer_u32_t *connect_avg_time, duer_u32_t *max_connect_time, duer_u32_t *count_connect) { *max_connect_time = s_max_connect_time_ms / 1000; // unit is ms *count_connect = s_count_connect; if (s_count_connect > 0) { *connect_avg_time = (s_total_connect_time_ms * 0.001) / s_count_connect; // unit is ms } else { *connect_avg_time = 0; } } DUER_EXT_IMPL const char *baidu_ca_get_uuid(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; if (ctx) { return (char *)ctx->uuid; } return NULL; } DUER_EXT_IMPL const char *baidu_ca_get_client_id(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; if (ctx) { return (char *)ctx->client_id; } return NULL; } DUER_EXT_IMPL const char *baidu_ca_get_bduss(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; if (ctx) { return (char *)ctx->bduss; } return NULL; } DUER_EXT_IMPL const char *baidu_ca_get_user_agent(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; if (ctx) { return (char *)ctx->user_agent; } return NULL; } DUER_EXT_IMPL const char *baidu_ca_get_bind_token(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; if (ctx) { return ctx->bindToken; } return NULL; } DUER_EXT_IMPL const char *baidu_ca_get_rsa_cacrt(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; if (ctx) { return ctx->cert; } return NULL; } DUER_LOC_IMPL duer_status_t duer_engine_coap_handler(duer_context ctx, duer_coap_handler coap, const duer_msg_t *msg, const duer_addr_t *addr) { duer_status_t rs = DUER_ERR_FAILED; baidu_ca_t *ptr = (baidu_ca_t *)ctx; if (ptr && msg && addr) { rs = DUER_OK; DUER_LOGV("==> duer_engine_coap_handler: state = %d", ptr->state); #if defined(DUER_LWM2M_REGISTER) if (ptr->reg == coap) { if (ptr->state == DUER_ST_REGISTER_CONNECTED && ptr->msg_id_reg == msg->msg_id) { ptr->msg_id_reg = 0; if (msg->msg_code == DUER_MSG_RSP_CREATED) { ptr->state = DUER_ST_REGISTERED; } } else if (ptr->state == DUER_ST_STOPED && ptr->msg_id_unreg == msg->msg_id) { ptr->msg_id_unreg = 0; } } else #endif if (ptr->sr == coap) { if (ptr->state == DUER_ST_SR_DATA_RECEIVING) { if (msg->msg_code == DUER_MSG_RSP_CONTENT) { DUER_LOGD("ca status: DUER_ST_SR_INITIALIZED"); ptr->state = DUER_ST_SR_INITIALIZED; duer_ds_log_ca_start_state_change(DUER_ST_SR_DATA_RECEIVING, DUER_ST_SR_INITIALIZED); // for debug // char *payload = (char *)DUER_MALLOC(msg->payload_len + 1); // DUER_MEMCPY(payload, msg->payload, msg->payload_len); // payload[msg->payload_len] = '\0'; // DUER_LOGI("register ack payload: %s", payload); // DUER_LOGI("register ack msg_id: %d", msg->msg_id); } else { ptr->state = DUER_ST_REGISTER_FAIL; duer_ds_log_ca_start_state_change(DUER_ST_SR_DATA_RECEIVING, DUER_ST_REGISTER_FAIL); DUER_LOGE("register fail, code: %d", msg->msg_code); duer_ds_log_ca_cache_error(DUER_DS_LOG_CA_START_STATE_REG_FAIL); } } if (ptr->f_response) { ptr->f_response(ptr->ctx_response, (duer_msg_t *)msg, NULL); } } #if defined(DUER_UDP_REPORTER) else if (ptr->rpt == coap) { if (ptr->f_response) { ptr->f_response(ptr->ctx_response, (duer_msg_t *)msg, NULL); } } #endif DUER_LOGV("<== duer_engine_coap_handler: rs = %d", rs); } return rs; } #if defined(DUER_UDP_REPORTER) || defined(DUER_LWM2M_REGISTER) DUER_LOC_IMPL duer_bool baidu_ca_match_address(const duer_addr_t *l, const duer_addr_t *r) { if (l) { DUER_LOGV("baidu_ca_match_address: l = {ip:%s, port:%d, type:%d, length:%d}", l->host, l->port, l->type, l->host_size); } if (r) { DUER_LOGV("baidu_ca_match_address: r = {ip:%s, port:%d, type:%d, length:%d}", r->host, r->port, r->type, r->host_size); } if (l == r || (l && r && l->port == r->port && l->type == r->type && l->host_size == r->host_size && DUER_MEMCMP(r->host, l->host, r->host_size) == 0)) { return DUER_TRUE; } return DUER_FALSE; } #endif #if defined(DUER_LWM2M_REGISTER) DUER_LOC_IMPL duer_status_t baidu_ca_register(baidu_ca_t *ctx) { duer_status_t rs = DUER_ERR_FAILED; duer_coap_ep_t ep; DUER_LOGV("==> baidu_ca_register"); if (!ctx) { goto exit; } if (!ctx->reg) { if (!(ctx->reg = duer_coap_acquire(duer_engine_coap_handler, ctx, ctx->ctx_socket, ctx->uuid))) { goto exit; } duer_coap_set_tx_callback(ctx->reg, ctx->f_transmit); } if (ctx->state == DUER_ST_UNREGISTERED) { rs = duer_coap_connect(ctx->reg, &ctx->addr_reg, ctx->cert, ctx->cert_length); if (rs == DUER_OK) { ctx->state = DUER_ST_REGISTER_CONNECTED; } } if (ctx->state != DUER_ST_REGISTER_CONNECTED) { goto exit; } // Send register message if (ctx->msg_id_reg == 0) { DUER_MEMSET(&ep, 0, sizeof(ep)); ep.name_ptr = (char *)ctx->uuid; ep.name_len = DUER_STRLEN(ctx->uuid); ep.type_ptr = (char *)ctx->token; ep.type_len = DUER_STRLEN(ctx->token); ep.lifetime_ptr = DUER_COAP_LIFETIME; ep.lifetime_len = DUER_STRLEN(DUER_COAP_LIFETIME); rs = duer_coap_register(ctx->reg, &ep); if (rs == 0) { rs = DUER_ERR_FAILED; } if (rs > 0) { ctx->msg_id_reg = (duer_u16_t)rs; } else { goto exit; } } rs = duer_coap_data_available(ctx->reg); exit: DUER_LOGV("<== baidu_ca_register: rs = %d", rs); return rs; } #endif DUER_LOC_IMPL char *baidu_ca_get_service_router_payload( const char *uuid, const char *token, const char *cuid, const char *bduss, const char *client_id, const char *user_agent) { char *rs = NULL; baidu_json *item = baidu_json_CreateObject(); if (item) { baidu_json_AddStringToObject(item, SR_TAG_UUID, uuid); baidu_json_AddStringToObject(item, SR_TAG_TOKEN, token); if (cuid != NULL) { baidu_json_AddStringToObject(item, SR_TAG_CUID, cuid); } if (bduss != NULL) { baidu_json_AddStringToObject(item, SR_TAG_BDUSS, bduss); } if (client_id != NULL) { baidu_json_AddStringToObject(item, SR_TAG_CLIENT_ID, client_id); } if (user_agent != NULL) { baidu_json_AddStringToObject(item, SR_TAG_USER_AGENT, user_agent); } rs = baidu_json_PrintUnformatted(item); baidu_json_Delete(item); } return rs; } DUER_LOC_IMPL duer_status_t baidu_ca_create_service_router(baidu_ca_t *ctx) { duer_status_t rs = DUER_ERR_FAILED; duer_msg_t msg_reg; DUER_LOGV("==> baidu_ca_create_service_router"); if (!ctx) { goto exit; } if (!ctx->sr) { ctx->sr = duer_coap_acquire(duer_engine_coap_handler, ctx, ctx->ctx_socket, ctx->uuid); if (!ctx->sr) { goto exit; } duer_coap_set_tx_callback(ctx->sr, ctx->f_transmit); } if (ctx->state == DUER_ST_SR_CONNECTING) { //record the start connect time if (ctx->start_connect_time == 0) { ctx->start_connect_time = duer_timestamp(); } duer_ds_log_ca_start_connect(ctx->addr_sr.host, ctx->addr_sr.port); #ifndef NET_TRANS_ENCRYPTED_BY_AES_CBC rs = duer_coap_connect(ctx->sr, &ctx->addr_sr, ctx->cert, ctx->cert_length); #else // bindToken is the key for AES encryption rs = duer_coap_connect(ctx->sr, &ctx->addr_sr, ctx->bindToken, DUER_STRLEN(ctx->bindToken)); #endif // NET_TRANS_ENCRYPTED_BY_AES_CBC // baidu_ca_unload_configuration(ctx); //release the bjson format of the profile to save memory DUER_LOGD("ca state: DUER_ST_SR_CONNECTING, rs:%d", rs); if (rs == DUER_OK) { ctx->state = DUER_ST_SR_DATA_SENDING; //after success connect, calculate the connect time int time_end = duer_timestamp(); int time_cost = time_end - ctx->start_connect_time; if (time_cost > s_max_connect_time_ms) { s_max_connect_time_ms = time_cost; } ++s_count_connect; s_total_connect_time_ms += time_cost; ctx->start_connect_time = 0; } } if (ctx->state == DUER_ST_SR_DATA_SENDING) { DUER_MEMSET(&msg_reg, 0, sizeof(msg_reg)); msg_reg.msg_type = DUER_MSG_TYPE_CONFIRMABLE; msg_reg.msg_code = DUER_MSG_REQ_POST; msg_reg.path = (duer_u8_t *)DUER_SR_REG_PATH; msg_reg.path_len = DUER_STRLEN(DUER_SR_REG_PATH); msg_reg.payload = (duer_u8_t *)baidu_ca_get_service_router_payload( ctx->uuid, ctx->token, ctx->cuid, ctx->bduss, ctx->client_id, ctx->user_agent); msg_reg.payload_len = DUER_STRLEN((char *)msg_reg.payload); rs = duer_coap_send(ctx->sr, &msg_reg); baidu_json_release(msg_reg.payload); DUER_LOGD("ca state: DUER_ST_SR_DATA_SENDING, rs:%d", rs); if (rs < DUER_OK) { goto exit; } ctx->state = DUER_ST_SR_DATA_RECEIVING; duer_ds_log_ca_start_state_change(DUER_ST_SR_DATA_SENDING, DUER_ST_SR_DATA_RECEIVING); } if (ctx->state == DUER_ST_SR_DATA_RECEIVING) { rs = duer_coap_data_available(ctx->sr); DUER_LOGD("ca state: DUER_ST_SR_DATA_RECEIVING, rs:%d", rs); if (rs < DUER_OK) { goto exit; } } if (ctx->state == DUER_ST_SR_INITIALIZED) { DUER_LOGD("ca state: DUER_ST_SR_INITIALIZED"); baidu_ca_add_resources(ctx, ctx->res_list, ctx->res_size); if (ctx->res_list) { DUER_FREE(ctx->res_list); ctx->res_list = NULL; ctx->res_size = 0; ctx->res_capa = 0; } } if (ctx->state == DUER_ST_REGISTER_FAIL) { rs = DUER_ERR_REG_FAIL; } exit: DUER_LOGV("<== baidu_ca_create_service_router: rs = %d", rs); return rs; } #if defined(DUER_UDP_REPORTER) DUER_LOC_IMPL duer_status_t baidu_ca_create_reporter(baidu_ca_t *ctx) { duer_status_t rs = DUER_ERR_FAILED; DUER_LOGV("==> baidu_ca_create_reporter"); if (!ctx) { goto exit; } if (!ctx->rpt) { ctx->rpt = duer_coap_acquire(duer_engine_coap_handler, ctx, ctx->ctx_socket, ctx->uuid); if (!ctx->rpt) { goto exit; } duer_coap_set_tx_callback(ctx->rpt, ctx->f_transmit); } if (ctx->state == DUER_ST_SR_INITIALIZED) { rs = duer_coap_connect(ctx->rpt, &ctx->addr_rpt, ctx->cert, ctx->cert_length); if (rs == DUER_OK) { ctx->state = DUER_ST_RPT_CONNECTED; } } if (ctx->state == DUER_ST_RPT_CONNECTED) { #if defined(DUER_READ_TIMEOUT) && (DUER_READ_TIMEOUT > 0) duer_coap_set_read_timeout(ctx->rpt, DUER_READ_TIMEOUT); #endif ctx->state = DUER_ST_RPT_INITIALIZED; rs = DUER_OK; } exit: DUER_LOGV("<== baidu_ca_create_reporter: rs = %d", rs); return rs; } #endif DUER_LOC_IMPL duer_status_t baidu_ca_run(baidu_ca_t *ctx) { duer_status_t rs = DUER_ERR_FAILED; if (!ctx) { goto exit; } DUER_LOGV("==> baidu_ca_run: ctx = %p, state = %d", ctx, ctx->state); switch (ctx->state) { case DUER_ST_UNREGISTERED: DUER_LOGD("ca status: %d", ctx->state); ctx->state = DUER_ST_REGISTER_CONNECTED; rs = DUER_OK; break; case DUER_ST_REGISTER_CONNECTED: #if defined(DUER_LWM2M_REGISTER) rs = baidu_ca_register(ctx); break; #else DUER_LOGD("ca status: %d", ctx->state); ctx->state = DUER_ST_REGISTERED; rs = DUER_OK; break; #endif case DUER_ST_REGISTERED: DUER_LOGD("ca status: %d", ctx->state); ctx->state = DUER_ST_SR_CONNECTING; rs = DUER_OK; break; case DUER_ST_SR_CONNECTING: case DUER_ST_SR_DATA_SENDING: case DUER_ST_SR_DATA_RECEIVING: DUER_LOGD("ca status: %d", ctx->state); rs = baidu_ca_create_service_router(ctx); break; case DUER_ST_SR_INITIALIZED: #if defined(DUER_UDP_REPORTER) rs = baidu_ca_create_reporter(ctx); break; #endif case DUER_ST_RPT_INITIALIZED: DUER_LOGD("ca status: DUER_ST_RPT_INITIALIZED -> DUER_ST_STARTED"); ctx->state = DUER_ST_STARTED; duer_ds_log_ca_start_state_change(DUER_ST_RPT_INITIALIZED, DUER_ST_STARTED); rs = DUER_OK; break; case DUER_ST_STOPED: rs = DUER_ERR_FAILED; break; case DUER_ST_STARTED: rs = DUER_OK; break; default: // do noting break; } DUER_LOGV("<== baidu_ca_run: rs = %d", rs); exit: return rs; } DUER_EXT_IMPL duer_handler baidu_ca_acquire(duer_transevt_func soc_ctx) { baidu_ca_t *hdlr = NULL; DUER_LOGV("==> baidu_ca_acquire"); DUER_MEMDBG_USAGE(); hdlr = DUER_MALLOC(sizeof(baidu_ca_t)); if (!hdlr) { DUER_LOGE("alloc failed..."); DUER_DS_LOG_CA_MEMORY_OVERFLOW(); baidu_ca_release(hdlr); return NULL; } duer_coap_trace_enable(); DUER_MEMSET(hdlr, 0, sizeof(baidu_ca_t)); hdlr->state = DUER_ST_STOPED; hdlr->mutex = duer_mutex_create(); hdlr->gen_token = 0xC000; hdlr->ctx_socket = soc_ctx; DUER_LOGV("<== baidu_ca_acquire: hdlr = %p", hdlr); return hdlr; } DUER_EXT duer_status_t baidu_ca_add_resources(duer_handler hdlr, const duer_res_t list_res[], duer_size_t list_res_size) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_status_t rs = DUER_ERR_FAILED; if (ctx->state >= DUER_ST_SR_INITIALIZED) { duer_u8_t i = 0; while (i < list_res_size) { duer_coap_resource_add(ctx->sr, list_res + i); i++; } rs = DUER_OK; goto exit; } //Note: if exccute here, the path/static data should be something with long-time life // e.g. static chars; or try to add resource after the CA started. DUER_LOGW("add_resource at CA not started, all the content(static_data, path)should be static!"); if (ctx->res_list == NULL) { ctx->res_capa = (list_res_size / DUER_RES_INC_COUNT + 1) * DUER_RES_INC_COUNT; ctx->res_list = DUER_MALLOC(sizeof(duer_res_t) * ctx->res_capa); ctx->res_size = 0; } else if (ctx->res_capa < ctx->res_size + list_res_size) { ctx->res_capa = ((ctx->res_size + list_res_size) / DUER_RES_INC_COUNT + 1) * DUER_RES_INC_COUNT; ctx->res_list = (duer_res_t *)DUER_REALLOC(ctx->res_list, sizeof(duer_res_t) * ctx->res_capa); } if (ctx->res_list == NULL) { DUER_LOGE(" stored the resource failed..."); DUER_DS_LOG_CA_MEMORY_OVERFLOW(); goto exit; } DUER_MEMCPY(ctx->res_list + ctx->res_size, list_res, sizeof(duer_res_t) * list_res_size); ctx->res_size += list_res_size; rs = DUER_OK; exit: return rs; } duer_status_t baidu_ca_unload_configuration(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; ctx->cert = NULL; ctx->cert_length = 0; if (ctx->conf) { duer_conf_destroy(ctx->conf); ctx->conf = NULL; } return DUER_OK; } DUER_EXT_IMPL duer_status_t baidu_ca_load_configuration(duer_handler hdlr, const void *data, duer_size_t size) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_status_t rs = DUER_ERR_FAILED; const char *string_addr = NULL; if (!ctx) { DUER_LOGE("invalid handler with null"); goto error; } if (ctx->conf) { duer_conf_destroy(ctx->conf); ctx->conf = NULL; } ctx->conf = duer_conf_create(data, size); if (!ctx->conf) { DUER_LOGE(" create the configuation failed..."); goto error; } string_addr = duer_conf_get_string(ctx->conf, DUER_CONF_KEY_UUID); if (ctx->uuid) { DUER_FREE(ctx->uuid); ctx->uuid = NULL; } if (string_addr) { ctx->uuid = DUER_MALLOC(DUER_STRLEN(string_addr) + 1); } if (!string_addr || !ctx->uuid) { DUER_LOGE(" obtain the uuid failed..."); goto error; } else { DUER_MEMCPY(ctx->uuid, string_addr, DUER_STRLEN(string_addr) + 1); } string_addr = duer_conf_get_string(ctx->conf, DUER_CONF_KEY_TOKEN); if (ctx->token) { DUER_FREE(ctx->token); ctx->token = NULL; } if (string_addr) { ctx->token = DUER_MALLOC(DUER_STRLEN(string_addr) + 1); } if (!string_addr || !ctx->token) { DUER_LOGE(" obtain the token failed..."); goto error; } else { DUER_MEMCPY(ctx->token, string_addr, DUER_STRLEN(string_addr) + 1); } string_addr = duer_conf_get_string(ctx->conf, DUER_CONF_KEY_BINDTOKEN); if (ctx->bindToken) { DUER_FREE(ctx->bindToken); ctx->bindToken = NULL; } if (string_addr) { ctx->bindToken = DUER_MALLOC(DUER_STRLEN(string_addr) + 1); } if (!string_addr || !ctx->bindToken) { // DUER_LOGE(" obtain the bindToken failed..."); // goto error; } else { DUER_MEMCPY(ctx->bindToken, string_addr, DUER_STRLEN(string_addr) + 1); } ctx->cert = duer_conf_get_string(ctx->conf, DUER_CONF_KEY_CERT); if (!ctx->cert) { DUER_LOGE(" obtain the cert failed..."); goto error; } ctx->cert_length = DUER_STRLEN(ctx->cert) + 1; string_addr = duer_conf_get_string(ctx->conf, DUER_CONF_KEY_HOST); if (ctx->serverAddr) { DUER_FREE(ctx->serverAddr); ctx->serverAddr = NULL; } if (string_addr) { ctx->serverAddr = DUER_MALLOC(DUER_STRLEN(string_addr) + 1); } if (!string_addr || !ctx->serverAddr) { DUER_LOGE(" obtain the hostname failed..."); goto error; } else { DUER_MEMCPY(ctx->serverAddr, string_addr, DUER_STRLEN(string_addr) + 1); } // cuid may be not exist string_addr = (char *)duer_conf_get_string(ctx->conf, DUER_CONF_KEY_CUID); if (ctx->cuid) { DUER_FREE(ctx->cuid); ctx->cuid = NULL; } if (string_addr) { ctx->cuid = DUER_MALLOC(DUER_STRLEN(string_addr) + 1); } if (string_addr && !ctx->cuid) { DUER_LOGE(" malloc the cuid failed..."); goto error; } else { if (ctx->cuid) { DUER_MEMCPY(ctx->cuid, string_addr, DUER_STRLEN(string_addr) + 1); DUER_LOGI("profile include cuid:%s", ctx->cuid); } } // bduss may be not exist string_addr = (char *)duer_conf_get_string(ctx->conf, DUER_CONF_KEY_BDUSS); if (ctx->bduss) { DUER_FREE(ctx->bduss); ctx->bduss = NULL; } if (string_addr) { ctx->bduss = DUER_MALLOC(DUER_STRLEN(string_addr) + 1); } if (string_addr && !ctx->bduss) { DUER_LOGE(" malloc the bduss failed..."); goto error; } else { if (ctx->bduss) { DUER_MEMCPY(ctx->bduss, string_addr, DUER_STRLEN(string_addr) + 1); DUER_LOGI("profile include bduss:%s", ctx->bduss); } } // client_id may be not exist string_addr = (char *)duer_conf_get_string(ctx->conf, DUER_CONF_KEY_CLIENT_ID); if (ctx->client_id) { DUER_FREE(ctx->client_id); ctx->client_id = NULL; } if (string_addr) { ctx->client_id = DUER_MALLOC(DUER_STRLEN(string_addr) + 1); } if (string_addr && !ctx->client_id) { DUER_LOGE(" malloc the client_id failed..."); goto error; } else { if (ctx->client_id) { DUER_MEMCPY(ctx->client_id, string_addr, DUER_STRLEN(string_addr) + 1); DUER_LOGI("profile include client_id:%s", ctx->client_id); } } // user_agent may be not exist string_addr = (char *)duer_conf_get_string(ctx->conf, DUER_CONF_KEY_USER_AGENT); if (ctx->user_agent) { DUER_FREE(ctx->user_agent); ctx->user_agent = NULL; } if (string_addr) { ctx->user_agent = DUER_MALLOC(DUER_STRLEN(string_addr) + 1); } if (string_addr && !ctx->user_agent) { DUER_LOGE(" malloc the user_agent failed..."); goto error; } else { if (ctx->user_agent) { DUER_MEMCPY(ctx->user_agent, string_addr, DUER_STRLEN(string_addr) + 1); DUER_LOGI("profile include user_agent:%s", ctx->user_agent); } } #if defined(DUER_LWM2M_REGISTER) ctx->addr_reg.host = ctx->serverAddr; ctx->addr_reg.host_size = DUER_STRLEN(ctx->serverAddr); ctx->addr_reg.port = duer_conf_get_ushort(ctx->conf, DUER_CONF_KEY_PORT_REG); ctx->addr_reg.type = DUER_PROTO_UDP; #endif #if defined(DUER_UDP_REPORTER) ctx->addr_sr.host = SR_HOST; ctx->addr_sr.host_size = DUER_STRLEN(SR_HOST); ctx->addr_sr.port = SR_PORT; #else ctx->addr_sr.host = ctx->serverAddr; ctx->addr_sr.host_size = DUER_STRLEN(ctx->serverAddr); ctx->addr_sr.port = duer_conf_get_ushort(ctx->conf, DUER_CONF_KEY_PORT_RPT); #endif ctx->addr_sr.type = DUER_PROTO_TCP; #if defined(DUER_UDP_REPORTER) ctx->addr_rpt.host = ctx->serverAddr; ctx->addr_rpt.host_size = DUER_STRLEN(ctx->serverAddr); ctx->addr_rpt.port = duer_conf_get_ushort(ctx->conf, DUER_CONF_KEY_PORT_RPT); ctx->addr_rpt.type = DUER_PROTO_UDP; #endif if (ctx->report_query) { DUER_FREE(ctx->report_query); ctx->report_query = NULL; } ctx->report_query_len = DUER_STRLEN(DUER_RPT_QUERY_UUID) + DUER_STRLEN(ctx->uuid) + 1 // '&' + DUER_STRLEN(DUER_RPT_QUERY_TOKEN) + DUER_STRLEN(ctx->token); ctx->report_query = DUER_MALLOC(ctx->report_query_len + 1); if (!ctx->report_query) { DUER_DS_LOG_CA_MEMORY_OVERFLOW(); goto error; } DUER_SNPRINTF( ctx->report_query, ctx->report_query_len + 1, DUER_RPT_QUERY_UUID"%s&"DUER_RPT_QUERY_TOKEN"%s", ctx->uuid, ctx->token); rs = DUER_OK; error: return rs; } DUER_EXT_IMPL duer_status_t baidu_ca_do_start(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_status_t rs = DUER_ERR_FAILED; DUER_LOGV("==> baidu_ca_do_start"); if (!ctx) { goto exit; } duer_mutex_lock(ctx->mutex); rs = DUER_OK; while (ctx->state != DUER_ST_STARTED && rs == DUER_OK) { DUER_LOGD("ca status: %d", ctx->state); rs = baidu_ca_run(ctx); } duer_mutex_unlock(ctx->mutex); exit: DUER_LOGV("<== baidu_ca_do_start: rs = %d", rs); return rs; } DUER_EXT_IMPL duer_status_t baidu_ca_start(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_status_t rs = DUER_ERR_FAILED; DUER_LOGV("==> baidu_ca_start"); if (!ctx) { goto exit; } if (ctx->state == DUER_ST_STOPED) { DUER_LOGD("ca status: DUER_ST_STOPED -> DUER_ST_UNREGISTERED"); ctx->state = DUER_ST_UNREGISTERED; } if (ctx->state == DUER_ST_REGISTER_FAIL) { rs = DUER_ERR_REG_FAIL; } else { rs = baidu_ca_do_start(hdlr); } exit: DUER_LOGV("<== baidu_ca_start: rs = %d", rs); return rs; } DUER_EXT_IMPL duer_bool baidu_ca_is_started(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; return (ctx != NULL && ctx->state == DUER_ST_STARTED) ? DUER_TRUE : DUER_FALSE; } DUER_EXT_IMPL duer_bool baidu_ca_is_stopped(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; return (ctx == NULL || ctx->state == DUER_ST_STOPED) ? DUER_TRUE : DUER_FALSE; } DUER_EXT_IMPL duer_status_t baidu_ca_report_set_response_callback( duer_handler hdlr, duer_notify_f f_response, duer_context context) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; if (ctx) { ctx->f_response = f_response; ctx->ctx_response = context; return DUER_OK; } return DUER_ERR_FAILED; } DUER_EXT duer_status_t baidu_ca_report_set_data_tx_callback(duer_handler hdlr, duer_transmit_f f_transmit) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; if (ctx) { ctx->f_transmit = f_transmit; return DUER_OK; } return DUER_ERR_FAILED; } static duer_msg_t *baidu_ca_build_coap_message() { duer_msg_t *msg = DUER_MALLOC(sizeof(duer_msg_t)); // ~= 36 if (msg) { DUER_MEMSET(msg, 0, sizeof(duer_msg_t)); msg->create_timestamp = duer_timestamp(); } return msg; } DUER_EXT duer_msg_t *baidu_ca_build_report_message(duer_handler hdlr, duer_bool confirmable) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_msg_t *msg = NULL; do { if (!ctx) { break; } msg = baidu_ca_build_coap_message(); if (!msg) { DUER_DS_LOG_CA_MEMORY_OVERFLOW(); break; } msg->msg_type = confirmable == DUER_FALSE ? DUER_MSG_TYPE_NON_CONFIRMABLE : DUER_MSG_TYPE_CONFIRMABLE; msg->msg_code = DUER_MSG_REQ_POST; msg->path = (duer_u8_t *)DUER_REPORT_PATH; msg->path_len = DUER_STRLEN(DUER_REPORT_PATH); msg->query = (duer_u8_t *)ctx->report_query; msg->query_len = ctx->report_query_len; msg->token_len = sizeof(ctx->gen_token); msg->token = DUER_MALLOC(msg->token_len); if (msg->token) { DUER_MEMCPY(msg->token, &ctx->gen_token, msg->token_len); } else { DUER_DS_LOG_CA_MEMORY_OVERFLOW(); } ctx->gen_token++; } while (0); return msg; } DUER_EXT duer_msg_t *baidu_ca_build_response_message(duer_handler hdlr, const duer_msg_t *msg, duer_u8_t msg_code) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_msg_t *rs = NULL; const char *token = NULL; do { if (!ctx || !msg) { DUER_LOGE("paramter error: ctx = %p, msg = %p", ctx, msg); break; } if (msg_code != DUER_MSG_EMPTY_MESSAGE) { // empty message don't need token if (msg->token_len > 0 && msg->token) { token = DUER_MALLOC(msg->token_len); if (!token) { DUER_DS_LOG_CA_MEMORY_OVERFLOW(); break; } } } rs = baidu_ca_build_coap_message(); if (!rs) { DUER_DS_LOG_CA_MEMORY_OVERFLOW(); break; } if (msg->msg_type == DUER_MSG_TYPE_CONFIRMABLE) { rs->msg_type = DUER_MSG_TYPE_ACKNOWLEDGEMENT; rs->msg_id = msg->msg_id; } else { rs->msg_type = msg->msg_type; } // DUER_MSG_RSP_INVALID means a seperate response if (msg_code != DUER_MSG_RSP_INVALID) { rs->msg_code = msg_code; if (token) { rs->token_len = msg->token_len; rs->token = (duer_u8_t *)token; DUER_MEMCPY(rs->token, msg->token, rs->token_len); } } } while (0); if (!rs) { if (token) { DUER_FREE((char *)token); token = NULL; } } return rs; } DUER_EXT duer_msg_t *baidu_ca_build_seperate_response_message(duer_handler hdlr, const char *ptoken, duer_size_t token_len, int msg_code, duer_bool confirmable) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_msg_t *rs = NULL; const char *token = NULL; do { if (!ctx) { DUER_LOGE("paramter error: ctx = %p", ctx); break; } if (token_len > 0 && ptoken) { token = DUER_MALLOC(token_len); if (!token) { DUER_DS_LOG_CA_MEMORY_OVERFLOW(); break; } } else { DUER_LOGI("token should not be null!!"); break; } rs = baidu_ca_build_coap_message(); if (!rs) { DUER_DS_LOG_CA_MEMORY_OVERFLOW(); break; } rs->msg_type = confirmable == DUER_FALSE ? DUER_MSG_TYPE_NON_CONFIRMABLE : DUER_MSG_TYPE_CONFIRMABLE; rs->msg_code = msg_code; if (token) { rs->token_len = token_len; rs->token = (duer_u8_t *)token; DUER_MEMCPY(rs->token, ptoken, rs->token_len); } } while (0); if (!rs) { if (token) { DUER_FREE((char *)token); token = NULL; } } return rs; } /* * Release the message that generated by baidu_ca_build_XXXX_message. * * @Param hdlr, in, the handler will be operated * @Param msg, in, the message that remote requested */ DUER_EXT void baidu_ca_release_message(duer_handler hdlr, duer_msg_t *msg) { if (msg) { if (msg->token) { DUER_FREE(msg->token); msg->token = NULL; } DUER_FREE(msg); } } DUER_EXT duer_status_t baidu_ca_send_data(duer_handler hdlr, const duer_msg_t *msg, const duer_addr_t *addr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_status_t rs = DUER_ERR_FAILED; DUER_LOGV("==> baidu_ca_send_data"); #if defined(DUER_UDP_REPORTER) if (ctx->state >= DUER_ST_SR_INITIALIZED && baidu_ca_match_address(&(ctx->addr_sr), addr)) #endif { DUER_LOGV(" ctx->sr matched: %p", addr); rs = duer_coap_send(ctx->sr, msg); goto exit; } #if defined(DUER_UDP_REPORTER) if (ctx->state >= DUER_ST_RPT_INITIALIZED && (!addr || baidu_ca_match_address(&(ctx->addr_rpt), addr))) { duer_mutex_lock(ctx->mutex); DUER_LOGV(" ctx->rpt matched: %p", addr); rs = duer_coap_send(ctx->rpt, msg); duer_mutex_unlock(ctx->mutex); goto exit; } rs = baidu_ca_do_start(hdlr); if (rs < DUER_OK) { DUER_LOGD(" start failed..."); goto exit; } #endif exit: DUER_LOGV("<== baidu_ca_send_data: rs = %d", rs); DUER_MEMDBG_USAGE(); return rs; } DUER_EXT duer_status_t baidu_ca_send_data_directly(duer_handler hdlr, const void *data, duer_size_t size, const duer_addr_t *addr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_status_t rs = DUER_ERR_FAILED; DUER_LOGV("==> baidu_ca_send_data"); #if defined(DUER_UDP_REPORTER) if (ctx->state >= DUER_ST_SR_INITIALIZED && baidu_ca_match_address(&(ctx->addr_sr), addr)) #endif { DUER_LOGV(" ctx->sr matched: %p", addr); rs = duer_coap_send_data(ctx->sr, data, size); goto exit; } #if defined(DUER_UDP_REPORTER) if (ctx->state >= DUER_ST_RPT_INITIALIZED && (!addr || baidu_ca_match_address(&(ctx->addr_rpt), addr))) { duer_mutex_lock(ctx->mutex); DUER_LOGV(" ctx->rpt matched: %p", addr); rs = duer_coap_send_data(ctx->rpt, data, size); duer_mutex_unlock(ctx->mutex); goto exit; } rs = baidu_ca_do_start(hdlr); if (rs < DUER_OK) { DUER_LOGD(" start failed..."); goto exit; } #endif exit: DUER_LOGV("<== baidu_ca_send_data: rs = %d", rs); //DUER_MEMDBG_USAGE(); return rs; } DUER_EXT_IMPL duer_status_t baidu_ca_data_available(duer_handler hdlr, const duer_addr_t *addr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_status_t rs = DUER_ERR_FAILED; DUER_LOGV("==> baidu_ca_data_available"); if (ctx->state >= DUER_ST_SR_INITIALIZED #if defined(DUER_UDP_REPORTER) && baidu_ca_match_address(&(ctx->addr_sr), addr) #endif ) { DUER_LOGV(" ctx->sr matched: %p", addr); rs = duer_coap_data_available(ctx->sr); } #if defined(DUER_UDP_REPORTER) if (ctx->state >= DUER_ST_RPT_INITIALIZED && (!addr || baidu_ca_match_address(&(ctx->addr_rpt), addr))) { duer_mutex_lock(ctx->mutex); DUER_LOGV(" ctx->rpt matched: %p", addr); rs = duer_coap_data_available(ctx->rpt); duer_mutex_unlock(ctx->mutex); } #endif if (ctx->state < DUER_ST_STARTED) { rs = baidu_ca_do_start(hdlr); if (rs < DUER_OK && rs != DUER_ERR_TRANS_WOULD_BLOCK) { DUER_LOGW(" start failed..."); } } DUER_LOGV("<== baidu_ca_data_available: rs = %d", rs); return rs; } DUER_EXT duer_status_t baidu_ca_exec(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_status_t rs = DUER_OK; duer_u32_t timestamp = duer_timestamp() / 1000; DUER_LOGV("==> baidu_ca_exec"); if (ctx) { #if defined(DUER_LWM2M_REGISTER) duer_coap_exec(ctx->reg, timestamp); #endif #if defined(DUER_UDP_REPORTER) duer_coap_exec(ctx->rpt, timestamp); #endif duer_coap_exec(ctx->sr, timestamp); } DUER_LOGV("<== baidu_ca_exec: rs = %d", rs); return rs; } DUER_EXT_IMPL duer_status_t baidu_ca_stop(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; duer_status_t rs = DUER_OK; DUER_LOGV("==> baidu_ca_stop"); if (ctx->state > DUER_ST_STOPED) { ctx->state = DUER_ST_STOPED; if (ctx->sr) { duer_coap_release(ctx->sr); ctx->sr = NULL; } #if defined(DUER_UDP_REPORTER) if (ctx->rpt) { duer_coap_release(ctx->rpt); ctx->rpt = NULL; } #endif #if defined(DUER_LWM2M_REGISTER) if (ctx->reg) { duer_coap_unregister(ctx->reg); duer_coap_release(ctx->reg); ctx->reg = NULL; } #endif } DUER_LOGV("<== baidu_ca_stop: rs = %d", rs); return rs; } DUER_EXT_IMPL duer_status_t baidu_ca_release(duer_handler hdlr) { baidu_ca_t *ctx = (baidu_ca_t *)hdlr; DUER_LOGV("==> baidu_ca_release"); if (ctx) { if (ctx->conf) { duer_conf_destroy(ctx->conf); ctx->conf = NULL; } baidu_ca_stop(ctx); if (ctx->report_query) { DUER_FREE(ctx->report_query); ctx->report_query = NULL; } if (ctx->uuid) { DUER_FREE(ctx->uuid); ctx->uuid = NULL; } if (ctx->token) { DUER_FREE(ctx->token); ctx->token = NULL; } if (ctx->bindToken) { DUER_FREE(ctx->bindToken); ctx->bindToken = NULL; } if (ctx->cuid) { DUER_FREE(ctx->cuid); ctx->cuid = NULL; } if (ctx->bduss) { DUER_FREE(ctx->bduss); ctx->bduss = NULL; } if (ctx->client_id) { DUER_FREE(ctx->client_id); ctx->client_id = NULL; } if (ctx->user_agent) { DUER_FREE(ctx->user_agent); ctx->user_agent = NULL; } if (ctx->serverAddr) { DUER_FREE(ctx->serverAddr); ctx->serverAddr = NULL; } if (ctx->res_list) { DUER_FREE(ctx->res_list); ctx->res_list = NULL; } duer_coap_trace_disable(); duer_mutex_destroy(ctx->mutex); ctx->mutex = NULL; DUER_FREE(ctx); } DUER_MEMDBG_USAGE(); DUER_LOGV("<== baidu_ca_release"); return DUER_OK; }