[coap] simplify Coap::Message implementation (#12313)

This change simplifies the `Coap::Message` implementation and removes
the fragile `HelpData` struct which was used to cache header
information within reserved portion of message.

The `Coap::Msg` class is updated to hold the parsed CoAP header
information (type, code, message ID, token). It now inherits from a
new `HeaderInfo` class which contains the parsed fields. This change
helps to simplify many of the call sites which previously had to parse
the header information themselves.

The key changes are:
- The `HelpData` struct is removed from `Coap::Message`.
- `Coap::Msg` is updated to track parsed header info in `HeaderInfo`.
- `otCoapMessageInit()` and `otCoapMessageInitResponse()` now return an
  `otError`.
- Methods are renamed to harmonize their names.
- A new unit test `test_coap_message.cpp` is added to verify the
  `Coap::Message` implementation.
This commit is contained in:
Abtin Keshavarzian
2026-01-23 10:52:42 -08:00
committed by GitHub
parent 3b676fb6f3
commit 5cae26e22b
35 changed files with 1294 additions and 636 deletions
+19 -12
View File
@@ -312,26 +312,33 @@ typedef struct otCoapTxParameters
// `otCoapMessage*` APIs - Constructing or parsing a CoAP message.
/**
* Initializes the CoAP header.
* Initializes a CoAP message.
*
* @param[in,out] aMessage A pointer to the CoAP message to initialize.
* @param[in] aType CoAP message type.
* @param[in] aCode CoAP message code.
* This function initializes the CoAP header, erasing any previously written content in the message. The Message ID is
* set to zero, and the token is empty (zero-length).
*
* @param[in,out] aMessage A pointer to the CoAP message to initialize.
* @param[in] aType The CoAP Type.
* @param[in] aCode The CoAP Code.
*
* @retval OT_ERROR_NONE Successfully initialized the message.
* @retval OT_ERROR_NO_BUFS Insufficient message buffers available to write the CoAP header.
*/
void otCoapMessageInit(otMessage *aMessage, otCoapType aType, otCoapCode aCode);
otError otCoapMessageInit(otMessage *aMessage, otCoapType aType, otCoapCode aCode);
/**
* Initializes a response message.
* Initializes a CoAP message as a response to a request.
*
* @note Both message ID and token are set according to @p aRequest.
* This function initializes the CoAP header, erasing any previously written content in the message. The Message ID and
* Token are copied from the request message.
*
* @param[in,out] aResponse A pointer to the CoAP response message.
* @param[in] aRequest A pointer to the CoAP request message.
* @param[in] aType CoAP message type.
* @param[in] aCode CoAP message code.
* @param[in,out] aResponse A pointer to the CoAP response message to initialize.
* @param[in] aRequest A pointer to the CoAP request message.
* @param[in] aType The CoAP Type for the response.
* @param[in] aCode The CoAP Code for the response.
*
* @retval OT_ERROR_NONE Successfully initialized the response message.
* @retval OT_ERROR_NO_BUFS Insufficient message buffers available to initialize the response message.
* @retval OT_ERROR_NO_BUFS Insufficient message buffers available to write the CoAP header.
*/
otError otCoapMessageInitResponse(otMessage *aResponse, const otMessage *aRequest, otCoapType aType, otCoapCode aCode);
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (573)
#define OPENTHREAD_API_VERSION (574)
/**
* @addtogroup api-instance
+6 -5
View File
@@ -89,7 +89,7 @@ otError Coap::CancelResourceSubscription(bool aSendCancelMessage)
message = otCoapNewMessage(GetInstancePtr(), nullptr);
VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
otCoapMessageInit(message, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_GET);
SuccessOrExit(error = otCoapMessageInit(message, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_GET));
SuccessOrExit(error = otCoapMessageWriteToken(message, &mRequestToken));
SuccessOrExit(error = otCoapMessageAppendObserveOption(message, 1));
@@ -268,9 +268,10 @@ template <> otError Coap::Process<Cmd("set")>(Arg aArgs[])
notificationMessage = otCoapNewMessage(GetInstancePtr(), nullptr);
VerifyOrExit(notificationMessage != nullptr, error = OT_ERROR_NO_BUFS);
otCoapMessageInit(notificationMessage,
(isConNotification ? OT_COAP_TYPE_CONFIRMABLE : OT_COAP_TYPE_NON_CONFIRMABLE),
OT_COAP_CODE_CONTENT);
SuccessOrExit(
error = otCoapMessageInit(notificationMessage,
(isConNotification ? OT_COAP_TYPE_CONFIRMABLE : OT_COAP_TYPE_NON_CONFIRMABLE),
OT_COAP_CODE_CONTENT));
SuccessOrExit(error = otCoapMessageWriteToken(notificationMessage, &mSubscriberToken));
SuccessOrExit(error = otCoapMessageAppendObserveOption(notificationMessage, mObserveSerial++));
@@ -704,7 +705,7 @@ otError Coap::ProcessRequest(Arg aArgs[], otCoapCode aCoapCode)
message = otCoapNewMessage(GetInstancePtr(), nullptr);
VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
otCoapMessageInit(message, coapType, aCoapCode);
SuccessOrExit(error = otCoapMessageInit(message, coapType, aCoapCode));
otCoapMessageGenerateToken(message, OT_COAP_DEFAULT_TOKEN_LENGTH);
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
+1 -1
View File
@@ -525,7 +525,7 @@ otError CoapSecure::ProcessRequest(Arg aArgs[], otCoapCode aCoapCode)
message = otCoapNewMessage(GetInstancePtr(), nullptr);
VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS);
otCoapMessageInit(message, coapType, aCoapCode);
SuccessOrExit(error = otCoapMessageInit(message, coapType, aCoapCode));
otCoapMessageGenerateToken(message, OT_COAP_DEFAULT_TOKEN_LENGTH);
SuccessOrExit(error = otCoapMessageAppendUriPathOptions(message, coapUri));
+8 -14
View File
@@ -44,20 +44,14 @@ otMessage *otCoapNewMessage(otInstance *aInstance, const otMessageSettings *aSet
return AsCoreType(aInstance).Get<Coap::ApplicationCoap>().NewMessage(Message::Settings::From(aSettings));
}
void otCoapMessageInit(otMessage *aMessage, otCoapType aType, otCoapCode aCode)
otError otCoapMessageInit(otMessage *aMessage, otCoapType aType, otCoapCode aCode)
{
AsCoapMessage(aMessage).Init(MapEnum(aType), MapEnum(aCode));
return AsCoapMessage(aMessage).Init(MapEnum(aType), MapEnum(aCode));
}
otError otCoapMessageInitResponse(otMessage *aResponse, const otMessage *aRequest, otCoapType aType, otCoapCode aCode)
{
Coap::Message &response = AsCoapMessage(aResponse);
const Coap::Message &request = AsCoapMessage(aRequest);
response.Init(MapEnum(aType), MapEnum(aCode));
response.SetMessageId(request.GetMessageId());
return response.WriteTokenFromMessage(request);
return AsCoapMessage(aResponse).InitAsResponse(MapEnum(aType), MapEnum(aCode), AsCoapMessage(aRequest));
}
otError otCoapMessageWriteToken(otMessage *aMessage, const otCoapToken *aToken)
@@ -151,23 +145,23 @@ otError otCoapMessageAppendUriQueryOption(otMessage *aMessage, const char *aUriQ
return AsCoapMessage(aMessage).AppendUriQueryOption(aUriQuery);
}
otError otCoapMessageSetPayloadMarker(otMessage *aMessage) { return AsCoapMessage(aMessage).SetPayloadMarker(); }
otError otCoapMessageSetPayloadMarker(otMessage *aMessage) { return AsCoapMessage(aMessage).AppendPayloadMarker(); }
otCoapType otCoapMessageGetType(const otMessage *aMessage)
{
return static_cast<otCoapType>(AsCoapMessage(aMessage).GetType());
return static_cast<otCoapType>(AsCoapMessage(aMessage).ReadType());
}
otCoapCode otCoapMessageGetCode(const otMessage *aMessage)
{
return static_cast<otCoapCode>(AsCoapMessage(aMessage).GetCode());
return static_cast<otCoapCode>(AsCoapMessage(aMessage).ReadCode());
}
void otCoapMessageSetCode(otMessage *aMessage, otCoapCode aCode) { AsCoapMessage(aMessage).SetCode(MapEnum(aCode)); }
void otCoapMessageSetCode(otMessage *aMessage, otCoapCode aCode) { AsCoapMessage(aMessage).WriteCode(MapEnum(aCode)); }
const char *otCoapMessageCodeToString(const otMessage *aMessage) { return AsCoapMessage(aMessage).CodeToString(); }
uint16_t otCoapMessageGetMessageId(const otMessage *aMessage) { return AsCoapMessage(aMessage).GetMessageId(); }
uint16_t otCoapMessageGetMessageId(const otMessage *aMessage) { return AsCoapMessage(aMessage).ReadMessageId(); }
otError otCoapMessageReadToken(const otMessage *aMessage, otCoapToken *aToken)
{
+6 -6
View File
@@ -149,7 +149,7 @@ void Manager::HandleMulticastListenerRegistration(const Coap::Msg &aMsg)
bool hasCommissionerSessionIdTlv = false;
bool processTimeoutTlv = false;
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest(), error = kErrorParse);
VerifyOrExit(aMsg.IsConfirmablePostRequest(), error = kErrorParse);
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
// Required by Test Specification 5.10.22 DUA-TC-26, only for certification purpose
@@ -366,7 +366,7 @@ void Manager::HandleDuaRegistration(const Coap::Msg &aMsg)
#endif
VerifyOrExit(aMsg.mMessageInfo.GetPeerAddr().GetIid().IsRoutingLocator(), error = kErrorDrop);
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest(), error = kErrorParse);
VerifyOrExit(aMsg.IsConfirmablePostRequest(), error = kErrorParse);
SuccessOrExit(error = Tlv::Find<ThreadTargetTlv>(aMsg.mMessage, target));
SuccessOrExit(error = Tlv::Find<ThreadMeshLocalEidTlv>(aMsg.mMessage, meshLocalIid));
@@ -542,7 +542,7 @@ template <> void Manager::HandleTmf<kUriBackboneQuery>(Coap::Msg &aMsg)
VerifyOrExit(aMsg.mMessageInfo.IsHostInterface(), error = kErrorDrop);
VerifyOrExit(Get<Local>().IsPrimary(), error = kErrorInvalidState);
VerifyOrExit(aMsg.mMessage.IsNonConfirmablePostRequest(), error = kErrorParse);
VerifyOrExit(aMsg.IsNonConfirmablePostRequest(), error = kErrorParse);
SuccessOrExit(error = Tlv::Find<ThreadTargetTlv>(aMsg.mMessage, dua));
@@ -574,9 +574,9 @@ template <> void Manager::HandleTmf<kUriBackboneAnswer>(Coap::Msg &aMsg)
VerifyOrExit(aMsg.mMessageInfo.IsHostInterface(), error = kErrorDrop);
VerifyOrExit(Get<Local>().IsPrimary(), error = kErrorInvalidState);
VerifyOrExit(aMsg.mMessage.IsPostRequest(), error = kErrorParse);
VerifyOrExit(aMsg.IsPostRequest(), error = kErrorParse);
proactive = !aMsg.mMessage.IsConfirmable();
proactive = !aMsg.IsConfirmable();
SuccessOrExit(error = Tlv::Find<ThreadTargetTlv>(aMsg.mMessage, dua));
SuccessOrExit(error = Tlv::Find<ThreadMeshLocalEidTlv>(aMsg.mMessage, meshLocalIid));
@@ -637,7 +637,7 @@ Error Manager::SendBackboneAnswer(const Ip6::Address &aDstAddr,
SuccessOrExit(error = message->Init(proactive ? Coap::kTypeNonConfirmable : Coap::kTypeConfirmable, Coap::kCodePost,
kUriBackboneAnswer));
SuccessOrExit(error = message->SetPayloadMarker());
SuccessOrExit(error = message->AppendPayloadMarker());
SuccessOrExit(error = Tlv::Append<ThreadTargetTlv>(*message, aDua));
+138 -70
View File
@@ -40,6 +40,81 @@ namespace Coap {
RegisterLogModule("Coap");
//---------------------------------------------------------------------------------------------------------------------
// Msg
Error Msg::ParseHeaderAndOptions(PayloadMarkerMode aPayloadMarkerMode)
{
// Parses and validates CoAP headers and options. Assumes
// `GetHeaderOffset()` points to the header start.
// `aPayloadMarkerMode` determines behavior regarding "payload
// marker". Either rejects the message if payload marker is present
// with no payload (used on a received message), or removes the
// payload marker in such a situation (used on a message to be
// sent). Upon completion, `GetOffset()` is updated to the start of
// the payload.
Error error;
Option::Iterator iterator;
uint16_t payloadOffset;
bool emptyPayload;
SuccessOrExit(error = mMessage.ParseHeaderInfo(*this));
SuccessOrExit(error = iterator.Init(mMessage));
while (!iterator.IsDone())
{
SuccessOrExit(error = iterator.Advance());
}
payloadOffset = iterator.GetPayloadMessageOffset();
emptyPayload = (payloadOffset == mMessage.GetLength());
if (iterator.HasPayloadMarker())
{
switch (aPayloadMarkerMode)
{
case kRejectIfNoPayloadWithPayloadMarker:
VerifyOrExit(!emptyPayload, error = kErrorParse);
break;
case kRemovePayloadMarkerIfNoPayload:
if (emptyPayload)
{
mMessage.RemoveFooter(sizeof(uint8_t));
payloadOffset--;
}
break;
}
}
mMessage.SetOffset(payloadOffset);
exit:
return error;
}
uint16_t Msg::GetHeaderSize(void) const
{
// Determines the size of the CoAP header including the token
// but excluding any appended Options.
return sizeof(Message::Header) + GetToken().GetLength();
}
void Msg::UpdateType(Type aType)
{
mType = aType;
mMessage.WriteType(aType);
}
void Msg::UpdateMessageId(uint16_t aMessageId)
{
mMessageId = aMessageId;
mMessage.WriteMessageId(aMessageId);
}
//---------------------------------------------------------------------------------------------------------------------
// CoapBase
@@ -137,7 +212,7 @@ Message *CoapBase::InitMessage(Message *aMessage, Type aType, Uri aUri)
VerifyOrExit(aMessage != nullptr);
SuccessOrExit(error = aMessage->Init(aType, kCodePost, aUri));
SuccessOrExit(error = aMessage->SetPayloadMarker());
SuccessOrExit(error = aMessage->AppendPayloadMarker());
exit:
FreeAndNullMessageOnError(aMessage, error);
@@ -150,8 +225,8 @@ Message *CoapBase::InitResponse(Message *aMessage, const Message &aRequest)
VerifyOrExit(aMessage != nullptr);
SuccessOrExit(error = aMessage->SetDefaultResponseHeader(aRequest));
SuccessOrExit(error = aMessage->SetPayloadMarker());
SuccessOrExit(error = aMessage->InitAsResponse(kTypeAck, kCodeChanged, aRequest));
SuccessOrExit(error = aMessage->AppendPayloadMarker());
exit:
FreeAndNullMessageOnError(aMessage, error);
@@ -199,46 +274,46 @@ Error CoapBase::SendMessage(Message &aMessage,
Msg txMsg(aMessage, aMessageInfo);
Metadata metadata;
SuccessOrExit(error = txMsg.ParseHeaderAndOptions(Msg::kRemovePayloadMarkerIfNoPayload));
if (aTxParameters == nullptr)
{
aTxParameters = &TxParameters::GetDefault();
}
else
{
SuccessOrExit(error = aTxParameters->ValidateFor(txMsg.mMessage));
SuccessOrExit(error = aTxParameters->ValidateFor(txMsg));
}
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
metadata.mBlockwiseReceiveHook = aReceiveHook;
metadata.mBlockwiseTransmitHook = aTransmitHook;
SuccessOrExit(error = ProcessBlockwiseSend(txMsg.mMessage, aTransmitHook, aContext));
SuccessOrExit(error = ProcessBlockwiseSend(txMsg, aTransmitHook, aContext));
#endif
switch (txMsg.mMessage.GetType())
switch (txMsg.GetType())
{
case kTypeAck:
mResponseCache.Add(txMsg, aTxParameters->CalculateExchangeLifetime());
break;
case kTypeReset:
OT_ASSERT(txMsg.mMessage.GetCode() == kCodeEmpty);
OT_ASSERT(txMsg.GetCode() == kCodeEmpty);
break;
default:
txMsg.mMessage.SetMessageId(mMessageId++);
txMsg.UpdateMessageId(mMessageId++);
break;
}
txMsg.mMessage.Finish();
if (txMsg.mMessage.IsConfirmable())
if (txMsg.IsConfirmable())
{
copyLength = txMsg.mMessage.GetLength();
}
else if (txMsg.mMessage.IsNonConfirmable() && (aHandler != nullptr))
else if (txMsg.IsNonConfirmable() && (aHandler != nullptr))
{
// As we do not retransmit non confirmable messages, create a
// copy of header only, for token information.
copyLength = txMsg.mMessage.GetOptionStart();
copyLength = txMsg.GetHeaderSize();
}
if (copyLength > 0)
@@ -248,7 +323,8 @@ Error CoapBase::SendMessage(Message &aMessage,
bool shouldObserve = false;
SuccessOrExit(error = ProcessObserveSend(txMsg, shouldObserve));
metadata.mObserve = shouldObserve;
metadata.mObserve = shouldObserve;
metadata.mIsRequest = txMsg.IsRequest();
}
#endif
@@ -261,7 +337,7 @@ Error CoapBase::SendMessage(Message &aMessage,
metadata.mRetransmissionsRemaining = aTxParameters->mMaxRetransmit;
metadata.mRetransmissionTimeout = aTxParameters->CalculateInitialRetransmissionTimeout();
metadata.mAcknowledged = false;
metadata.mConfirmable = txMsg.mMessage.IsConfirmable();
metadata.mConfirmable = txMsg.IsConfirmable();
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
metadata.mHopLimit = txMsg.mMessageInfo.GetHopLimit();
metadata.mIsHostInterface = txMsg.mMessageInfo.IsHostInterface();
@@ -339,7 +415,7 @@ Error CoapBase::SendAck(const Msg &aRxMsg) { return SendEmptyMessage(kTypeAck, a
Error CoapBase::SendEmptyAck(const Msg &aRxMsg, Code aCode)
{
return (aRxMsg.mMessage.IsConfirmable() ? SendHeaderResponse(aCode, aRxMsg) : kErrorInvalidArgs);
return (aRxMsg.IsConfirmable() ? SendHeaderResponse(aCode, aRxMsg) : kErrorInvalidArgs);
}
Error CoapBase::SendEmptyAck(const Msg &aRxMsg) { return SendEmptyAck(aRxMsg, kCodeChanged); }
@@ -351,14 +427,11 @@ Error CoapBase::SendEmptyMessage(Type aType, const Msg &aRxMsg)
Error error = kErrorNone;
Message *message = nullptr;
VerifyOrExit(aRxMsg.mMessage.IsConfirmable(), error = kErrorInvalidArgs);
VerifyOrExit(aRxMsg.IsConfirmable(), error = kErrorInvalidArgs);
VerifyOrExit((message = NewMessage()) != nullptr, error = kErrorNoBufs);
message->Init(aType, kCodeEmpty);
message->SetMessageId(aRxMsg.mMessage.GetMessageId());
message->Finish();
SuccessOrExit(error = message->Init(aType, kCodeEmpty, aRxMsg.GetMessageId()));
SuccessOrExit(error = Send(*message, aRxMsg.mMessageInfo));
exit:
@@ -371,18 +444,17 @@ Error CoapBase::SendHeaderResponse(Message::Code aCode, const Msg &aRxMsg)
Error error = kErrorNone;
Message *message = nullptr;
VerifyOrExit(aRxMsg.mMessage.IsRequest(), error = kErrorInvalidArgs);
VerifyOrExit(aRxMsg.IsRequest(), error = kErrorInvalidArgs);
VerifyOrExit((message = NewMessage()) != nullptr, error = kErrorNoBufs);
switch (aRxMsg.mMessage.GetType())
switch (aRxMsg.GetType())
{
case kTypeConfirmable:
message->Init(kTypeAck, aCode);
message->SetMessageId(aRxMsg.mMessage.GetMessageId());
SuccessOrExit(error = message->Init(kTypeAck, aCode, aRxMsg.GetMessageId()));
break;
case kTypeNonConfirmable:
message->Init(kTypeNonConfirmable, aCode);
SuccessOrExit(error = message->Init(kTypeNonConfirmable, aCode));
break;
default:
@@ -408,7 +480,7 @@ void CoapBase::ScheduleRetransmissionTimer(void)
metadata.ReadFrom(message);
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
if (IsObserveSubscription(message, metadata))
if (IsObserveSubscription(metadata))
{
// This is an RFC7641 subscription which is already acknowledged.
// We do not time it out, so skip it when determining the next
@@ -441,7 +513,7 @@ void CoapBase::HandleRetransmissionTimer(void)
if (now >= metadata.mNextTimerShot)
{
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
if (IsObserveSubscription(message, metadata))
if (IsObserveSubscription(metadata))
{
continue;
}
@@ -570,11 +642,11 @@ Message *CoapBase::FindRelatedRequest(const Msg &aMsg, Metadata &aMetadata)
aMetadata.mDestinationPort == aMsg.mMessageInfo.GetPeerPort()) ||
aMetadata.mDestinationAddress.IsMulticast() || aMetadata.mDestinationAddress.GetIid().IsAnycastLocator()))
{
switch (aMsg.mMessage.GetType())
switch (aMsg.GetType())
{
case kTypeReset:
case kTypeAck:
if (aMsg.mMessage.GetMessageId() == message.GetMessageId())
if (aMsg.GetMessageId() == message.ReadMessageId())
{
request = &message;
ExitNow();
@@ -603,16 +675,18 @@ void CoapBase::Receive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageIn
{
Msg rxMsg(AsCoapMessage(&aMessage), aMessageInfo);
if (rxMsg.mMessage.ParseHeader() != kErrorNone)
rxMsg.mMessage.SetHeaderOffset(rxMsg.mMessage.GetOffset());
if (rxMsg.ParseHeaderAndOptions(Msg::kRejectIfNoPayloadWithPayloadMarker) != kErrorNone)
{
LogDebg("Failed to parse CoAP header");
if (!aMessageInfo.GetSockAddr().IsMulticast() && rxMsg.mMessage.IsConfirmable())
if (!aMessageInfo.GetSockAddr().IsMulticast() && rxMsg.IsConfirmable())
{
IgnoreError(SendReset(rxMsg));
}
}
else if (rxMsg.mMessage.IsRequest())
else if (rxMsg.IsRequest())
{
ProcessReceivedRequest(rxMsg);
}
@@ -643,7 +717,7 @@ void CoapBase::ProcessReceivedResponse(Msg &aRxMsg)
// response, and we have a response handler; then we're dealing
// with RFC7641 rules here. If there is no response handler, then
// we're wasting our time!
if (metadata.mObserve && request->IsRequest() && (metadata.mResponseHandler != nullptr))
if (metadata.mObserve && metadata.mIsRequest && (metadata.mResponseHandler != nullptr))
{
Option::Iterator iterator;
@@ -652,10 +726,10 @@ void CoapBase::ProcessReceivedResponse(Msg &aRxMsg)
}
#endif
switch (aRxMsg.mMessage.GetType())
switch (aRxMsg.GetType())
{
case kTypeReset:
if (aRxMsg.mMessage.IsEmpty())
if (aRxMsg.IsEmpty())
{
FinalizeCoapTransaction(*request, metadata, nullptr, kErrorAbort);
}
@@ -664,12 +738,12 @@ void CoapBase::ProcessReceivedResponse(Msg &aRxMsg)
break;
case kTypeAck:
if (aRxMsg.mMessage.IsEmpty())
if (aRxMsg.IsEmpty())
{
// Empty acknowledgment.
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
if (metadata.mObserve && !request->IsRequest())
if (metadata.mObserve && !metadata.mIsRequest)
{
// This is the ACK to our RFC7641 CON notification.
// There will be no "separate" response so pass it back
@@ -697,7 +771,7 @@ void CoapBase::ProcessReceivedResponse(Msg &aRxMsg)
}
}
}
else if (aRxMsg.mMessage.IsResponse() && aRxMsg.mMessage.HasSameTokenAs(*request))
else if (aRxMsg.IsResponse() && aRxMsg.mMessage.HasSameTokenAs(*request))
{
// Piggybacked response.
@@ -777,7 +851,7 @@ exit:
{
bool didHandle = InvokeResponseFallback(aRxMsg);
if (!didHandle && aRxMsg.mMessage.RequireResetOnError())
if (!didHandle && aRxMsg.RequireResetOnError())
{
// Successfully parsed a header but no matching request was
// found - reject the message by sending reset.
@@ -893,10 +967,10 @@ Error CoapBase::SendMessage(Message &aMessage,
return SendMessage(aMessage, aMessageInfo, aTxParameters, aHandler, aContext, nullptr, nullptr);
}
Error CoapBase::ProcessBlockwiseSend(Message &aMessage, BlockwiseTransmitHook aTransmitHook, void *aContext)
Error CoapBase::ProcessBlockwiseSend(Msg &aMsg, BlockwiseTransmitHook aTransmitHook, void *aContext)
{
Error error = kErrorNone;
uint8_t type = aMessage.GetType();
uint8_t type = aMsg.GetType();
bool moreBlocks = false;
uint16_t blockSize;
uint8_t buf[kMaxBlockSize];
@@ -906,7 +980,7 @@ Error CoapBase::ProcessBlockwiseSend(Message &aMessage, BlockwiseTransmitHook aT
VerifyOrExit(aTransmitHook != nullptr);
SuccessOrExit(aMessage.ReadBlockOptionValues(type == kTypeAck ? kOptionBlock2 : kOptionBlock1, blockInfo));
SuccessOrExit(aMsg.mMessage.ReadBlockOptionValues(type == kTypeAck ? kOptionBlock2 : kOptionBlock1, blockInfo));
VerifyOrExit(blockInfo.mBlockNumber == 0);
@@ -914,17 +988,17 @@ Error CoapBase::ProcessBlockwiseSend(Message &aMessage, BlockwiseTransmitHook aT
VerifyOrExit(blockSize <= kMaxBlockSize, error = kErrorNoBufs);
SuccessOrExit(error = aTransmitHook(aContext, buf, 0, &blockSize, &moreBlocks));
SuccessOrExit(error = aMessage.AppendBytes(buf, blockSize));
SuccessOrExit(error = aMsg.mMessage.AppendBytes(buf, blockSize));
switch (type)
{
case kTypeAck:
SuccessOrExit(error = CacheLastBlockResponse(&aMessage));
SuccessOrExit(error = CacheLastBlockResponse(&aMsg.mMessage));
break;
case kTypeNonConfirmable:
// Block-Wise messages always have to be confirmable
aMessage.SetType(kTypeConfirmable);
aMsg.UpdateType(kTypeConfirmable);
break;
default:
@@ -980,31 +1054,29 @@ Error CoapBase::ProcessBlockwiseResponse(Msg &aRxMsg, Message &aRequest, const M
FinalizeCoapTransaction(aRequest, aMetadata, &aRxMsg, kErrorNone);
break;
case 1: // Block1 option
if (aRxMsg.mMessage.GetCode() == kCodeContinue && aMetadata.mBlockwiseTransmitHook != nullptr)
if (aRxMsg.GetCode() == kCodeContinue && aMetadata.mBlockwiseTransmitHook != nullptr)
{
error = SendNextBlock1Request(aRequest, aRxMsg, aMetadata);
}
if (aRxMsg.mMessage.GetCode() != kCodeContinue || aMetadata.mBlockwiseTransmitHook == nullptr ||
error != kErrorNone)
if (aRxMsg.GetCode() != kCodeContinue || aMetadata.mBlockwiseTransmitHook == nullptr || error != kErrorNone)
{
FinalizeCoapTransaction(aRequest, aMetadata, &aRxMsg, error);
}
break;
case 2: // Block2 option
if (aRxMsg.mMessage.GetCode() < kCodeBadRequest && aMetadata.mBlockwiseReceiveHook != nullptr)
if (aRxMsg.GetCode() < kCodeBadRequest && aMetadata.mBlockwiseReceiveHook != nullptr)
{
error = SendNextBlock2Request(aRequest, aRxMsg, aMetadata, totalTransferSize, false);
}
if (aRxMsg.mMessage.GetCode() >= kCodeBadRequest || aMetadata.mBlockwiseReceiveHook == nullptr ||
error != kErrorNone)
if (aRxMsg.GetCode() >= kCodeBadRequest || aMetadata.mBlockwiseReceiveHook == nullptr || error != kErrorNone)
{
FinalizeCoapTransaction(aRequest, aMetadata, &aRxMsg, error);
}
break;
case 3: // Block1 & Block2 option
if (aRxMsg.mMessage.GetCode() < kCodeBadRequest && aMetadata.mBlockwiseReceiveHook != nullptr)
if (aRxMsg.GetCode() < kCodeBadRequest && aMetadata.mBlockwiseReceiveHook != nullptr)
{
error = SendNextBlock2Request(aRequest, aRxMsg, aMetadata, totalTransferSize, true);
}
@@ -1162,12 +1234,12 @@ Error CoapBase::PrepareNextBlockRequest(uint16_t aBlockOptionNumber,
Message &aRequest,
const BlockInfo &aBlockInfo)
{
Error error = kErrorNone;
Error error;
bool isOptionSet = false;
Option::Iterator iterator;
Metadata metadata;
aRequest.Init(kTypeConfirmable, static_cast<ot::Coap::Code>(aRequestOld.GetCode()));
SuccessOrExit(error = aRequest.Init(kTypeConfirmable, static_cast<ot::Coap::Code>(aRequestOld.ReadCode())));
metadata.ReadFrom(aRequestOld);
metadata.RemoveFrom(aRequestOld);
@@ -1253,7 +1325,7 @@ Error CoapBase::SendNextBlock1Request(Message &aRequest, Msg &aRxMsg, const Meta
SuccessOrExit(error = PrepareNextBlockRequest(kOptionBlock1, aRequest, *request, requestBlockInfo));
SuccessOrExit(error = request->SetPayloadMarker());
SuccessOrExit(error = request->AppendPayloadMarker());
SuccessOrExit(error = request->AppendBytes(buf, blockSize));
@@ -1352,8 +1424,7 @@ Error CoapBase::ProcessBlock1Request(Msg &aRxMsg, const ResourceBlockWise &aReso
{
// Set up next response
VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorFailed);
response->Init(kTypeAck, kCodeContinue);
response->SetMessageId(aRxMsg.mMessage.GetMessageId());
SuccessOrExit(error = response->Init(kTypeAck, kCodeContinue, aRxMsg.GetMessageId()));
SuccessOrExit(error = response->WriteTokenFromMessage(aRxMsg.mMessage));
SuccessOrExit(error = response->AppendBlockOption(kOptionBlock1, msgBlockInfo));
@@ -1405,9 +1476,8 @@ Error CoapBase::ProcessBlock2Request(Msg &aRxMsg, const ResourceBlockWise &aReso
}
VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorNoBufs);
response->Init(kTypeAck, kCodeContent);
response->SetMessageId(aRxMsg.mMessage.GetMessageId());
SuccessOrExit(error = response->Init(kTypeAck, kCodeContent, aRxMsg.GetMessageId()));
SuccessOrExit(error = response->WriteTokenFromMessage(aRxMsg.mMessage));
responseBlockInfo.mMoreBlocks = false;
@@ -1448,7 +1518,7 @@ Error CoapBase::ProcessBlock2Request(Msg &aRxMsg, const ResourceBlockWise &aReso
SuccessOrExit(error = iterator.Advance());
}
SuccessOrExit(error = response->SetPayloadMarker());
SuccessOrExit(error = response->AppendPayloadMarker());
SuccessOrExit(error = response->AppendBytes(buf, blockSize));
if (responseBlockInfo.mMoreBlocks)
@@ -1512,7 +1582,7 @@ Error CoapBase::ProcessObserveSend(Msg &aTxMsg, bool &aShouldObserve)
// Special case, if we're sending a GET with Observe=1, that is a
// cancellation.
if (aShouldObserve && aTxMsg.mMessage.IsGetRequest())
if (aShouldObserve && aTxMsg.IsGetRequest())
{
uint64_t value = 0;
@@ -1540,12 +1610,12 @@ exit:
return error;
}
bool CoapBase::IsObserveSubscription(const Message &aMessage, const Metadata &aMetadata)
bool CoapBase::IsObserveSubscription(const Metadata &aMetadata)
{
// Indicate whether the message is an RFC7641 subscription which
// is already acknowledged.
return aMessage.IsRequest() && aMetadata.mObserve && aMetadata.mAcknowledged;
return aMetadata.mIsRequest && aMetadata.mObserve && aMetadata.mAcknowledged;
}
#endif // OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
@@ -1588,8 +1658,6 @@ Error CoapBase::ResponseCache::SendCachedResponse(const Msg &aRxMsg, CoapBase &a
response = match->Clone(match->GetLength() - sizeof(ResponseMetadata));
VerifyOrExit(response != nullptr, error = kErrorNoBufs);
response->Finish();
error = aCoapBase.Send(*response, aRxMsg.mMessageInfo);
exit:
@@ -1600,11 +1668,11 @@ exit:
const Message *CoapBase::ResponseCache::FindMatching(const Msg &aRxMsg) const
{
const Message *match = nullptr;
uint16_t requestMsgId = aRxMsg.mMessage.GetMessageId();
uint16_t requestMsgId = aRxMsg.GetMessageId();
for (const Message &response : mResponses)
{
if (response.GetMessageId() == requestMsgId)
if (response.ReadMessageId() == requestMsgId)
{
ResponseMetadata metadata;
@@ -1745,7 +1813,7 @@ const TxParameters &TxParameters::GetDefault(void)
return AsCoreType(&kDefaultTxParameters);
}
Error TxParameters::ValidateFor(const Message &aMessage) const
Error TxParameters::ValidateFor(const Msg &aMsg) const
{
Error error = kErrorInvalidArgs;
uint32_t duration;
@@ -1754,7 +1822,7 @@ Error TxParameters::ValidateFor(const Message &aMessage) const
if (mAckTimeout == 0)
{
// Fire and forget is only allowed for non-confirmable messages.
VerifyOrExit(aMessage.IsNonConfirmable());
VerifyOrExit(aMsg.IsNonConfirmable());
error = kErrorNone;
ExitNow();
}
+34 -18
View File
@@ -55,6 +55,8 @@
namespace ot {
class UnitTester;
namespace Coap {
/**
@@ -63,6 +65,7 @@ namespace Coap {
* @{
*/
class Msg;
class CoapBase;
/**
@@ -112,7 +115,7 @@ private:
static constexpr uint8_t kMaxRetransmit = OT_COAP_MAX_RETRANSMIT;
static constexpr uint32_t kMinAckTimeout = OT_COAP_MIN_ACK_TIMEOUT;
Error ValidateFor(const Message &aMessage) const;
Error ValidateFor(const Msg &aMsg) const;
uint32_t CalculateInitialRetransmissionTimeout(void) const;
uint32_t CalculateExchangeLifetime(void) const;
uint32_t CalculateMaxTransmitWait(void) const;
@@ -122,11 +125,12 @@ private:
};
/**
* Represents a CoAP message and its associated `Ip6::MessageInfo`.
* Represents a CoAP message and its associated `Ip6::MessageInfo` along with parse CoAP Header information.
*/
class Msg
class Msg : public HeaderInfo
{
friend class CoapBase;
friend class ot::UnitTester;
public:
Message &mMessage; ///< The CoAP message.
@@ -138,6 +142,17 @@ private:
, mMessageInfo(aMessageInfo)
{
}
enum PayloadMarkerMode : uint8_t
{
kRejectIfNoPayloadWithPayloadMarker,
kRemovePayloadMarkerIfNoPayload,
};
Error ParseHeaderAndOptions(PayloadMarkerMode aPayloadMarkerMode);
uint16_t GetHeaderSize(void) const;
void UpdateType(Type aType);
void UpdateMessageId(uint16_t aMessageId);
};
/**
@@ -342,9 +357,9 @@ public:
* Allocates and initializes a new CoAP Confirmable Post message with Network Control priority level.
*
* The CoAP header is initialized as `kTypeConfirmable` and `kCodePost` with a given URI path and a randomly
* generated token (of default length). This method also sets the payload marker (`SetPayloadMarker()` on message.
* Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and
* remove the payload marker when there is no payload.
* generated token (of default length). This method also sets the payload marker (`AppendPayloadMarker()` on
* message. Even if message has no payload, calling `AppendPayloadMarker()` is harmless, since `SendMessage()` will
* check and remove the payload marker when there is no payload.
*
* @param[in] aUri The URI.
*
@@ -356,8 +371,8 @@ public:
* Allocates and initializes a new CoAP Confirmable Post message with normal priority level.
*
* The CoAP header is initialized as `kTypeConfirmable` and `kCodePost` with a given URI and a randomly
* generated token (of default length). This method also sets the payload marker (calling `SetPayloadMarker()`).
* Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and
* generated token (of default length). This method also sets the payload marker (calling `AppendPayloadMarker()`).
* Even if message has no payload, calling `AppendPayloadMarker()` is harmless, since `SendMessage()` will check and
* remove the payload marker when there is no payload.
*
* @param[in] aUri The URI.
@@ -371,8 +386,8 @@ public:
* level.
*
* The CoAP header is initialized as `kTypeNonConfirmable` and `kCodePost` with a given URI and a randomly
* generated token (of default length). This method also sets the payload marker (calling `SetPayloadMarker()`).
* Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and
* generated token (of default length). This method also sets the payload marker (calling `AppendPayloadMarker()`).
* Even if message has no payload, calling `AppendPayloadMarker()` is harmless, since `SendMessage()` will check and
* remove the payload marker when there is no payload.
*
* @param[in] aUri The URI.
@@ -385,8 +400,8 @@ public:
* Allocates and initializes a new CoAP Non-confirmable Post message with normal priority level.
*
* The CoAP header is initialized as `kTypeNonConfirmable` and `kCodePost` with a given URI and a randomly
* generated token (of default length). This method also sets the payload marker (calling `SetPayloadMarker()`).
* Even if message has no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and
* generated token (of default length). This method also sets the payload marker (calling `AppendPayloadMarker()`).
* Even if message has no payload, calling `AppendPayloadMarker()` is harmless, since `SendMessage()` will check and
* remove the payload marker when there is no payload.
*
* @param[in] aUri The URI.
@@ -400,8 +415,8 @@ public:
* given request message.
*
* The CoAP header is initialized as `kTypeAck` with `kCodeChanged`. The token and message ID is copied from
* @p aRequest. This method also sets the payload marker (calling `SetPayloadMarker()`). Even if message has
* no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and remove the payload
* @p aRequest. This method also sets the payload marker (calling `AppendPayloadMarker()`). Even if message has
* no payload, calling `AppendPayloadMarker()` is harmless, since `SendMessage()` will check and remove the payload
* marker when there is no payload.
*
* @returns A pointer to the message or `nullptr` if failed to allocate message.
@@ -413,8 +428,8 @@ public:
* request message.
*
* The CoAP header is initialized as `kTypeAck` with `kCodeChanged`. The token and message ID is copied from
* @p aRequest. This method also sets the payload marker (calling `SetPayloadMarker()`). Even if message has
* no payload, calling `SetPayloadMarker()` is harmless, since `SendMessage()` will check and remove the payload
* @p aRequest. This method also sets the payload marker (calling `AppendPayloadMarker()`). Even if message has
* no payload, calling `AppendPayloadMarker()` is harmless, since `SendMessage()` will check and remove the payload
* marker when there is no payload.
*
* @returns A pointer to the message or `nullptr` if failed to allocate message.
@@ -754,6 +769,7 @@ private:
#endif
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
bool mObserve : 1; // Information that this request involves Observations.
bool mIsRequest : 1;
#endif
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
BlockwiseReceiveHook mBlockwiseReceiveHook; // Function pointer called on Block2 response reception.
@@ -810,7 +826,7 @@ private:
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
Error ProcessBlockwiseSend(Message &aMessage, BlockwiseTransmitHook aTransmitHook, void *aContext);
Error ProcessBlockwiseSend(Msg &aMsg, BlockwiseTransmitHook aTransmitHook, void *aContext);
Error ProcessBlockwiseResponse(Msg &aRxMsg, Message &aRequest, const Metadata &aMetadata);
Error ProcessBlockwiseRequest(Msg &aRxMsg, Message::UriPathStringBuffer &aUriPath, bool &aDidHandle);
void FreeLastBlockResponse(void);
@@ -835,7 +851,7 @@ private:
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
Error ProcessObserveSend(Msg &aTxMsg, bool &aShouldObserve);
static bool IsObserveSubscription(const Message &aMessage, const Metadata &aMetadata);
static bool IsObserveSubscription(const Metadata &aMetadata);
#endif
MessageQueue mPendingRequests;
+280 -145
View File
@@ -86,31 +86,44 @@ exit:
return error;
}
//---------------------------------------------------------------------------------------------------------------------
// `HeaderInfo`
bool HeaderInfo::IsRequest(void) const { return IsValueInRange<uint8_t>(mCode, kCodeGet, kCodeDelete); }
bool HeaderInfo::IsConfirmablePostRequest(void) const { return IsConfirmable() && IsPostRequest(); }
bool HeaderInfo::IsNonConfirmablePostRequest(void) const { return IsNonConfirmable() && IsPostRequest(); }
//---------------------------------------------------------------------------------------------------------------------
// `Message`
void Message::Init(void)
Error Message::Init(Type aType, Code aCode) { return Init(aType, aCode, 0); }
Error Message::Init(Type aType, Code aCode, uint16_t aMessageId)
{
GetHelpData().Clear();
SetVersion(Header::kVersion1);
Header header;
// Erase any previously written content in the message.
IgnoreError(SetLength(0));
SetOffset(0);
GetHelpData().mHeaderLength = kMinHeaderLength;
SetHeaderOffset(0);
IgnoreError(SetLength(GetHelpData().mHeaderLength));
}
header.Clear();
header.SetVersion(Header::kVersion1);
header.SetType(aType);
header.SetCode(aCode);
header.SetMessageId(aMessageId);
void Message::Init(Type aType, Code aCode)
{
Init();
SetType(aType);
SetCode(aCode);
return Append(header);
}
Error Message::Init(Type aType, Code aCode, Uri aUri)
{
Error error;
Init(aType, aCode);
SuccessOrExit(error = Init(aType, aCode));
SuccessOrExit(error = WriteRandomToken(Token::kDefaultLength));
SuccessOrExit(error = AppendUriPathOptions(PathForUri(aUri)));
@@ -123,23 +136,120 @@ Error Message::InitAsPost(const Ip6::Address &aDestination, Uri aUri)
return Init(aDestination.IsMulticast() ? kTypeNonConfirmable : kTypeConfirmable, kCodePost, aUri);
}
bool Message::IsConfirmablePostRequest(void) const { return IsConfirmable() && IsPostRequest(); }
bool Message::IsNonConfirmablePostRequest(void) const { return IsNonConfirmable() && IsPostRequest(); }
void Message::Finish(void)
Error Message::InitAsResponse(Type aType, Code aCode, const Message &aRequest)
{
// If the payload marker is set but the message contains no
// payload, we remove the payload marker from the message. Note
// that the presence of a marker followed by a zero-length payload
// will be processed as a message format error on the receiver.
Error error;
if (GetHelpData().mPayloadMarkerSet && (GetHelpData().mHeaderLength == GetLength()))
{
RemoveFooter(sizeof(uint8_t));
}
SuccessOrExit(error = Init(aType, aCode, aRequest.ReadMessageId()));
error = WriteTokenFromMessage(aRequest);
WriteBytes(0, &GetHelpData().mHeader, GetOptionStart());
exit:
return error;
}
Error Message::ReadHeader(Header &aHeader) const
{
Error error;
SuccessOrExit(error = Read(GetHeaderOffset(), aHeader));
VerifyOrExit(aHeader.GetVersion() == Header::kVersion1, error = kErrorParse);
VerifyOrExit(aHeader.GetTokenLength() <= Token::kMaxLength, error = kErrorParse);
exit:
return error;
}
void Message::WriteHeader(const Header &aHeader) { Write(GetHeaderOffset(), aHeader); }
Error Message::ParseHeaderInfo(HeaderInfo &aInfo) const
{
Error error;
Header header;
aInfo.Clear();
SuccessOrExit(error = ReadHeader(header));
aInfo.mType = header.GetType();
aInfo.mCode = header.GetCode();
aInfo.mMessageId = header.GetMessageId();
error = ReadToken(header, aInfo.mToken);
exit:
return error;
}
uint8_t Message::ReadType(void) const
{
uint8_t type = 0;
Header header;
SuccessOrExit(ReadHeader(header));
type = header.GetType();
exit:
return type;
}
void Message::WriteType(Type aType)
{
Header header;
SuccessOrExit(ReadHeader(header));
header.SetType(aType);
WriteHeader(header);
exit:
return;
}
uint8_t Message::ReadCode(void) const
{
uint8_t code = 0;
Header header;
SuccessOrExit(ReadHeader(header));
code = header.GetCode();
exit:
return code;
}
void Message::WriteCode(Code aCode)
{
Header header;
SuccessOrExit(ReadHeader(header));
header.SetCode(aCode);
WriteHeader(header);
exit:
return;
}
uint16_t Message::ReadMessageId(void) const
{
uint16_t messageId = 0;
Header header;
SuccessOrExit(ReadHeader(header));
messageId = header.GetMessageId();
exit:
return messageId;
}
void Message::WriteMessageId(uint16_t aMessageId)
{
Header header;
SuccessOrExit(ReadHeader(header));
header.SetMessageId(aMessageId);
WriteHeader(header);
exit:
return;
}
uint8_t Message::WriteExtendedOptionField(uint16_t aValue, uint8_t *&aBuffer)
@@ -186,18 +296,34 @@ uint8_t Message::WriteExtendedOptionField(uint16_t aValue, uint8_t *&aBuffer)
Error Message::AppendOptionHeader(uint16_t aNumber, uint16_t aLength)
{
/*
* Appends a CoAP Option header field (Option Delta/Length) per RFC 7252.
*/
// Appends a CoAP Option header field (Option Delta/Length) per RFC 7252.
Error error = kErrorNone;
uint16_t delta;
uint8_t header[kMaxOptionHeaderSize];
uint16_t headerLength;
uint8_t *cur;
Error error;
Option::Iterator iterator;
uint16_t lastNumber;
uint16_t delta;
uint8_t header[kMaxOptionHeaderSize];
uint16_t headerLength;
uint8_t *cur;
VerifyOrExit(aNumber >= GetHelpData().mOptionLast, error = kErrorInvalidArgs);
delta = aNumber - GetHelpData().mOptionLast;
// Parses the already appended options in the message
// to determine the last option number. Also ensures
// that "payload marker" is not appended.
SuccessOrExit(error = iterator.Init(*this));
lastNumber = 0;
while (!iterator.IsDone())
{
lastNumber = iterator.GetOption()->GetNumber();
SuccessOrExit(error = iterator.Advance());
}
VerifyOrExit(!iterator.HasPayloadMarker(), error = kErrorParse);
VerifyOrExit(aNumber >= lastNumber, error = kErrorInvalidArgs);
delta = aNumber - lastNumber;
cur = &header[1];
@@ -206,12 +332,8 @@ Error Message::AppendOptionHeader(uint16_t aNumber, uint16_t aLength)
headerLength = static_cast<uint16_t>(cur - header);
VerifyOrExit(static_cast<uint32_t>(GetLength()) + headerLength + aLength < kMaxHeaderLength, error = kErrorNoBufs);
SuccessOrExit(error = AppendBytes(header, headerLength));
GetHelpData().mOptionLast = aNumber;
exit:
return error;
}
@@ -223,8 +345,6 @@ Error Message::AppendOption(uint16_t aNumber, uint16_t aLength, const void *aVal
SuccessOrExit(error = AppendOptionHeader(aNumber, aLength));
SuccessOrExit(error = AppendBytes(aValue, aLength));
GetHelpData().mHeaderLength = GetLength();
exit:
return error;
}
@@ -236,8 +356,6 @@ Error Message::AppendOptionFromMessage(uint16_t aNumber, uint16_t aLength, const
SuccessOrExit(error = AppendOptionHeader(aNumber, aLength));
SuccessOrExit(error = AppendBytesFromMessage(aMessage, aOffset, aLength));
GetHelpData().mHeaderLength = GetLength();
exit:
return error;
}
@@ -407,38 +525,12 @@ exit:
#endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
Error Message::SetPayloadMarker(void)
Error Message::AppendPayloadMarker(void)
{
Error error = kErrorNone;
uint8_t marker = kPayloadMarker;
VerifyOrExit(GetLength() < kMaxHeaderLength, error = kErrorNoBufs);
SuccessOrExit(error = Append(marker));
GetHelpData().mPayloadMarkerSet = true;
GetHelpData().mHeaderLength = GetLength();
// Set offset to the start of payload.
SetOffset(GetHelpData().mHeaderLength);
exit:
return error;
}
Error Message::ParseHeader(void)
{
Error error = kErrorNone;
uint16_t offset = GetOffset();
Error error;
uint8_t marker = kPayloadMarker;
Option::Iterator iterator;
OT_ASSERT(GetReserved() >=
sizeof(HelpData) + static_cast<size_t>((reinterpret_cast<uint8_t *>(&GetHelpData()) - GetFirstData())));
GetHelpData().Clear();
GetHelpData().mHeaderOffset = offset;
SuccessOrExit(error = GetHelpData().mHeader.ParseFrom(*this));
SuccessOrExit(error = iterator.Init(*this));
while (!iterator.IsDone())
@@ -446,8 +538,51 @@ Error Message::ParseHeader(void)
SuccessOrExit(error = iterator.Advance());
}
GetHelpData().mHeaderLength = iterator.GetPayloadMessageOffset() - GetHelpData().mHeaderOffset;
MoveOffset(GetHelpData().mHeaderLength);
VerifyOrExit(!iterator.HasPayloadMarker());
SuccessOrExit(error = Append(marker));
SetOffset(GetLength());
exit:
return error;
}
uint16_t Message::DetermineTokenOffset(void) const
{
uint16_t offset;
if (CanAddSafely<uint16_t>(GetHeaderOffset(), sizeof(Header)))
{
offset = GetHeaderOffset() + sizeof(Header);
}
else
{
SetToUintMax(offset);
}
return offset;
}
Error Message::DetermineOptionStartOffset(uint16_t &aOffset) const
{
Error error;
uint8_t tokenLength;
uint16_t offset;
SuccessOrExit(error = ReadTokenLength(tokenLength));
offset = DetermineTokenOffset();
if (CanAddSafely<uint16_t>(offset, tokenLength))
{
offset += tokenLength;
}
else
{
SetToUintMax(offset);
}
aOffset = offset;
exit:
return error;
@@ -455,10 +590,11 @@ exit:
Error Message::ReadTokenLength(uint8_t &aLength) const
{
Error error = kErrorNone;
Error error = kErrorNone;
Header header;
VerifyOrExit(GetHelpData().mHeader.IsValid(), error = kErrorParse);
aLength = GetHelpData().mHeader.GetTokenLength();
SuccessOrExit(error = ReadHeader(header));
aLength = header.GetTokenLength();
exit:
return error;
@@ -466,16 +602,51 @@ exit:
Error Message::ReadToken(Token &aToken) const
{
return aToken.SetToken(GetHelpData().mHeader.GetToken(), GetHelpData().mHeader.GetTokenLength());
Error error;
Header header;
SuccessOrExit(error = ReadHeader(header));
error = ReadToken(header, aToken);
exit:
return error;
}
Error Message::ReadToken(const Header &aHeader, Token &aToken) const
{
aToken.mLength = aHeader.GetTokenLength();
return Read(DetermineTokenOffset(), aToken.m8, aToken.mLength);
}
Error Message::WriteToken(const Token &aToken)
{
Error error;
Error error;
Header header;
uint16_t tokenOffset = DetermineTokenOffset();
SuccessOrExit(error = GetHelpData().mHeader.SetToken(aToken));
GetHelpData().mHeaderLength += aToken.GetLength();
error = SetLength(GetHelpData().mHeaderLength);
VerifyOrExit(aToken.IsValid(), error = kErrorInvalidArgs);
SuccessOrExit(error = ReadHeader(header));
if (tokenOffset == GetLength())
{
// A token has not been written yet, so grow the message to make
// space for it.
SuccessOrExit(error = IncreaseLength(aToken.GetLength()));
header.SetTokenLength(aToken.GetLength());
WriteHeader(header);
}
else
{
// If a token was previously written, we only allow it to be
// overwritten by a new token of the same length.
VerifyOrExit(header.GetTokenLength() == aToken.GetLength(), error = kErrorInvalidArgs);
}
WriteBytes(tokenOffset, aToken.GetBytes(), aToken.GetLength());
exit:
return error;
@@ -519,22 +690,13 @@ exit:
return hasSame;
}
Error Message::SetDefaultResponseHeader(const Message &aRequest)
{
Init(kTypeAck, kCodeChanged);
SetMessageId(aRequest.GetMessageId());
return WriteTokenFromMessage(aRequest);
}
Message *Message::Clone(uint16_t aLength) const
{
Message *message = static_cast<Message *>(ot::Message::Clone(aLength));
VerifyOrExit(message != nullptr);
message->GetHelpData() = GetHelpData();
message->SetHeaderOffset(GetHeaderOffset());
exit:
return message;
@@ -576,45 +738,10 @@ const char *Message::CodeToString(void) const
static_assert(Stringify::IsSorted(kCodeTable), "kCodeTable is not sorted");
return Stringify::Lookup(GetCode(), kCodeTable, "Unknown");
return Stringify::Lookup(ReadCode(), kCodeTable, "Unknown");
}
#endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
//---------------------------------------------------------------------------------------------------------------------
// `Message::Header`
bool Message::Header::IsValid(void) const
{
return (GetVersion() == kVersion1) && (GetTokenLength() <= Token::kMaxLength);
}
Error Message::Header::ParseFrom(const Message &aMessage)
{
Error error;
uint16_t offset = aMessage.GetOffset();
SuccessOrExit(error = aMessage.Read(offset, this, kMinSize));
VerifyOrExit(IsValid(), error = kErrorParse);
SuccessOrExit(error = aMessage.Read(offset + kMinSize, mToken, GetTokenLength()));
exit:
return error;
}
Error Message::Header::SetToken(const Token &aToken)
{
Error error = kErrorNone;
VerifyOrExit(aToken.IsValid(), error = kErrorInvalidArgs);
SetTokenLength(aToken.mLength);
memcpy(mToken, aToken.GetBytes(), aToken.GetLength());
exit:
return error;
}
//---------------------------------------------------------------------------------------------------------------------
// `Message::Iterator`
@@ -627,23 +754,30 @@ Message::ConstIterator MessageQueue::begin(void) const { return Message::ConstIt
Error Option::Iterator::Init(const Message &aMessage)
{
Error error = kErrorParse;
uint32_t offset = static_cast<uint32_t>(aMessage.GetHelpData().mHeaderOffset) + aMessage.GetOptionStart();
Error error;
uint16_t offset;
SuccessOrExit(error = aMessage.DetermineOptionStartOffset(offset));
// Note that the case where `offset == aMessage.GetLength())` is
// valid and indicates an empty payload (no CoAP Option and no
// Payload Marker).
VerifyOrExit(offset <= aMessage.GetLength(), MarkAsParseErrored());
VerifyOrExit(offset <= aMessage.GetLength(), error = kErrorParse);
mOption.mNumber = 0;
mOption.mLength = 0;
mMessage = &aMessage;
mNextOptionOffset = static_cast<uint16_t>(offset);
mNextOptionOffset = offset;
error = Advance();
exit:
if (error != kErrorNone)
{
MarkAsDone();
}
return error;
}
@@ -658,22 +792,23 @@ Error Option::Iterator::Advance(void)
error = Read(sizeof(uint8_t), &headerByte);
if ((error != kErrorNone) || (headerByte == Message::kPayloadMarker))
if (error != kErrorNone)
{
// Reached the end without seeing the payload marker.
MarkAsDone();
SetHasPayloadMarker(false);
ExitNow(error = kErrorNone);
}
if (headerByte == Message::kPayloadMarker)
{
// Payload Marker indicates end of options and start of payload.
// Absence of a Payload Marker indicates a zero-length payload.
MarkAsDone();
if (error == kErrorNone)
{
// The presence of a marker followed by a zero-length payload
// MUST be processed as a message format error.
VerifyOrExit(mNextOptionOffset < GetMessage().GetLength(), error = kErrorParse);
}
ExitNow(error = kErrorNone);
SetHasPayloadMarker(true);
ExitNow();
}
optionDelta = (headerByte & Message::kOptionDeltaMask) >> Message::kOptionDeltaOffset;
@@ -691,7 +826,7 @@ Error Option::Iterator::Advance(void)
exit:
if (error != kErrorNone)
{
MarkAsParseErrored();
MarkAsDone();
}
return error;
+284 -283
View File
@@ -69,8 +69,10 @@ namespace Coap {
* @{
*/
class Msg;
class Message;
class Option;
class CoapBase;
/**
* CoAP Type values.
@@ -263,18 +265,177 @@ private:
Error GenerateRandom(uint8_t aLength);
};
/**
* Represents information from a parsed CoAP Header in a CoAP message.
*/
class HeaderInfo : public Clearable<HeaderInfo>
{
friend class Message;
friend class Msg;
public:
/**
* Returns the Type value.
*
* @returns The Type value.
*/
uint8_t GetType(void) const { return mType; }
/**
* Returns the Code value.
*
* @returns The Code value.
*/
uint8_t GetCode(void) const { return mCode; }
/**
* Returns the Message ID value.
*
* @returns The Message ID value.
*/
uint16_t GetMessageId(void) const { return mMessageId; }
/**
* Returns the Token.
*
* @returns The Token.
*/
const Token &GetToken(void) const { return mToken; }
/**
* Checks if a header is an empty message header (`kCodeEmpty`).
*
* @retval TRUE Message is an empty message header.
* @retval FALSE Message is not an empty message header.
*/
bool IsEmpty(void) const { return (mCode == kCodeEmpty); }
/**
* Checks if a header is a request header.
*
* @retval TRUE Message is a request header.
* @retval FALSE Message is not a request header.
*/
bool IsRequest(void) const;
/**
* Indicates whether or not the CoAP code in header is "Get" request.
*
* @retval TRUE Message is a Get request.
* @retval FALSE Message is not a Get request.
*/
bool IsGetRequest(void) const { return (mCode == kCodeGet); }
/**
* Indicates whether or not the CoAP code in header is "Post" request.
*
* @retval TRUE Message is a Post request.
* @retval FALSE Message is not a Post request.
*/
bool IsPostRequest(void) const { return (mCode == kCodePost); }
/**
* Indicates whether or not the CoAP code in header is "Put" request.
*
* @retval TRUE Message is a Put request.
* @retval FALSE Message is not a Put request.
*/
bool IsPutRequest(void) const { return (mCode == kCodePut); }
/**
* Indicates whether or not the CoAP code in header is "Delete" request.
*
* @retval TRUE Message is a Delete request.
* @retval FALSE Message is not a Delete request.
*/
bool IsDeleteRequest(void) const { return (mCode == kCodeDelete); }
/**
* Checks if a header is a response header.
*
* @retval TRUE Message is a response header.
* @retval FALSE Message is not a response header.
*/
bool IsResponse(void) const { return mCode >= kCodeResponseMin; }
/**
* Checks if a header is a CON message header.
*
* @retval TRUE Message is a CON message header.
* @retval FALSE Message is not is a CON message header.
*/
bool IsConfirmable(void) const { return (GetType() == kTypeConfirmable); }
/**
* Checks if a header is a NON message header.
*
* @retval TRUE Message is a NON message header.
* @retval FALSE Message is not is a NON message header.
*/
bool IsNonConfirmable(void) const { return (mType == kTypeNonConfirmable); }
/**
* Checks if a header is a ACK message header.
*
* @retval TRUE Message is a ACK message header.
* @retval FALSE Message is not is a ACK message header.
*/
bool IsAck(void) const { return (mType == kTypeAck); }
/**
* Checks if a header is a RST message header.
*
* @retval TRUE Message is a RST message header.
* @retval FALSE Message is not is a RST message header.
*/
bool IsReset(void) const { return (mType == kTypeReset); }
/**
* Indicates whether or not the header is a confirmable Post request (`kTypeConfirmable` with`kCodePost`).
*
* @retval TRUE Message is a confirmable Post request.
* @retval FALSE Message is not a confirmable Post request.
*/
bool IsConfirmablePostRequest(void) const;
/**
* Indicates whether the message is a non-confirmable Post request (`kTypeNonConfirmable` with `kCodePost`).
*
* @retval TRUE Message is a non-confirmable Post request.
* @retval FALSE Message is not a non-confirmable Post request.
*/
bool IsNonConfirmablePostRequest(void) const;
/**
* Checks if the message requires a reset response if an error during low level CoAP processing occurred.
*
* A reset message is expected to be sent for NON and CON messages if the message can not be processed or a
* duplicated message has been received.
*
* @retval TRUE Expect to respond with CoAP reset message on error.
* @retval FALSE No CoAP reset message should be sent on error.
*/
bool RequireResetOnError(void) { return IsConfirmable() || IsNonConfirmable(); }
private:
uint8_t mType;
uint8_t mCode;
uint16_t mMessageId;
Token mToken;
};
/**
* Implements CoAP message generation and parsing.
*/
class Message : public ot::Message
{
friend class Msg;
friend class Option;
friend class MessageQueue;
friend class CoapBase;
public:
static constexpr uint8_t kDefaultTokenLength = OT_COAP_DEFAULT_TOKEN_LENGTH; ///< Default token length.
static constexpr uint8_t kMaxReceivedUriPath = 32; ///< Max URI path length on rx msgs.
static constexpr uint8_t kMaxTokenLength = OT_COAP_MAX_TOKEN_LENGTH; ///< Maximum token length.
static constexpr uint8_t kMaxReceivedUriPath = 32; ///< Max URI path length on rx msgs.
typedef ot::Coap::Type Type; ///< CoAP Type.
typedef ot::Coap::Code Code; ///< CoAP Code.
@@ -282,91 +443,121 @@ public:
typedef char UriPathStringBuffer[kMaxReceivedUriPath + 1]; ///< Buffer to store a received URI Path string.
/**
* Initializes the CoAP header.
* Initializes the CoAP message with a given Type and Code.
*
* This method erases any previously written content in the message. The Message ID is set to zero, and the token
* is empty (zero-length).
*
* @param[in] aType The CoAP Type value.
* @param[in] aCode The CoAP Code value.
*
* @retval kErrorNone Successfully initialized the message.
* @retval kErrorNoBufs Could not grow the message to write the CoAP header.
*/
void Init(void);
Error Init(Type aType, Code aCode);
/**
* Initializes the CoAP header with specific Type and Code.
* Initializes the CoAP message with a given Type, Code, and Message ID.
*
* @param[in] aType The Type value.
* @param[in] aCode The Code value.
* This method erases any previously written content in the message. The token is empty (zero-length).
*
* @param[in] aType The CoAP Type value.
* @param[in] aCode The CoAP Code value.
* @param[in] aMessageId The CoAP Message ID value.
*
* @retval kErrorNone Successfully initialized the message.
* @retval kErrorNoBufs Could not grow the message to write the CoAP header.
*/
void Init(Type aType, Code aCode);
Error Init(Type aType, Code aCode, uint16_t aMessageId);
/**
* Initializes the CoAP header with specific Type and Code.
* Initializes the message with a Type, Code, adds a random token, and appends a URI-path option.
*
* @param[in] aType The Type value.
* @param[in] aCode The Code value.
* @param[in] aUri The URI.
* This method erases any previously written content in the message. The Message ID is set to zero. A random token
* of default length (`Token::kDefaultLength`) is generated and added to the message.
*
* @retval kErrorNone Successfully appended the option.
* @retval kErrorNoBufs The option length exceeds the buffer size.
* @param[in] aType The CoAP Type value.
* @param[in] aCode The CoAP Code value.
* @param[in] aUri The URI string.
*
* @retval kErrorNone Successfully initialized the message and appended the URI-path option.
* @retval kErrorNoBufs Could not grow the message to append the option.
*/
Error Init(Type aType, Code aCode, Uri aUri);
/**
* Initializes the CoAP header as `kCodePost` with a given URI Path with its type determined from a
* given destination IPv6 address.
* Initializes a CoAP POST message, appends a URI Path, and adds a random token.
*
* @param[in] aDestination The message destination IPv6 address used to determine the CoAP type,
* `kTypeNonConfirmable` if multicast address, `kTypeConfirmable` otherwise.
* @param[in] aUri The URI.
* This method erases any previously written content in the message.
*
* @retval kErrorNone Successfully appended the option.
* @retval kErrorNoBufs The option length exceeds the buffer size.
* The CoAP Type is determined from the destination IPv6 address: `kTypeNonConfirmable` for multicast and
* `kTypeConfirmable` otherwise. The Message ID is set to zero. A random token of default length
* (`Token::kDefaultLength`) is generated and added.
*
* @param[in] aDestination The message destination IPv6 address, used to determine the CoAP Type.
* @param[in] aUri The URI string.
*
* @retval kErrorNone Successfully initialized the message and appended the URI-path option.
* @retval kErrorNoBufs Could not grow the message to append the option.
*/
Error InitAsPost(const Ip6::Address &aDestination, Uri aUri);
/**
* Writes header to the message. This must be called before sending the message.
* Initializes a CoAP message as a response to a request message.
*
* Also checks whether the payload marker is set (`SetPayloadMarker()`) but the message contains no
* payload, and if so it removes the payload marker from the message.
* This method erases any previously written content in the message. The Message ID and Token are copied from the
* request message.
*
* @param[in] aType The CoAP Type value.
* @param[in] aCode The CoAP Code value.
* @param[in] aRequest The request message to respond to.
*
* @retval kErrorNone Successfully initialized the message.
* @retval kErrorNoBufs Could not grow the message to write the CoAP header.
*/
void Finish(void);
Error InitAsResponse(Type aType, Code aCode, const Message &aRequest);
/**
* Returns the Version value.
* Parses the CoAP header and token.
*
* @returns The Version value.
* @param[out] aInfo A reference to `HeaderInfo` to populate.
*
* @retval kErrorNone Successfully parsed the CoAP header. @p aInfo is updated.
* @retval kErrorParse Failed to parse.
*/
uint8_t GetVersion(void) const { return GetHelpData().mHeader.GetVersion(); }
Error ParseHeaderInfo(HeaderInfo &aInfo) const;
/**
* Sets the Version value.
* Reads the Type value.
*
* @param[in] aVersion The Version value.
* @returns The Type value, or zero if the CoAP header is invalid or cannot be parsed.
*/
void SetVersion(uint8_t aVersion) { GetHelpData().mHeader.SetVersion(aVersion); }
uint8_t ReadType(void) const;
/**
* Returns the Type value.
* Writes the Type value in CoAP header.
*
* @returns The Type value.
*/
uint8_t GetType(void) const { return GetHelpData().mHeader.GetType(); }
/**
* Sets the Type value.
* This method requires that the message contains a valid CoAP header. Otherwise, no change is made.
*
* @param[in] aType The Type value.
*/
void SetType(Type aType) { GetHelpData().mHeader.SetType(aType); }
void WriteType(Type aType);
/**
* Returns the Code value.
* Reads the Code value.
*
* @returns The Code value.
* @returns The Code value, or zero if the CoAP header is invalid or cannot be parsed.
*/
uint8_t GetCode(void) const { return GetHelpData().mHeader.GetCode(); }
uint8_t ReadCode(void) const;
/**
* Sets the Code value.
* Writes the Code value.
*
* This method requires that the message contains a valid CoAP header. Otherwise, no change is made.
*
* @param[in] aCode The Code value.
*/
void SetCode(Code aCode) { GetHelpData().mHeader.SetCode(aCode); }
void WriteCode(Code aCode);
#if OPENTHREAD_CONFIG_COAP_API_ENABLE
/**
@@ -378,18 +569,20 @@ public:
#endif
/**
* Returns the Message ID value.
* Reads the Message ID value.
*
* @returns The Message ID value.
* @returns The Message ID value, or zero if the CoAP header is invalid or cannot be parsed.
*/
uint16_t GetMessageId(void) const { return GetHelpData().mHeader.GetMessageId(); }
uint16_t ReadMessageId(void) const;
/**
* Sets the Message ID value.
* Writes the Message ID value in CoAP header.
*
* This method requires that the message contains a valid CoAP header. Otherwise, no change is made.
*
* @param[in] aMessageId The Message ID value.
*/
void SetMessageId(uint16_t aMessageId) { GetHelpData().mHeader.SetMessageId(aMessageId); }
void WriteMessageId(uint16_t aMessageId);
/**
* Reads the Token length from the message
@@ -623,164 +816,14 @@ public:
Error AppendUriQueryOption(const char *aUriQuery) { return AppendStringOption(kOptionUriQuery, aUriQuery); }
/**
* Reads and reassembles the URI path string and fills it into @p aUriPath.
* Appends a Payload Marker indicating the beginning of the payload.
*
* @retval kErrorNone URI path string has been reassembled.
* @retval kErrorNoBufs URI path string is too long.
* It also sets the offset to the start of the payload.
*
* @retval kErrorNone Payload Marker was successfully added.
* @retval kErrorNoBufs Could not grow the message to append the payload marker.
*/
Error GetUriPath(char *aUriPath) const;
/**
* Adds Payload Marker indicating beginning of the payload to the CoAP header.
*
* It also set offset to the start of payload.
*
* @retval kErrorNone Payload Marker successfully added.
* @retval kErrorNoBufs Message Payload Marker exceeds the buffer size.
*/
Error SetPayloadMarker(void);
/**
* Returns the offset of the first CoAP option.
*
* @returns The offset of the first CoAP option.
*/
uint16_t GetOptionStart(void) const { return kMinHeaderLength + GetHelpData().mHeader.GetTokenLength(); }
/**
* Parses CoAP header and moves offset end of CoAP header.
*
* @retval kErrorNone Successfully parsed CoAP header from the message.
* @retval kErrorParse Failed to parse the CoAP header.
*/
Error ParseHeader(void);
/**
* Sets a default response header based on request header.
*
* @param[in] aRequest The request message.
*
* @retval kErrorNone Successfully set the default response header.
* @retval kErrorNoBufs Insufficient message buffers available to set the default response header.
*/
Error SetDefaultResponseHeader(const Message &aRequest);
/**
* Checks if a header is an empty message header.
*
* @retval TRUE Message is an empty message header.
* @retval FALSE Message is not an empty message header.
*/
bool IsEmpty(void) const { return (GetCode() == kCodeEmpty); }
/**
* Checks if a header is a request header.
*
* @retval TRUE Message is a request header.
* @retval FALSE Message is not a request header.
*/
bool IsRequest(void) const { return (GetCode() >= kCodeGet) && (GetCode() <= kCodeDelete); }
/**
* Indicates whether or not the CoAP code in header is "Get" request.
*
* @retval TRUE Message is a Get request.
* @retval FALSE Message is not a Get request.
*/
bool IsGetRequest(void) const { return GetCode() == kCodeGet; }
/**
* Indicates whether or not the CoAP code in header is "Post" request.
*
* @retval TRUE Message is a Post request.
* @retval FALSE Message is not a Post request.
*/
bool IsPostRequest(void) const { return GetCode() == kCodePost; }
/**
* Indicates whether or not the CoAP code in header is "Put" request.
*
* @retval TRUE Message is a Put request.
* @retval FALSE Message is not a Put request.
*/
bool IsPutRequest(void) const { return GetCode() == kCodePut; }
/**
* Indicates whether or not the CoAP code in header is "Delete" request.
*
* @retval TRUE Message is a Delete request.
* @retval FALSE Message is not a Delete request.
*/
bool IsDeleteRequest(void) const { return GetCode() == kCodeDelete; }
/**
* Checks if a header is a response header.
*
* @retval TRUE Message is a response header.
* @retval FALSE Message is not a response header.
*/
bool IsResponse(void) const { return GetCode() >= OT_COAP_CODE_RESPONSE_MIN; }
/**
* Checks if a header is a CON message header.
*
* @retval TRUE Message is a CON message header.
* @retval FALSE Message is not is a CON message header.
*/
bool IsConfirmable(void) const { return (GetType() == kTypeConfirmable); }
/**
* Checks if a header is a NON message header.
*
* @retval TRUE Message is a NON message header.
* @retval FALSE Message is not is a NON message header.
*/
bool IsNonConfirmable(void) const { return (GetType() == kTypeNonConfirmable); }
/**
* Checks if a header is a ACK message header.
*
* @retval TRUE Message is a ACK message header.
* @retval FALSE Message is not is a ACK message header.
*/
bool IsAck(void) const { return (GetType() == kTypeAck); }
/**
* Checks if a header is a RST message header.
*
* @retval TRUE Message is a RST message header.
* @retval FALSE Message is not is a RST message header.
*/
bool IsReset(void) const { return (GetType() == kTypeReset); }
/**
* Indicates whether or not the header is a confirmable Post request (i.e, `kTypeConfirmable` with
* `kCodePost`).
*
* @retval TRUE Message is a confirmable Post request.
* @retval FALSE Message is not a confirmable Post request.
*/
bool IsConfirmablePostRequest(void) const;
/**
* Indicates whether or not the header is a non-confirmable Post request (i.e, `kTypeNonConfirmable` with
* `kCodePost`).
*
* @retval TRUE Message is a non-confirmable Post request.
* @retval FALSE Message is not a non-confirmable Post request.
*/
bool IsNonConfirmablePostRequest(void) const;
/**
* Checks if the message requires an reset response if an error during low level CoAP processing occurred.
*
* A reset message is expected to be sent for NON and CON messages if the message can not be processed or a
* duplicated message has been received.
*
* @retval TRUE Expect to respond with CoAP reset message on error.
* @retval FALSE No CoAP reset message should be sent on error.
*/
bool RequireResetOnError(void) { return IsConfirmable() || IsNonConfirmable(); }
Error AppendPayloadMarker(void);
/**
* Creates a copy of this CoAP message.
@@ -806,11 +849,6 @@ public:
*/
Message *Clone(void) const { return Clone(GetLength()); }
/**
* Returns the minimal reserved bytes required for CoAP message.
*/
static uint16_t GetHelpDataReserved(void) { return sizeof(HelpData) + kHelpDataAlignment; }
/**
* Returns a pointer to the next message after this as a `Coap::Message`.
*
@@ -862,11 +900,6 @@ private:
static constexpr uint8_t kPayloadMarker = 0xff;
static constexpr uint8_t kHelpDataAlignment = sizeof(uint16_t); // Alignment of help data.
static constexpr uint16_t kMinHeaderLength = 4;
static constexpr uint16_t kMaxHeaderLength = 512;
static constexpr uint16_t kOption1ByteExtensionOffset = 13; // Delta/Length offset as specified (RFC 7252).
static constexpr uint16_t kOption2ByteExtensionOffset = 269; // Delta/Length offset as specified (RFC 7252).
@@ -878,25 +911,21 @@ private:
static constexpr uint32_t kBlockNumMax = 0xffff;
OT_TOOL_PACKED_BEGIN
class Header
class Header : public Clearable<Header>
{
public:
static constexpr uint8_t kVersion1 = 1;
uint8_t GetSize(void) const { return kMinSize + GetTokenLength(); }
bool IsValid(void) const;
Error ParseFrom(const Message &aMessage);
uint8_t GetVersion(void) const { return ReadBits<uint8_t, kVersionMask>(mVersionTypeToken); }
void SetVersion(uint8_t aVersion) { WriteBits<uint8_t, kVersionMask>(mVersionTypeToken, aVersion); }
uint8_t GetType(void) const { return ReadBits<uint8_t, kTypeMask>(mVersionTypeToken); }
void SetType(Type aType) { WriteBits<uint8_t, kTypeMask>(mVersionTypeToken, aType); }
uint8_t GetCode(void) const { return mCode; }
void SetCode(Code aCode) { mCode = aCode; }
uint16_t GetMessageId(void) const { return BigEndian::HostSwap16(mMessageId); }
void SetMessageId(uint16_t aMessageId) { mMessageId = BigEndian::HostSwap16(aMessageId); }
const uint8_t *GetToken(void) const { return mToken; }
uint8_t GetTokenLength(void) const { return ReadBits<uint8_t, kTokenLengthMask>(mVersionTypeToken); }
Error SetToken(const Token &aToken);
uint8_t GetVersion(void) const { return ReadBits<uint8_t, kVersionMask>(mVersionTypeToken); }
void SetVersion(uint8_t aVersion) { WriteBits<uint8_t, kVersionMask>(mVersionTypeToken, aVersion); }
uint8_t GetType(void) const { return ReadBits<uint8_t, kTypeMask>(mVersionTypeToken); }
void SetType(Type aType) { WriteBits<uint8_t, kTypeMask>(mVersionTypeToken, aType); }
uint8_t GetCode(void) const { return mCode; }
void SetCode(Code aCode) { mCode = aCode; }
uint16_t GetMessageId(void) const { return BigEndian::HostSwap16(mMessageId); }
void SetMessageId(uint16_t aMessageId) { mMessageId = BigEndian::HostSwap16(aMessageId); }
uint8_t GetTokenLength(void) const { return ReadBits<uint8_t, kTokenLengthMask>(mVersionTypeToken); }
void SetTokenLength(uint8_t aLength) { WriteBits<uint8_t, kTokenLengthMask>(mVersionTypeToken, aLength); }
private:
/*
@@ -907,31 +936,15 @@ private:
* |Ver| T | TKL | (Version, Type and Token Length).
* +-+-+-+-+-+-+-+-+
*/
static constexpr uint8_t kVersionMask = 0x3 << 6;
static constexpr uint8_t kTypeMask = 0x3 << 4;
static constexpr uint8_t kTokenLengthMask = 0xf << 0;
static constexpr uint16_t kMinSize = 4;
void SetTokenLength(uint8_t aLength) { WriteBits<uint8_t, kTokenLengthMask>(mVersionTypeToken, aLength); }
static constexpr uint8_t kVersionMask = 0x3 << 6;
static constexpr uint8_t kTypeMask = 0x3 << 4;
static constexpr uint8_t kTokenLengthMask = 0xf << 0;
uint8_t mVersionTypeToken; // The CoAP Version, Type, and Token Length
uint8_t mCode;
uint16_t mMessageId;
uint8_t mToken[kMaxTokenLength];
} OT_TOOL_PACKED_END;
/**
* Represents a HelpData used by this CoAP message.
*/
struct HelpData : public Clearable<HelpData>
{
Header mHeader;
uint16_t mOptionLast;
uint16_t mHeaderOffset; ///< The byte offset for the CoAP Header
uint16_t mHeaderLength;
bool mPayloadMarkerSet;
};
class ConstIterator : public ot::Message::ConstIterator
{
public:
@@ -953,23 +966,15 @@ private:
Message *operator->(void) { return static_cast<Message *>(ot::Message::Iterator::operator->()); }
};
static_assert(sizeof(HelpData) <= sizeof(Ip6::Header) + sizeof(Ip6::HopByHopHeader) + sizeof(Ip6::MplOption) +
sizeof(Ip6::Udp::Header),
"HelpData size exceeds the size of the reserved region in the message");
const HelpData &GetHelpData(void) const
{
static_assert(sizeof(HelpData) + kHelpDataAlignment <= kHeadBufferDataSize,
"Insufficient buffer size for CoAP processing! Increase OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE.");
return *static_cast<const HelpData *>(OT_ALIGN(GetFirstData(), kHelpDataAlignment));
}
HelpData &GetHelpData(void) { return AsNonConst(AsConst(this)->GetHelpData()); }
uint8_t WriteExtendedOptionField(uint16_t aValue, uint8_t *&aBuffer);
Error AppendOptionHeader(uint16_t aNumber, uint16_t aLength);
uint16_t GetHeaderOffset(void) const { return GetMeshDest(); }
void SetHeaderOffset(uint16_t aOffset) { SetMeshDest(aOffset); }
uint16_t DetermineTokenOffset(void) const;
Error DetermineOptionStartOffset(uint16_t &aOffset) const;
Error ReadHeader(Header &aHeader) const;
void WriteHeader(const Header &aHeader);
Error ReadToken(const Header &aHeader, Token &aToken) const;
uint8_t WriteExtendedOptionField(uint16_t aValue, uint8_t *&aBuffer);
Error AppendOptionHeader(uint16_t aNumber, uint16_t aLength);
};
/**
@@ -1091,16 +1096,6 @@ public:
*/
bool IsDone(void) const { return mOption.mLength == kIteratorDoneLength; }
/**
* Indicates whether or not there was a earlier parse error (i.e., whether the iterator is valid).
*
* After a parse errors, iterator would also be marked as done.
*
* @retval TRUE There was an earlier parse error and the iterator is not valid.
* @retval FALSE There was no earlier parse error and the iterator is valid.
*/
bool HasParseErrored(void) const { return mNextOptionOffset == kNextOptionOffsetParseError; }
/**
* Advances the iterator to the next CoAP Option in the header.
*
@@ -1164,12 +1159,22 @@ public:
/**
* Gets the offset of beginning of the CoAP message payload (after the CoAP header).
*
* MUST be used after the iterator is done (i.e. iterated through all options).
* MUST be used after the iterator is done (i.e. successfully iterated through all options).
*
* @returns The offset of beginning of the CoAP message payload
*/
uint16_t GetPayloadMessageOffset(void) const { return mNextOptionOffset; }
/**
* Inidcated whether or not the option ended with a payload marker.
*
* MUST be used after the iterator is done (i.e. successfully iterated through all options).
*
* @retval TRUE The message contains a payload marker.
* @retval FALAE The message does not contain a payload marker.
*/
bool HasPayloadMarker(void) const { return IsDone() && (mOption.mNumber != 0); }
/**
* Gets the offset of beginning of the CoAP Option Value.
*
@@ -1183,12 +1188,8 @@ public:
// `mOption.mLength` value to indicate iterator is done.
static constexpr uint16_t kIteratorDoneLength = 0xffff;
// Special `mNextOptionOffset` value to indicate a parse error.
static constexpr uint16_t kNextOptionOffsetParseError = 0;
void MarkAsDone(void) { mOption.mLength = kIteratorDoneLength; }
void MarkAsParseErrored(void) { MarkAsDone(), mNextOptionOffset = kNextOptionOffsetParseError; }
void MarkAsDone(void) { mOption.mLength = kIteratorDoneLength; }
void SetHasPayloadMarker(bool aHasPayloadMarker) { mOption.mNumber = aHasPayloadMarker; }
Error Read(uint16_t aLength, void *aBuffer);
Error ReadExtendedOptionField(uint16_t &aValue);
Error InitOrAdvance(const Message *aMessage, uint16_t aNumber);
+1 -1
View File
@@ -125,7 +125,7 @@ void SecureSession::HandleDtlsReceive(uint8_t *aBuf, uint16_t aLength)
{
ot::Message *message = nullptr;
VerifyOrExit((message = Get<MessagePool>().Allocate(Message::kTypeIp6, Message::GetHelpDataReserved())) != nullptr);
VerifyOrExit((message = Get<MessagePool>().Allocate(Message::kTypeIp6)) != nullptr);
SuccessOrExit(message->AppendBytes(aBuf, aLength));
CoapBase::Receive(*message, GetMessageInfo());
+1 -1
View File
@@ -59,7 +59,7 @@ Error AnnounceBeginClient::SendRequest(uint32_t aChannelMask,
VerifyOrExit((message = Get<Tmf::Agent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = message->InitAsPost(aAddress, kUriAnnounceBegin));
SuccessOrExit(error = message->SetPayloadMarker());
SuccessOrExit(error = message->AppendPayloadMarker());
SuccessOrExit(
error = Tlv::Append<MeshCoP::CommissionerSessionIdTlv>(*message, Get<MeshCoP::Commissioner>().GetSessionId()));
+18 -18
View File
@@ -360,7 +360,7 @@ template <> void Manager::HandleTmf<kUriRelayRx>(Coap::Msg &aMsg)
VerifyOrExit(mIsRunning);
VerifyOrExit(aMsg.mMessage.IsNonConfirmablePostRequest());
VerifyOrExit(aMsg.IsNonConfirmablePostRequest());
LogInfo("Received %s from %s", UriToString<kUriRelayRx>(), aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString());
@@ -597,7 +597,7 @@ bool Manager::CoapDtlsSession::HandleResource(const char *aUriPath, Coap::Msg &a
HandleTmfCommissionerKeepAlive(aMsg);
break;
case kUriRelayTx:
HandleTmfRelayTx(aMsg.mMessage);
HandleTmfRelayTx(aMsg);
break;
case kUriCommissionerGet:
case kUriActiveGet:
@@ -605,7 +605,7 @@ bool Manager::CoapDtlsSession::HandleResource(const char *aUriPath, Coap::Msg &a
HandleTmfDatasetGet(aMsg.mMessage, uri);
break;
case kUriProxyTx:
HandleTmfProxyTx(aMsg.mMessage);
HandleTmfProxyTx(aMsg);
break;
default:
didHandle = false;
@@ -756,7 +756,7 @@ void Manager::CoapDtlsSession::HandleLeaderResponseToFwdTmf(const ForwardContext
forwardMessage.Reset(NewPriorityMessage());
VerifyOrExit(forwardMessage != nullptr, error = kErrorNoBufs);
if (aResponse->GetCode() == Coap::kCodeChanged)
if (aResponse->ReadCode() == Coap::kCodeChanged)
{
uint8_t state;
@@ -784,13 +784,13 @@ void Manager::CoapDtlsSession::HandleLeaderResponseToFwdTmf(const ForwardContext
}
}
forwardMessage->Init(Coap::kTypeNonConfirmable, static_cast<Coap::Code>(aResponse->GetCode()));
SuccessOrExit(error =
forwardMessage->Init(Coap::kTypeNonConfirmable, static_cast<Coap::Code>(aResponse->ReadCode())));
SuccessOrExit(error = forwardMessage->WriteToken(aForwardContext.mToken));
if (aResponse->GetLength() > aResponse->GetOffset())
{
SuccessOrExit(error = forwardMessage->SetPayloadMarker());
SuccessOrExit(error = forwardMessage->AppendPayloadMarker());
}
SuccessOrExit(error = ForwardToCommissioner(forwardMessage.PassOwnership(), *aResponse));
@@ -897,7 +897,7 @@ void Manager::CoapDtlsSession::SendErrorMessage(Error aError, const Coap::Token
code = (aError == kErrorParse) ? Coap::kCodeBadRequest : Coap::kCodeInternalError;
message->Init(Coap::kTypeNonConfirmable, code);
SuccessOrExit(error = message->Init(Coap::kTypeNonConfirmable, code));
SuccessOrExit(error = message->WriteToken(aToken));
SuccessOrExit(error = SendMessage(message.PassOwnership()));
@@ -906,7 +906,7 @@ exit:
LogWarnOnError(error, "send error CoAP message");
}
void Manager::CoapDtlsSession::HandleTmfProxyTx(Coap::Message &aMessage)
void Manager::CoapDtlsSession::HandleTmfProxyTx(Coap::Msg &aMsg)
{
Error error = kErrorNone;
OwnedPtr<Message> message;
@@ -918,9 +918,9 @@ void Manager::CoapDtlsSession::HandleTmfProxyTx(Coap::Message &aMessage)
VerifyOrExit(IsActiveCommissioner(), error = kErrorInvalidState);
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMessage, Tlv::kUdpEncapsulation, offsetRange));
SuccessOrExit(error = Tlv::FindTlvValueOffsetRange(aMsg.mMessage, Tlv::kUdpEncapsulation, offsetRange));
SuccessOrExit(error = aMessage.Read(offsetRange, udpEncapHeader));
SuccessOrExit(error = aMsg.mMessage.Read(offsetRange, udpEncapHeader));
offsetRange.AdvanceOffset(sizeof(UdpEncapsulationTlvHeader));
VerifyOrExit(udpEncapHeader.GetSourcePort() > 0 && udpEncapHeader.GetDestinationPort() > 0, error = kErrorDrop);
@@ -928,13 +928,13 @@ void Manager::CoapDtlsSession::HandleTmfProxyTx(Coap::Message &aMessage)
message.Reset(Get<Ip6::Udp>().NewMessage());
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange));
SuccessOrExit(error = message->AppendBytesFromMessage(aMsg.mMessage, offsetRange));
messageInfo.SetSockPort(udpEncapHeader.GetSourcePort());
messageInfo.SetSockAddr(Get<Manager>().GetCommissionerAloc());
messageInfo.SetPeerPort(udpEncapHeader.GetDestinationPort());
SuccessOrExit(error = Tlv::Find<Ip6AddressTlv>(aMessage, messageInfo.GetPeerAddr()));
SuccessOrExit(error = Tlv::Find<Ip6AddressTlv>(aMsg.mMessage, messageInfo.GetPeerAddr()));
// On success the message ownership is transferred.
SuccessOrExit(error = Get<Ip6::Udp>().SendDatagram(*message, messageInfo));
@@ -946,7 +946,7 @@ exit:
LogWarnOnError(error, "send proxy stream");
}
void Manager::CoapDtlsSession::HandleTmfRelayTx(Coap::Message &aMessage)
void Manager::CoapDtlsSession::HandleTmfRelayTx(Coap::Msg &aMsg)
{
Error error = kErrorNone;
uint16_t joinerRouterRloc;
@@ -954,19 +954,19 @@ void Manager::CoapDtlsSession::HandleTmfRelayTx(Coap::Message &aMessage)
Tmf::MessageInfo messageInfo(GetInstance());
OffsetRange offsetRange;
VerifyOrExit(aMessage.IsNonConfirmablePostRequest());
VerifyOrExit(aMsg.IsNonConfirmablePostRequest());
VerifyOrExit(IsActiveCommissioner(), error = kErrorInvalidState);
Log<kUriRelayTx>(kReceive);
SuccessOrExit(error = Tlv::Find<JoinerRouterLocatorTlv>(aMessage, joinerRouterRloc));
SuccessOrExit(error = Tlv::Find<JoinerRouterLocatorTlv>(aMsg.mMessage, joinerRouterRloc));
message.Reset(Get<Tmf::Agent>().NewPriorityNonConfirmablePostMessage(kUriRelayTx));
VerifyOrExit(message != nullptr, error = kErrorNoBufs);
offsetRange.InitFromMessageOffsetToEnd(aMessage);
SuccessOrExit(error = message->AppendBytesFromMessage(aMessage, offsetRange));
offsetRange.InitFromMessageOffsetToEnd(aMsg.mMessage);
SuccessOrExit(error = message->AppendBytesFromMessage(aMsg.mMessage, offsetRange));
messageInfo.SetSockAddrToRlocPeerAddrTo(joinerRouterRloc);
messageInfo.SetSockPortToTmf();
+2 -2
View File
@@ -304,8 +304,8 @@ private:
Error ForwardToCommissioner(OwnedPtr<Coap::Message> aForwardMessage, const Message &aMessage);
void HandleTmfCommissionerKeepAlive(Coap::Msg &aMsg);
void HandleTmfRelayTx(Coap::Message &aMessage);
void HandleTmfProxyTx(Coap::Message &aMessage);
void HandleTmfRelayTx(Coap::Msg &aMsg);
void HandleTmfProxyTx(Coap::Msg &aMsg);
void HandleTmfDatasetGet(Coap::Message &aMessage, Uri aUri);
Error ForwardToLeader(const Coap::Msg &aMsg, Uri aUri);
void SendErrorMessage(Error aError, const Coap::Token &aToken);
+6 -6
View File
@@ -627,7 +627,7 @@ exit:
void Commissioner::HandleMgmtCommissionerGetResponse(Coap::Message *aMessage, Error aResult)
{
VerifyOrExit(aResult == kErrorNone && aMessage->GetCode() == Coap::kCodeChanged);
VerifyOrExit(aResult == kErrorNone && aMessage->ReadCode() == Coap::kCodeChanged);
LogInfo("Received %s response", UriToString<kUriCommissionerGet>());
exit:
@@ -688,7 +688,7 @@ void Commissioner::HandleMgmtCommissionerSetResponse(Coap::Message *aMessage, Er
uint8_t state;
SuccessOrExit(error = aResult);
VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged && Tlv::Find<StateTlv>(*aMessage, state) == kErrorNone &&
VerifyOrExit(aMessage->ReadCode() == Coap::kCodeChanged && Tlv::Find<StateTlv>(*aMessage, state) == kErrorNone &&
state != StateTlv::kPending,
error = kErrorParse);
@@ -727,7 +727,7 @@ void Commissioner::HandleLeaderPetitionResponse(Coap::Message *aMessage, Error a
bool retransmit = false;
VerifyOrExit(mState != kStateActive);
VerifyOrExit(aResult == kErrorNone && aMessage->GetCode() == Coap::kCodeChanged,
VerifyOrExit(aResult == kErrorNone && aMessage->ReadCode() == Coap::kCodeChanged,
retransmit = (mState == kStatePetition));
LogInfo("Received %s response", UriToString<kUriLeaderPetition>());
@@ -799,7 +799,7 @@ void Commissioner::HandleLeaderKeepAliveResponse(Coap::Message *aMessage, Error
uint8_t state;
VerifyOrExit(mState == kStateActive);
VerifyOrExit(aResult == kErrorNone && aMessage->GetCode() == Coap::kCodeChanged,
VerifyOrExit(aResult == kErrorNone && aMessage->ReadCode() == Coap::kCodeChanged,
IgnoreError(Stop(kDoNotSendKeepAlive)));
LogInfo("Received %s response", UriToString<kUriLeaderKeepAlive>());
@@ -824,7 +824,7 @@ template <> void Commissioner::HandleTmf<kUriRelayRx>(Coap::Msg &aMsg)
VerifyOrExit(mState == kStateActive, error = kErrorInvalidState);
VerifyOrExit(aMsg.mMessage.IsNonConfirmablePostRequest());
VerifyOrExit(aMsg.IsNonConfirmablePostRequest());
SuccessOrExit(error = Tlv::Find<JoinerUdpPortTlv>(aMsg.mMessage, joinerPort));
SuccessOrExit(error = Tlv::Find<JoinerIidTlv>(aMsg.mMessage, joinerIid));
@@ -893,7 +893,7 @@ void Commissioner::HandleJoinerSessionTimer(void)
template <> void Commissioner::HandleTmf<kUriDatasetChanged>(Coap::Msg &aMsg)
{
VerifyOrExit(mState == kStateActive);
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
LogInfo("Received %s", UriToString<kUriDatasetChanged>());
+2 -2
View File
@@ -62,7 +62,7 @@ Error EnergyScanClient::SendQuery(uint32_t aChannelMas
VerifyOrExit((message = Get<Tmf::Agent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = message->InitAsPost(aAddress, kUriEnergyScan));
SuccessOrExit(error = message->SetPayloadMarker());
SuccessOrExit(error = message->AppendPayloadMarker());
SuccessOrExit(
error = Tlv::Append<MeshCoP::CommissionerSessionIdTlv>(*message, Get<MeshCoP::Commissioner>().GetSessionId()));
@@ -90,7 +90,7 @@ template <> void EnergyScanClient::HandleTmf<kUriEnergyReport>(Coap::Msg &aMsg)
uint32_t mask;
MeshCoP::EnergyListTlv energyListTlv;
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
LogInfo("Received %s", UriToString<kUriEnergyReport>());
+6 -3
View File
@@ -471,12 +471,15 @@ exit:
void Joiner::HandleJoinerFinalizeResponse(Coap::Message *aMessage, Error aResult)
{
uint8_t state;
uint8_t state;
Coap::HeaderInfo header;
VerifyOrExit(mState == kStateConnected && aResult == kErrorNone);
OT_ASSERT(aMessage != nullptr);
VerifyOrExit(aMessage->IsAck() && aMessage->GetCode() == Coap::kCodeChanged);
SuccessOrExit(aMessage->ParseHeaderInfo(header));
VerifyOrExit(header.IsAck() && header.GetCode() == Coap::kCodeChanged);
SuccessOrExit(Tlv::Find<StateTlv>(*aMessage, state));
@@ -499,7 +502,7 @@ template <> void Joiner::HandleTmf<kUriJoinerEntrust>(Coap::Msg &aMsg)
Error error;
Dataset::Info datasetInfo;
VerifyOrExit(mState == kStateEntrust && aMsg.mMessage.IsConfirmablePostRequest(), error = kErrorDrop);
VerifyOrExit(mState == kStateEntrust && aMsg.IsConfirmablePostRequest(), error = kErrorDrop);
LogInfo("Received %s", UriToString<kUriJoinerEntrust>());
LogCert("[THCI] direction=recv | type=JOIN_ENT.ntf");
+2 -2
View File
@@ -162,7 +162,7 @@ template <> void JoinerRouter::HandleTmf<kUriRelayTx>(Coap::Msg &aMsg)
Message::Settings settings(kNoLinkSecurity, Message::kPriorityNet);
Ip6::MessageInfo messageInfo;
VerifyOrExit(aMsg.mMessage.IsNonConfirmablePostRequest(), error = kErrorDrop);
VerifyOrExit(aMsg.IsNonConfirmablePostRequest(), error = kErrorDrop);
LogInfo("Received %s", UriToString<kUriRelayTx>());
@@ -310,7 +310,7 @@ void JoinerRouter::HandleJoinerEntrustResponse(Coap::Message *aMessage, Error aR
VerifyOrExit(aResult == kErrorNone && aMessage != nullptr);
VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged);
VerifyOrExit(aMessage->ReadCode() == Coap::kCodeChanged);
LogInfo("Receive %s response", UriToString<kUriJoinerEntrust>());
LogCert("[THCI] direction=recv | type=JOIN_ENT.rsp");
+2 -2
View File
@@ -60,7 +60,7 @@ Error PanIdQueryClient::SendQuery(uint16_t aPanId,
VerifyOrExit((message = Get<Tmf::Agent>().NewPriorityMessage()) != nullptr, error = kErrorNoBufs);
SuccessOrExit(error = message->InitAsPost(aAddress, kUriPanIdQuery));
SuccessOrExit(error = message->SetPayloadMarker());
SuccessOrExit(error = message->AppendPayloadMarker());
SuccessOrExit(
error = Tlv::Append<MeshCoP::CommissionerSessionIdTlv>(*message, Get<MeshCoP::Commissioner>().GetSessionId()));
@@ -86,7 +86,7 @@ template <> void PanIdQueryClient::HandleTmf<kUriPanIdConflict>(Coap::Msg &aMsg)
uint16_t panId;
uint32_t mask;
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
LogInfo("Received %s", UriToString<kUriPanIdConflict>());
+1 -1
View File
@@ -1119,7 +1119,7 @@ template <> void TcatAgent::HandleTmf<kUriTcatEnable>(Coap::Msg &aMsg)
uint16_t durationSec = 0;
uint32_t durationMs;
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
LogInfo("Received %s from %s", UriToString<kUriTcatEnable>(),
aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString());
message = Get<Tmf::Agent>().NewResponseMessage(aMsg.mMessage);
+7 -6
View File
@@ -655,7 +655,7 @@ template <> void AddressResolver::HandleTmf<kUriAddressNotify>(Coap::Msg &aMsg)
CacheEntry *entry;
CacheEntry *prev;
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
SuccessOrExit(Tlv::Find<ThreadTargetTlv>(aMsg.mMessage, target));
SuccessOrExit(Tlv::Find<ThreadMeshLocalEidTlv>(aMsg.mMessage, meshLocalIid));
@@ -725,9 +725,10 @@ void AddressResolver::SendAddressError(const Ip6::Address &aTarget,
VerifyOrExit((message = Get<Tmf::Agent>().NewMessage()) != nullptr, error = kErrorNoBufs);
message->Init(aDestination == nullptr ? Coap::kTypeNonConfirmable : Coap::kTypeConfirmable, Coap::kCodePost);
SuccessOrExit(error = message->Init(aDestination == nullptr ? Coap::kTypeNonConfirmable : Coap::kTypeConfirmable,
Coap::kCodePost));
SuccessOrExit(error = message->AppendUriPathOptions(PathForUri(kUriAddressError)));
SuccessOrExit(error = message->SetPayloadMarker());
SuccessOrExit(error = message->AppendPayloadMarker());
SuccessOrExit(error = Tlv::Append<ThreadTargetTlv>(*message, aTarget));
SuccessOrExit(error = Tlv::Append<ThreadMeshLocalEidTlv>(*message, aMeshLocalIid));
@@ -766,11 +767,11 @@ template <> void AddressResolver::HandleTmf<kUriAddressError>(Coap::Msg &aMsg)
Ip6::Address destination;
#endif
VerifyOrExit(aMsg.mMessage.IsPostRequest(), error = kErrorDrop);
VerifyOrExit(aMsg.IsPostRequest(), error = kErrorDrop);
LogInfo("Received %s", UriToString<kUriAddressError>());
if (aMsg.mMessage.IsConfirmable() && !aMsg.mMessageInfo.GetSockAddr().IsMulticast())
if (aMsg.IsConfirmable() && !aMsg.mMessageInfo.GetSockAddr().IsMulticast())
{
if (Get<Tmf::Agent>().SendEmptyAck(aMsg) == kErrorNone)
{
@@ -842,7 +843,7 @@ template <> void AddressResolver::HandleTmf<kUriAddressQuery>(Coap::Msg &aMsg)
Ip6::Address target;
uint32_t lastTransactionTime;
VerifyOrExit(aMsg.mMessage.IsNonConfirmablePostRequest());
VerifyOrExit(aMsg.IsNonConfirmablePostRequest());
SuccessOrExit(Tlv::Find<ThreadTargetTlv>(aMsg.mMessage, target));
+2 -2
View File
@@ -58,7 +58,7 @@ template <> void AnnounceBeginServer::HandleTmf<kUriAnnounceBegin>(Coap::Msg &aM
uint8_t count;
uint16_t period;
VerifyOrExit(aMsg.mMessage.IsPostRequest());
VerifyOrExit(aMsg.IsPostRequest());
SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMsg.mMessage, mask));
SuccessOrExit(Tlv::Find<MeshCoP::CountTlv>(aMsg.mMessage, count));
@@ -66,7 +66,7 @@ template <> void AnnounceBeginServer::HandleTmf<kUriAnnounceBegin>(Coap::Msg &aM
SendAnnounce(mask, count, period);
if (aMsg.mMessage.IsConfirmable() && !aMsg.mMessageInfo.GetSockAddr().IsMulticast())
if (aMsg.IsConfirmable() && !aMsg.mMessageInfo.GetSockAddr().IsMulticast())
{
SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMsg));
LogInfo("Sent %s response", UriToString<kUriAnnounceBegin>());
+1 -1
View File
@@ -113,7 +113,7 @@ template <> void AnycastLocator::HandleTmf<kUriAnycastLocate>(Coap::Msg &aMsg)
{
Coap::Message *message = nullptr;
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
message = Get<Tmf::Agent>().NewResponseMessage(aMsg.mMessage);
VerifyOrExit(message != nullptr);
+4 -4
View File
@@ -557,7 +557,7 @@ void DuaManager::HandleDuaResponse(Coap::Message *aMessage, Error aResult)
VerifyOrExit(aResult == kErrorNone, error = kErrorParse);
OT_ASSERT(aMessage != nullptr);
VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged || aMessage->GetCode() >= Coap::kCodeBadRequest,
VerifyOrExit(aMessage->ReadCode() == Coap::kCodeChanged || aMessage->ReadCode() >= Coap::kCodeBadRequest,
error = kErrorParse);
error = ProcessDuaResponse(*aMessage);
@@ -575,9 +575,9 @@ template <> void DuaManager::HandleTmf<kUriDuaRegistrationNotify>(Coap::Msg &aMs
{
Error error;
VerifyOrExit(aMsg.mMessage.IsPostRequest(), error = kErrorParse);
VerifyOrExit(aMsg.IsPostRequest(), error = kErrorParse);
if (aMsg.mMessage.IsConfirmable() && Get<Tmf::Agent>().SendEmptyAck(aMsg) == kErrorNone)
if (aMsg.IsConfirmable() && Get<Tmf::Agent>().SendEmptyAck(aMsg) == kErrorNone)
{
LogInfo("Sent %s ack", UriToString<kUriDuaRegistrationNotify>());
}
@@ -595,7 +595,7 @@ Error DuaManager::ProcessDuaResponse(Coap::Message &aMessage)
Ip6::Address target;
uint8_t status;
if (aMessage.GetCode() >= Coap::kCodeBadRequest)
if (aMessage.ReadCode() >= Coap::kCodeBadRequest)
{
status = kDuaGeneralFailure;
target = mRegisteringDua;
+2 -2
View File
@@ -58,7 +58,7 @@ template <> void EnergyScanServer::HandleTmf<kUriEnergyScan>(Coap::Msg &aMsg)
uint32_t mask;
MeshCoP::Tlv tlv;
VerifyOrExit(aMsg.mMessage.IsPostRequest());
VerifyOrExit(aMsg.IsPostRequest());
SuccessOrExit(Tlv::Find<MeshCoP::CountTlv>(aMsg.mMessage, count));
count = Clamp(count, kMinCount, kMaxCount);
@@ -87,7 +87,7 @@ template <> void EnergyScanServer::HandleTmf<kUriEnergyScan>(Coap::Msg &aMsg)
mCommissioner = aMsg.mMessageInfo.GetPeerAddr();
if (aMsg.mMessage.IsConfirmable() && !aMsg.mMessageInfo.GetSockAddr().IsMulticast())
if (aMsg.IsConfirmable() && !aMsg.mMessageInfo.GetSockAddr().IsMulticast())
{
SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMsg));
LogInfo("Sent %s ack", UriToString<kUriEnergyScan>());
+1 -1
View File
@@ -1683,7 +1683,7 @@ private:
struct AddrSolicitInfo
{
Error ParseFrom(const Coap::Message &aMessage);
Error ParseFrom(const Coap::Msg &aMsg);
Mac::ExtAddress mExtAddress;
uint16_t mRequestedRloc16;
+9 -9
View File
@@ -3333,7 +3333,7 @@ void Mle::HandleAddressSolicitResponse(Coap::Message *aMessage, const Ip6::Messa
VerifyOrExit(aResult == kErrorNone && aMessage != nullptr && aMessageInfo != nullptr);
VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged);
VerifyOrExit(aMessage->ReadCode() == Coap::kCodeChanged);
Log(kMessageReceive, kTypeAddressReply, aMessageInfo->GetPeerAddr());
@@ -3459,18 +3459,18 @@ exit:
return willBecomeRouter;
}
Error Mle::AddrSolicitInfo::ParseFrom(const Coap::Message &aMessage)
Error Mle::AddrSolicitInfo::ParseFrom(const Coap::Msg &aMsg)
{
// Parses a `kUriAddressSolicit` request message.
Error error;
VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = kErrorParse);
VerifyOrExit(aMsg.IsConfirmablePostRequest(), error = kErrorParse);
SuccessOrExit(error = Tlv::Find<ThreadExtMacAddressTlv>(aMessage, mExtAddress));
SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(aMessage, mReason));
SuccessOrExit(error = Tlv::Find<ThreadExtMacAddressTlv>(aMsg.mMessage, mExtAddress));
SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(aMsg.mMessage, mReason));
switch (Tlv::Find<ThreadRloc16Tlv>(aMessage, mRequestedRloc16))
switch (Tlv::Find<ThreadRloc16Tlv>(aMsg.mMessage, mRequestedRloc16))
{
case kErrorNone:
break;
@@ -3482,7 +3482,7 @@ Error Mle::AddrSolicitInfo::ParseFrom(const Coap::Message &aMessage)
}
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
switch (Tlv::Find<XtalAccuracyTlv>(aMessage, mXtalAccuracy))
switch (Tlv::Find<XtalAccuracyTlv>(aMsg.mMessage, mXtalAccuracy))
{
case kErrorNone:
break;
@@ -3576,7 +3576,7 @@ template <> void Mle::HandleTmf<kUriAddressSolicit>(Coap::Msg &aMsg)
Log(kMessageReceive, kTypeAddressSolicit, aMsg.mMessageInfo.GetPeerAddr());
SuccessOrExit(info.ParseFrom(aMsg.mMessage));
SuccessOrExit(info.ParseFrom(aMsg));
ProcessAddressSolicit(info);
@@ -3637,7 +3637,7 @@ template <> void Mle::HandleTmf<kUriAddressRelease>(Coap::Msg &aMsg)
VerifyOrExit(mRole == kRoleLeader);
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
Log(kMessageReceive, kTypeAddressRelease, aMsg.mMessageInfo.GetPeerAddr());
+1 -1
View File
@@ -468,7 +468,7 @@ Error MlrManager::ParseMlrResponse(Error aResult,
aStatus = kMlrGeneralFailure;
VerifyOrExit(aResult == kErrorNone && aMessage != nullptr, error = kErrorParse);
VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged, error = kErrorParse);
VerifyOrExit(aMessage->ReadCode() == Coap::kCodeChanged, error = kErrorParse);
SuccessOrExit(error = Tlv::Find<ThreadStatusTlv>(*aMessage, aStatus));
+7 -7
View File
@@ -630,13 +630,13 @@ exit:
template <> void Server::HandleTmf<kUriDiagnosticGetQuery>(Coap::Msg &aMsg)
{
VerifyOrExit(aMsg.mMessage.IsPostRequest());
VerifyOrExit(aMsg.IsPostRequest());
LogInfo("Received %s from %s", UriToString<kUriDiagnosticGetQuery>(),
aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString());
// DIAG_GET.qry may be sent as a confirmable request.
if (aMsg.mMessage.IsConfirmable())
if (aMsg.IsConfirmable())
{
IgnoreError(Get<Tmf::Agent>().SendEmptyAck(aMsg));
}
@@ -886,7 +886,7 @@ void Server::HandleAnswerResponse(Coap::Message &aNextAnswer,
SuccessOrExit(error);
VerifyOrExit(aResponse != nullptr && aMessageInfo != nullptr, error = kErrorDrop);
VerifyOrExit(aResponse->GetCode() == Coap::kCodeChanged, error = kErrorDrop);
VerifyOrExit(aResponse->ReadCode() == Coap::kCodeChanged, error = kErrorDrop);
SendNextAnswer(aNextAnswer, aMessageInfo->GetPeerAddr());
@@ -999,7 +999,7 @@ template <> void Server::HandleTmf<kUriDiagnosticGetRequest>(Coap::Msg &aMsg)
Error error = kErrorNone;
Coap::Message *response = nullptr;
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest(), error = kErrorDrop);
VerifyOrExit(aMsg.IsConfirmablePostRequest(), error = kErrorDrop);
LogInfo("Received %s from %s", UriToString<kUriDiagnosticGetRequest>(),
aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString());
@@ -1021,7 +1021,7 @@ template <> void Server::HandleTmf<kUriDiagnosticReset>(Coap::Msg &aMsg)
uint8_t type;
Tlv tlv;
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
LogInfo("Received %s from %s", UriToString<kUriDiagnosticReset>(),
aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString());
@@ -1152,7 +1152,7 @@ exit:
void Client::HandleGetResponse(Coap::Message *aMessage, const Ip6::MessageInfo *aMessageInfo, Error aResult)
{
SuccessOrExit(aResult);
VerifyOrExit(aMessage->GetCode() == Coap::kCodeChanged, aResult = kErrorFailed);
VerifyOrExit(aMessage->ReadCode() == Coap::kCodeChanged, aResult = kErrorFailed);
exit:
mGetCallback.InvokeIfSet(aResult, aMessage, aMessageInfo);
@@ -1160,7 +1160,7 @@ exit:
template <> void Client::HandleTmf<kUriDiagnosticGetAnswer>(Coap::Msg &aMsg)
{
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
LogInfo("Received %s from %s", ot::UriToString<kUriDiagnosticGetAnswer>(),
aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString());
+2 -2
View File
@@ -52,7 +52,7 @@ template <> void PanIdQueryServer::HandleTmf<kUriPanIdQuery>(Coap::Msg &aMsg)
uint16_t panId;
uint32_t mask;
VerifyOrExit(aMsg.mMessage.IsPostRequest());
VerifyOrExit(aMsg.IsPostRequest());
SuccessOrExit(MeshCoP::ChannelMaskTlv::FindIn(aMsg.mMessage, mask));
SuccessOrExit(Tlv::Find<MeshCoP::PanIdTlv>(aMsg.mMessage, panId));
@@ -62,7 +62,7 @@ template <> void PanIdQueryServer::HandleTmf<kUriPanIdQuery>(Coap::Msg &aMsg)
mPanId = panId;
mTimer.Start(kScanDelay);
if (aMsg.mMessage.IsConfirmable() && !aMsg.mMessageInfo.GetSockAddr().IsMulticast())
if (aMsg.IsConfirmable() && !aMsg.mMessageInfo.GetSockAddr().IsMulticast())
{
SuccessOrExit(Get<Tmf::Agent>().SendEmptyAck(aMsg));
LogInfo("Sent %s ack", UriToString<kUriPanIdQuery>());
+1 -1
View File
@@ -114,7 +114,7 @@ exit:
template <> void Client::HandleTmf<kUriHistoryAnswer>(Coap::Msg &aMsg)
{
VerifyOrExit(aMsg.mMessage.IsConfirmablePostRequest());
VerifyOrExit(aMsg.IsConfirmablePostRequest());
IgnoreError(Get<Tmf::Agent>().SendEmptyAck(aMsg));
LogInfo("Received %s from %s", ot::UriToString<kUriHistoryAnswer>(),
+3 -3
View File
@@ -49,12 +49,12 @@ Server::Server(Instance &aInstance)
template <> void Server::HandleTmf<kUriHistoryQuery>(Coap::Msg &aMsg)
{
VerifyOrExit(aMsg.mMessage.IsPostRequest());
VerifyOrExit(aMsg.IsPostRequest());
LogInfo("Received %s from %s", UriToString<kUriHistoryQuery>(),
aMsg.mMessageInfo.GetPeerAddr().ToString().AsCString());
if (aMsg.mMessage.IsConfirmable())
if (aMsg.IsConfirmable())
{
IgnoreError(Get<Tmf::Agent>().SendEmptyAck(aMsg));
}
@@ -282,7 +282,7 @@ void Server::HandleAnswerResponse(Coap::Message &aNextAnswer,
SuccessOrExit(error);
VerifyOrExit(aResponse != nullptr && aMessageInfo != nullptr, error = kErrorDrop);
VerifyOrExit(aResponse->GetCode() == Coap::kCodeChanged, error = kErrorDrop);
VerifyOrExit(aResponse->ReadCode() == Coap::kCodeChanged, error = kErrorDrop);
SendNextAnswer(aNextAnswer, aMessageInfo->GetPeerAddr());
+6 -4
View File
@@ -199,13 +199,15 @@ void Otns::EmitCoapStatus(const char *aAction,
const Ip6::MessageInfo &aMessageInfo,
Error *aError) const
{
Error error;
char uriPath[Coap::Message::kMaxReceivedUriPath + 1];
StatusString string;
Error error;
char uriPath[Coap::Message::kMaxReceivedUriPath + 1];
StatusString string;
Coap::HeaderInfo header;
SuccessOrExit(error = aMessage.ParseHeaderInfo(header));
SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath));
string.Append("coap=%s,%d,%d,%d,%s,%s,%d", aAction, aMessage.GetMessageId(), aMessage.GetType(), aMessage.GetCode(),
string.Append("coap=%s,%d,%d,%d,%s,%s,%d", aAction, header.GetMessageId(), header.GetType(), header.GetCode(),
uriPath, aMessageInfo.GetPeerAddr().ToString().AsCString(), aMessageInfo.GetPeerPort());
if (aError != nullptr)
+1
View File
@@ -206,6 +206,7 @@ ot_unit_test(checksum)
ot_unit_test(child)
ot_unit_test(child_table)
ot_unit_test(cmd_line_parser)
ot_unit_test(coap_message)
ot_unit_test(crc)
ot_unit_test(data)
ot_unit_test(dataset)
+429
View File
@@ -0,0 +1,429 @@
/*
* Copyright (c) 2026, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "instance/instance.hpp"
#include "test_platform.h"
#include "test_util.hpp"
namespace ot {
class UnitTester
{
public:
static void TestCoapMessage(void)
{
Instance *instance;
Coap::Message *message;
Coap::HeaderInfo headerInfo;
Coap::Token readToken;
Coap::Token token;
Coap::Option::Iterator iterator;
uint8_t tokenLength;
uint16_t length;
Ip6::MessageInfo messageInfo;
Coap::Message::UriPathStringBuffer uriBuffer;
printf("TestCoapMessage()\n");
instance = static_cast<Instance *>(testInitInstance());
VerifyOrQuit(instance != nullptr);
message = AsCoapMessagePtr(instance->Get<MessagePool>().Allocate(Message::kTypeOther));
VerifyOrQuit(message != nullptr);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(message->Init(Coap::kTypeNonConfirmable, Coap::kCodePut));
SuccessOrQuit(message->ParseHeaderInfo(headerInfo));
VerifyOrQuit(headerInfo.GetType() == Coap::kTypeNonConfirmable);
VerifyOrQuit(headerInfo.GetCode() == Coap::kCodePut);
VerifyOrQuit(headerInfo.GetMessageId() == 0);
VerifyOrQuit(headerInfo.GetToken().GetLength() == 0);
VerifyOrQuit(message->ReadType() == Coap::kTypeNonConfirmable);
VerifyOrQuit(message->ReadCode() == Coap::kCodePut);
VerifyOrQuit(message->ReadMessageId() == 0);
SuccessOrQuit(message->ReadTokenLength(tokenLength));
VerifyOrQuit(tokenLength == 0);
SuccessOrQuit(message->ReadToken(readToken));
VerifyOrQuit(readToken.GetLength() == 0);
SuccessOrQuit(iterator.Init(*message));
VerifyOrQuit(iterator.IsDone());
VerifyOrQuit(!iterator.HasPayloadMarker());
VerifyOrQuit(iterator.GetPayloadMessageOffset() == message->GetLength());
{
Coap::Msg msg(*message, messageInfo);
SuccessOrQuit(msg.ParseHeaderAndOptions(Coap::Msg::kRemovePayloadMarkerIfNoPayload));
VerifyOrQuit(msg.GetType() == Coap::kTypeNonConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodePut);
VerifyOrQuit(msg.GetMessageId() == 0);
VerifyOrQuit(msg.GetToken().GetLength() == 0);
VerifyOrQuit(msg.mMessage.GetOffset() == msg.mMessage.GetLength());
}
// AppendPayloadMaker
SuccessOrQuit(message->AppendPayloadMarker());
VerifyOrQuit(message->GetOffset() == message->GetLength());
SuccessOrQuit(iterator.Init(*message));
VerifyOrQuit(iterator.IsDone());
VerifyOrQuit(iterator.HasPayloadMarker());
VerifyOrQuit(iterator.GetPayloadMessageOffset() == message->GetLength());
{
Coap::Msg msg(*message, messageInfo);
VerifyOrQuit(msg.ParseHeaderAndOptions(Coap::Msg::kRejectIfNoPayloadWithPayloadMarker) != kErrorNone);
}
// AppendPayloadMaker again should not make any changes
length = message->GetLength();
SuccessOrQuit(message->AppendPayloadMarker());
VerifyOrQuit(message->GetLength() == length);
VerifyOrQuit(message->GetOffset() == length);
// Ensure payload marker is removed since we have no payload
{
Coap::Msg msg(*message, messageInfo);
SuccessOrQuit(msg.ParseHeaderAndOptions(Coap::Msg::kRemovePayloadMarkerIfNoPayload));
VerifyOrQuit(msg.GetType() == Coap::kTypeNonConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodePut);
VerifyOrQuit(msg.GetMessageId() == 0);
VerifyOrQuit(msg.GetToken().GetLength() == 0);
VerifyOrQuit(msg.mMessage.GetOffset() == msg.mMessage.GetLength());
}
SuccessOrQuit(iterator.Init(*message));
VerifyOrQuit(iterator.IsDone());
VerifyOrQuit(!iterator.HasPayloadMarker());
VerifyOrQuit(iterator.GetPayloadMessageOffset() == message->GetLength());
SuccessOrQuit(message->Append<uint8_t>(0xaa));
VerifyOrQuit(iterator.Init(*message) != kErrorNone);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(message->Init(Coap::kTypeConfirmable, Coap::kCodePost, 0x1234));
SuccessOrQuit(message->ParseHeaderInfo(headerInfo));
VerifyOrQuit(headerInfo.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(headerInfo.GetCode() == Coap::kCodePost);
VerifyOrQuit(headerInfo.GetMessageId() == 0x1234);
VerifyOrQuit(headerInfo.GetToken().GetLength() == 0);
VerifyOrQuit(message->ReadType() == Coap::kTypeConfirmable);
VerifyOrQuit(message->ReadCode() == Coap::kCodePost);
VerifyOrQuit(message->ReadMessageId() == 0x1234);
SuccessOrQuit(message->ReadTokenLength(tokenLength));
VerifyOrQuit(tokenLength == 0);
SuccessOrQuit(message->ReadToken(readToken));
VerifyOrQuit(readToken.GetLength() == 0);
SuccessOrQuit(iterator.Init(*message));
VerifyOrQuit(iterator.IsDone());
VerifyOrQuit(!iterator.HasPayloadMarker());
VerifyOrQuit(iterator.GetPayloadMessageOffset() == message->GetLength());
{
Coap::Msg msg(*message, messageInfo);
SuccessOrQuit(msg.ParseHeaderAndOptions(Coap::Msg::kRemovePayloadMarkerIfNoPayload));
VerifyOrQuit(msg.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodePost);
VerifyOrQuit(msg.GetMessageId() == 0x1234);
VerifyOrQuit(msg.GetToken().GetLength() == 0);
VerifyOrQuit(msg.mMessage.GetOffset() == msg.mMessage.GetLength());
}
// Write Token
token.mLength = 2;
token.m8[0] = 0x11;
token.m8[1] = 0x22;
SuccessOrQuit(message->WriteToken(token));
SuccessOrQuit(message->ParseHeaderInfo(headerInfo));
VerifyOrQuit(headerInfo.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(headerInfo.GetCode() == Coap::kCodePost);
VerifyOrQuit(headerInfo.GetMessageId() == 0x1234);
VerifyOrQuit(headerInfo.GetToken().GetLength() == 2);
SuccessOrQuit(message->ReadToken(readToken));
VerifyOrQuit(readToken.GetLength() == 2);
VerifyOrQuit(readToken == token);
SuccessOrQuit(iterator.Init(*message));
VerifyOrQuit(iterator.IsDone());
VerifyOrQuit(!iterator.HasPayloadMarker());
VerifyOrQuit(iterator.GetPayloadMessageOffset() == message->GetLength());
{
Coap::Msg msg(*message, messageInfo);
SuccessOrQuit(msg.ParseHeaderAndOptions(Coap::Msg::kRemovePayloadMarkerIfNoPayload));
VerifyOrQuit(msg.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodePost);
VerifyOrQuit(msg.GetMessageId() == 0x1234);
VerifyOrQuit(msg.GetToken().GetLength() == 2);
VerifyOrQuit(msg.GetToken() == token);
VerifyOrQuit(msg.mMessage.GetOffset() == msg.mMessage.GetLength());
}
// Append URI-Path Option
SuccessOrQuit(message->AppendUriPathOptions("uri"));
SuccessOrQuit(message->ParseHeaderInfo(headerInfo));
VerifyOrQuit(headerInfo.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(headerInfo.GetCode() == Coap::kCodePost);
VerifyOrQuit(headerInfo.GetMessageId() == 0x1234);
VerifyOrQuit(headerInfo.GetToken().GetLength() == 2);
SuccessOrQuit(iterator.Init(*message));
VerifyOrQuit(!iterator.IsDone());
VerifyOrQuit(iterator.GetOption() != nullptr);
VerifyOrQuit(iterator.GetOption()->GetNumber() == Coap::kOptionUriPath);
VerifyOrQuit(iterator.GetOption()->GetLength() == 3);
SuccessOrQuit(iterator.Advance());
VerifyOrQuit(iterator.IsDone());
VerifyOrQuit(!iterator.HasPayloadMarker());
VerifyOrQuit(iterator.GetPayloadMessageOffset() == message->GetLength());
SuccessOrQuit(message->AppendPayloadMarker());
SuccessOrQuit(iterator.Init(*message));
VerifyOrQuit(!iterator.IsDone());
SuccessOrQuit(iterator.Advance());
VerifyOrQuit(iterator.IsDone());
VerifyOrQuit(iterator.HasPayloadMarker());
VerifyOrQuit(iterator.GetPayloadMessageOffset() == message->GetLength());
// Append some payload after marker
length = message->GetLength();
SuccessOrQuit(message->Append<uint8_t>(0xef));
SuccessOrQuit(iterator.Init(*message));
VerifyOrQuit(!iterator.IsDone());
SuccessOrQuit(iterator.Advance());
VerifyOrQuit(iterator.IsDone());
VerifyOrQuit(iterator.HasPayloadMarker());
VerifyOrQuit(iterator.GetPayloadMessageOffset() == length);
{
Coap::Msg msg(*message, messageInfo);
SuccessOrQuit(msg.ParseHeaderAndOptions(Coap::Msg::kRemovePayloadMarkerIfNoPayload));
VerifyOrQuit(msg.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodePost);
VerifyOrQuit(msg.GetMessageId() == 0x1234);
VerifyOrQuit(msg.GetToken().GetLength() == 2);
VerifyOrQuit(msg.GetToken() == token);
VerifyOrQuit(msg.mMessage.GetOffset() == length);
}
// Re-write Token
token.mLength = 2;
token.m8[0] = 0x33;
token.m8[1] = 0x44;
SuccessOrQuit(message->WriteToken(token));
SuccessOrQuit(message->ParseHeaderInfo(headerInfo));
VerifyOrQuit(headerInfo.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(headerInfo.GetCode() == Coap::kCodePost);
VerifyOrQuit(headerInfo.GetMessageId() == 0x1234);
VerifyOrQuit(headerInfo.GetToken().GetLength() == 2);
SuccessOrQuit(message->ReadToken(readToken));
VerifyOrQuit(readToken.GetLength() == 2);
VerifyOrQuit(readToken == token);
{
Coap::Msg msg(*message, messageInfo);
SuccessOrQuit(msg.ParseHeaderAndOptions(Coap::Msg::kRemovePayloadMarkerIfNoPayload));
VerifyOrQuit(msg.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodePost);
VerifyOrQuit(msg.GetMessageId() == 0x1234);
VerifyOrQuit(msg.GetToken().GetLength() == 2);
VerifyOrQuit(msg.GetToken() == token);
VerifyOrQuit(msg.mMessage.GetOffset() == length);
}
// Re-write token - changing token length afterwards is not allowed
token.mLength = 3;
token.m8[2] = 0x55;
VerifyOrQuit(message->WriteToken(token) != kErrorNone);
SuccessOrQuit(message->ParseHeaderInfo(headerInfo));
VerifyOrQuit(headerInfo.GetToken().GetLength() == 2);
token.mLength = 2;
SuccessOrQuit(message->ReadToken(readToken));
VerifyOrQuit(readToken.GetLength() == 2);
VerifyOrQuit(readToken == token);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(message->Init(Coap::kTypeConfirmable, Coap::kCodeGet, kUriCommissionerSet));
SuccessOrQuit(message->ParseHeaderInfo(headerInfo));
VerifyOrQuit(headerInfo.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(headerInfo.GetCode() == Coap::kCodeGet);
VerifyOrQuit(headerInfo.GetMessageId() == 0);
VerifyOrQuit(headerInfo.GetToken().GetLength() == Coap::Token::kDefaultLength);
VerifyOrQuit(message->ReadType() == Coap::kTypeConfirmable);
VerifyOrQuit(message->ReadCode() == Coap::kCodeGet);
VerifyOrQuit(message->ReadMessageId() == 0);
SuccessOrQuit(message->ReadTokenLength(tokenLength));
VerifyOrQuit(tokenLength == Coap::Token::kDefaultLength);
SuccessOrQuit(iterator.Init(*message));
VerifyOrQuit(!iterator.IsDone());
VerifyOrQuit(iterator.GetOption() != nullptr);
VerifyOrQuit(iterator.GetOption()->GetNumber() == Coap::kOptionUriPath);
SuccessOrQuit(iterator.Advance());
VerifyOrQuit(!iterator.IsDone());
VerifyOrQuit(iterator.GetOption() != nullptr);
VerifyOrQuit(iterator.GetOption()->GetNumber() == Coap::kOptionUriPath);
SuccessOrQuit(iterator.Advance());
VerifyOrQuit(iterator.IsDone());
VerifyOrQuit(!iterator.HasPayloadMarker());
VerifyOrQuit(iterator.GetPayloadMessageOffset() == message->GetLength());
SuccessOrQuit(message->ReadUriPathOptions(uriBuffer));
VerifyOrQuit(StringMatch(uriBuffer, PathForUri(kUriCommissionerSet)));
{
Coap::Msg msg(*message, messageInfo);
SuccessOrQuit(msg.ParseHeaderAndOptions(Coap::Msg::kRemovePayloadMarkerIfNoPayload));
VerifyOrQuit(msg.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodeGet);
VerifyOrQuit(msg.GetMessageId() == 0);
VerifyOrQuit(msg.GetToken().GetLength() == 2);
VerifyOrQuit(msg.mMessage.GetOffset() == msg.mMessage.GetLength());
}
// Re-write code, type, and message ID
message->WriteType(Coap::kTypeNonConfirmable);
message->WriteCode(Coap::kCodePost);
message->WriteMessageId(0x9876);
SuccessOrQuit(message->ParseHeaderInfo(headerInfo));
VerifyOrQuit(headerInfo.GetType() == Coap::kTypeNonConfirmable);
VerifyOrQuit(headerInfo.GetCode() == Coap::kCodePost);
VerifyOrQuit(headerInfo.GetMessageId() == 0x9876);
{
Coap::Msg msg(*message, messageInfo);
SuccessOrQuit(msg.ParseHeaderAndOptions(Coap::Msg::kRemovePayloadMarkerIfNoPayload));
VerifyOrQuit(msg.GetType() == Coap::kTypeNonConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodePost);
VerifyOrQuit(msg.GetMessageId() == 0x9876);
VerifyOrQuit(msg.GetToken().GetLength() == 2);
VerifyOrQuit(msg.mMessage.GetOffset() == msg.mMessage.GetLength());
// Msg::UpdateType()
msg.UpdateType(Coap::kTypeConfirmable);
VerifyOrQuit(msg.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodePost);
VerifyOrQuit(msg.GetMessageId() == 0x9876);
VerifyOrQuit(message->ReadType() == Coap::kTypeConfirmable);
// Msg::UpdateMessageId()
msg.UpdateMessageId(0xabcd);
VerifyOrQuit(msg.GetType() == Coap::kTypeConfirmable);
VerifyOrQuit(msg.GetCode() == Coap::kCodePost);
VerifyOrQuit(msg.GetMessageId() == 0xabcd);
VerifyOrQuit(message->ReadMessageId() == 0xabcd);
}
message->Free();
testFreeInstance(instance);
}
};
} // namespace ot
int main(void)
{
ot::UnitTester::TestCoapMessage();
printf("All tests passed\n");
return 0;
}