OpenHarmony解读之设备认证:数据接收管理-消息解析
一、概述
从本文开始,将介绍在HiChain机制中如何处理本端接收到的数据及其响应对端的过程。这个过程的入口函数为receive_data,在receive_data函数中,主要分为三个阶段:消息解析阶段、消息处理阶段和通知对端阶段,本文的重点是总体分析receive_data函数,然后对消息解析阶段的部分内容进行分析。
二、源码分析
这一模块的源码位于:/base/security/deviceauth。
- receive_data函数的整体分析:
/*函数功能:HiChain处理接收到的消息数据函数参数: handle:HiChain实例对象,这里其实是void *类型 data:待处理的的消息数据函数返回值: 成功:返回0 失败:返回其他*/DLL_API_PUBLIC int32_t receive_data(hc_handle handle, struct uint8_buff *data){ LOGI("Begin receive data"); check_ptr_return_val(handle, HC_INPUT_ERROR);//检查实例对象是否为空 check_ptr_return_val(data, HC_INPUT_ERROR);//检查数据是否为空 check_ptr_return_val(data->val, HC_INPUT_ERROR);//检查数据地址是否为空 LOGI("Receive data from peer"); struct hichain *hichain = (struct hichain *)handle;//定义局部变量接收该hichain实例 struct message receive = { 0, 0, 0 };//初始化接收消息体 struct message send = { INFORM_MESSAGE, 0, 0 };//初始化发送消息体 void *send_data = NULL;//声明发送消息的地址 uint32_t send_data_len = 0; int32_t ret = deserialize_message(data, &receive);//反序列化/无序化消息,即解析data原始消息内容,封装成格式化的消息保存在receive指向的地址空间中,通过执行对应消息码类型的解析函数进行解析 if (ret != HC_OK) { goto inform; } struct header_analysis nav = navigate_message(receive.msg_code);//导航消息,根据消息码查表,得到 "消息模块-消息类型(消息码低四位)-是否请求消息" 一一对应的格式 ret = check_message_support(hichain, &nav, &receive);//检查消息是否可支持,解析出操作码,并与消息码进行对应,检查是否一致 if (ret != HC_OK) { goto inform; } //若消息合法且系统可支持,则继续 ret = build_object(hichain, nav.modular, !nav.is_request_msg, NULL);//构建HC子对象,根据nav.is_request_msg判断是否属于客户端 if (ret != HC_OK) { goto inform; } ret = proc_message(hichain, &nav, &receive, &send);//根据modular和is_request_msg查询全局分布式消息表,找到对应的消息处理函数并执行 if (ret != HC_OK) { goto inform; } ret = connect_message(hichain, &nav, &send);//连接消息inform://通知对端 encap_inform_message(ret, &send);//为"通知消息"申请内存空间 /* serialization 消息序列化,即构造通知消息*/ ret = build_send_data_by_struct(&send, &send_data, &send_data_len);//构造结构化的发送消息 if (ret == HC_OK) { DBG_OUT("Send data to peer"); hichain->cb.transmit(&hichain->identity, send_data, send_data_len);//调用软总线模块回调函数进行数据传输 FREE(send_data); } else if (ret == HC_NO_MESSAGE_TO_SEND) { LOGI("Had no message to send"); ret = HC_OK; } else { LOGE("build send data failed, error code is %d", ret); } set_result(hichain, receive.msg_code, send.msg_code, ret);//设置最终结果 destroy_receive_data_struct(&receive);//销毁接收数据结构 destroy_send_data(&send);//销毁发送数据空间 LOGI("End receive data"); return ret; /* hc_error */}
- 在receive_data函数中,首先调用deserialize_message函数对消息进行无序化处理,具体分析如下:
/*函数功能:反序列化/无序化消息函数参数: data:接收到的数据地址,传入参数 receive:用于保存反序列化后消息的地址,传出参数函数返回值: 成功:返回0 失败:返回错误码详细: 主要进行消息码的解析和不同类型消息有效负载的解析,将解析后的消息数据保存在receive参数的地址空间中*/static int32_t deserialize_message(const struct uint8_buff *data, struct message *receive){ /* message head deserialization 消息头反序列化*/ struct pass_through_data *pass_through_data = parse_data((const char *)data->val);//从收到的数据中解析出消息码和有效负载,将有效载荷由cjson格式的数据转化为无格式的json字符串 if (pass_through_data == NULL) { LOGE("Parse data failed"); return HC_BUILD_OBJECT_FAILED; } /* message payload deserialization 有效负载反序列化,根据消息码为不同的消息类型提供对应的解析函数,然后执行对应解析函数进行解析,将解析完成后的消息保存到receive参数中*/ int32_t ret = build_struct_by_receive_data(pass_through_data->message_code, pass_through_data->payload_data, JSON_STRING_DATA, receive); if (ret != HC_OK) { LOGE("Build struct by receive data failed, error code is %d", ret); } free_data(pass_through_data); pass_through_data = NULL; return ret;}
- parse_data函数:从收到的数据中解析出消息码和有效负载,将有效载荷由cjson格式的数据转化为无格式的json字符串。
/*函数功能:解析收到的数据成固定的pass_through_data消息格式,解析出数据之中的消息码和有效负载函数参数: data:数据地址函数返回值: 成功:返回pass_through_data格式化后的数据,包含消息码 失败:返回NULL详细: 解析出消息码和有效负载之后,将有效载荷由cjson格式的数据转化为无格式的字符串*/struct pass_through_data *parse_data(const char *data){ const char *payload = NULL; struct pass_through_data *msg_data = (struct pass_through_data *)MALLOC(sizeof(struct pass_through_data));//为解析后的消息数据申请内存空间 if (msg_data == NULL) { return NULL; } json_handle obj = parse_json(data);//将json格式的数据解析成cjson结构体对象 if (obj == NULL) { LOGE("Passthrough Data parse_json failed"); goto error; } int32_t message_code = get_json_int(obj, FIELD_MESSAGE);//获取该cjson数据中的int类型的数据,即为消息码;子实体为FIELD_MESSAGE="message" if (message_code == -1) { LOGE("Passthrough Data failed, field is null in message"); goto error; } json_pobject obj_value = get_json_obj(obj, FIELD_PAYLOAD);//获取该cjson对象中的FIELD_PAYLOAD="payload"子对象 payload = json_to_string(obj_value);//将Cjson结构体格式的对象转换为无格式字符串 if (payload == NULL) { LOGE("Passthrough Data failed, field is null in payload"); goto error; } (void)memset_s(msg_data, sizeof(*msg_data), 0, sizeof(*msg_data));//清空msg_data地址空间 msg_data->message_code = message_code;//赋值解析出来的消息码 int32_t len = strlen(payload); if (len > 0) { ++len; /* add terminator 添加终止符*/ char *tmp_data = (char *)MALLOC(len);//申请暂存payload数据的内存空间 if (tmp_data == NULL) { goto error; } (void)memset_s(tmp_data, len, 0, len);//清空tmp_data地址空间 (void)memcpy_s(tmp_data, len, payload, len);//将payload字符串拷贝到tmp_data中 msg_data->payload_data = tmp_data;//将该字符串数据直接赋给消息的有效载荷 } FREE((char *)payload);//释放payload空间 free_json(obj);//释放Cjson对象obj return msg_data;error: if (payload != NULL) { FREE((char *)payload); } free_json(obj);//释放cjson结构体对象 FREE(msg_data); return NULL;}//将json格式的数据解析成cjson结构体对象json_handle parse_json(const char *data){ cJSON *root = NULL; if (data != NULL) { root = cJSON_Parse(data);//将json格式的数据解析成cjson结构体对象 } return (void *)root;}//将json格式的数据解析成cjson结构体对象json_handle parse_json(const char *data){ cJSON *root = NULL; if (data != NULL) { root = cJSON_Parse(data);//将json格式的数据解析成cjson结构体对象 } return (void *)root;}//获取该cjson对象中的field子对象json_pobject get_json_obj(json_pobject parent, const char *field){ return cJSON_GetObjectItem((cJSON *)parent, field);//通过键名称在该root节点下查找子节点}//将Cjson结构体格式的对象转换为无格式字符串char *json_to_string(json_pobject obj){ if (obj != NULL) { //需要注意的是 json 格式的数据,虽然也是一个字符串的样子,但这个时候还是无法当成普通的字符串进行使用, //需要调用 cJSON_PrintUnformatted(root) 或者 cJSON_Print(root)来将json对象转换成普通的字符串,并且都是以该json对象的根为基点。 //两个API的区别即是:一个是没有格式的:也就是转换出的字符串中间不会有"\n" "\t"之类的东西存在,而cJSON_Print(root)打印出来是人看起来很舒服的格式. char *ret = cJSON_PrintUnformatted(obj); return ret; } return NULL;}
- build_struct_by_receive_data函数:根据消息码为不同的消息类型提供对应的解析函数,然后执行对应解析函数进行解析,将解析完成后的消息保存到receive参数中。
/*函数功能:根据消息码为不同的消息类型提供对应的解析函数,然后执行对应解析函数进行解析,将解析完成后的消息保存到message参数中函数参数: msg_code:消息码 payload_data:有效负载地址 type:json对象的数据类型 message:传出参数,保存解析完成的消息数据函数返回值: 成功:返回0; 失败:返回错误码详细:*/static int32_t build_struct_by_receive_data(uint32_t msg_code, const char *payload_data, enum json_object_data_type type, struct message *message){ const struct parse_message_map map[] = { { PAKE_REQUEST, parse_pake_request },//PAKE请求消息 { PAKE_RESPONSE, parse_pake_response },//PAKE响应消息 { PAKE_CLIENT_CONFIRM, parse_pake_client_confirm },//PAKE客户端认证消息 { PAKE_SERVER_CONFIRM_RESPONSE, parse_pake_server_confirm },//PAKE服务端认证响应消息 { AUTH_START_REQUEST, parse_auth_start_request },//认证开始请求消息 { AUTH_START_RESPONSE, parse_auth_start_response },//认证开始响应消息 { AUTH_ACK_REQUEST, parse_auth_ack_request },//认证确认请求消息 { AUTH_ACK_RESPONSE, parse_auth_ack_response },//认证确认响应消息 { ADD_AUTHINFO_REQUEST, parse_add_auth_info_request },//添加认证信息请求消息 { REMOVE_AUTHINFO_REQUEST, parse_rmv_auth_info_request },//移除认证信息请求信息 { ADD_AUTHINFO_RESPONSE, parse_add_auth_info_response },//添加认证信息响应消息 { REMOVE_AUTHINFO_RESPONSE, parse_rmv_auth_info_response },//移除认证信息响应消息 { EXCHANGE_REQUEST, parse_exchange_request },//交换请求 { EXCHANGE_RESPONSE, parse_exchange_response },//交换响应 { SEC_CLONE_START_REQUEST, sec_clone_parse_client_request },//安全克隆启动请求 { SEC_CLONE_ACK_REQUEST, sec_clone_parse_client_ack } };//安全克隆确认请求 for (uint32_t i = 0; i < sizeof(map) / sizeof(struct parse_message_map); i++) {//遍历消息解析表,查找对应消息码的解析函数,然后执行解析函数 if (map[i].msg_code != msg_code) { continue; } void *payload = map[i].parse_message(payload_data, type);//执行对应消息码的解析函数!!! if (payload == NULL) { return HC_BUILD_OBJECT_FAILED;//返回错误码 } message->msg_code = map[i].msg_code;//赋值消息码 message->payload = payload;//赋值解析后的消息有效负载 return HC_OK; } LOGE("Unsupport parse 0x%04x message", message->msg_code);//未知消息 return HC_UNKNOW_MESSAGE;}