从本文开始,将介绍在HiChain机制中如何处理本端接收到的数据及其响应对端的过程。这个过程的入口函数为receive_data,在receive_data函数中,主要分为三个阶段:消息解析阶段、消息处理阶段和通知对端阶段,本文的重点是总体分析receive_data函数,然后对消息解析阶段的部分内容进行分析。
这一模块的源码位于:/base/security/deviceauth。
/*
函数功能: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 */
}
/*
函数功能:反序列化/无序化消息
函数参数:
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;
}
/*
函数功能:解析收到的数据成固定的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;
}
/*
函数功能:根据消息码为不同的消息类型提供对应的解析函数,然后执行对应解析函数进行解析,将解析完成后的消息保存到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;
}