Separate response support (#1571)

* Move empty message to coap_base.

Both client and server needs this feature to handle separate
response.

* remove unnecessary check

* make CoapBase::SendEmptyMessage() private.

* add comment to indicate intentional fall through
This commit is contained in:
Buke Po
2017-04-10 10:17:21 -07:00
committed by Jonathan Hui
parent 84eee68a4f
commit e9f53b9e1d
4 changed files with 80 additions and 40 deletions
+26
View File
@@ -86,5 +86,31 @@ void CoapBase::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMes
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
ThreadError CoapBase::SendEmptyMessage(Header::Type aType, const Header &aRequestHeader,
const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
Coap::Header responseHeader;
Message *message = NULL;
VerifyOrExit(aRequestHeader.GetType() == kCoapTypeConfirmable, error = kThreadError_InvalidArgs);
responseHeader.Init(aType, kCoapCodeEmpty);
responseHeader.SetMessageId(aRequestHeader.GetMessageId());
VerifyOrExit((message = NewMessage(responseHeader)) != NULL, error = kThreadError_NoBufs);
SuccessOrExit(error = mSender(this, *message, aMessageInfo));
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
} // namespace Coap
} // namespace Thread
+46
View File
@@ -152,6 +152,36 @@ public:
*/
uint16_t GetPort(void) { return mSocket.GetSockName().mPort; };
/**
* This method sends a CoAP reset message.
*
* @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 SendReset(Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo) {
return SendEmptyMessage(kCoapTypeReset, aRequestHeader, aMessageInfo);
};
/**
* This method sends a CoAP ACK empty message which is used in Separate Response for confirmable requests.
*
* @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 SendAck(Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo) {
return SendEmptyMessage(kCoapTypeAcknowledgment, aRequestHeader, aMessageInfo);
};
protected:
ThreadError Start(const Ip6::SockAddr &aSockAddr);
ThreadError Stop(void);
@@ -161,6 +191,22 @@ protected:
ReceiverFunction mReceiver;
private:
/**
* This method sends a CoAP empty message, i.e. a header-only message with code equals kCoapCodeEmpty.
*
* @param[in] aType The message type
* @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 SendEmptyMessage(Header::Type aType, const Header &aRequestHeader,
const Ip6::MessageInfo &aMessageInfo);
static void HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
};
+8 -32
View File
@@ -229,31 +229,6 @@ exit:
return error;
}
void Client::SendEmptyMessage(const Ip6::Address &aAddress, uint16_t aPort, uint16_t aMessageId, Header::Type aType)
{
Header header;
Ip6::MessageInfo messageInfo;
Message *message;
ThreadError error = kThreadError_None;
header.Init(aType, kCoapCodeEmpty);
header.SetMessageId(aMessageId);
VerifyOrExit((message = NewMessage(header)) != NULL);
messageInfo.SetPeerAddr(aAddress);
messageInfo.SetPeerPort(aPort);
SuccessOrExit(error = mSender(this, *message, messageInfo));
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
}
void Client::HandleRetransmissionTimer(void *aContext)
{
static_cast<Client *>(aContext)->HandleRetransmissionTimer();
@@ -435,13 +410,14 @@ void Client::ProcessReceivedMessage(Message &aMessage, const Ip6::MessageInfo &a
break;
case kCoapTypeConfirmable:
case kCoapTypeNonConfirmable:
if (responseHeader.IsConfirmable())
{
// Send empty ACK if it is a CON message.
SendEmptyAck(aMessageInfo.GetPeerAddr(), aMessageInfo.GetPeerPort(), responseHeader.GetMessageId());
}
// Send empty ACK if it is a CON message.
SendAck(responseHeader, aMessageInfo);
// fall through
;
case kCoapTypeNonConfirmable:
// Separate response.
FinalizeCoapTransaction(*message, requestMetadata, &responseHeader, &aMessage, &aMessageInfo, kThreadError_None);
break;
@@ -454,7 +430,7 @@ exit:
if (responseHeader.IsConfirmable() || responseHeader.IsNonConfirmable())
{
// Successfully parsed a header but no matching request was found - reject the message by sending reset.
SendReset(aMessageInfo.GetPeerAddr(), aMessageInfo.GetPeerPort(), responseHeader.GetMessageId());
SendReset(responseHeader, aMessageInfo);
}
}
}
-8
View File
@@ -241,14 +241,6 @@ private:
Message *aResponse, const Ip6::MessageInfo *aMessageInfo, ThreadError aResult);
ThreadError SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void SendEmptyMessage(const Ip6::Address &aAddress, uint16_t aPort, uint16_t aMessageId, Header::Type aType);
void SendReset(const Ip6::Address &aAddress, uint16_t aPort, uint16_t aMessageId) {
SendEmptyMessage(aAddress, aPort, aMessageId, kCoapTypeReset);
};
void SendEmptyAck(const Ip6::Address &aAddress, uint16_t aPort, uint16_t aMessageId) {
SendEmptyMessage(aAddress, aPort, aMessageId, kCoapTypeAcknowledgment);
};
static void HandleRetransmissionTimer(void *aContext);
void HandleRetransmissionTimer(void);