OpenHarmony解读之设备认证:数据接收管理-消息解析

一、概述

从本文开始,将介绍在HiChain机制中如何处理本端接收到的数据及其响应对端的过程。这个过程的入口函数为receive_data,在receive_data函数中,主要分为三个阶段:消息解析阶段消息处理阶段通知对端阶段,本文的重点是总体分析receive_data函数,然后对消息解析阶段的部分内容进行分析。

二、源码分析

这一模块的源码位于:/base/security/deviceauth。

  1. 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 */
}
  1. 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;
}
  1. 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;
}
  1. 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值