diff --git a/include/openthread/types.h b/include/openthread/types.h index c501c7f5c..c5e48cc11 100644 --- a/include/openthread/types.h +++ b/include/openthread/types.h @@ -924,6 +924,8 @@ typedef struct otBufferInfo uint16_t mArpBuffers; ///< The number of buffers in the ARP send queue. uint16_t mCoapClientMessages; ///< The number of messages in the CoAP client send queue. uint16_t mCoapClientBuffers; ///< The number of buffers in the CoAP client send queue. + uint16_t mCoapServerMessages; ///< The number of messages in the CoAP server responses queue. + uint16_t mCoapServerBuffers; ///< The number of buffers in the CoAP server responses queue. } otBufferInfo; /** diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index f94573845..348978271 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -433,7 +433,8 @@ void Interpreter::ProcessBufferInfo(int argc, char *argv[]) sServer->OutputFormat("mpl: %d %d\r\n", bufferInfo.mMplMessages, bufferInfo.mMplBuffers); sServer->OutputFormat("mle: %d %d\r\n", bufferInfo.mMleMessages, bufferInfo.mMleBuffers); sServer->OutputFormat("arp: %d %d\r\n", bufferInfo.mArpMessages, bufferInfo.mArpBuffers); - sServer->OutputFormat("coap: %d %d\r\n", bufferInfo.mCoapClientMessages, bufferInfo.mCoapClientBuffers); + sServer->OutputFormat("coap client: %d %d\r\n", bufferInfo.mCoapClientMessages, bufferInfo.mCoapClientBuffers); + sServer->OutputFormat("coap server: %d %d\r\n", bufferInfo.mCoapServerMessages, bufferInfo.mCoapServerBuffers); AppendResult(kThreadError_None); } diff --git a/src/core/api/instance_api.cpp b/src/core/api/instance_api.cpp index 8301cc649..df2201494 100644 --- a/src/core/api/instance_api.cpp +++ b/src/core/api/instance_api.cpp @@ -65,7 +65,7 @@ otInstance::otInstance(void) : , mLinkRaw(*this) #endif // OPENTHREAD_ENABLE_RAW_LINK_API #if OPENTHREAD_ENABLE_APPLICATION_COAP - , mApplicationCoapServer(mIp6.mUdp, OT_DEFAULT_COAP_PORT) + , mApplicationCoapServer(mThreadNetif, OT_DEFAULT_COAP_PORT) #endif // OPENTHREAD_ENABLE_APPLICATION_COAP #if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL , mLogLevel(static_cast(OPENTHREAD_CONFIG_LOG_LEVEL)) diff --git a/src/core/api/message_api.cpp b/src/core/api/message_api.cpp index bcb754a55..07989d5f1 100644 --- a/src/core/api/message_api.cpp +++ b/src/core/api/message_api.cpp @@ -173,6 +173,9 @@ void otMessageGetBufferInfo(otInstance *aInstance, otBufferInfo *aBufferInfo) aInstance->mThreadNetif.GetCoapClient().GetRequestMessages().GetInfo(aBufferInfo->mCoapClientMessages, aBufferInfo->mCoapClientBuffers); + + aInstance->mThreadNetif.GetCoapServer().GetCachedResponses().GetInfo(aBufferInfo->mCoapServerMessages, + aBufferInfo->mCoapServerBuffers); } #ifdef __cplusplus diff --git a/src/core/coap/coap_base.hpp b/src/core/coap/coap_base.hpp index 098454aad..a91cce02a 100644 --- a/src/core/coap/coap_base.hpp +++ b/src/core/coap/coap_base.hpp @@ -51,6 +51,33 @@ namespace Coap { * */ +/** + * Protocol Constants (RFC 7252). + * + */ +enum +{ + kAckTimeout = OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT, + kAckRandomFactorNumerator = OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_NUMERATOR, + kAckRandomFactorDenominator = OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_DENOMINATOR, + kMaxRetransmit = OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT, + kNStart = 1, + kDefaultLeisure = 5, + kProbingRate = 1, + + // Note that 2 << (kMaxRetransmit - 1) is equal to kMaxRetransmit power of 2 + kMaxTransmitSpan = kAckTimeout * ((2 << (kMaxRetransmit - 1)) - 1) * + kAckRandomFactorNumerator / kAckRandomFactorDenominator, + kMaxTransmitWait = kAckTimeout * ((2 << kMaxRetransmit) - 1) * + kAckRandomFactorNumerator / kAckRandomFactorDenominator, + kMaxLatency = 100, + kProcessingDelay = kAckTimeout, + kMaxRtt = 2 * kMaxLatency + kProcessingDelay, + kExchangeLifetime = kMaxTransmitSpan + 2 * (kMaxLatency) + kProcessingDelay, + kNonLifetime = kMaxTransmitSpan + kMaxLatency +}; + + enum { kMeshCoPMessagePriority = Message::kPriorityHigh, // The priority for MeshCoP message diff --git a/src/core/coap/coap_client.cpp b/src/core/coap/coap_client.cpp index a55733bbd..8af285feb 100644 --- a/src/core/coap/coap_client.cpp +++ b/src/core/coap/coap_client.cpp @@ -87,7 +87,7 @@ ThreadError Client::SendMessage(Message &aMessage, const Ip6::MessageInfo &aMess Message *storedCopy = NULL; uint16_t copyLength = 0; - SuccessOrExit(error = header.FromMessage(aMessage, false)); + SuccessOrExit(error = header.FromMessage(aMessage, 0)); // Set Message Id if it was not already set. if (header.GetMessageId() == 0) @@ -335,7 +335,7 @@ Message *Client::FindRelatedRequest(const Header &aResponseHeader, const Ip6::Me aRequestMetadata.mDestinationAddress.IsAnycastRoutingLocator()) && (aRequestMetadata.mDestinationPort == aMessageInfo.GetPeerPort())) { - assert(aRequestHeader.FromMessage(*message, true) == kThreadError_None); + assert(aRequestHeader.FromMessage(*message, sizeof(RequestMetadata)) == kThreadError_None); switch (aResponseHeader.GetType()) { @@ -387,7 +387,7 @@ void Client::ProcessReceivedMessage(Message &aMessage, const Ip6::MessageInfo &a Message *message = NULL; ThreadError error; - SuccessOrExit(error = responseHeader.FromMessage(aMessage, false)); + SuccessOrExit(error = responseHeader.FromMessage(aMessage, 0)); aMessage.MoveOffset(responseHeader.GetLength()); message = FindRelatedRequest(responseHeader, aMessageInfo, requestHeader, requestMetadata); diff --git a/src/core/coap/coap_client.hpp b/src/core/coap/coap_client.hpp index 6c720159f..41455b427 100644 --- a/src/core/coap/coap_client.hpp +++ b/src/core/coap/coap_client.hpp @@ -48,32 +48,6 @@ namespace Coap { class Client; -/** - * Protocol Constants (RFC 7252). - * - */ -enum -{ - kAckTimeout = OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT, - kAckRandomFactorNumerator = OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_NUMERATOR, - kAckRandomFactorDenominator = OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_DENOMINATOR, - kMaxRetransmit = OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT, - kNStart = 1, - kDefaultLeisure = 5, - kProbingRate = 1, - - // Note that 2 << (kMaxRetransmit - 1) is equal to kMaxRetransmit power of 2 - kMaxTransmitSpan = kAckTimeout * ((2 << (kMaxRetransmit - 1)) - 1) * - kAckRandomFactorNumerator / kAckRandomFactorDenominator, - kMaxTransmitWait = kAckTimeout * ((2 << kMaxRetransmit) - 1) * - kAckRandomFactorNumerator / kAckRandomFactorDenominator, - kMaxLatency = 100, - kProcessingDelay = kAckTimeout, - kMaxRtt = 2 * kMaxLatency + kProcessingDelay, - kExchangeLifetime = kMaxTransmitSpan + 2 * (kMaxLatency) + kProcessingDelay, - kNonLifetime = kMaxTransmitSpan + kMaxLatency -}; - /** * This class implements metadata required for CoAP retransmission. * diff --git a/src/core/coap/coap_header.cpp b/src/core/coap/coap_header.cpp index 6e72cf9c2..1267bbce7 100644 --- a/src/core/coap/coap_header.cpp +++ b/src/core/coap/coap_header.cpp @@ -59,7 +59,7 @@ void Header::Init(Type aType, Code aCode) SetCode(aCode); } -ThreadError Header::FromMessage(const Message &aMessage, bool aCopiedMessage) +ThreadError Header::FromMessage(const Message &aMessage, uint16_t aMetadataSize) { ThreadError error = kThreadError_Parse; uint16_t offset = aMessage.GetOffset(); @@ -69,10 +69,7 @@ ThreadError Header::FromMessage(const Message &aMessage, bool aCopiedMessage) uint16_t optionDelta; uint16_t optionLength; - if (aCopiedMessage) - { - length -= sizeof(RequestMetadata); - } + length -= aMetadataSize; VerifyOrExit(length >= kTokenOffset, error = kThreadError_Parse); aMessage.Read(offset, kTokenOffset, mHeader.mBytes); diff --git a/src/core/coap/coap_header.hpp b/src/core/coap/coap_header.hpp index d9bd94f6c..8af76aab5 100644 --- a/src/core/coap/coap_header.hpp +++ b/src/core/coap/coap_header.hpp @@ -109,13 +109,13 @@ public: * This method parses the CoAP header from a message. * * @param[in] aMessage A reference to the message. - * @param[in] aCopiedMessage To indicate if this message is a copied one or not + * @param[in] aMetadataSize A size of metadata appended to the message. * * @retval kThreadError_None Successfully parsed the message. * @retval kThreadError_Parse Failed to parse the message. * */ - ThreadError FromMessage(const Message &aMessage, bool aCopiedMessage); + ThreadError FromMessage(const Message &aMessage, uint16_t aMetadataSize); /** * This method returns the Version value. diff --git a/src/core/coap/coap_server.cpp b/src/core/coap/coap_server.cpp index 1fe2382bc..0736a9ae3 100644 --- a/src/core/coap/coap_server.cpp +++ b/src/core/coap/coap_server.cpp @@ -33,12 +33,14 @@ #include #include +#include namespace Thread { namespace Coap { -Server::Server(Ip6::Udp &aUdp, uint16_t aPort, SenderFunction aSender, ReceiverFunction aReceiver): - CoapBase(aUdp, aSender, aReceiver) +Server::Server(Ip6::Netif &aNetif, uint16_t aPort, SenderFunction aSender, ReceiverFunction aReceiver): + CoapBase(aNetif.GetIp6().mUdp, aSender, aReceiver), + mResponsesQueue(aNetif) { mPort = aPort; mResources = NULL; @@ -54,6 +56,8 @@ ThreadError Server::Start(void) ThreadError Server::Stop(void) { + mResponsesQueue.DequeueAllResponses(); + return CoapBase::Stop(); } @@ -114,6 +118,8 @@ exit: ThreadError Server::SendMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { + mResponsesQueue.EnqueueResponse(aMessage, aMessageInfo); + return mSender(this, aMessage, aMessageInfo); } @@ -147,10 +153,26 @@ void Server::ProcessReceivedMessage(Message &aMessage, const Ip6::MessageInfo &a char uriPath[Resource::kMaxReceivedUriPath] = ""; char *curUriPath = uriPath; const Header::Option *coapOption; + Message *response; - SuccessOrExit(header.FromMessage(aMessage, false)); + SuccessOrExit(header.FromMessage(aMessage, 0)); aMessage.MoveOffset(header.GetLength()); + switch (mResponsesQueue.GetMatchedResponseCopy(header, aMessageInfo, &response)) + { + case kThreadError_None: + SendMessage(*response, aMessageInfo); + + // fall through + + case kThreadError_NoBufs: + ExitNow(); + + case kThreadError_NotFound: + default: + break; + } + coapOption = header.GetCurrentOption(); while (coapOption != NULL) @@ -204,5 +226,174 @@ ThreadError Server::SetPort(uint16_t aPort) return mSocket.Bind(sockaddr); } +ThreadError ResponsesQueue::GetMatchedResponseCopy(const Header &aHeader, + const Ip6::MessageInfo &aMessageInfo, + Message **aResponse) +{ + ThreadError error = kThreadError_NotFound; + Message *message; + EnqueuedResponseHeader enqueuedResponseHeader; + Ip6::MessageInfo messageInfo; + Header header; + + for (message = mQueue.GetHead(); message != NULL; message = message->GetNext()) + { + enqueuedResponseHeader.ReadFrom(*message); + messageInfo = enqueuedResponseHeader.GetMessageInfo(); + + // Check source endpoint + if (messageInfo.GetPeerPort() != aMessageInfo.GetPeerPort()) + { + continue; + } + + if (messageInfo.GetPeerAddr() != aMessageInfo.GetPeerAddr()) + { + continue; + } + + // Check Message Id + if (header.FromMessage(*message, sizeof(EnqueuedResponseHeader)) != kThreadError_None) + { + continue; + } + + if (header.GetMessageId() != aHeader.GetMessageId()) + { + continue; + } + + *aResponse = message->Clone(); + VerifyOrExit(*aResponse != NULL, error = kThreadError_NoBufs); + + EnqueuedResponseHeader::RemoveFrom(**aResponse); + + error = kThreadError_None; + break; + } + +exit: + return error; +} + +ThreadError ResponsesQueue::GetMatchedResponseCopy(const Message &aRequest, + const Ip6::MessageInfo &aMessageInfo, + Message **aResponse) +{ + ThreadError error = kThreadError_None; + Header header; + + SuccessOrExit(error = header.FromMessage(aRequest, 0)); + + error = GetMatchedResponseCopy(header, aMessageInfo, aResponse); + +exit: + return error; +} + +void ResponsesQueue::EnqueueResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) +{ + Header header; + Message *copy; + EnqueuedResponseHeader enqueuedResponseHeader(aMessageInfo); + uint16_t messageCount; + uint16_t bufferCount; + + SuccessOrExit(header.FromMessage(aMessage, 0)); + VerifyOrExit(header.GetType() == kCoapTypeAcknowledgment || + header.GetType() == kCoapTypeReset,); + + switch (GetMatchedResponseCopy(aMessage, aMessageInfo, ©)) + { + case kThreadError_NotFound: + break; + + case kThreadError_None: + copy->Free(); + + // fall through + + case kThreadError_NoBufs: + default: + ExitNow(); + } + + mQueue.GetInfo(messageCount, bufferCount); + + if (messageCount >= kMaxCachedResponses) + { + DequeueOldestResponse(); + } + + copy = aMessage.Clone(); + VerifyOrExit(copy != NULL,); + + enqueuedResponseHeader.AppendTo(*copy); + mQueue.Enqueue(*copy); + + if (!mTimer.IsRunning()) + { + mTimer.Start(Timer::SecToMsec(kExchangeLifetime)); + } + +exit: + return; +} + +void ResponsesQueue::DequeueOldestResponse(void) +{ + Message *message; + + VerifyOrExit((message = mQueue.GetHead()) != NULL,); + DequeueResponse(*message); + +exit: + return; +} + +void ResponsesQueue::DequeueAllResponses(void) +{ + Message *message; + + while ((message = mQueue.GetHead()) != NULL) + { + DequeueResponse(*message); + } +} + +void ResponsesQueue::HandleTimer(void *aContext) +{ + static_cast(aContext)->HandleTimer(); +} + +void ResponsesQueue::HandleTimer(void) +{ + Message *message; + EnqueuedResponseHeader enqueuedResponseHeader; + + while ((message = mQueue.GetHead()) != NULL) + { + enqueuedResponseHeader.ReadFrom(*message); + + if (enqueuedResponseHeader.IsEarlier(Timer::GetNow())) + { + DequeueResponse(*message); + } + else + { + mTimer.Start(enqueuedResponseHeader.GetRemainingTime()); + break; + } + } +} + +uint32_t EnqueuedResponseHeader::GetRemainingTime(void) const +{ + int32_t remainingTime = static_cast(mDequeueTime - Timer::GetNow()); + + return remainingTime >= 0 ? static_cast(remainingTime) : 0; +} + + } // namespace Coap } // namespace Thread diff --git a/src/core/coap/coap_server.hpp b/src/core/coap/coap_server.hpp index 7034e010f..6fd25030b 100644 --- a/src/core/coap/coap_server.hpp +++ b/src/core/coap/coap_server.hpp @@ -38,7 +38,10 @@ #include #include +#include #include +#include +#include #include namespace Thread { @@ -93,6 +96,190 @@ private: } }; +/** + * This class implements metadata required for caching CoAP responses. + * + */ +class EnqueuedResponseHeader +{ +public: + /** + * Default constructor creating empty object. + * + */ + EnqueuedResponseHeader(void): mDequeueTime(0), mMessageInfo() {} + + /** + * Constructor creating object with valid dequeue time and message info. + * + * @param[in] aMessageInfo The message info containing source endpoint identification. + * + */ + EnqueuedResponseHeader(const Ip6::MessageInfo &aMessageInfo): + mDequeueTime(Timer::GetNow() + Timer::SecToMsec(kExchangeLifetime)), + mMessageInfo(aMessageInfo) {} + + /** + * This method append metadata to the message. + * + * @param[in] aMessage A reference to the message. + * + * @retval kThreadError_None Successfully appended the bytes. + * @retval kThreadError_NoBufs Insufficient available buffers to grow the message. + */ + ThreadError AppendTo(Message &aMessage) const { return aMessage.Append(this, sizeof(*this)); } + + /** + * This method reads request data from the message. + * + * @param[in] aMessage A reference to the message. + * + * @returns The number of bytes read. + * + */ + uint16_t ReadFrom(const Message &aMessage) { + return aMessage.Read(aMessage.GetLength() - sizeof(*this), sizeof(*this), this); + } + + /** + * This method removes metadata from the message. + * + * @param[in] aMessage A reference to the message. + * + */ + static void RemoveFrom(Message &aMessage) { + assert(aMessage.SetLength(aMessage.GetLength() - sizeof(EnqueuedResponseHeader)) == kThreadError_None); + } + + /** + * This method checks if the message shall be sent before the given time. + * + * @param[in] aTime A time to compare. + * + * @retval TRUE If the message shall be sent before the given time. + * @retval FALSE Otherwise. + * + */ + bool IsEarlier(uint32_t aTime) const { return (static_cast(aTime - mDequeueTime) > 0); } + + /** + * This method returns number of milliseconds in which the message should be sent. + * + * @returns The number of milliseconds in which the message should be sent. + * + */ + uint32_t GetRemainingTime(void) const; + + /** + * This method returns the message info of cached CoAP response. + * + * @returns The message info of the cached CoAP response. + * + */ + const Ip6::MessageInfo &GetMessageInfo(void) const { return mMessageInfo; } + +private: + uint32_t mDequeueTime; + const Ip6::MessageInfo mMessageInfo; +}; + +/** + * This class caches CoAP responses to implement message deduplication. + * + */ +class ResponsesQueue +{ +public: + /** + * Default class constructor. + * + * @param[in] aNetif A reference to the network interface that CoAP server should be assigned to. + * + */ + ResponsesQueue(Ip6::Netif &aNetif): + mTimer(aNetif.GetIp6().mTimerScheduler, &ResponsesQueue::HandleTimer, this) {} + + /** + * Add given response to the cache. + * + * If matching response (the same Message ID, source endpoint address and port) exists in the cache given + * response is not added. + * The CoAP response is copied before it is added to the cache. + * + * @param[in] aMessage The CoAP response to add to the cache. + * @param[in] aMessageInfo The message info corresponding to @p aMessage. + * + */ + void EnqueueResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); + + /** + * Remove the oldest response from the cache. + * + */ + void DequeueOldestResponse(void); + + /** + * Remove all responses from the cache. + * + */ + void DequeueAllResponses(void); + + /** + * Get a copy of CoAP response from the cache that matches given Message ID and source endpoint. + * + * @param[in] aHeader The CoAP message header containing Message ID. + * @param[in] aMessageInfo The message info containing source endpoint address and port. + * @param[out] aResponse A pointer to a copy of a cached CoAP response matching given arguments. + * + * @retval kThreadError_None Matching response found and successfully created a copy. + * @retval kThreadError_NoBufs Matching response found but there is not sufficient buffer to create a copy. + * @retval kThreadError_NotFound Matching response not found. + * + */ + ThreadError GetMatchedResponseCopy(const Header &aHeader, + const Ip6::MessageInfo &aMessageInfo, + Message **aResponse); + + /** + * Get a copy of CoAP response from the cache that matches given Message ID and source endpoint. + * + * @param[in] aRequest The CoAP message containing Message ID. + * @param[in] aMessageInfo The message info containing source endpoint address and port. + * @param[out] aResponse A pointer to a copy of a cached CoAP response matching given arguments. + * + * @retval kThreadError_None Matching response found and successfully created a copy. + * @retval kThreadError_NoBufs Matching response found but there is not sufficient buffer to create a copy. + * @retval kThreadError_NotFound Matching response not found. + * @retval kThreadError_Parse Could not parse CoAP header in the request message. + * + */ + ThreadError GetMatchedResponseCopy(const Message &aRequest, + const Ip6::MessageInfo &aMessageInfo, + Message **aResponse); + + /** + * Get a reference to the cached CoAP responses queue. + * + * @returns A reference to the cached CoAP responses queue. + * + */ + const MessageQueue &GetResponses(void) const { return mQueue; } + +private: + enum + { + kMaxCachedResponses = OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES, + }; + + void DequeueResponse(Message &aMessage) { mQueue.Dequeue(aMessage); aMessage.Free(); } + + MessageQueue mQueue; + Timer mTimer; + + static void HandleTimer(void *aContext); + void HandleTimer(void); +}; + /** * This class implements the CoAP server. * @@ -103,13 +290,13 @@ public: /** * This constructor initializes the object. * - * @param[in] aUdp A reference to the UDP object. + * @param[in] aNetif A reference to the network interface that CoAP server should be assigned to. * @param[in] aPort The port to listen on. * @param[in] aSender A pointer to a function for sending messages. * @param[in] aReceiver A pointer to a function for handling received messages. * */ - Server(Ip6::Udp &aUdp, uint16_t aPort, SenderFunction aSender = &Server::Send, + Server(Ip6::Netif &aNetif, uint16_t aPort, SenderFunction aSender = &Server::Send, ReceiverFunction aReceiver = &Server::Receive); /** @@ -222,6 +409,8 @@ public: */ ThreadError SetPort(uint16_t aPort); + const MessageQueue &GetCachedResponses(void) const { return mResponsesQueue.GetResponses(); } + protected: void ProcessReceivedMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); @@ -236,8 +425,11 @@ private: uint16_t mPort; Resource *mResources; + + ResponsesQueue mResponsesQueue; }; + /** * @} * diff --git a/src/core/coap/secure_coap_server.cpp b/src/core/coap/secure_coap_server.cpp index f15ac6cd8..8eb92ffc1 100644 --- a/src/core/coap/secure_coap_server.cpp +++ b/src/core/coap/secure_coap_server.cpp @@ -42,7 +42,7 @@ namespace Thread { namespace Coap { SecureServer::SecureServer(ThreadNetif &aNetif, uint16_t aPort): - Server(aNetif.GetIp6().mUdp, aPort, &SecureServer::Send, &SecureServer::Receive), + Server(aNetif, aPort, &SecureServer::Send, &SecureServer::Receive), mTransmitCallback(NULL), mContext(NULL), mNetif(aNetif), diff --git a/src/core/openthread-core-default-config.h b/src/core/openthread-core-default-config.h index 709eb5e5a..7b1adb201 100644 --- a/src/core/openthread-core-default-config.h +++ b/src/core/openthread-core-default-config.h @@ -321,6 +321,18 @@ #define OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT 4 #endif // OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT +/** + * @def OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES + * + * Maximum number of cached responses for CoAP Confirmable messages. + * + * Cached responses are used for message deduplication. + * + */ +#ifndef OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES +#define OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES 10 +#endif // OPENTHREAD_CONFIG_COAP_SERVER_MAX_CACHED_RESPONSES + /** * @def OPENTHREAD_CONFIG_DNS_RESPONSE_TIMEOUT * diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp index ef2e58bdd..516199663 100644 --- a/src/core/thread/thread_netif.cpp +++ b/src/core/thread/thread_netif.cpp @@ -55,7 +55,7 @@ static const uint8_t kThreadMasterKey[] = ThreadNetif::ThreadNetif(Ip6::Ip6 &aIp6): Netif(aIp6, OT_NETIF_INTERFACE_ID_THREAD), - mCoapServer(aIp6.mUdp, kCoapUdpPort), + mCoapServer(*this, kCoapUdpPort), mCoapClient(*this), mAddressResolver(*this), #if OPENTHREAD_ENABLE_DHCP6_CLIENT