diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp index a8556de99..fd9ef695d 100644 --- a/src/core/coap/coap.cpp +++ b/src/core/coap/coap.cpp @@ -126,7 +126,21 @@ exit: otError CoapBase::Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - return mSender(*this, aMessage, aMessageInfo); + otError error; + +#if OPENTHREAD_CONFIG_OTNS_ENABLE + Get().EmitCoapSend(static_cast(aMessage), aMessageInfo); +#endif + + error = mSender(*this, aMessage, aMessageInfo); + +#if OPENTHREAD_CONFIG_OTNS_ENABLE + if (error != OT_ERROR_NONE) + { + Get().EmitCoapSendFailure(error, static_cast(aMessage), aMessageInfo); + } +#endif + return error; } otError CoapBase::SendMessage(Message & aMessage, @@ -531,6 +545,10 @@ void CoapBase::Receive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageIn { ProcessReceivedResponse(message, aMessageInfo); } + +#if OPENTHREAD_CONFIG_OTNS_ENABLE + Get().EmitCoapReceive(message, aMessageInfo); +#endif } void CoapBase::ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) @@ -666,11 +684,9 @@ exit: void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - char uriPath[Resource::kMaxReceivedUriPath + 1]; - char * curUriPath = uriPath; - Message * cachedResponse = nullptr; - otError error = OT_ERROR_NOT_FOUND; - Option::Iterator iterator; + char uriPath[Message::kMaxReceivedUriPath + 1]; + Message *cachedResponse = nullptr; + otError error = OT_ERROR_NOT_FOUND; if (mInterceptor != nullptr) { @@ -693,26 +709,7 @@ void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo break; } - SuccessOrExit(error = iterator.Init(aMessage, kOptionUriPath)); - - while (!iterator.IsDone()) - { - uint16_t optionLength = iterator.GetOption()->GetLength(); - - if (curUriPath != uriPath) - { - *curUriPath++ = '/'; - } - - VerifyOrExit(curUriPath + optionLength < OT_ARRAY_END(uriPath), error = OT_ERROR_PARSE); - - IgnoreError(iterator.ReadOptionValue(curUriPath)); - curUriPath += optionLength; - - SuccessOrExit(error = iterator.Advance(kOptionUriPath)); - } - - *curUriPath = '\0'; + SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath)); for (const Resource *resource = mResources.GetHead(); resource; resource = resource->GetNext()) { diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp index aec4e253e..1177995e9 100644 --- a/src/core/coap/coap.hpp +++ b/src/core/coap/coap.hpp @@ -146,11 +146,6 @@ class Resource : public otCoapResource, public LinkedListEntry friend class CoapBase; public: - enum - { - kMaxReceivedUriPath = 32, ///< Maximum supported URI path on received messages. - }; - /** * This constructor initializes the resource. * diff --git a/src/core/coap/coap_message.cpp b/src/core/coap/coap_message.cpp index 67320f2e5..552cc7f07 100644 --- a/src/core/coap/coap_message.cpp +++ b/src/core/coap/coap_message.cpp @@ -227,6 +227,37 @@ exit: return error; } +otError Message::ReadUriPathOptions(char (&aUriPath)[kMaxReceivedUriPath + 1]) const +{ + char * curUriPath = aUriPath; + otError error = OT_ERROR_NONE; + Option::Iterator iterator; + + SuccessOrExit(error = iterator.Init(*this, kOptionUriPath)); + + while (!iterator.IsDone()) + { + uint16_t optionLength = iterator.GetOption()->GetLength(); + + if (curUriPath != aUriPath) + { + *curUriPath++ = '/'; + } + + VerifyOrExit(curUriPath + optionLength < OT_ARRAY_END(aUriPath), error = OT_ERROR_PARSE); + + IgnoreError(iterator.ReadOptionValue(curUriPath)); + curUriPath += optionLength; + + SuccessOrExit(error = iterator.Advance(kOptionUriPath)); + } + + *curUriPath = '\0'; + +exit: + return error; +} + otError Message::AppendBlockOption(Message::BlockType aType, uint32_t aNum, bool aMore, otCoapBlockSize aSize) { otError error = OT_ERROR_NONE; diff --git a/src/core/coap/coap_message.hpp b/src/core/coap/coap_message.hpp index c44de7cb1..445941ace 100644 --- a/src/core/coap/coap_message.hpp +++ b/src/core/coap/coap_message.hpp @@ -166,6 +166,7 @@ public: enum : uint8_t { kDefaultTokenLength = OT_COAP_DEFAULT_TOKEN_LENGTH, ///< Default token length + kMaxReceivedUriPath = 32, ///< Maximum supported URI path on received messages. kMaxTokenLength = OT_COAP_MAX_TOKEN_LENGTH, ///< Maximum token length. }; @@ -470,6 +471,18 @@ public: */ otError AppendUriPathOptions(const char *aUriPath); + /** + * This method reads the Uri-Path options and constructs the URI path in the buffer referenced by @p `aUriPath`. + * + * @param[in] aUriPath A reference to the buffer for storing URI path. + * NOTE: The buffer size must be `kMaxReceivedUriPath + 1`. + * + * @retval OT_ERROR_NONE Successfully read the Uri-Path options. + * @retval OT_ERROR_PARSE CoAP Option header not well-formed. + * + */ + otError ReadUriPathOptions(char (&aUriPath)[kMaxReceivedUriPath + 1]) const; + /** * This method appends a Block option * diff --git a/src/core/utils/otns.cpp b/src/core/utils/otns.cpp index 0e0647f91..f75b3423b 100644 --- a/src/core/utils/otns.cpp +++ b/src/core/utils/otns.cpp @@ -155,6 +155,55 @@ void Otns::EmitDeviceMode(Mle::DeviceMode aMode) aMode.IsFullNetworkData() ? "n" : ""); } +void Otns::EmitCoapSend(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + char uriPath[Coap::Message::kMaxReceivedUriPath + 1]; + otError error; + + SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath)); + + EmitStatus("coap=send,%d,%d,%d,%s,%s,%d", aMessage.GetMessageId(), aMessage.GetType(), aMessage.GetCode(), uriPath, + aMessageInfo.GetPeerAddr().ToString().AsCString(), aMessageInfo.GetPeerPort()); +exit: + if (error != OT_ERROR_NONE) + { + otLogWarnCore("Otns::EmitCoapSend failed: %s", otThreadErrorToString(error)); + } +} + +void Otns::EmitCoapReceive(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + char uriPath[Coap::Message::kMaxReceivedUriPath + 1]; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath)); + + EmitStatus("coap=recv,%d,%d,%d,%s,%s,%d", aMessage.GetMessageId(), aMessage.GetType(), aMessage.GetCode(), uriPath, + aMessageInfo.GetPeerAddr().ToString().AsCString(), aMessageInfo.GetPeerPort()); +exit: + if (error != OT_ERROR_NONE) + { + otLogWarnCore("Otns::EmitCoapReceive failed: %s", otThreadErrorToString(error)); + } +} + +void Otns::EmitCoapSendFailure(otError aError, Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + char uriPath[Coap::Message::kMaxReceivedUriPath + 1]; + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath)); + + EmitStatus("coap=send_error,%d,%d,%d,%s,%s,%d,%s", aMessage.GetMessageId(), aMessage.GetType(), aMessage.GetCode(), + uriPath, aMessageInfo.GetPeerAddr().ToString().AsCString(), aMessageInfo.GetPeerPort(), + otThreadErrorToString(aError)); +exit: + if (error != OT_ERROR_NONE) + { + otLogWarnCore("Otns::EmitCoapSendFailure failed: %s", otThreadErrorToString(error)); + } +} + } // namespace Utils } // namespace ot diff --git a/src/core/utils/otns.hpp b/src/core/utils/otns.hpp index c83ce7ddf..2d670d958 100644 --- a/src/core/utils/otns.hpp +++ b/src/core/utils/otns.hpp @@ -42,6 +42,7 @@ #include #include +#include "coap/coap_message.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" #include "common/notifier.hpp" @@ -142,6 +143,34 @@ public: */ static void EmitDeviceMode(Mle::DeviceMode aMode); + /** + * This function emits the sending COAP message info to OTNS. + * + * @param[in] aMessage The sending COAP message. + * @param[in] aMessageInfo The message info. + * + */ + static void EmitCoapSend(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + /** + * This function emits the COAP message sending failure to OTNS. + * + * @param[in] aError The error in sending the COAP message. + * @param[in] aMessage The COAP message failed to send. + * @param[in] aMessageInfo The message info. + * + */ + static void EmitCoapSendFailure(otError aError, Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + /** + * This function emits the received COAP message info to OTNS. + * + * @param[in] aMessage The received COAP message. + * @param[in] aMessageInfo The message info. + * + */ + static void EmitCoapReceive(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + private: static void EmitStatus(const char *aFmt, ...); void HandleNotifierEvents(Events aEvents);