mirror of
https://github.com/espressif/openthread.git
synced 2026-09-06 09:10:04 +00:00
[coap] update/simplify CoAP Options generation/processing (#5503)
This commit simplifies the generation/processing of CoAP Options in a CoAP message. It adds helper methods `ReadExtendedOptionField()`, `WriteExtendedOptionField` to decode/encode extended Option Header fields (Option Number Delta or Option Length). It simplifies `Option::Iterator` (using `Init()`/`Advance()` to parse and iterate through all CoAP Options in a message). Note that the public OT `otCoap` APIs and their behavior remain as before and unchanged.
This commit is contained in:
@@ -169,37 +169,49 @@ const uint8_t *otCoapMessageGetToken(const otMessage *aMessage)
|
||||
|
||||
otError otCoapOptionIteratorInit(otCoapOptionIterator *aIterator, const otMessage *aMessage)
|
||||
{
|
||||
return static_cast<Coap::OptionIterator *>(aIterator)->Init(static_cast<const Coap::Message *>(aMessage));
|
||||
return static_cast<Coap::Option::Iterator *>(aIterator)->Init(*static_cast<const Coap::Message *>(aMessage));
|
||||
}
|
||||
|
||||
const otCoapOption *otCoapOptionIteratorGetFirstOptionMatching(otCoapOptionIterator *aIterator, uint16_t aOption)
|
||||
{
|
||||
return static_cast<Coap::OptionIterator *>(aIterator)->GetFirstOptionMatching(aOption);
|
||||
Coap::Option::Iterator &iterator = *static_cast<Coap::Option::Iterator *>(aIterator);
|
||||
|
||||
IgnoreError(iterator.Init(iterator.GetMessage(), aOption));
|
||||
return iterator.GetOption();
|
||||
}
|
||||
|
||||
const otCoapOption *otCoapOptionIteratorGetFirstOption(otCoapOptionIterator *aIterator)
|
||||
{
|
||||
return static_cast<Coap::OptionIterator *>(aIterator)->GetFirstOption();
|
||||
Coap::Option::Iterator &iterator = *static_cast<Coap::Option::Iterator *>(aIterator);
|
||||
|
||||
IgnoreError(iterator.Init(iterator.GetMessage()));
|
||||
return iterator.GetOption();
|
||||
}
|
||||
|
||||
const otCoapOption *otCoapOptionIteratorGetNextOptionMatching(otCoapOptionIterator *aIterator, uint16_t aOption)
|
||||
{
|
||||
return static_cast<Coap::OptionIterator *>(aIterator)->GetNextOptionMatching(aOption);
|
||||
Coap::Option::Iterator &iterator = *static_cast<Coap::Option::Iterator *>(aIterator);
|
||||
|
||||
IgnoreError(iterator.Advance(aOption));
|
||||
return iterator.GetOption();
|
||||
}
|
||||
|
||||
const otCoapOption *otCoapOptionIteratorGetNextOption(otCoapOptionIterator *aIterator)
|
||||
{
|
||||
return static_cast<Coap::OptionIterator *>(aIterator)->GetNextOption();
|
||||
Coap::Option::Iterator &iterator = *static_cast<Coap::Option::Iterator *>(aIterator);
|
||||
|
||||
IgnoreError(iterator.Advance());
|
||||
return iterator.GetOption();
|
||||
}
|
||||
|
||||
otError otCoapOptionIteratorGetOptionUintValue(otCoapOptionIterator *aIterator, uint64_t *const aValue)
|
||||
{
|
||||
return static_cast<Coap::OptionIterator *>(aIterator)->GetOptionValue(*aValue);
|
||||
return static_cast<Coap::Option::Iterator *>(aIterator)->ReadOptionValue(*aValue);
|
||||
}
|
||||
|
||||
otError otCoapOptionIteratorGetOptionValue(otCoapOptionIterator *aIterator, void *aValue)
|
||||
{
|
||||
return static_cast<Coap::OptionIterator *>(aIterator)->GetOptionValue(aValue);
|
||||
return static_cast<Coap::Option::Iterator *>(aIterator)->ReadOptionValue(aValue);
|
||||
}
|
||||
|
||||
otError otCoapSendRequestWithParameters(otInstance * aInstance,
|
||||
|
||||
+28
-31
@@ -171,18 +171,18 @@ otError CoapBase::SendMessage(Message & aMessage,
|
||||
|
||||
#if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
|
||||
// Whether or not to turn on special "Observe" handling.
|
||||
OptionIterator iterator;
|
||||
bool observe;
|
||||
Option::Iterator iterator;
|
||||
bool observe;
|
||||
|
||||
SuccessOrExit(error = iterator.Init(&aMessage));
|
||||
observe = (iterator.GetFirstOptionMatching(kOptionObserve) != nullptr);
|
||||
SuccessOrExit(error = iterator.Init(aMessage, kOptionObserve));
|
||||
observe = !iterator.IsDone();
|
||||
|
||||
// Special case, if we're sending a GET with Observe=1, that is a cancellation.
|
||||
if (observe && aMessage.IsGetRequest())
|
||||
{
|
||||
uint64_t observeVal = 0;
|
||||
|
||||
SuccessOrExit(error = iterator.GetOptionValue(observeVal));
|
||||
SuccessOrExit(error = iterator.ReadOptionValue(observeVal));
|
||||
|
||||
if (observeVal == 1)
|
||||
{
|
||||
@@ -570,10 +570,10 @@ void CoapBase::ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo
|
||||
if (metadata.mObserve && request->IsRequest())
|
||||
{
|
||||
// We sent Observe in our request, see if we received Observe in the response too.
|
||||
OptionIterator iterator;
|
||||
Option::Iterator iterator;
|
||||
|
||||
SuccessOrExit(error = iterator.Init(&aMessage));
|
||||
responseObserve = (iterator.GetFirstOptionMatching(kOptionObserve) != nullptr);
|
||||
SuccessOrExit(error = iterator.Init(aMessage, kOptionObserve));
|
||||
responseObserve = !iterator.IsDone();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -687,11 +687,11 @@ exit:
|
||||
|
||||
void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
{
|
||||
char uriPath[Resource::kMaxReceivedUriPath];
|
||||
char * curUriPath = uriPath;
|
||||
Message * cachedResponse = nullptr;
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
OptionIterator iterator;
|
||||
char uriPath[Resource::kMaxReceivedUriPath];
|
||||
char * curUriPath = uriPath;
|
||||
Message * cachedResponse = nullptr;
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
Option::Iterator iterator;
|
||||
|
||||
if (mInterceptor != nullptr)
|
||||
{
|
||||
@@ -714,29 +714,26 @@ void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo
|
||||
break;
|
||||
}
|
||||
|
||||
SuccessOrExit(error = iterator.Init(&aMessage));
|
||||
for (const otCoapOption *option = iterator.GetFirstOption(); option != nullptr; option = iterator.GetNextOption())
|
||||
SuccessOrExit(error = iterator.Init(aMessage, kOptionUriPath));
|
||||
|
||||
while (!iterator.IsDone())
|
||||
{
|
||||
switch (option->mNumber)
|
||||
uint16_t optionLength = iterator.GetOption()->GetLength();
|
||||
|
||||
if (curUriPath != uriPath)
|
||||
{
|
||||
case kOptionUriPath:
|
||||
if (curUriPath != uriPath)
|
||||
{
|
||||
*curUriPath++ = '/';
|
||||
}
|
||||
|
||||
VerifyOrExit(option->mLength < sizeof(uriPath) - static_cast<size_t>(curUriPath + 1 - uriPath), OT_NOOP);
|
||||
|
||||
IgnoreError(iterator.GetOptionValue(curUriPath));
|
||||
curUriPath += option->mLength;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
*curUriPath++ = '/';
|
||||
}
|
||||
|
||||
VerifyOrExit(curUriPath + optionLength < OT_ARRAY_END(uriPath), OT_NOOP);
|
||||
|
||||
IgnoreError(iterator.ReadOptionValue(curUriPath));
|
||||
curUriPath += optionLength;
|
||||
|
||||
SuccessOrExit(error = iterator.Advance(kOptionUriPath));
|
||||
}
|
||||
|
||||
curUriPath[0] = '\0';
|
||||
*curUriPath = '\0';
|
||||
|
||||
for (const Resource *resource = mResources.GetHead(); resource; resource = resource->GetNext())
|
||||
{
|
||||
|
||||
+193
-227
@@ -112,60 +112,71 @@ void Message::Finish(void)
|
||||
Write(0, GetOptionStart(), &GetHelpData().mHeader);
|
||||
}
|
||||
|
||||
uint8_t Message::WriteExtendedOptionField(uint16_t aValue, uint8_t *&aBuffer)
|
||||
{
|
||||
/*
|
||||
* This method encodes a CoAP Option header field (Option Delta/Length) per
|
||||
* RFC 7252. The returned value is a 4-bit unsigned integer. Extended fields
|
||||
* (if needed) are written into the given buffer `aBuffer` and the pointer
|
||||
* would also be updated.
|
||||
*
|
||||
* If `aValue < 13 (kOption1ByteExtensionOffset)`, it is returned as is
|
||||
* (no extension).
|
||||
*
|
||||
* If `13 <= aValue < 269 (kOption2ByteExtensionOffset)`, one-byte
|
||||
* extension is used, and the value minus 13 is written in `aBuffer` as an
|
||||
* 8-bit unsigned integer, and `13 (kOption1ByteExtension)` is returned.
|
||||
*
|
||||
* If `269 <= aValue`, two-byte extension is used and the value minis 269
|
||||
* is written as a 16-bit unsigned integer and `14 (kOption2ByteExtension)`
|
||||
* is returned.
|
||||
*
|
||||
*/
|
||||
|
||||
uint8_t rval;
|
||||
|
||||
if (aValue < kOption1ByteExtensionOffset)
|
||||
{
|
||||
rval = static_cast<uint8_t>(aValue);
|
||||
}
|
||||
else if (aValue < kOption2ByteExtensionOffset)
|
||||
{
|
||||
rval = kOption1ByteExtension;
|
||||
*aBuffer = static_cast<uint8_t>(aValue - kOption1ByteExtensionOffset);
|
||||
aBuffer += sizeof(uint8_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
rval = kOption2ByteExtension;
|
||||
Encoding::BigEndian::WriteUint16(aValue - kOption2ByteExtensionOffset, aBuffer);
|
||||
aBuffer += sizeof(uint16_t);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
otError Message::AppendOption(uint16_t aNumber, uint16_t aLength, const void *aValue)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t optionDelta = aNumber - GetHelpData().mOptionLast;
|
||||
uint16_t optionLength;
|
||||
uint8_t buf[kMaxOptionHeaderSize] = {0};
|
||||
uint8_t *cur = &buf[1];
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t delta;
|
||||
uint8_t header[kMaxOptionHeaderSize];
|
||||
uint16_t headerLength;
|
||||
uint8_t *cur;
|
||||
|
||||
// Assure that no option is inserted out of order.
|
||||
VerifyOrExit(aNumber >= GetHelpData().mOptionLast, error = OT_ERROR_INVALID_ARGS);
|
||||
delta = aNumber - GetHelpData().mOptionLast;
|
||||
|
||||
// Calculate the total option size and check the buffers.
|
||||
optionLength = 1 + aLength;
|
||||
optionLength += optionDelta < kOption1ByteExtensionOffset ? 0 : (optionDelta < kOption2ByteExtensionOffset ? 1 : 2);
|
||||
optionLength += aLength < kOption1ByteExtensionOffset ? 0 : (aLength < kOption2ByteExtensionOffset ? 1 : 2);
|
||||
VerifyOrExit(GetLength() + optionLength < kMaxHeaderLength, error = OT_ERROR_NO_BUFS);
|
||||
cur = &header[1];
|
||||
|
||||
// Insert option delta.
|
||||
if (optionDelta < kOption1ByteExtensionOffset)
|
||||
{
|
||||
*buf = (optionDelta << kOptionDeltaOffset) & kOptionDeltaMask;
|
||||
}
|
||||
else if (optionDelta < kOption2ByteExtensionOffset)
|
||||
{
|
||||
*buf |= kOption1ByteExtension << kOptionDeltaOffset;
|
||||
*cur++ = (optionDelta - kOption1ByteExtensionOffset) & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
*buf |= kOption2ByteExtension << kOptionDeltaOffset;
|
||||
optionDelta -= kOption2ByteExtensionOffset;
|
||||
*cur++ = optionDelta >> 8;
|
||||
*cur++ = optionDelta & 0xff;
|
||||
}
|
||||
header[0] = static_cast<uint8_t>(WriteExtendedOptionField(delta, cur) << kOptionDeltaOffset);
|
||||
header[0] |= static_cast<uint8_t>(WriteExtendedOptionField(aLength, cur) << kOptionLengthOffset);
|
||||
|
||||
// Insert option length.
|
||||
if (aLength < kOption1ByteExtensionOffset)
|
||||
{
|
||||
*buf |= aLength;
|
||||
}
|
||||
else if (aLength < kOption2ByteExtensionOffset)
|
||||
{
|
||||
*buf |= kOption1ByteExtension;
|
||||
*cur++ = (aLength - kOption1ByteExtensionOffset) & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
*buf |= kOption2ByteExtension;
|
||||
optionLength = aLength - kOption2ByteExtensionOffset;
|
||||
*cur++ = optionLength >> 8;
|
||||
*cur++ = optionLength & 0xff;
|
||||
}
|
||||
headerLength = static_cast<uint16_t>(cur - header);
|
||||
|
||||
SuccessOrExit(error = Append(buf, static_cast<uint16_t>(cur - buf)));
|
||||
VerifyOrExit(static_cast<uint32_t>(GetLength()) + headerLength + aLength < kMaxHeaderLength,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
|
||||
SuccessOrExit(error = Append(header, headerLength));
|
||||
SuccessOrExit(error = Append(aValue, aLength));
|
||||
|
||||
GetHelpData().mOptionLast = aNumber;
|
||||
@@ -178,13 +189,12 @@ exit:
|
||||
|
||||
otError Message::AppendUintOption(uint16_t aNumber, uint32_t aValue)
|
||||
{
|
||||
uint16_t length = sizeof(aValue);
|
||||
uint8_t *value;
|
||||
uint8_t buffer[sizeof(uint32_t)];
|
||||
const uint8_t *value = &buffer[0];
|
||||
uint16_t length = sizeof(uint32_t);
|
||||
|
||||
aValue = Encoding::BigEndian::HostSwap32(aValue);
|
||||
value = reinterpret_cast<uint8_t *>(&aValue);
|
||||
Encoding::BigEndian::WriteUint32(aValue, buffer);
|
||||
|
||||
// skip preceding zeros
|
||||
while (value[0] == 0 && length > 0)
|
||||
{
|
||||
value++;
|
||||
@@ -199,11 +209,6 @@ otError Message::AppendStringOption(uint16_t aNumber, const char *aValue)
|
||||
return AppendOption(aNumber, static_cast<uint16_t>(strlen(aValue)), aValue);
|
||||
}
|
||||
|
||||
otError Message::AppendObserveOption(uint32_t aObserve)
|
||||
{
|
||||
return AppendUintOption(kOptionObserve, aObserve & 0xFFFFFF);
|
||||
}
|
||||
|
||||
otError Message::AppendUriPathOptions(const char *aUriPath)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
@@ -240,30 +245,10 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Message::AppendProxyUriOption(const char *aProxyUri)
|
||||
{
|
||||
return AppendStringOption(kOptionProxyUri, aProxyUri);
|
||||
}
|
||||
|
||||
otError Message::AppendContentFormatOption(otCoapOptionContentFormat aContentFormat)
|
||||
{
|
||||
return AppendUintOption(kOptionContentFormat, static_cast<uint32_t>(aContentFormat));
|
||||
}
|
||||
|
||||
otError Message::AppendMaxAgeOption(uint32_t aMaxAge)
|
||||
{
|
||||
return AppendUintOption(kOptionMaxAge, aMaxAge);
|
||||
}
|
||||
|
||||
otError Message::AppendUriQueryOption(const char *aUriQuery)
|
||||
{
|
||||
return AppendStringOption(kOptionUriQuery, aUriQuery);
|
||||
}
|
||||
|
||||
otError Message::SetPayloadMarker(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t marker = 0xff;
|
||||
uint8_t marker = kPayloadMarker;
|
||||
|
||||
VerifyOrExit(GetLength() < kMaxHeaderLength, error = OT_ERROR_NO_BUFS);
|
||||
SuccessOrExit(error = Append(&marker, sizeof(marker)));
|
||||
@@ -278,8 +263,8 @@ exit:
|
||||
|
||||
otError Message::ParseHeader(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
OptionIterator iterator;
|
||||
otError error = OT_ERROR_NONE;
|
||||
Option::Iterator iterator;
|
||||
|
||||
OT_ASSERT(mBuffer.mHead.mMetadata.mReserved >=
|
||||
sizeof(GetHelpData()) +
|
||||
@@ -292,13 +277,14 @@ otError Message::ParseHeader(void)
|
||||
|
||||
VerifyOrExit(GetTokenLength() <= kMaxTokenLength, error = OT_ERROR_PARSE);
|
||||
|
||||
SuccessOrExit(error = iterator.Init(this));
|
||||
for (const otCoapOption *option = iterator.GetFirstOption(); option != nullptr; option = iterator.GetNextOption())
|
||||
SuccessOrExit(error = iterator.Init(*this));
|
||||
|
||||
while (!iterator.IsDone())
|
||||
{
|
||||
SuccessOrExit(error = iterator.Advance());
|
||||
}
|
||||
|
||||
VerifyOrExit(iterator.mNextOptionOffset > 0, error = OT_ERROR_PARSE);
|
||||
GetHelpData().mHeaderLength = iterator.mNextOptionOffset - GetHelpData().mHeaderOffset;
|
||||
GetHelpData().mHeaderLength = iterator.GetPayloadMessageOffset() - GetHelpData().mHeaderOffset;
|
||||
MoveOffset(GetHelpData().mHeaderLength);
|
||||
|
||||
exit:
|
||||
@@ -327,6 +313,13 @@ otError Message::SetToken(uint8_t aTokenLength)
|
||||
return SetToken(token, aTokenLength);
|
||||
}
|
||||
|
||||
bool Message::IsTokenEqual(const Message &aMessage) const
|
||||
{
|
||||
uint8_t tokenLength = GetTokenLength();
|
||||
|
||||
return ((tokenLength == aMessage.GetTokenLength()) && (memcmp(GetToken(), aMessage.GetToken(), tokenLength) == 0));
|
||||
}
|
||||
|
||||
otError Message::SetDefaultResponseHeader(const Message &aRequest)
|
||||
{
|
||||
Init(kTypeAck, kCodeChanged);
|
||||
@@ -448,194 +441,167 @@ const char *Message::CodeToString(void) const
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
|
||||
|
||||
otError OptionIterator::Init(const Message *aMessage)
|
||||
otError Option::Iterator::Init(const Message &aMessage)
|
||||
{
|
||||
otError err = OT_ERROR_NONE;
|
||||
otError error = OT_ERROR_PARSE;
|
||||
uint32_t offset = static_cast<uint32_t>(aMessage.GetHelpData().mHeaderOffset) + aMessage.GetOptionStart();
|
||||
|
||||
/*
|
||||
* Check that:
|
||||
* Length - Offset: the length of the payload
|
||||
* is greater than:
|
||||
* Start position of options
|
||||
*
|
||||
* → Check options start before the message ends, or bail ::Init with
|
||||
* OT_ERROR_PARSE as the reason.
|
||||
*/
|
||||
VerifyOrExit(aMessage->GetLength() - aMessage->GetHelpData().mHeaderOffset >= aMessage->GetOptionStart(),
|
||||
err = OT_ERROR_PARSE);
|
||||
// Note that the case where `offset == aMessage.GetLength())` is
|
||||
// valid and indicates an empty payload (no CoAP Option and no
|
||||
// Payload Marker).
|
||||
|
||||
mMessage = aMessage;
|
||||
GetFirstOption();
|
||||
VerifyOrExit(offset <= aMessage.GetLength(), MarkAsParseErrored());
|
||||
|
||||
mOption.mNumber = 0;
|
||||
mOption.mLength = 0;
|
||||
mMessage = &aMessage;
|
||||
mNextOptionOffset = static_cast<uint16_t>(offset);
|
||||
|
||||
error = Advance();
|
||||
|
||||
exit:
|
||||
return err;
|
||||
return error;
|
||||
}
|
||||
|
||||
const otCoapOption *OptionIterator::GetFirstOptionMatching(uint16_t aOption)
|
||||
otError Option::Iterator::Advance(void)
|
||||
{
|
||||
const otCoapOption *rval = nullptr;
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t headerByte;
|
||||
uint16_t optionDelta;
|
||||
uint16_t optionLength;
|
||||
|
||||
for (const otCoapOption *option = GetFirstOption(); option != nullptr; option = GetNextOption())
|
||||
VerifyOrExit(!IsDone(), OT_NOOP);
|
||||
|
||||
error = Read(sizeof(uint8_t), &headerByte);
|
||||
|
||||
if ((error != OT_ERROR_NONE) || (headerByte == Message::kPayloadMarker))
|
||||
{
|
||||
if (option->mNumber == aOption)
|
||||
// Payload Marker indicates end of options and start of payload.
|
||||
// Absence of a Payload Marker indicates a zero-length payload.
|
||||
|
||||
MarkAsDone();
|
||||
|
||||
if (error == OT_ERROR_NONE)
|
||||
{
|
||||
// Found, stop searching
|
||||
rval = option;
|
||||
break;
|
||||
// The presence of a marker followed by a zero-length payload
|
||||
// MUST be processed as a message format error.
|
||||
|
||||
VerifyOrExit(mNextOptionOffset < GetMessage().GetLength(), error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
ExitNow(error = OT_ERROR_NONE);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
optionDelta = (headerByte & Message::kOptionDeltaMask) >> Message::kOptionDeltaOffset;
|
||||
SuccessOrExit(error = ReadExtendedOptionField(optionDelta));
|
||||
|
||||
const otCoapOption *OptionIterator::GetFirstOption(void)
|
||||
{
|
||||
const otCoapOption *option = nullptr;
|
||||
const Message & message = GetMessage();
|
||||
|
||||
ClearOption();
|
||||
|
||||
mNextOptionOffset = message.GetHelpData().mHeaderOffset + message.GetOptionStart();
|
||||
|
||||
if (mNextOptionOffset < message.GetLength())
|
||||
{
|
||||
option = GetNextOption();
|
||||
}
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
const otCoapOption *OptionIterator::GetNextOptionMatching(uint16_t aOption)
|
||||
{
|
||||
const otCoapOption *rval = nullptr;
|
||||
|
||||
for (const otCoapOption *option = GetNextOption(); option != nullptr; option = GetNextOption())
|
||||
{
|
||||
if (option->mNumber == aOption)
|
||||
{
|
||||
// Found, stop searching
|
||||
rval = option;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
const otCoapOption *OptionIterator::GetNextOption(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t optionDelta;
|
||||
uint16_t optionLength;
|
||||
uint8_t buf[Message::kMaxOptionHeaderSize];
|
||||
uint8_t * cur = buf + 1;
|
||||
otCoapOption * rval = nullptr;
|
||||
const Message &message = GetMessage();
|
||||
|
||||
VerifyOrExit(mNextOptionOffset < message.GetLength(), error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
message.Read(mNextOptionOffset, sizeof(buf), buf);
|
||||
|
||||
optionDelta = buf[0] >> 4;
|
||||
optionLength = buf[0] & 0xf;
|
||||
mNextOptionOffset += sizeof(uint8_t);
|
||||
|
||||
if (optionDelta < Message::kOption1ByteExtension)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if (optionDelta == Message::kOption1ByteExtension)
|
||||
{
|
||||
optionDelta = Message::kOption1ByteExtensionOffset + cur[0];
|
||||
mNextOptionOffset += sizeof(uint8_t);
|
||||
cur++;
|
||||
}
|
||||
else if (optionDelta == Message::kOption2ByteExtension)
|
||||
{
|
||||
optionDelta = Message::kOption2ByteExtensionOffset + static_cast<uint16_t>((cur[0] << 8) | cur[1]);
|
||||
mNextOptionOffset += sizeof(uint16_t);
|
||||
cur += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// RFC7252 (Section 3):
|
||||
// Reserved for payload marker.
|
||||
VerifyOrExit(optionLength == 0xf, error = OT_ERROR_PARSE);
|
||||
|
||||
// The presence of a marker followed by a zero-length payload MUST be processed
|
||||
// as a message format error.
|
||||
VerifyOrExit(mNextOptionOffset < message.GetLength(), error = OT_ERROR_PARSE);
|
||||
|
||||
ExitNow(error = OT_ERROR_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (optionLength < Message::kOption1ByteExtension)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if (optionLength == Message::kOption1ByteExtension)
|
||||
{
|
||||
optionLength = Message::kOption1ByteExtensionOffset + cur[0];
|
||||
mNextOptionOffset += sizeof(uint8_t);
|
||||
}
|
||||
else if (optionLength == Message::kOption2ByteExtension)
|
||||
{
|
||||
optionLength = Message::kOption2ByteExtensionOffset + static_cast<uint16_t>((cur[0] << 8) | cur[1]);
|
||||
mNextOptionOffset += sizeof(uint16_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
VerifyOrExit(optionLength <= message.GetLength() - mNextOptionOffset, error = OT_ERROR_PARSE);
|
||||
|
||||
rval = &mOption;
|
||||
rval->mNumber += optionDelta;
|
||||
rval->mLength = optionLength;
|
||||
optionLength = (headerByte & Message::kOptionLengthMask) >> Message::kOptionLengthOffset;
|
||||
SuccessOrExit(error = ReadExtendedOptionField(optionLength));
|
||||
|
||||
VerifyOrExit(optionLength <= GetMessage().GetLength() - mNextOptionOffset, error = OT_ERROR_PARSE);
|
||||
mNextOptionOffset += optionLength;
|
||||
|
||||
mOption.mNumber += optionDelta;
|
||||
mOption.mLength = optionLength;
|
||||
|
||||
exit:
|
||||
if (error == OT_ERROR_PARSE)
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
mNextOptionOffset = 0;
|
||||
MarkAsParseErrored();
|
||||
}
|
||||
|
||||
return rval;
|
||||
return error;
|
||||
}
|
||||
|
||||
otError OptionIterator::GetOptionValue(uint64_t &aValue) const
|
||||
otError Option::Iterator::ReadOptionValue(void *aValue) const
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t value[sizeof(aValue)];
|
||||
|
||||
VerifyOrExit(mOption.mLength <= sizeof(aValue), error = OT_ERROR_NO_BUFS);
|
||||
SuccessOrExit(error = GetOptionValue(value));
|
||||
VerifyOrExit(!IsDone(), error = OT_ERROR_NOT_FOUND);
|
||||
GetMessage().Read(mNextOptionOffset - mOption.mLength, mOption.mLength, aValue);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Option::Iterator::ReadOptionValue(uint64_t &aUintValue) const
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t buffer[sizeof(uint64_t)];
|
||||
|
||||
VerifyOrExit(!IsDone(), error = OT_ERROR_NOT_FOUND);
|
||||
|
||||
VerifyOrExit(mOption.mLength <= sizeof(uint64_t), error = OT_ERROR_NO_BUFS);
|
||||
IgnoreError(ReadOptionValue(buffer));
|
||||
|
||||
aUintValue = 0;
|
||||
|
||||
aValue = 0;
|
||||
for (uint16_t pos = 0; pos < mOption.mLength; pos++)
|
||||
{
|
||||
aValue <<= 8;
|
||||
aValue |= value[pos];
|
||||
aUintValue <<= CHAR_BIT;
|
||||
aUintValue |= buffer[pos];
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError OptionIterator::GetOptionValue(void *aValue) const
|
||||
otError Option::Iterator::Read(uint16_t aLength, void *aBuffer)
|
||||
{
|
||||
// Reads `aLength` bytes from the message into `aBuffer` at
|
||||
// `mNextOptionOffset` and updates the `mNextOptionOffset` on a
|
||||
// successful read (i.e., when entire `aLength` bytes can be read).
|
||||
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(GetMessage().Read(mNextOptionOffset, aLength, aBuffer) == aLength, error = OT_ERROR_PARSE);
|
||||
mNextOptionOffset += aLength;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Option::Iterator::ReadExtendedOptionField(uint16_t &aValue)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mNextOptionOffset > 0, error = OT_ERROR_NOT_FOUND);
|
||||
VerifyOrExit(aValue >= Message::kOption1ByteExtension, OT_NOOP);
|
||||
|
||||
VerifyOrExit(GetMessage().Read(mNextOptionOffset - mOption.mLength, mOption.mLength, aValue) == mOption.mLength,
|
||||
error = OT_ERROR_PARSE);
|
||||
if (aValue == Message::kOption1ByteExtension)
|
||||
{
|
||||
uint8_t value8;
|
||||
|
||||
SuccessOrExit(error = Read(sizeof(uint8_t), &value8));
|
||||
aValue = static_cast<uint16_t>(value8) + Message::kOption1ByteExtensionOffset;
|
||||
}
|
||||
else if (aValue == Message::kOption2ByteExtension)
|
||||
{
|
||||
uint16_t value16;
|
||||
|
||||
SuccessOrExit(error = Read(sizeof(uint16_t), &value16));
|
||||
value16 = Encoding::BigEndian::HostSwap16(value16);
|
||||
aValue = value16 + Message::kOption2ByteExtensionOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_PARSE;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Option::Iterator::InitOrAdvance(const Message *aMessage, uint16_t aNumber)
|
||||
{
|
||||
otError error = (aMessage != nullptr) ? Init(*aMessage) : Advance();
|
||||
|
||||
while ((error == OT_ERROR_NONE) && !IsDone() && (GetOption()->GetNumber() != aNumber))
|
||||
{
|
||||
error = Advance();
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Coap
|
||||
} // namespace ot
|
||||
|
||||
+183
-85
@@ -66,7 +66,7 @@ using ot::Encoding::BigEndian::HostSwap16;
|
||||
*
|
||||
*/
|
||||
|
||||
class OptionIterator;
|
||||
class Option;
|
||||
|
||||
/**
|
||||
* CoAP Type values.
|
||||
@@ -159,7 +159,7 @@ enum : uint16_t
|
||||
*/
|
||||
class Message : public ot::Message
|
||||
{
|
||||
friend class OptionIterator;
|
||||
friend class Option;
|
||||
|
||||
public:
|
||||
enum : uint8_t
|
||||
@@ -404,16 +404,14 @@ public:
|
||||
* @retval FALSE If Tokens differ in length or value.
|
||||
*
|
||||
*/
|
||||
bool IsTokenEqual(const Message &aMessage) const
|
||||
{
|
||||
return ((GetTokenLength() == aMessage.GetTokenLength()) &&
|
||||
(memcmp(GetToken(), aMessage.GetToken(), GetTokenLength()) == 0));
|
||||
}
|
||||
bool IsTokenEqual(const Message &aMessage) const;
|
||||
|
||||
/**
|
||||
* This method appends a CoAP option.
|
||||
*
|
||||
* @param[in] aOption The CoAP Option.
|
||||
* @param[in] aNumber The CoAP Option number.
|
||||
* @param[in] aLength The CoAP Option length.
|
||||
* @param[in] aValue A pointer to the CoAP Option value (@p aLength bytes are used as Option value).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully appended the option.
|
||||
* @retval OT_ERROR_INVALID_ARGS The option type is not equal or greater than the last option type.
|
||||
@@ -423,8 +421,7 @@ public:
|
||||
otError AppendOption(uint16_t aNumber, uint16_t aLength, const void *aValue);
|
||||
|
||||
/**
|
||||
* This method appends an unsigned integer CoAP option as specified in
|
||||
* https://tools.ietf.org/html/rfc7252#section-3.2
|
||||
* This method appends an unsigned integer CoAP option as specified in RFC-7252 section-3.2
|
||||
*
|
||||
* @param[in] aNumber The CoAP Option number.
|
||||
* @param[in] aValue The CoAP Option unsigned integer value.
|
||||
@@ -458,7 +455,7 @@ public:
|
||||
* @retval OT_ERROR_INVALID_ARGS The option type is not equal or greater than the last option type.
|
||||
* @retval OT_ERROR_NO_BUFS The option length exceeds the buffer size.
|
||||
*/
|
||||
otError AppendObserveOption(uint32_t aObserve);
|
||||
otError AppendObserveOption(uint32_t aObserve) { return AppendUintOption(kOptionObserve, aObserve & kObserveMask); }
|
||||
|
||||
/**
|
||||
* This method appends a Uri-Path option.
|
||||
@@ -497,7 +494,7 @@ public:
|
||||
* @retval OT_ERROR_NO_BUFS The option length exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
otError AppendProxyUriOption(const char *aProxyUri);
|
||||
otError AppendProxyUriOption(const char *aProxyUri) { return AppendStringOption(kOptionProxyUri, aProxyUri); }
|
||||
|
||||
/**
|
||||
* This method appends a Content-Format option.
|
||||
@@ -509,7 +506,10 @@ public:
|
||||
* @retval OT_ERROR_NO_BUFS The option length exceeds the buffer size.
|
||||
*
|
||||
*/
|
||||
otError AppendContentFormatOption(otCoapOptionContentFormat aContentFormat);
|
||||
otError AppendContentFormatOption(otCoapOptionContentFormat aContentFormat)
|
||||
{
|
||||
return AppendUintOption(kOptionContentFormat, static_cast<uint32_t>(aContentFormat));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method appends a Max-Age option.
|
||||
@@ -520,7 +520,7 @@ public:
|
||||
* @retval OT_ERROR_INVALID_ARGS The option type is not equal or greater than the last option type.
|
||||
* @retval OT_ERROR_NO_BUFS The option length exceeds the buffer size.
|
||||
*/
|
||||
otError AppendMaxAgeOption(uint32_t aMaxAge);
|
||||
otError AppendMaxAgeOption(uint32_t aMaxAge) { return AppendUintOption(kOptionMaxAge, aMaxAge); }
|
||||
|
||||
/**
|
||||
* This method appends a single Uri-Query option.
|
||||
@@ -531,7 +531,7 @@ public:
|
||||
* @retval OT_ERROR_INVALID_ARGS The option type is not equal or greater than the last option type.
|
||||
* @retval OT_ERROR_NO_BUFS The option length exceeds the buffer size.
|
||||
*/
|
||||
otError AppendUriQueryOption(const char *aUriQuery);
|
||||
otError AppendUriQueryOption(const char *aUriQuery) { return AppendStringOption(kOptionUriQuery, aUriQuery); }
|
||||
|
||||
/**
|
||||
* This method adds Payload Marker indicating beginning of the payload to the CoAP header.
|
||||
@@ -788,9 +788,12 @@ private:
|
||||
kOptionLengthOffset = 0,
|
||||
kOptionLengthMask = 0xf << kOptionLengthOffset,
|
||||
|
||||
kMaxOptionHeaderSize = 5,
|
||||
kOption1ByteExtension = 13, // Indicates a 1 byte extension (RFC 7252).
|
||||
kOption2ByteExtension = 14, // Indicates a 2 byte extension (RFC 7252).
|
||||
kMaxOptionHeaderSize = 5,
|
||||
|
||||
kOption1ByteExtension = 13, // Indicates a one-byte extension.
|
||||
kOption2ByteExtension = 14, // Indicates a two-byte extension.
|
||||
|
||||
kPayloadMarker = 0xff,
|
||||
|
||||
kHelpDataAlignment = sizeof(uint16_t), ///< Alignment of help data.
|
||||
};
|
||||
@@ -811,9 +814,10 @@ private:
|
||||
kBlockNumOffset = 4,
|
||||
};
|
||||
|
||||
enum
|
||||
enum : uint32_t
|
||||
{
|
||||
kBlockNumMax = 0xFFFFF,
|
||||
kObserveMask = 0xffffff,
|
||||
kBlockNumMax = 0xffff,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -858,6 +862,8 @@ private:
|
||||
GetHelpData().mHeader.mVersionTypeToken &= ~kTokenLengthMask;
|
||||
GetHelpData().mHeader.mVersionTypeToken |= ((aTokenLength << kTokenLengthOffset) & kTokenLengthMask);
|
||||
}
|
||||
|
||||
uint8_t WriteExtendedOptionField(uint16_t aValue, uint8_t *&aBuffer);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -911,88 +917,180 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* This class acts as an iterator for CoAP options.
|
||||
* This class represents a CoAP option.
|
||||
*
|
||||
*/
|
||||
class OptionIterator : public ::otCoapOptionIterator
|
||||
class Option : public otCoapOption
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Initialize the state of the iterator to iterate over the given message.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully initialized
|
||||
* @retval OT_ERROR_PARSE Message state is inconsistent
|
||||
* This class represents an iterator for CoAP options.
|
||||
*
|
||||
*/
|
||||
otError Init(const Message *aMessage);
|
||||
class Iterator : public otCoapOptionIterator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the iterator to iterate over CoAP Options in a CoAP message.
|
||||
*
|
||||
* The iterator MUST be initialized before any other methods are used, otherwise its behavior is undefined.
|
||||
*
|
||||
* After initialization, the iterator is either updated to point to the first option, or it is marked as done
|
||||
* (i.e., `IsDone()` returns `true`) when there is no option or if there is a parse error.
|
||||
*
|
||||
* @param[in] aMessage The CoAP message.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully initialized. Iterator is either at the first option or done.
|
||||
* @retval OT_ERROR_PARSE CoAP Option header in @p aMessage is not well-formed.
|
||||
*
|
||||
*/
|
||||
otError Init(const Message &aMessage);
|
||||
|
||||
/**
|
||||
* This method initializes the iterator to iterate over CoAP Options in a CoAP message matching a given Option
|
||||
* Number value.
|
||||
*
|
||||
* The iterator MUST be initialized before any other methods are used, otherwise its behavior is undefined.
|
||||
*
|
||||
* After initialization, the iterator is either updated to point to the first option matching the given Option
|
||||
* Number value, or it is marked as done (i.e., `IsDone()` returns `true`) when there is no matching option or
|
||||
* if there is a parse error.
|
||||
*
|
||||
* @param[in] aMessage The CoAP message.
|
||||
* @param[in] aNumber The CoAP Option Number.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully initialized. Iterator is either at the first matching option or done.
|
||||
* @retval OT_ERROR_PARSE CoAP Option header in @p aMessage is not well-formed.
|
||||
*
|
||||
*/
|
||||
otError Init(const Message &aMessage, uint16_t aNumber) { return InitOrAdvance(&aMessage, aNumber); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the iterator is done (i.e., has reached the end of CoAP Option Header).
|
||||
*
|
||||
* @retval TRUE Iterator is done (reached end of Option header).
|
||||
* @retval FALSE Iterator is not done and currently pointing to a CoAP Option.
|
||||
*
|
||||
*/
|
||||
bool IsDone(void) const { return mOption.mLength == kIteratorDoneLength; }
|
||||
|
||||
/**
|
||||
* This method 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; }
|
||||
|
||||
/**
|
||||
* This method advances the iterator to the next CoAP Option in the header.
|
||||
*
|
||||
* The iterator is updated to point to the next option or marked as done when there are no more options.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully advanced the iterator.
|
||||
* @retval OT_ERROR_PARSE CoAP Option header is not well-formed.
|
||||
*
|
||||
*/
|
||||
otError Advance(void);
|
||||
|
||||
/**
|
||||
* This method advances the iterator to the next CoAP Option in the header matching a given Option Number value.
|
||||
*
|
||||
* The iterator is updated to point to the next matching option or marked as done when there are no more
|
||||
* matching options.
|
||||
*
|
||||
* @param[in] aNumber The CoAP Option Number.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully advanced the iterator.
|
||||
* @retval OT_ERROR_PARSE CoAP Option header is not well-formed.
|
||||
*
|
||||
*/
|
||||
otError Advance(uint16_t aNumber) { return InitOrAdvance(nullptr, aNumber); }
|
||||
|
||||
/**
|
||||
* This method gets the CoAP message associated with the iterator.
|
||||
*
|
||||
* @returns A reference to the CoAP message.
|
||||
*
|
||||
*/
|
||||
const Message &GetMessage(void) const { return *static_cast<const Message *>(mMessage); }
|
||||
|
||||
/**
|
||||
* This methods gets a pointer to the current CoAP Option to which the iterator is currently pointing.
|
||||
*
|
||||
* @returns A pointer to the current CoAP Option, or nullptr if iterator is done (or there was an earlier
|
||||
* parse error).
|
||||
*
|
||||
*/
|
||||
const Option *GetOption(void) const { return IsDone() ? nullptr : static_cast<const Option *>(&mOption); }
|
||||
|
||||
/**
|
||||
* This method reads the current Option Value into a given buffer.
|
||||
*
|
||||
* @param[out] aValue The pointer to a buffer to copy the Option Value. The buffer is assumed to be
|
||||
* sufficiently large (i.e. at least `GetOption()->GetLength()` bytes).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully read and copied the Option Value into given buffer.
|
||||
* @retval OT_ERROR_NOT_FOUND Iterator is done (not pointing to any option).
|
||||
*
|
||||
*/
|
||||
otError ReadOptionValue(void *aValue) const;
|
||||
|
||||
/**
|
||||
* This method read the current Option Value which is assumed to be an unsigned integer.
|
||||
*
|
||||
* @param[out] aValue A reference to `uint64_t` to output the read Option Value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully read the Option value.
|
||||
* @retval OT_ERROR_NO_BUFS Value is too long to fit in an `uint64_t`.
|
||||
* @retval OT_ERROR_NOT_FOUND Iterator is done (not pointing to any option).
|
||||
*
|
||||
*/
|
||||
otError ReadOptionValue(uint64_t &aValue) const;
|
||||
|
||||
/**
|
||||
* This method gets the offset of beginning of the CoAP message payload (after the CoAP header).
|
||||
*
|
||||
* This method MUST be used after the iterator is done (i.e. iterated through all options).
|
||||
*
|
||||
* @returns The offset of beginning of the CoAP message payload
|
||||
*
|
||||
*/
|
||||
uint16_t GetPayloadMessageOffset(void) const { return mNextOptionOffset; }
|
||||
|
||||
private:
|
||||
enum : uint16_t
|
||||
{
|
||||
kIteratorDoneLength = 0xffff, // `mOption.mLength` value to indicate iterator is done.
|
||||
kNextOptionOffsetParseError = 0, // Special `mNextOptionOffset` value to indicate a parse error.
|
||||
};
|
||||
|
||||
void MarkAsDone(void) { mOption.mLength = kIteratorDoneLength; }
|
||||
void MarkAsParseErrored(void) { MarkAsDone(), mNextOptionOffset = kNextOptionOffsetParseError; }
|
||||
|
||||
otError Read(uint16_t aLength, void *aBuffer);
|
||||
otError ReadExtendedOptionField(uint16_t &aValue);
|
||||
otError InitOrAdvance(const Message *aMessage, uint16_t aNumber);
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the first option matching the given option number.
|
||||
* This method gets the CoAP Option Number.
|
||||
*
|
||||
* The internal option pointer is advanced until matching option is seen, if no matching
|
||||
* option is seen, the iterator will advance to the end of the options block.
|
||||
* @returns The CoAP Option Number.
|
||||
*
|
||||
* @param[in] aOption Option number to look for.
|
||||
*
|
||||
* @returns A pointer to the first matching option. If no option matching @p aOption is seen, nullptr pointer is
|
||||
* returned.
|
||||
*/
|
||||
const otCoapOption *GetFirstOptionMatching(uint16_t aOption);
|
||||
uint16_t GetNumber(void) const { return mNumber; }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the first option.
|
||||
* This method gets the CoAP Option Length (length of Option Value in bytes).
|
||||
*
|
||||
* @returns A pointer to the first option. If no option is present nullptr pointer is returned.
|
||||
*/
|
||||
const otCoapOption *GetFirstOption(void);
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the next option matching the given option number.
|
||||
*
|
||||
* The internal option pointer is advanced until matching option is seen, if no matching
|
||||
* option is seen, the iterator will advance to the end of the options block.
|
||||
*
|
||||
* @param[in] aOption Option number to look for.
|
||||
*
|
||||
* @returns A pointer to the next matching option (relative to current iterator position). If no option matching @p
|
||||
* aOption is seen, nullptr pointer is returned.
|
||||
*/
|
||||
const otCoapOption *GetNextOptionMatching(uint16_t aOption);
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the next option.
|
||||
*
|
||||
* @returns A pointer to the next option. If no more options are present nullptr pointer is returned.
|
||||
*/
|
||||
const otCoapOption *GetNextOption(void);
|
||||
|
||||
/**
|
||||
* This function fills current option value into @p aValue. The option is assumed to be an unsigned integer.
|
||||
*
|
||||
* @param[out] aValue Buffer to store the option value.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully filled value.
|
||||
* @retval OT_ERROR_NOT_FOUND No more options, aIterator->mNextOptionOffset is set to offset of payload.
|
||||
* @retval OT_ERROR_NO_BUFS Value is too long to fit in a uint64_t.
|
||||
* @returns The CoAP Option Length (in bytes).
|
||||
*
|
||||
*/
|
||||
otError GetOptionValue(uint64_t &aValue) const;
|
||||
|
||||
/**
|
||||
* This function fills current option value into @p aValue.
|
||||
*
|
||||
* @param[out] aValue Buffer to store the option value. This buffer is assumed to be sufficiently large
|
||||
* (see @ref otCoapOption::mLength).
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully filled value.
|
||||
* @retval OT_ERROR_NOT_FOUND No more options, mNextOptionOffset is set to offset of payload.
|
||||
*
|
||||
*/
|
||||
otError GetOptionValue(void *aValue) const;
|
||||
|
||||
private:
|
||||
void ClearOption(void) { memset(&mOption, 0, sizeof(mOption)); }
|
||||
const Message &GetMessage(void) const { return *static_cast<const Message *>(mMessage); }
|
||||
uint16_t GetLength(void) const { return mLength; }
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user