diff --git a/src/core/coap/coap.cpp b/src/core/coap/coap.cpp index bb76b5326..9613d95c7 100644 --- a/src/core/coap/coap.cpp +++ b/src/core/coap/coap.cpp @@ -245,15 +245,36 @@ exit: return error; } -ThreadError Coap::SendEmptyAck(const Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo) +ThreadError Coap::SendHeaderResponse(Header::Code aCode, const Header &aRequestHeader, + const Ip6::MessageInfo &aMessageInfo) { ThreadError error = kThreadError_None; Header responseHeader; + Header::Type requestType; Message *message = NULL; - VerifyOrExit(aRequestHeader.GetType() == kCoapTypeConfirmable, error = kThreadError_InvalidArgs); + VerifyOrExit(aRequestHeader.IsRequest(), error = kThreadError_InvalidArgs); - responseHeader.SetDefaultResponseHeader(aRequestHeader); + requestType = aRequestHeader.GetType(); + + switch (requestType) + { + case kCoapTypeConfirmable: + responseHeader.Init(kCoapTypeAcknowledgment, aCode); + responseHeader.SetMessageId(aRequestHeader.GetMessageId()); + break; + + case kCoapTypeNonConfirmable: + responseHeader.Init(kCoapTypeNonConfirmable, aCode); + responseHeader.SetMessageId(mMessageId++); + break; + + default: + ExitNow(error = kThreadError_InvalidArgs); + break; + } + + responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength()); VerifyOrExit((message = NewMessage(responseHeader)) != NULL, error = kThreadError_NoBufs); @@ -614,20 +635,20 @@ void Coap::ProcessReceivedRequest(Header &aHeader, Message &aMessage, const Ip6: char uriPath[Resource::kMaxReceivedUriPath] = ""; char *curUriPath = uriPath; const Header::Option *coapOption; - Message *response = NULL; - ThreadError error = kThreadError_None; + Message *cachedResponse = NULL; + ThreadError error = kThreadError_NotFound; if (mInterceptor != NULL) { - SuccessOrExit(mInterceptor(aMessage, aMessageInfo)); + SuccessOrExit(error = mInterceptor(aMessage, aMessageInfo)); } aMessage.MoveOffset(aHeader.GetLength()); - switch (mResponsesQueue.GetMatchedResponseCopy(aHeader, aMessageInfo, &response)) + switch (mResponsesQueue.GetMatchedResponseCopy(aHeader, aMessageInfo, &cachedResponse)) { case kThreadError_None: - error = Send(*response, aMessageInfo); + error = Send(*cachedResponse, aMessageInfo); // fall through ; @@ -671,6 +692,7 @@ void Coap::ProcessReceivedRequest(Header &aHeader, Message &aMessage, const Ip6: if (strcmp(resource->mUriPath, uriPath) == 0) { resource->HandleRequest(aHeader, aMessage, aMessageInfo); + error = kThreadError_None; ExitNow(); } } @@ -678,13 +700,24 @@ void Coap::ProcessReceivedRequest(Header &aHeader, Message &aMessage, const Ip6: if (mDefaultHandler) { mDefaultHandler(mDefaultHandlerContext, &aHeader, &aMessage, &aMessageInfo); + error = kThreadError_None; } exit: - if (error != kThreadError_None && response != NULL) + if (error != kThreadError_None) { - response->Free(); + otLogInfoCoapErr(mNetif.GetInstance(), error, "Failed to process request"); + + if (error == kThreadError_NotFound) + { + SendNotFound(aHeader, aMessageInfo); + } + + if (cachedResponse != NULL) + { + cachedResponse->Free(); + } } return; diff --git a/src/core/coap/coap.hpp b/src/core/coap/coap.hpp index 22c4e0a96..681c6af81 100644 --- a/src/core/coap/coap.hpp +++ b/src/core/coap/coap.hpp @@ -551,6 +551,20 @@ public: return SendEmptyMessage(kCoapTypeReset, aRequestHeader, aMessageInfo); }; + /** + * This method sends header-only CoAP response message. + * + * @param[in] aCode The CoAP code of this response. + * @param[in] aRequestHeader A reference to the CoAP Header that was used in CoAP request. + * @param[in] aMessageInfo The message info corresponding to the CoAP request. + * + * @retval kThreadError_None Successfully enqueued the CoAP response message. + * @retval kThreadError_NoBufs Insufficient buffers available to send the CoAP response. + * @retval kThreadError_InvalidArgs The @p aRequestHeader header is not of confirmable type. + * + */ + ThreadError SendHeaderResponse(Header::Code aCode, const Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo); + /** * This method sends a CoAP ACK empty message which is used in Separate Response for confirmable requests. * @@ -577,7 +591,25 @@ public: * @retval kThreadError_InvalidArgs The @p aRequestHeader header is not of confirmable type. * */ - ThreadError SendEmptyAck(const Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo); + ThreadError SendEmptyAck(const Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo) { + return (aRequestHeader.GetType() == kCoapTypeConfirmable ? + SendHeaderResponse(kCoapResponseChanged, aRequestHeader, aMessageInfo) : + kThreadError_InvalidArgs); + } + + /** + * This method sends a header-only CoAP message to indicate no resource matched for the request. + * + * @param[in] aRequestHeader A reference to the CoAP Header that was used in CoAP request. + * @param[in] aMessageInfo The message info corresponding to the CoAP request. + * + * @retval kThreadError_None Successfully enqueued the CoAP response message. + * @retval kThreadError_NoBufs Insufficient buffers available to send the CoAP response. + * + */ + ThreadError SendNotFound(const Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo) { + return SendHeaderResponse(kCoapResponseNotFound, aRequestHeader, aMessageInfo); + } /** * This method aborts CoAP transactions associated with given handler and context.