[coap] improve block-wise transfer handling (#12248)

This commit enhances the CoAP block-wise transfer implementation by
removing the `BlockWiseData` struct within `Message::HelpData` and its
associated getter/setter methods (e.g., `GetBlockWiseBlockNumber()`,
`SetBlockWiseBlockNumber()`). The `Message` object is no longer
responsible for carrying temporary state related to block-wise transfers,
addressing the fragility of the previous design which used the reserved
header portion of the `Message` to store these properties.

A new `BlockInfo` struct has been introduced to cleanly encapsulate the
three pieces of information from a Block option: `mBlockNumber`,
`mBlockSzx` (size exponent), and `mMoreBlocks` flag. It also includes
utility methods like `GetBlockSize()` and `GetBlockOffsetPosition()` to
simplify calculations.

All methods involved in block-wise transfers in `coap.cpp` (e.g.,
`ProcessBlockwiseSend`, `SendNextBlock1Request`) have been updated to
use the new `BlockInfo` struct. They now create local `BlockInfo`
variables and call `ReadBlockOptionValues()` to populate them.

This commit also includes minor cleanups and improvements:

- "Block size" is now used consistently instead of block length (e.g.,
  `kMaxBlockLength` is renamed to `kMaxBlockSize`).
- `OffsetRange` is now used to read the payload in
  `SendNextBlock2Request` and `ProcessBlock1Request`, simplifying the
  code.
This commit is contained in:
Abtin Keshavarzian
2026-01-05 11:26:55 -08:00
committed by GitHub
parent f4c51b8232
commit ac6cdb02f7
5 changed files with 231 additions and 286 deletions
+14 -2
View File
@@ -104,12 +104,24 @@ uint16_t otCoapBlockSizeFromExponent(otCoapBlockSzx aSize) { return Coap::BlockS
otError otCoapMessageAppendBlock2Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSzx aSize)
{
return AsCoapMessage(aMessage).AppendBlockOption(Coap::Message::kBlockType2, aNum, aMore, MapEnum(aSize));
Coap::BlockInfo blockInfo;
blockInfo.mBlockNumber = aNum;
blockInfo.mBlockSzx = MapEnum(aSize);
blockInfo.mMoreBlocks = aMore;
return AsCoapMessage(aMessage).AppendBlockOption(Coap::kOptionBlock2, blockInfo);
}
otError otCoapMessageAppendBlock1Option(otMessage *aMessage, uint32_t aNum, bool aMore, otCoapBlockSzx aSize)
{
return AsCoapMessage(aMessage).AppendBlockOption(Coap::Message::kBlockType1, aNum, aMore, MapEnum(aSize));
Coap::BlockInfo blockInfo;
blockInfo.mBlockNumber = aNum;
blockInfo.mBlockSzx = MapEnum(aSize);
blockInfo.mMoreBlocks = aMore;
return AsCoapMessage(aMessage).AppendBlockOption(Coap::kOptionBlock1, blockInfo);
}
otError otCoapMessageAppendProxyUriOption(otMessage *aMessage, const char *aUriPath)
+127 -151
View File
@@ -915,24 +915,26 @@ Error CoapBase::SendMessage(Message &aMessage,
Error CoapBase::ProcessBlockwiseSend(Message &aMessage, BlockwiseTransmitHook aTransmitHook, void *aContext)
{
Error error = kErrorNone;
uint8_t type = aMessage.GetType();
bool moreBlocks = false;
uint16_t bufLen;
uint8_t buf[kMaxBlockLength];
Error error = kErrorNone;
uint8_t type = aMessage.GetType();
bool moreBlocks = false;
uint16_t blockSize;
uint8_t buf[kMaxBlockSize];
BlockInfo blockInfo;
VerifyOrExit(type != kTypeReset);
VerifyOrExit(aTransmitHook != nullptr);
VerifyOrExit(aMessage.GetBlockWiseBlockNumber() == 0);
SuccessOrExit(aMessage.ReadBlockOptionValues(type == kTypeAck ? kOptionBlock2 : kOptionBlock1));
SuccessOrExit(aMessage.ReadBlockOptionValues(type == kTypeAck ? kOptionBlock2 : kOptionBlock1, blockInfo));
bufLen = BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize());
VerifyOrExit(bufLen <= kMaxBlockLength, error = kErrorNoBufs);
VerifyOrExit(blockInfo.mBlockNumber == 0);
SuccessOrExit(error = aTransmitHook(aContext, buf, 0, &bufLen, &moreBlocks));
SuccessOrExit(error = aMessage.AppendBytes(buf, bufLen));
blockSize = blockInfo.GetBlockSize();
VerifyOrExit(blockSize <= kMaxBlockSize, error = kErrorNoBufs);
SuccessOrExit(error = aTransmitHook(aContext, buf, 0, &blockSize, &moreBlocks));
SuccessOrExit(error = aMessage.AppendBytes(buf, blockSize));
switch (type)
{
@@ -1168,7 +1170,7 @@ void CoapBase::FreeLastBlockResponse(void)
Error CoapBase::CacheLastBlockResponse(Message *aResponse)
{
Error error = kErrorNone;
// Save last response for block-wise transfer
FreeLastBlockResponse();
if ((mLastResponse = aResponse->Clone()) == nullptr)
@@ -1179,29 +1181,29 @@ Error CoapBase::CacheLastBlockResponse(Message *aResponse)
return error;
}
Error CoapBase::PrepareNextBlockRequest(Message::BlockType aType,
bool aMoreBlocks,
Message &aRequestOld,
Message &aRequest,
Message &aMessage)
Error CoapBase::PrepareNextBlockRequest(uint16_t aBlockOptionNumber,
Message &aRequestOld,
Message &aRequest,
const BlockInfo &aBlockInfo)
{
Error error = kErrorNone;
bool isOptionSet = false;
uint16_t blockOption = 0;
Option::Iterator iterator;
Metadata metadata;
blockOption = (aType == Message::kBlockType1) ? kOptionBlock1 : kOptionBlock2;
aRequest.Init(kTypeConfirmable, static_cast<ot::Coap::Code>(aRequestOld.GetCode()));
// Iterate after metadata copied and removed.
metadata.ReadFrom(aRequestOld);
metadata.RemoveFrom(aRequestOld);
// Per RFC 7959, all requests in a block-wise transfer MUST use the same token.
// Per RFC 7959, all requests in a block-wise transfer MUST use the
// same token.
IgnoreError(aRequest.SetTokenFromMessage(aRequestOld));
SuccessOrExit(error = iterator.Init(aRequestOld));
// Copy options from last response to next message
SuccessOrExit(error = iterator.Init(aRequestOld));
for (; !iterator.IsDone() && iterator.GetOption()->GetLength() != 0; error = iterator.Advance())
{
uint16_t optionNumber = iterator.GetOption()->GetNumber();
@@ -1209,14 +1211,9 @@ Error CoapBase::PrepareNextBlockRequest(Message::BlockType aType,
SuccessOrExit(error);
// Check if option to copy next is higher than or equal to Block1 option
if (optionNumber >= blockOption && !isOptionSet)
if (optionNumber >= aBlockOptionNumber && !isOptionSet)
{
// Write Block1 option to next message
SuccessOrExit(error = aRequest.AppendBlockOption(aType, aMessage.GetBlockWiseBlockNumber() + 1, aMoreBlocks,
aMessage.GetBlockWiseBlockSize()));
aRequest.SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber() + 1);
aRequest.SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
aRequest.SetMoreBlocksFlag(aMoreBlocks);
SuccessOrExit(error = aRequest.AppendBlockOption(aBlockOptionNumber, aBlockInfo));
isOptionSet = true;
@@ -1235,12 +1232,7 @@ Error CoapBase::PrepareNextBlockRequest(Message::BlockType aType,
if (!isOptionSet)
{
// Write Block1 option to next message
SuccessOrExit(error = aRequest.AppendBlockOption(aType, aMessage.GetBlockWiseBlockNumber() + 1, aMoreBlocks,
aMessage.GetBlockWiseBlockSize()));
aRequest.SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber() + 1);
aRequest.SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
aRequest.SetMoreBlocksFlag(aMoreBlocks);
SuccessOrExit(error = aRequest.AppendBlockOption(aBlockOptionNumber, aBlockInfo));
}
error = metadata.AppendTo(aRequestOld);
@@ -1252,52 +1244,54 @@ exit:
Error CoapBase::SendNextBlock1Request(Message &aRequest,
Message &aMessage,
const Ip6::MessageInfo &aMessageInfo,
const Metadata &aCoapMetadata)
const Metadata &aMetadata)
{
Error error = kErrorNone;
Message *request = nullptr;
bool moreBlocks = false;
uint8_t buf[kMaxBlockLength] = {0};
uint16_t bufLen = kMaxBlockLength;
Error error = kErrorNone;
Message *request = nullptr;
uint8_t buf[kMaxBlockSize] = {0};
uint16_t blockSize;
BlockInfo msgBlockInfo;
BlockInfo requestBlockInfo;
SuccessOrExit(error = aRequest.ReadBlockOptionValues(kOptionBlock1));
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1));
SuccessOrExit(error = aRequest.ReadBlockOptionValues(kOptionBlock1, requestBlockInfo));
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1, msgBlockInfo));
// Conclude block-wise transfer if last block has been received
if (!aRequest.IsMoreBlocksFlagSet())
if (!requestBlockInfo.mMoreBlocks)
{
FinalizeCoapTransaction(aRequest, aCoapMetadata, &aMessage, &aMessageInfo, kErrorNone);
FinalizeCoapTransaction(aRequest, aMetadata, &aMessage, &aMessageInfo, kErrorNone);
ExitNow();
}
// Get next block
VerifyOrExit((bufLen = BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
error = kErrorNoBufs);
blockSize = msgBlockInfo.GetBlockSize();
VerifyOrExit(blockSize <= kMaxBlockSize, error = kErrorNoBufs);
SuccessOrExit(error = aCoapMetadata.mBlockwiseTransmitHook(aCoapMetadata.mResponseContext, buf,
BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
(aMessage.GetBlockWiseBlockNumber() + 1),
&bufLen, &moreBlocks));
requestBlockInfo.mBlockNumber = msgBlockInfo.mBlockNumber + 1;
requestBlockInfo.mBlockSzx = msgBlockInfo.mBlockSzx;
requestBlockInfo.mMoreBlocks = false;
// Check if block length is valid
VerifyOrExit(bufLen <= BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()), error = kErrorInvalidArgs);
SuccessOrExit(error = aMetadata.mBlockwiseTransmitHook(aMetadata.mResponseContext, buf,
requestBlockInfo.GetBlockOffsetPosition(), &blockSize,
&requestBlockInfo.mMoreBlocks));
VerifyOrExit(blockSize <= msgBlockInfo.GetBlockSize(), error = kErrorInvalidArgs);
// Init request for next block
VerifyOrExit((request = NewMessage()) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = PrepareNextBlockRequest(Message::kBlockType1, moreBlocks, aRequest, *request, aMessage));
SuccessOrExit(error = PrepareNextBlockRequest(kOptionBlock1, aRequest, *request, requestBlockInfo));
SuccessOrExit(error = request->SetPayloadMarker());
SuccessOrExit(error = request->AppendBytes(buf, bufLen));
SuccessOrExit(error = request->AppendBytes(buf, blockSize));
DequeueMessage(aRequest);
LogInfo("Send Block1 Nr. %d, Size: %d bytes, More Blocks Flag: %d", request->GetBlockWiseBlockNumber(),
BlockSizeFromExponent(request->GetBlockWiseBlockSize()), request->IsMoreBlocksFlagSet());
LogInfo("Send Block1 Nr. %d, Size: %d bytes, More Blocks Flag: %d", requestBlockInfo.mBlockNumber,
requestBlockInfo.GetBlockSize(), requestBlockInfo.mMoreBlocks);
SuccessOrExit(error = SendMessage(*request, aMessageInfo, /* aTxParamters */ nullptr,
aCoapMetadata.mResponseHandler, aCoapMetadata.mResponseContext,
aCoapMetadata.mBlockwiseTransmitHook, aCoapMetadata.mBlockwiseReceiveHook));
SuccessOrExit(error = SendMessage(*request, aMessageInfo, /* aTxParamters */ nullptr, aMetadata.mResponseHandler,
aMetadata.mResponseContext, aMetadata.mBlockwiseTransmitHook,
aMetadata.mBlockwiseReceiveHook));
exit:
FreeMessageOnError(request, error);
@@ -1308,57 +1302,54 @@ exit:
Error CoapBase::SendNextBlock2Request(Message &aRequest,
Message &aMessage,
const Ip6::MessageInfo &aMessageInfo,
const Metadata &aCoapMetadata,
const Metadata &aMetadata,
uint32_t aTotalLength,
bool aBeginBlock1Transfer)
{
Error error = kErrorNone;
Message *request = nullptr;
uint8_t buf[kMaxBlockLength] = {0};
uint16_t bufLen = kMaxBlockLength;
Error error = kErrorNone;
Message *request = nullptr;
uint8_t buf[kMaxBlockSize];
OffsetRange offsetRange;
BlockInfo msgBlockInfo;
BlockInfo requestBlockInfo;
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2));
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2, msgBlockInfo));
// Check payload and block length
VerifyOrExit((aMessage.GetLength() - aMessage.GetOffset()) <=
BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) &&
(aMessage.GetLength() - aMessage.GetOffset()) <= kMaxBlockLength,
error = kErrorNoBufs);
VerifyOrExit(msgBlockInfo.GetBlockSize() <= kMaxBlockSize, error = kErrorNoBufs);
// Read and then forward payload to receive hook function
bufLen = aMessage.ReadBytes(aMessage.GetOffset(), buf, aMessage.GetLength() - aMessage.GetOffset());
SuccessOrExit(error = aCoapMetadata.mBlockwiseReceiveHook(aCoapMetadata.mResponseContext, buf,
BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
aMessage.GetBlockWiseBlockNumber(),
bufLen, aMessage.IsMoreBlocksFlagSet(), aTotalLength));
offsetRange.InitFromMessageOffsetToEnd(aMessage);
VerifyOrExit(offsetRange.GetLength() <= msgBlockInfo.GetBlockSize(), error = kErrorNoBufs);
// CoAP Block-Wise Transfer continues
LogInfo("Received Block2 Nr. %d , Size: %d bytes, More Blocks Flag: %d", aMessage.GetBlockWiseBlockNumber(),
BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()), aMessage.IsMoreBlocksFlagSet());
aMessage.ReadBytes(offsetRange, buf);
SuccessOrExit(
error = aMetadata.mBlockwiseReceiveHook(aMetadata.mResponseContext, buf, msgBlockInfo.GetBlockOffsetPosition(),
offsetRange.GetLength(), msgBlockInfo.mMoreBlocks, aTotalLength));
// Conclude block-wise transfer if last block has been received
if (!aMessage.IsMoreBlocksFlagSet())
LogInfo("Received Block2 Nr. %d , Size: %d bytes, More Blocks Flag: %d", msgBlockInfo.mBlockNumber,
msgBlockInfo.GetBlockSize(), msgBlockInfo.mMoreBlocks);
if (!msgBlockInfo.mMoreBlocks)
{
FinalizeCoapTransaction(aRequest, aCoapMetadata, &aMessage, &aMessageInfo, kErrorNone);
FinalizeCoapTransaction(aRequest, aMetadata, &aMessage, &aMessageInfo, kErrorNone);
ExitNow();
}
// Init request for next block
VerifyOrExit((request = NewMessage()) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = PrepareNextBlockRequest(Message::kBlockType2, aMessage.IsMoreBlocksFlagSet(), aRequest,
*request, aMessage));
requestBlockInfo = msgBlockInfo;
requestBlockInfo.mBlockNumber++;
SuccessOrExit(error = PrepareNextBlockRequest(kOptionBlock2, aRequest, *request, requestBlockInfo));
if (!aBeginBlock1Transfer)
{
DequeueMessage(aRequest);
}
LogInfo("Request Block2 Nr. %d, Size: %d bytes", request->GetBlockWiseBlockNumber(),
BlockSizeFromExponent(request->GetBlockWiseBlockSize()));
LogInfo("Request Block2 Nr. %d, Size: %d bytes", requestBlockInfo.mBlockNumber, requestBlockInfo.GetBlockSize());
SuccessOrExit(error =
SendMessage(*request, aMessageInfo, /* aTxParameters */ nullptr, aCoapMetadata.mResponseHandler,
aCoapMetadata.mResponseContext, nullptr, aCoapMetadata.mBlockwiseReceiveHook));
SuccessOrExit(error = SendMessage(*request, aMessageInfo, /* aTxParameters */ nullptr, aMetadata.mResponseHandler,
aMetadata.mResponseContext, nullptr, aMetadata.mBlockwiseReceiveHook));
exit:
FreeMessageOnError(request, error);
@@ -1371,40 +1362,35 @@ Error CoapBase::ProcessBlock1Request(Message &aMessage,
const ResourceBlockWise &aResource,
uint32_t aTotalLength)
{
Error error = kErrorNone;
Message *response = nullptr;
uint8_t buf[kMaxBlockLength] = {0};
uint16_t bufLen = kMaxBlockLength;
Error error = kErrorNone;
Message *response = nullptr;
uint8_t buf[kMaxBlockSize];
OffsetRange offsetRange;
BlockInfo msgBlockInfo;
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1));
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1, msgBlockInfo));
// Read and then forward payload to receive hook function
VerifyOrExit((aMessage.GetLength() - aMessage.GetOffset()) <= kMaxBlockLength, error = kErrorNoBufs);
bufLen = aMessage.ReadBytes(aMessage.GetOffset(), buf, aMessage.GetLength() - aMessage.GetOffset());
SuccessOrExit(error = aResource.HandleBlockReceive(
buf, BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) * aMessage.GetBlockWiseBlockNumber(),
bufLen, aMessage.IsMoreBlocksFlagSet(), aTotalLength));
offsetRange.InitFromMessageOffsetToEnd(aMessage);
VerifyOrExit(offsetRange.GetLength() <= kMaxBlockSize, error = kErrorNoBufs);
if (aMessage.IsMoreBlocksFlagSet())
aMessage.ReadBytes(offsetRange, buf);
SuccessOrExit(error =
aResource.HandleBlockReceive(buf, msgBlockInfo.GetBlockOffsetPosition(), offsetRange.GetLength(),
msgBlockInfo.mMoreBlocks, aTotalLength));
if (msgBlockInfo.mMoreBlocks)
{
// Set up next response
VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorFailed);
response->Init(kTypeAck, kCodeContinue);
response->SetMessageId(aMessage.GetMessageId());
IgnoreReturnValue(response->SetToken(AsConst(aMessage).GetToken(), aMessage.GetTokenLength()));
IgnoreError(response->SetToken(AsConst(aMessage).GetToken(), aMessage.GetTokenLength()));
response->SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber());
response->SetMoreBlocksFlag(aMessage.IsMoreBlocksFlagSet());
response->SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
SuccessOrExit(error = response->AppendBlockOption(Message::kBlockType1, response->GetBlockWiseBlockNumber(),
response->IsMoreBlocksFlagSet(),
response->GetBlockWiseBlockSize()));
SuccessOrExit(error = response->AppendBlockOption(kOptionBlock1, msgBlockInfo));
SuccessOrExit(error = CacheLastBlockResponse(response));
LogInfo("Acknowledge Block1 Nr. %d, Size: %d bytes", response->GetBlockWiseBlockNumber(),
BlockSizeFromExponent(response->GetBlockWiseBlockSize()));
LogInfo("Acknowledge Block1 Nr. %d, Size: %d bytes", msgBlockInfo.mBlockNumber, msgBlockInfo.GetBlockSize());
SuccessOrExit(error = SendMessage(*response, aMessageInfo));
@@ -1430,57 +1416,49 @@ Error CoapBase::ProcessBlock2Request(Message &aMessage,
const Ip6::MessageInfo &aMessageInfo,
const ResourceBlockWise &aResource)
{
Error error = kErrorNone;
Message *response = nullptr;
uint8_t buf[kMaxBlockLength] = {0};
uint16_t bufLen = kMaxBlockLength;
bool moreBlocks = false;
uint64_t optionBuf = 0;
Error error = kErrorNone;
Message *response = nullptr;
uint64_t optionBuf = 0;
uint8_t buf[kMaxBlockSize] = {0};
uint16_t blockSize;
Option::Iterator iterator;
BlockInfo msgBlockInfo;
BlockInfo responseBlockInfo;
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2));
SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2, msgBlockInfo));
LogInfo("Request for Block2 Nr. %d, Size: %d bytes received", aMessage.GetBlockWiseBlockNumber(),
BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()));
LogInfo("Request for Block2 Nr. %d, Size: %d bytes received", msgBlockInfo.mBlockNumber,
msgBlockInfo.GetBlockSize());
if (aMessage.GetBlockWiseBlockNumber() == 0)
if (msgBlockInfo.mBlockNumber == 0)
{
aResource.HandleRequest(aMessage, aMessageInfo);
ExitNow();
}
// Set up next response
VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorNoBufs);
response->Init(kTypeAck, kCodeContent);
response->SetMessageId(aMessage.GetMessageId());
SuccessOrExit(error = response->SetTokenFromMessage(aMessage));
VerifyOrExit((bufLen = BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
error = kErrorNoBufs);
SuccessOrExit(error = aResource.HandleBlockTransmit(
buf, BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) * aMessage.GetBlockWiseBlockNumber(),
&bufLen, &moreBlocks));
responseBlockInfo.mMoreBlocks = false;
response->SetMoreBlocksFlag(moreBlocks);
VerifyOrExit((blockSize = msgBlockInfo.GetBlockSize()) <= kMaxBlockSize, error = kErrorNoBufs);
SuccessOrExit(error = aResource.HandleBlockTransmit(buf, msgBlockInfo.GetBlockOffsetPosition(), &blockSize,
&responseBlockInfo.mMoreBlocks));
if (moreBlocks)
if (responseBlockInfo.mMoreBlocks)
{
BlockSzx blockSzx;
SuccessOrExit(error = DetermineBlockSzxFromSize(bufLen, blockSzx));
response->SetBlockWiseBlockSize(blockSzx);
SuccessOrExit(error = DetermineBlockSzxFromSize(blockSize, responseBlockInfo.mBlockSzx));
}
else
{
// Verify that buffer length is not larger than requested block size
VerifyOrExit(bufLen <= BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()), error = kErrorInvalidArgs);
response->SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
VerifyOrExit(blockSize <= msgBlockInfo.GetBlockSize(), error = kErrorInvalidArgs);
responseBlockInfo.mBlockSzx = msgBlockInfo.mBlockSzx;
}
response->SetBlockWiseBlockNumber(
(BlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) * aMessage.GetBlockWiseBlockNumber()) /
(BlockSizeFromExponent(response->GetBlockWiseBlockSize())));
responseBlockInfo.mBlockNumber = msgBlockInfo.GetBlockOffsetPosition() / responseBlockInfo.GetBlockSize();
// Copy options from last response
SuccessOrExit(error = iterator.Init(*mLastResponse));
@@ -1491,9 +1469,7 @@ Error CoapBase::ProcessBlock2Request(Message &aMessage,
if (optionNumber == kOptionBlock2)
{
SuccessOrExit(error = response->AppendBlockOption(Message::kBlockType2, response->GetBlockWiseBlockNumber(),
response->IsMoreBlocksFlagSet(),
response->GetBlockWiseBlockSize()));
SuccessOrExit(error = response->AppendBlockOption(kOptionBlock2, responseBlockInfo));
}
else if (optionNumber == kOptionBlock1)
{
@@ -1505,9 +1481,9 @@ Error CoapBase::ProcessBlock2Request(Message &aMessage,
}
SuccessOrExit(error = response->SetPayloadMarker());
SuccessOrExit(error = response->AppendBytes(buf, bufLen));
SuccessOrExit(error = response->AppendBytes(buf, blockSize));
if (response->IsMoreBlocksFlagSet())
if (responseBlockInfo.mMoreBlocks)
{
SuccessOrExit(error = CacheLastBlockResponse(response));
}
@@ -1517,8 +1493,8 @@ Error CoapBase::ProcessBlock2Request(Message &aMessage,
FreeLastBlockResponse();
}
LogInfo("Send Block2 Nr. %d, Size: %d bytes, More Blocks Flag %d", response->GetBlockWiseBlockNumber(),
BlockSizeFromExponent(response->GetBlockWiseBlockSize()), response->IsMoreBlocksFlagSet());
LogInfo("Send Block2 Nr. %d, Size: %d bytes, More Blocks Flag %d", responseBlockInfo.mBlockNumber,
responseBlockInfo.GetBlockSize(), responseBlockInfo.mMoreBlocks);
SuccessOrExit(error = SendMessage(*response, aMessageInfo));
+7 -8
View File
@@ -728,7 +728,7 @@ protected:
void SetResourceHandler(ResourceHandler aHandler) { mResourceHandler = aHandler; }
private:
static constexpr uint16_t kMaxBlockLength = OPENTHREAD_CONFIG_COAP_MAX_BLOCK_LENGTH;
static constexpr uint16_t kMaxBlockSize = OPENTHREAD_CONFIG_COAP_MAX_BLOCK_LENGTH;
struct Metadata : public Message::FooterData<Metadata>
{
@@ -822,11 +822,10 @@ private:
bool &aDidHandle);
void FreeLastBlockResponse(void);
Error CacheLastBlockResponse(Message *aResponse);
Error PrepareNextBlockRequest(Message::BlockType aType,
bool aMoreBlocks,
Message &aRequestOld,
Message &aRequest,
Message &aMessage);
Error PrepareNextBlockRequest(uint16_t aBlockOptionNumber,
Message &aRequestOld,
Message &aRequest,
const BlockInfo &aBlockInfo);
Error ProcessBlock1Request(Message &aMessage,
const Ip6::MessageInfo &aMessageInfo,
const ResourceBlockWise &aResource,
@@ -837,11 +836,11 @@ private:
Error SendNextBlock1Request(Message &aRequest,
Message &aMessage,
const Ip6::MessageInfo &aMessageInfo,
const Metadata &aCoapMetadata);
const Metadata &aMetadata);
Error SendNextBlock2Request(Message &aRequest,
Message &aMessage,
const Ip6::MessageInfo &aMessageInfo,
const Metadata &aCoapMetadata,
const Metadata &aMetadata,
uint32_t aTotalLength,
bool aBeginBlock1Transfer);
+40 -30
View File
@@ -56,11 +56,6 @@ void Message::Init(void)
GetHelpData().mHeaderLength = kMinHeaderLength;
IgnoreError(SetLength(GetHelpData().mHeaderLength));
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
SetBlockWiseBlockNumber(0);
SetMoreBlocksFlag(false);
SetBlockWiseBlockSize(kBlockSzx16);
#endif
}
void Message::Init(Type aType, Code aCode)
@@ -295,56 +290,70 @@ exit:
return error;
}
Error Message::AppendBlockOption(Message::BlockType aType, uint32_t aNum, bool aMore, BlockSzx aSize)
Error Message::AppendBlockOption(uint16_t aBlockOptionNumber, const BlockInfo &aInfo)
{
Error error = kErrorNone;
uint32_t encoded = aSize;
Error error;
uint32_t encoded;
VerifyOrExit(aType == kBlockType1 || aType == kBlockType2, error = kErrorInvalidArgs);
VerifyOrExit(aSize <= kBlockSzx1024, error = kErrorInvalidArgs);
VerifyOrExit(aNum < kBlockNumMax, error = kErrorInvalidArgs);
switch (aBlockOptionNumber)
{
case kOptionBlock1:
case kOptionBlock2:
break;
default:
ExitNow(error = kErrorInvalidArgs);
}
encoded |= static_cast<uint32_t>(aMore << kBlockMOffset);
encoded |= aNum << kBlockNumOffset;
VerifyOrExit(aInfo.mBlockSzx <= kBlockSzx1024, error = kErrorInvalidArgs);
VerifyOrExit(aInfo.mBlockNumber < kBlockNumMax, error = kErrorInvalidArgs);
error = AppendUintOption((aType == kBlockType1) ? kOptionBlock1 : kOptionBlock2, encoded);
encoded = aInfo.mBlockSzx;
encoded |= static_cast<uint32_t>(aInfo.mMoreBlocks << kBlockMOffset);
encoded |= aInfo.mBlockNumber << kBlockNumOffset;
error = AppendUintOption(aBlockOptionNumber, encoded);
exit:
return error;
}
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
Error Message::ReadBlockOptionValues(uint16_t aBlockType)
Error Message::ReadBlockOptionValues(uint16_t aBlockOptionNumber, BlockInfo &aInfo) const
{
Error error = kErrorNone;
Error error;
uint8_t buf[kMaxOptionHeaderSize] = {0};
Option::Iterator iterator;
VerifyOrExit((aBlockType == kOptionBlock1) || (aBlockType == kOptionBlock2), error = kErrorInvalidArgs);
switch (aBlockOptionNumber)
{
case kOptionBlock1:
case kOptionBlock2:
break;
default:
ExitNow(error = kErrorInvalidArgs);
}
SuccessOrExit(error = iterator.Init(*this, aBlockType));
SuccessOrExit(error = iterator.Init(*this, aBlockOptionNumber));
SuccessOrExit(error = iterator.ReadOptionValue(buf));
SetBlockWiseBlockNumber(0);
SetMoreBlocksFlag(false);
switch (iterator.GetOption()->GetLength())
{
case 0:
case 1:
SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] & 0xf0) >> 4));
SetMoreBlocksFlag(static_cast<bool>((buf[0] & 0x08) >> 3 == 1));
SetBlockWiseBlockSize(static_cast<BlockSzx>(buf[0] & 0x07));
aInfo.mBlockNumber = static_cast<uint32_t>((buf[0] & 0xf0) >> 4);
aInfo.mMoreBlocks = (((buf[0] & 0x08) >> 3) == 1);
aInfo.mBlockSzx = (static_cast<BlockSzx>(buf[0] & 0x07));
break;
case 2:
SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] << 4) + ((buf[1] & 0xf0) >> 4)));
SetMoreBlocksFlag(static_cast<bool>((buf[1] & 0x08) >> 3 == 1));
SetBlockWiseBlockSize(static_cast<BlockSzx>(buf[1] & 0x07));
aInfo.mBlockNumber = static_cast<uint32_t>((buf[0] << 4) + ((buf[1] & 0xf0) >> 4));
aInfo.mMoreBlocks = ((buf[1] & 0x08) >> 3 == 1);
aInfo.mBlockSzx = (static_cast<BlockSzx>(buf[1] & 0x07));
break;
case 3:
SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] << 12) + (buf[1] << 4) + ((buf[2] & 0xf0) >> 4)));
SetMoreBlocksFlag(static_cast<bool>((buf[2] & 0x08) >> 3 == 1));
SetBlockWiseBlockSize(static_cast<BlockSzx>(buf[2] & 0x07));
aInfo.mBlockNumber = static_cast<uint32_t>((buf[0] << 12) + (buf[1] << 4) + ((buf[2] & 0xf0) >> 4));
aInfo.mMoreBlocks = ((buf[2] & 0x08) >> 3 == 1);
aInfo.mBlockSzx = (static_cast<BlockSzx>(buf[2] & 0x07));
break;
default:
error = kErrorInvalidArgs;
@@ -354,6 +363,7 @@ Error Message::ReadBlockOptionValues(uint16_t aBlockType)
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
Error Message::SetPayloadMarker(void)
+43 -95
View File
@@ -176,6 +176,30 @@ enum BlockSzx : uint8_t
*/
uint16_t BlockSizeFromExponent(BlockSzx aBlockSzx);
/**
* Represents information in a Block1 or Block2 Option (for block-wise transfer).
*/
struct BlockInfo
{
/**
* Returns the block size in bytes.
*
* @returns The block size in bytes derived from block size exponent (`mBlockSzx`).
*/
uint16_t GetBlockSize(void) const { return BlockSizeFromExponent(mBlockSzx); }
/**
* Returns the current block offset position.
*
* @returns The block offset position, i.e. the current block number multiplied by the block size.
*/
uint32_t GetBlockOffsetPosition(void) const { return mBlockNumber * GetBlockSize(); }
uint32_t mBlockNumber; ///< The block number.
BlockSzx mBlockSzx; ///< The block size exponent.
bool mMoreBlocks; ///< Whether more blocks are following (`M` flag).
};
/**
* Implements CoAP message generation and parsing.
*/
@@ -194,15 +218,6 @@ public:
typedef char UriPathStringBuffer[kMaxReceivedUriPath + 1]; ///< Buffer to store a received URI Path string.
/**
* CoAP Block1/Block2 Types
*/
enum BlockType : uint8_t
{
kBlockType1 = 1,
kBlockType2 = 2,
};
/**
* Initializes the CoAP header.
*/
@@ -480,18 +495,30 @@ public:
Error AppendUriQueryOptions(const char *aUriQuery);
/**
* Appends a Block option
*
* @param[in] aType Type of block option, 1 or 2.
* @param[in] aNum Current block number.
* @param[in] aMore Boolean to indicate more blocks are to be sent.
* @param[in] aSize Maximum block size.
* Appends a Block1 or Block2 option.
*
* @param[in] aBlockOptionNumber Block1 or Block2 option number.
* @param[out] aInfo A `BlockInfo` specifying block number, size, and more blocks flags.
* @retval kErrorNone Successfully appended the option.
* @retval kErrorInvalidArgs The option type is not equal or greater than the last option type.
* @retval kErrorNoBufs The option length exceeds the buffer size.
*/
Error AppendBlockOption(BlockType aType, uint32_t aNum, bool aMore, BlockSzx aSize);
Error AppendBlockOption(uint16_t aBlockOptionNumber, const BlockInfo &aInfo);
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
/**
* Reads the information contained in a Block1 or Block2 option from the CoAP message.
*
* @param[in] aBlockOptionNumber Block1 or Block2 option number.
* @param[out] aInfo A reference to `BlockInfo` to return the read Option
*
* @retval kErrorNone The option was read successfully. @p aInfo is updated.
* @retval kErrorNotFound The option has not been found.
* @retval kErrorInvalidArgs The option is invalid.
*/
Error ReadBlockOptionValues(uint16_t aBlockOptionNumber, BlockInfo &aInfo) const;
#endif
/**
* Appends a Proxy-Uri option.
@@ -540,49 +567,6 @@ public:
*/
Error AppendUriQueryOption(const char *aUriQuery) { return AppendStringOption(kOptionUriQuery, aUriQuery); }
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
/**
* Reads the information contained in a Block1 or Block2 option and set it in
* the HelpData of the message.
*
* @param[in] aBlockType Block1 or Block2 option value.
*
* @retval kErrorNone The option has been found and is valid.
* @retval kErrorNotFound The option has not been found.
* @retval kErrorInvalidArgs The option is invalid.
*/
Error ReadBlockOptionValues(uint16_t aBlockType);
/**
* Returns the current header length of a message.
*
* @returns The length of the message header.
*/
uint16_t GetHeaderLength(void) const { return GetHelpData().mHeaderLength; }
/**
* Returns the block number of a CoAP block-wise transfer message.
*
* @returns The block number.
*/
uint32_t GetBlockWiseBlockNumber(void) const { return GetHelpData().mBlockWiseData.mBlockNumber; }
/**
* Checks if the More Blocks flag is set.
*
* @retval TRUE More Blocks flag is set.
* @retval FALSE More Blocks flag is not set.
*/
bool IsMoreBlocksFlagSet(void) const { return GetHelpData().mBlockWiseData.mMoreBlocks; }
/**
* Returns the block size of a CoAP block-wise transfer message.
*
* @returns The block size.
*/
BlockSzx GetBlockWiseBlockSize(void) const { return GetHelpData().mBlockWiseData.mBlockSize; }
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
/**
* Reads and reassembles the URI path string and fills it into @p aUriPath.
*
@@ -626,30 +610,6 @@ public:
*/
Error SetDefaultResponseHeader(const Message &aRequest);
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
/**
* Sets the block number value in the message HelpData.
*
* @param[in] aBlockNumber Block number value to set.
*/
void SetBlockWiseBlockNumber(uint32_t aBlockNumber) { GetHelpData().mBlockWiseData.mBlockNumber = aBlockNumber; }
/**
* Sets the More Blocks flag in the message HelpData.
*
* @param[in] aMoreBlocks TRUE or FALSE.
*/
void SetMoreBlocksFlag(bool aMoreBlocks) { GetHelpData().mBlockWiseData.mMoreBlocks = aMoreBlocks; }
/**
* Sets the block size value in the message HelpData.
*
* @param[in] aBlockSize Block size value to set.
*/
void SetBlockWiseBlockSize(BlockSzx aBlockSize) { GetHelpData().mBlockWiseData.mBlockSize = aBlockSize; }
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
/**
* Checks if a header is an empty message header.
*
@@ -878,15 +838,6 @@ private:
static constexpr uint32_t kObserveMask = 0xffffff;
static constexpr uint32_t kBlockNumMax = 0xffff;
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
struct BlockWiseData
{
uint32_t mBlockNumber;
bool mMoreBlocks;
BlockSzx mBlockSize;
};
#endif
/**
* Represents a CoAP header excluding CoAP options.
*/
@@ -909,9 +860,6 @@ private:
uint16_t mHeaderOffset; ///< The byte offset for the CoAP Header
uint16_t mHeaderLength;
bool mPayloadMarkerSet;
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
BlockWiseData mBlockWiseData;
#endif
};
class ConstIterator : public ot::Message::ConstIterator