往期知识点记录:
- 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
- OpenHarmony分布式调度详解|dmslite.c
- OpenHarmony分布式调度详解|dmslite_feature.c 源码阅读
- OpenHarmony分布式调度详解|dmslite_session.c
- OpenHarmony分布式调度详解|dmslite_tlv_common.c
- OpenHarmony分布式调度详解|dmslite_famgr.c
- OpenHarmony分布式调度详解|dmslite_msg_handler.c
- OpenHarmony分布式调度详解|dmslite_pack.c
- OpenHarmony分布式调度详解|dmslite_permission.c
- OpenHarmony分布式调度详解|Service和Feature的定义和注册(1)
- OpenHarmony分布式调度详解|Service和Feature的定义和注册(2)
- 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, ¶m->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🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请看下图提示: