OpenHarmony之分布式软总线coap头文件& coap组包分析

往期知识点记录:

OpenHarmony之分布式软总线coap头文件分析

#ifndef HILINK_COAP_DEF_H
#define HILINK_COAP_DEF_H
#ifdef __cplusplus
extern "C" {
#endif
//一个消息报文最多option数量
#define COAP_MAX_OPTION 16
//传输使用协议 默认值UDP
enum COAP_ProtocolTypeEnum {
    COAP_UDP = 0,
    COAP_TCP
};
//动作类型
enum COAP_MethodTypeEnum {
    COAP_METHOD_GET = 1,
    COAP_METHOD_POST = 2,
    COAP_METHOD_PUT = 3,
    COAP_METHOD_DELETE = 4
};
enum COAP_MsgTypeEnum {
    COAP_TYPE_CON = 0, //CON 需要确认的请求
    COAP_TYPE_NONCON = 1, //NON 不需要确认的请求
    COAP_TYPE_ACK = 2,  //应答消息
    COAP_TYPE_RESET = 3 //复位消息
};
#define DISCOVERY_MSG_URI_HOST 3
#define DISCOVERY_MSG_URI_PATH 11
typedef struct {
    unsigned int ver : 2;   //版本
    unsigned int type : 2;  //msg类型 (CON,NON,ACK,RST)
    unsigned int tokenLen : 4;  //token 长度
    unsigned int code : 8;  //列代码  3bit --分类信息(请求,成功响应,客户端错误响应,服务端错误响应)  5bit--详细信息
    union {
        unsigned short msgLen;  
        unsigned short msgId;
    } varSection;
} COAP_Header;
typedef struct {
    const unsigned char *buffer;
    unsigned int len;
} COAP_Buffer;
typedef struct {
    unsigned short num;   //编号
    const unsigned char *optionBuf;  //option 参数和数据
    unsigned int len; // optionbuf长度
} COAP_Option;  //用于描述请求或响应对应的各个属性
typedef struct {
    enum COAP_ProtocolTypeEnum protocol;  //协议
    unsigned int len;
    COAP_Header header;   //头
    COAP_Buffer token;  //请求ID ,关联响应与请求
    unsigned char optionsNum;  // 消息报文中option的数量
    COAP_Option options[COAP_MAX_OPTION]; // 存储option
    COAP_Buffer payload;  //实际携带数据内容, 若有 加上标志OxFF
} COAP_Packet;   //coap 数据包结构
typedef COAP_Packet CoapPacket;
#ifdef __cplusplus
}
#endif
#endif /* HILINK_COAP_DEF_H */

分布式软总线discovery/coap/source/coap_adapter.c

COAP协议用于分布式通信中主从服务设备发现。
在discovery/coap/source/coap_adapter.c主要实现了COAP数据包的解析与组装。
coap_adapter.c(部分)详细注解如下:

/*
    函数功能:根据value(delta,len)判断 option delta/len extension 所在字节数
    函数参数:
        1.value:  option delta/len 的值
        2.dataPos 存储option的参数
        3.headerlen: 头长度
        4.buflen: 存储头信息空间的长度
    详细:
        1. 判断delta或者len是否等于13,如果等于那么需要占用delta(extension)一个字节,headerlen+1;如果headerlen>buflen 返回空间不足
        2. 只占1个字节 optionDelta = 13 + option Delta(extended),并且修改dataPos所指位置,使得判断len(extension) dataPos指向正确的位置
        3. 如果delta(len) ==14, 那么需要占用delta(extension)两个字节,headerlen=2;如果headerlen>buflen 返回空间不足
        4. 计算填入的数,如果填入的数大于其最大填入的数,返回错误,否则Delta/len = 14 + 255 + 填入的数
        5. option Delta只占4位,不可能等于15,所以无效
    函数返回值:
        成功返回:DISCOVERY_ERR_SUCCESS ,否则返回 非0
*/
static int COAP_ParseOptionExtension(unsigned short *value, const unsigned char **dataPos, unsigned char *headerLen,
    unsigned int bufLen)
{
    //如果value =13  ,那么需要占用option extension中一个字节数
    if (*value == COAP_EXTEND_DELTA_VALUE_UINT8) {
        (*headerLen)++; //头长度+1字节
        //头长度超过buflen
        if (bufLen < *headerLen) {
            return DISCOVERY_ERR_OPT_INVALID_SHORT_FOR_HEADER;
        }
        //optionDelta/len  = 13 + option Delta(extended)
        *value = (unsigned short)((*dataPos)[1] + COAP_LOW_DELTA_NUM);
        (*dataPos)++; // 修改dataPOS位置,使得判断len(extension)在正确的位置
        return DISCOVERY_ERR_SUCCESS;
    }
    //如果value == 14,那么需要占用option extension中两个字节数
    if (*value == COAP_EXTEND_DELTA_VALUE_UINT16) {
        *headerLen = (unsigned char)(*headerLen + COAP_OPTION_EXTENSION_LEN); //头长度+2字节
        if (bufLen < *headerLen) {
            return DISCOVERY_ERR_OPT_INVALID_SHORT_FOR_HEADER;
        }
        //填入的数
        unsigned short optionDeltaValue = (unsigned short)((*dataPos)[1] << COAP_SHIFT_BIT8) |
            (*dataPos)[COAP_OPTION_EXTENSION_LEN];
        //optionDeltaValue 大于最大值 
        if (optionDeltaValue > (0xFFFF - COAP_LOW_DELTA_NUM - COAP_MID_DELTA_NUM)) {
            return DISCOVERY_ERR_BAD_REQ;
        }
        //optionDelta/len = 14+255+option Delta (extended)
        *value = (unsigned short)(optionDeltaValue + COAP_LOW_DELTA_NUM + COAP_MID_DELTA_NUM);
        (*dataPos) += COAP_OPTION_EXTENSION_LEN; // 修改dataPOS位置
        return DISCOVERY_ERR_SUCCESS;
    }
    //option Delta == 15无效
    if (*value == COAP_EXTEND_DELTA_VALUE_INVALID) {
        return DISCOVERY_ERR_OPT_INVALID_DELTA;
    }
    return DISCOVERY_ERR_SUCCESS;
}

/*  option参数: 一个option 采用增量的方式表示  Delta,length,value 
    函数功能: option 参数 Delta len
    函数参数: 
        1.option: 待设置头信息的option
        2.runningDelta : 之前所有option Delta和
        3.buf : 存储option参数的区域
        4.bufLen: buf长度
    详细:
        1.提取出option delta/option len
        2.根据delta/len 判断占option delta/len(extension) 中的字节数
        3.设置option num = 之前所有的option Detal + option Detal
        4.修改runningDelta
    函数返回: 成功返回 0 , 否则返回非0 
*/
static int COAP_ParseOption(COAP_Option *option, unsigned short *runningDelta, const unsigned char **buf,
    unsigned int bufLen)
{
    const unsigned char *dataPos = NULL;
    unsigned char headLen; // 头长度
    unsigned short len;   //option len
    unsigned short delta; // option delta
    int ret;
    //buf 太小不足以保存头信息
    if (bufLen < 1)  {
        return DISCOVERY_ERR_OPT_INVALID_SHORT_FOR_HEADER;
    }
    dataPos = *buf;
    delta = (dataPos[0] & 0xF0) >> COAP_SHIFT_BIT4; // option delta 
    len = dataPos[0] & 0x0F;   //option len
    headLen = 1;  //delta与len 占1byte
    //根据取值 需要占用 delta extension的字节数
    ret = COAP_ParseOptionExtension(&delta, &dataPos, &headLen, bufLen);
    if (ret != DISCOVERY_ERR_SUCCESS) {
        return ret;
    }
    //根据取值 需要占用 len extension字节数
    ret = COAP_ParseOptionExtension(&len, &dataPos, &headLen, bufLen);
    if (ret != DISCOVERY_ERR_SUCCESS) {
        return ret;
    }
    if ((dataPos + 1 + len) > (*buf + bufLen)) {
        return DISCOVERY_ERR_OPT_INVALID_BIG;
    }
    option->num = (unsigned short)(delta + *runningDelta);  //option编号 等于本option delta + 上一个option delta
    option->optionBuf = dataPos + 1;
    option->len = len;
    *buf = dataPos + 1 + len; // 调整buf, 指向pkt下一个option或者payload
    *runningDelta = (unsigned short)(*runningDelta + delta); // 更新runningDelta
    return DISCOVERY_ERR_SUCCESS;
}

/*
    函数功能:coap 报文的TOKEN / OPTIONS / PAYLOAD
    函数参数:
        1.pkt : COAP包
        2.buf: 数据区
        3.buflen:buf长度
    详细:
        1.将dataPos指向buf中option的位置
        2.当dataPos不超过存储option区域 && dataPos指向的值不为OXff(有payload的标记)&& option的数量小于pkt包可以拥有的最大option数,去构造option参数
        3.如果option num 超过最大,返回错误
        4.pkt->optionNum = optionIndex; 此 packet 拥有的option个数
        5.判断dataPos是否等于0xff标志,表示是否有数据
        6.如果有数据: 将数据所在地址和长度分别复制给pkt相应属性
    函数返回:
        成功返回0, 否则返回非0
*/
static int COAP_ParseOptionsAndPayload(COAP_Packet *pkt, const unsigned char *buf,
    unsigned int buflen)
{
    unsigned char optionIndex = 0;//  记录option的个数
    unsigned short delta = 0;
    const unsigned char *dataPos = buf + HEADER_LEN + pkt->header.tokenLen; // 将指针指向option位置
    const unsigned char *end = buf + buflen;
    if (dataPos > end) {
        return DISCOVERY_ERR_OPT_OVERRUNS_PKT;
    }
    //当dataPos不超过存储option区域 && dataPos指向的值不为OXff(有payload的标记)&& option的数量小于pkt包可以拥有的最大option数
    while ((dataPos < end) && (*dataPos != 0xFF) && (optionIndex < COAP_MAX_OPTION)) {
        int ret = COAP_ParseOption(&((pkt->options)[optionIndex]), &delta, &dataPos, end - dataPos); // 去构造option参数
        if (ret != DISCOVERY_ERR_SUCCESS) {
            return ret;
        }
        optionIndex++;
    }
    //如果option num 超过最大
    if ((dataPos < end) && (*dataPos != 0xFF) && (optionIndex >= COAP_MAX_OPTION)) {
        return DISCOVERY_ERR_SERVER_ERR;
    }
    pkt->optionsNum = optionIndex; //此pkt拥有的option数量
    if ((dataPos < end) && (*dataPos != 0xFF)) {
        pkt->payload.buffer = NULL; // 没有数据
        pkt->payload.len = 0;
        return DISCOVERY_ERR_SUCCESS;
    }
    if (dataPos + 1 >= end) {
        return DISCOVERY_ERR_INVALID_PKT;
    }
    pkt->payload.buffer = dataPos + 1; //+1是因为存储数据之前有一个字节的分隔符 0xff表示有数据
    pkt->payload.len = (unsigned int)(long)(end - (dataPos + 1)); //数据长度
    return DISCOVERY_ERR_SUCCESS;
}

/*
    函数功能: 从buf中提取COAP包头
    函数参数: 
            1:pkt : COAP 包
            2:buf : 数据缓冲区
            3. buflen: buf长度
    详细:
        1.如果buflen 小于 coap 4字节头长度,返回错误
        2.从buf中提取ptk头部的各个属性(版本,消息类型,toklen:标识符长度; code,消息ID)
    函数返回: 成功返回0 否则返回非0
*/
static int COAP_ParseHeader(COAP_Packet *pkt, const unsigned char *buf, unsigned int bufLen)
{
    //buflen小于coap头,不能存储一个COAP PACKET头部
    if (bufLen < HEADER_LEN) {
        return DISCOVERY_ERR_HEADER_INVALID_SHORT;
    }
    pkt->header.ver = (((unsigned int)buf[0] >> COAP_SHIFT_BIT6) & 0x03);  // 版本(2位)
    pkt->header.type = ((((unsigned int)buf[0] & 0x30) >> COAP_SHIFT_BIT4) & 0x03); //msg类型(2)
    pkt->header.tokenLen = (((unsigned int)buf[0] & 0x0F)); // token长度(4)
    pkt->header.code = buf[1]; // 列代码(8)
    pkt->header.varSection.msgId = (unsigned short)((unsigned short)(buf[MSGID_HIGHT_BYTE] << COAP_SHIFT_BIT8)
       | buf[BUF_OFFSET_BYTE3]);
    return DISCOVERY_ERR_SUCCESS;
}

/*
    函数功能: 从buf解析出COAP包
    函数参数: 
            1.pkt: 用来保存从buf解析出来的包信息 
            2.buf: 数据缓冲区
            3.buflen : buf长度
    详细:
        1.判断各种条件是否满足要求
        2.从buf提取出coap头,并判断各个属性是否合法
        3.从buf提取出coap option和具体数据。
        4.一切都满足,就将buflen赋予pkt->len;
    函数返回: 成功返回0, 否则返回非0
*/
int COAP_SoftBusDecode(COAP_Packet *pkt, const unsigned char *buf, unsigned int bufLen)
{
    int ret;
    if (pkt == NULL || buf == NULL) {
        return -1;
    }
    if (bufLen == 0) {
        return -1;
    }
    if (pkt->protocol != COAP_UDP) {
        return -1;
    }
    ret = COAP_ParseHeader(pkt, buf, bufLen);
    if (ret != DISCOVERY_ERR_SUCCESS) {
        return ret;
    }
    if (pkt->header.ver != COAP_VERSION) {
        return DISCOVERY_ERR_VER_INVALID;
    }
    if (pkt->header.tokenLen > MAX_TOK_LEN) {
        return DISCOVERY_ERR_INVALID_TOKEN_LEN;
    }
    if ((bufLen > HEADER_LEN) && (pkt->header.code == 0)) {
        return DISCOVERY_ERR_INVALID_EMPTY_MSG;
    }
    //是否有token数据
    if (pkt->header.tokenLen == 0) {
        pkt->token.buffer = NULL;
        pkt->token.len = 0;
    } else if ((unsigned int)(pkt->header.tokenLen + HEADER_LEN) > bufLen) {
        return DISCOVERY_ERR_TOKEN_INVALID_SHORT;
    } else {
        pkt->token.buffer = &buf[BUF_OFFSET_BYTE4];
        pkt->token.len = pkt->header.tokenLen;
    }
    //提取出option参数和数据
    ret = COAP_ParseOptionsAndPayload(pkt, buf, bufLen);
    if (ret != DISCOVERY_ERR_SUCCESS) {
        return ret;
    }
    pkt->len = bufLen;
    return DISCOVERY_ERR_SUCCESS;
}

/*
    函数功能: 通过ptkParam 构造消息头
    函数参数: 
            1. pkt: COAP 包
            2. pktParam: 包参数
            3. buf:pkt对应读写缓冲区
    详细:  
            1.先检查包参数中的协议,消息类型
            2.用pktParam中的各种属性设置COAP数据包中Header属性
            3.如果协议为UDP,那么将数据包中Header属性中信息保存在读写缓冲区中
    函数返回值:成功返回0, 否则返回非零
*/
static int COAP_CreateHeader(COAP_Packet *pkt, const COAP_PacketParam *pktParam, COAP_ReadWriteBuffer *buf)
{
    if (buf->len != 0) {
        return DISCOVERY_ERR_INVALID_ARGUMENT;
    }
    if ((pktParam->protocol != COAP_UDP) && (pktParam->protocol != COAP_TCP)) {  //检查包参数中的协议
        return DISCOVERY_ERR_TRANSPORT_NOT_UDP_OR_TCP;
    } 
    pkt->protocol = pktParam->protocol; // 将包参数中的协议(UDP|TCP) 赋予给COAP包协议类型
    if (pktParam->type > COAP_TYPE_RESET) {  //检查包参数中的消息类型
        return DISCOVERY_ERR_UNKNOWN_MSG_TYPE;
    }
    if (buf->size < HEADER_LEN) {  
        return DISCOVERY_ERR_PKT_EXCEED_MAX_PDU;
    }
    pkt->header.type = (unsigned int)pktParam->type & 0x03; //  消息类型
    pkt->header.ver = COAP_VERSION;  //版本
    pkt->header.code = pktParam->code;  // 状态码
    if (pkt->protocol == COAP_UDP) {
        pkt->header.varSection.msgId = pktParam->msgId;
        //readWriteBuf[0] : ver Type Tokenlen
        buf->readWriteBuf[0] = (char)(pkt->header.ver << COAP_SHIFT_BIT6);  
        buf->readWriteBuf[0] = (char)((unsigned char)buf->readWriteBuf[0] |
            (unsigned char)(pkt->header.type << COAP_SHIFT_BIT4));
        //readWriteBuf[1] : code
        buf->readWriteBuf[1] = (char)pkt->header.code;   
        //readWriteBuf[2:3] : Message ID
        buf->readWriteBuf[BUF_OFFSET_BYTE2] = (char)((pkt->header.varSection.msgId & 0xFF00) >> COAP_SHIFT_BIT8);
        buf->readWriteBuf[BUF_OFFSET_BYTE3] = (char)(pkt->header.varSection.msgId & 0x00FF);
    } else {
        return DISCOVERY_ERR_NOT_SUPPORTED;
    }
    pkt->len = buf->len = HEADER_LEN;
    return DISCOVERY_ERR_SUCCESS;
}

/*
    函数功能:coap数据包添加数据
    函数参数:
            1.pkt: COAP报文结构
            2.payload: 数据缓冲区
            3.buf: pkt对应读写缓冲区
    详细:
            1. 检查各种参数
            2. 用COAP数据缓冲区的长度设置COAP数据包中payload属性中的len
            3. 如果是携带数据,那么就在加上payload标识符0XFF,pkt中payload.buffer指向实际存放实际的地址
            4. 将数据写入到读写缓冲区,buf->len 加上数据长度
    函数返回值:成功返回0, 其他返回非零
*/
static int COAP_AddData(COAP_Packet *pkt, const COAP_Buffer *payload, COAP_ReadWriteBuffer *buf)
{
    if ((payload->len == 0) && (payload->buffer == NULL)) {
        return DISCOVERY_ERR_INVALID_ARGUMENT;
    }
    if (buf->len < HEADER_LEN) {
        return DISCOVERY_ERR_INVALID_ARGUMENT;
    }
    if ((payload->len > 0xFFFF) || (buf->len + payload->len + 1) > buf->size) {
        return DISCOVERY_ERR_PKT_EXCEED_MAX_PDU;
    }
    pkt->payload.len = payload->len;
    if (payload->len != 0) {      
        pkt->payload.len = payload->len;
        //readWriteBuf[4] = 0XFF
        buf->readWriteBuf[buf->len] = 0xFF; //设置具有数据表示符0XFF
        (buf->len)++; 
        //实际数据区
        pkt->payload.buffer = (const unsigned char *)&buf->readWriteBuf[buf->len]; 
        //将数据写入读写缓冲区
        if (memcpy_s(&buf->readWriteBuf[buf->len], buf->size - buf->len, payload->buffer, payload->len) != EOK) {
            return DISCOVERY_ERR_INVALID_ARGUMENT;
        }
    }
    // 加上数据长度
    buf->len += payload->len;
    pkt->len = buf->len;
    return DISCOVERY_ERR_SUCCESS;
}


/*
    函数功能: 获取option(delta,length)
    函数参数:
            1.value : option delta/length值
            2. param :保存的区域
    函数功能: 
            将 value 与 13 和 13+259 比较,就可以知道option delta/length字段的值(0-12 , 13, 14)
    函数返回值: 无
*/ 
static void COAP_GetOptionParam(unsigned short value, unsigned char *param)
{
    if (value < COAP_LOW_DELTA_NUM) {
        *param = (unsigned char)(value & 0xFF);
        return;
    }
    if (value < (COAP_LOW_DELTA_NUM + COAP_MID_DELTA_NUM)) {
        *param = COAP_EXTEND_DELTA_VALUE_UINT8;
        return;
    }
    *param = COAP_EXTEND_DELTA_VALUE_UINT16;
    return;
}

/*
    函数功能: 获取option所占的字节数
*/
static unsigned short COAP_GetOptionLength(const COAP_Option *opt, unsigned short runningDelta)
{
    unsigned short optionLen = 1;  // (option delta, length)
    unsigned char delta = 0;  
    unsigned char len = 0;
    COAP_GetOptionParam((unsigned short)(opt->num - runningDelta), &delta);    //获取option delta 字段的值
    if (delta == COAP_EXTEND_DELTA_VALUE_UINT8) { 
        optionLen += 1;  // 占option delta(extended)字段中1个字节
    } else if (delta == COAP_EXTEND_DELTA_VALUE_UINT16) {
        optionLen += BUF_OFFSET_BYTE2; // 占option delta(extended)字段中2个字节
    }
    COAP_GetOptionParam((unsigned short)opt->len, &len);  // 获取option length字段值
    if (len == COAP_EXTEND_DELTA_VALUE_UINT8) {
        optionLen += 1;       // 占option length(extended)字段中1个字节
    } else if (len == COAP_EXTEND_DELTA_VALUE_UINT16) {
        optionLen += BUF_OFFSET_BYTE2; // 占option length(extended)字段中2个字节
    }
    return optionLen + opt->len;  //参数长度加上数据长度
}

用于向一个coap数据包添加option

/*
    函数功能:主要就是判断是否可以添加一个新的option
    函数参数:
            1.pkt : coap数据包
            2.option : 要检查的option
            3.buf : pkt对应的缓冲区
    详细:
            1.首先检查各属性是否合法
            2.获取当前runningDelta(pkt最后一个option的num)
            3.获取option的长度
    函数返回: 没有越界返回0, 否则返回非零
*/
static int COAP_CheckOption(const COAP_Packet *pkt, const COAP_Option *option, const COAP_ReadWriteBuffer *buf)
{
    unsigned short optionLen;
    unsigned short runningDelta = 0;
    if (buf->len < HEADER_LEN) { 
        return DISCOVERY_ERR_INVALID_ARGUMENT;
    }
    if ((option->optionBuf == NULL) && (option->len != 0)) {
        return DISCOVERY_ERR_INVALID_ARGUMENT;
    }
    if ((option->len > 0xFFFF) || (pkt->optionsNum >= COAP_MAX_OPTION)) {
        return DISCOVERY_ERR_BAD_REQ;
    }
    if (pkt->optionsNum != 0) {
        runningDelta = pkt->options[pkt->optionsNum - 1].num;  // 
    }
    optionLen = COAP_GetOptionLength(option, runningDelta);  //获取option长度
    if ((buf->len + optionLen) > buf->size) {
        return DISCOVERY_ERR_PKT_EXCEED_MAX_PDU;
    }
    return DISCOVERY_ERR_SUCCESS;
}
/*
    函数功能: 添加option
    函数参数: 
            1. pkt : coap包
            2. option: 待添加的option
            3.buf:pkt对应的读写缓冲区
    详细:
            1.检查是否还可以添加一个新option
            2.获取待添加的 option delta, option length 字段中的值
            3.添加option
            4.更新pkt中关于option的属性值
    函数返回值: 成功返回0, 否则返回非零
*/
static int COAP_AddOption(COAP_Packet *pkt, const COAP_Option *option, COAP_ReadWriteBuffer *buf)
{
    unsigned char delta;
    unsigned char len;
    unsigned short optionDelta;
    unsigned short prevOptionNum;
    if (COAP_CheckOption(pkt, option, buf) != DISCOVERY_ERR_SUCCESS) {  //检查是否还可添加
        return DISCOVERY_ERR_INVALID_ARGUMENT;
    }
    prevOptionNum = 0;
    if (pkt->optionsNum != 0) {
        prevOptionNum = pkt->options[pkt->optionsNum - 1].num; // 当前最后一个option的num
    }
    optionDelta = option->num - prevOptionNum;  // 获取待添加option的 delta值
    COAP_GetOptionParam(optionDelta, &delta); // 获取待添加option的option delta字段中的值  
    COAP_GetOptionParam(option->len, &len);  // 获取待添加option的option length字段的值
    buf->readWriteBuf[buf->len++] = (char)(((delta << COAP_SHIFT_BIT4) | len) & 0xFF); // 添加option 的 option delta option length 
    //如果option delta值为13/14,添加 option delta(extended)
    if (delta == COAP_EXTEND_DELTA_VALUE_UINT8) {  //新option delta字段的值 == 13 
        buf->readWriteBuf[buf->len++] = (char)(optionDelta - COAP_LOW_DELTA_NUM); //添加 option delta(extended)字段中的值  
    } else if (delta == COAP_EXTEND_DELTA_VALUE_UINT16) {  //新option delta字段的值 == 14
        //添加 option delta(extended)字段中的值 (需占两个字节)
        buf->readWriteBuf[buf->len++] = (char)((optionDelta - (COAP_LOW_DELTA_NUM + COAP_MID_DELTA_NUM))
                                                >> COAP_SHIFT_BIT8);
        buf->readWriteBuf[buf->len++] = (char)((optionDelta - (COAP_LOW_DELTA_NUM + COAP_MID_DELTA_NUM)) & 0xFF);
    }
    //如果option length值为13/14,添加 option length(extended)
    if (len == COAP_EXTEND_DELTA_VALUE_UINT8) {
        buf->readWriteBuf[buf->len++] = (char)(option->len - COAP_LOW_DELTA_NUM);
    } else if (len == COAP_EXTEND_DELTA_VALUE_UINT16) {
        buf->readWriteBuf[buf->len++] = (char)((option->len - (COAP_LOW_DELTA_NUM + COAP_MID_DELTA_NUM))
                                                >> COAP_SHIFT_BIT8);
        buf->readWriteBuf[buf->len++] = (char)((option->len - (COAP_LOW_DELTA_NUM + COAP_MID_DELTA_NUM)) & 0xFF);
    }
    //如果option具有负载数据,向buf添加其数据
    if (option->len != 0) {
        if (memcpy_s(&buf->readWriteBuf[buf->len], buf->size - buf->len, option->optionBuf, option->len) != EOK) {
            return DISCOVERY_ERR_OPT_INVALID_BIG;
        }
    }
    //更新pkt中关于option的属性值
    pkt->options[pkt->optionsNum].optionBuf = (const unsigned char *)&buf->readWriteBuf[buf->len];
    pkt->options[pkt->optionsNum].num = option->num;
    pkt->options[pkt->optionsNum].len = option->len;
    //更新添加之后pkt,buf以存储长度
    buf->len += option->len;
    pkt->len = buf->len;
    //option数量+1
    pkt->optionsNum++;
    return DISCOVERY_ERR_SUCCESS;
}

/*
    函数功能: 添加Token
    函数参数:
            1.pkt : COAP包
            2.token : 待添加的token数据
            3.buf: pkt对应的读写缓冲区
    详细:  
            1.检查各项属性是否合法
            2.更新pkt相关的token属性值
            3.将数据拷贝到缓冲区
    函数返回值: 成功返回0,其他返回非零
*/
static int COAP_AddToken(COAP_Packet *pkt, const COAP_Buffer *token, COAP_ReadWriteBuffer *buf)
{
    //token长度不为0,但是对应的缓冲区为空
    if ((token->len != 0) && (token->buffer == NULL)) {
        return DISCOVERY_ERR_INVALID_ARGUMENT;
    }
    //buf->len 长度不等于头长度( 在添加各种数据之前,buf中应只有头部参数)
    if (buf->len != HEADER_LEN) {
        return DISCOVERY_ERR_INVALID_ARGUMENT;
    }
    // 如果token数据长度超过最大
    if (token->len > MAX_TOK_LEN)  {
        return DISCOVERY_ERR_INVALID_TOKEN_LEN;
    }
    // 如果buf 不足够容下token
    if ((buf->len + token->len) > buf->size) {
        return DISCOVERY_ERR_PKT_EXCEED_MAX_PDU;
    }
    // 更新pkt有关token属性值
    pkt->token.len = token->len;  
    pkt->header.tokenLen = pkt->token.len & 0x0F;  // 更新头部字段TKL
    pkt->token.buffer = (const unsigned char *)&buf->readWriteBuf[buf->len]; 
    //有数据
    if (token->len != 0)  {
        if (pkt->protocol == COAP_UDP) {
            buf->readWriteBuf[0] = (char)((unsigned char)buf->readWriteBuf[0] | token->len);  
        } else {
            //coap over tcp 相比 coap over udp 头部没有ver T Message ID,不过引入一个可变大小的长度字段 ? 
            buf->readWriteBuf[BUF_OFFSET_BYTE2] = (char)((unsigned char)buf->readWriteBuf[BUF_OFFSET_BYTE2]
                                                  | token->len);
        }
        //将token数据拷贝到pkt对应的缓冲区
        if (memcpy_s(&buf->readWriteBuf[buf->len], pkt->header.tokenLen, token->buffer, token->len) != EOK) {
            return DISCOVERY_ERR_INVALID_ARGUMENT;
        }
    }
    buf->len += token->len;
    pkt->len = buf->len;
    return DISCOVERY_ERR_SUCCESS;
}

添加TOKEN,OPTION, DATA,创建coap报文主体

/*
    函数功能: 创建coap报文主体
    函数参数: 
            1. pkt: COAP包
            2. param: 包参数
            3. token : token
            4. payload : 数据
            5. buf: pkt对应读写缓冲区
    详细:
         1. 添加token
         2. 依次添加options
         3. 添加payload
    函数返回值: 成功返回0, 否则返回非0
*/
static int COAP_CreateBody(COAP_Packet *pkt, const COAP_PacketParam *param, const COAP_Buffer *token,
    const COAP_Buffer *payload, COAP_ReadWriteBuffer *buf)
{
    int i;
    int ret;
    if (token != NULL) {
        ret = COAP_AddToken(pkt, token, buf);
        if (ret != DISCOVERY_ERR_SUCCESS) {
            return ret;
        }
    }
    if (param->options != 0) {
        if (param->optionsNum > COAP_MAX_OPTION) {
            return DISCOVERY_ERR_SERVER_ERR;
        }
        for (i = 0; i < param->optionsNum; i++) {
            ret = COAP_AddOption(pkt, &param->options[i], buf);
            if (ret != DISCOVERY_ERR_SUCCESS) {
                return ret;
            }
        }
    }
    if (payload != NULL) {
        ret = COAP_AddData(pkt, payload, buf);
        if (ret != DISCOVERY_ERR_SUCCESS) {
            return ret;
        }
    }
    return DISCOVERY_ERR_SUCCESS;
}

组包:创建头部和数据包主体

/*
    函数功能 : 组包
    函数参数: 
            1.pkt : COAP包
            2.param : 包参数
            3.token : token
            4.payload: 数据
            5.buf : pkt对应的读写缓冲区
    详细:
            1.创建头
            2.创建主体
    函数返回: 成功返回0,否则返回非零
*/
int COAP_SoftBusEncode(COAP_Packet *pkt, const COAP_PacketParam *param, const COAP_Buffer *token,
    const COAP_Buffer *payload, COAP_ReadWriteBuffer *buf)
{
    int ret;
    if (pkt == NULL || param == NULL || buf == NULL || buf->readWriteBuf == NULL) {
        return DISCOVERY_ERR_INVALID_EMPTY_MSG;
    }
    ret = COAP_CreateHeader(pkt, param, buf);
    if (ret != DISCOVERY_ERR_SUCCESS) {
        return ret;
    }
    if ((param->code == 0) && ((token != NULL) || (param->options != NULL) || (payload != NULL))) {
        return DISCOVERY_ERR_INVALID_EMPTY_MSG;
    }
    ret = COAP_CreateBody(pkt, param, NULL, payload, buf);
    if (ret != DISCOVERY_ERR_SUCCESS) {
        return ret;
    }
    return DISCOVERY_ERR_SUCCESS;
}

coap Message ID

//初始化g_msgId,用作为COAP报文中Message ID
void COAP_SoftBusInitMsgId(void)
{
    g_msgId = (unsigned short)(RAND_DIVISOR);
}
//g_msgId+1(循环使用),作为下一个包的Message ID 
unsigned short COAP_SoftBusMsgId(void)
{
    if (++g_msgId == 0) {
        g_msgId++;
    }
    return g_msgId;
}

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请看下图提示:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值