mirror of
https://github.com/espressif/openthread.git
synced 2026-08-10 12:47:47 +00:00
[coap] make transmission parameters dynamically configurable (#4481)
This commit is contained in:
@@ -361,6 +361,40 @@ typedef struct otCoapResource
|
||||
struct otCoapResource *mNext; ///< The next CoAP resource in the list
|
||||
} otCoapResource;
|
||||
|
||||
/**
|
||||
* This structure represents the CoAP transmission parameters.
|
||||
*
|
||||
*/
|
||||
typedef struct otCoapTxParameters
|
||||
{
|
||||
/**
|
||||
* Minimum spacing before first retransmission when ACK is not received, in milliseconds (RFC7252 default value is
|
||||
* 2000ms).
|
||||
*
|
||||
*/
|
||||
uint32_t mAckTimeout;
|
||||
|
||||
/**
|
||||
* Numerator of ACK_RANDOM_FACTOR used to calculate maximum spacing before first retransmission when ACK is not
|
||||
* received (RFC7252 default value of ACK_RANDOM_FACTOR is 1.5; must not be decreased below 1).
|
||||
*
|
||||
*/
|
||||
uint8_t mAckRandomFactorNumerator;
|
||||
|
||||
/**
|
||||
* Denominator of ACK_RANDOM_FACTOR used to calculate maximum spacing before first retransmission when ACK is not
|
||||
* received (RFC7252 default value of ACK_RANDOM_FACTOR is 1.5; must not be decreased below 1).
|
||||
*
|
||||
*/
|
||||
uint8_t mAckRandomFactorDenominator;
|
||||
|
||||
/**
|
||||
* Maximum number of retransmissions for CoAP Confirmable messages (RFC7252 default value is 4).
|
||||
*
|
||||
*/
|
||||
uint8_t mMaxRetransmit;
|
||||
} otCoapTxParameters;
|
||||
|
||||
/**
|
||||
* This function initializes the CoAP header.
|
||||
*
|
||||
@@ -693,6 +727,30 @@ otError otCoapOptionIteratorGetOptionValue(otCoapOptionIterator *aIterator, void
|
||||
*/
|
||||
otMessage *otCoapNewMessage(otInstance *aInstance, const otMessageSettings *aSettings);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP request with custom transmission parameters.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aMessage A pointer to the message to send.
|
||||
* @param[in] aMessageInfo A pointer to the message info associated with @p aMessage.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or timeout.
|
||||
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
|
||||
* @param[in] aTxParameters A pointer to transmission parameters for this request. Use NULL for defaults.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent CoAP message.
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
*
|
||||
*/
|
||||
otError otCoapSendRequestWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext,
|
||||
const otCoapTxParameters *aTxParameters);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP request.
|
||||
*
|
||||
@@ -709,11 +767,14 @@ otMessage *otCoapNewMessage(otInstance *aInstance, const otMessageSettings *aSet
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
*
|
||||
*/
|
||||
otError otCoapSendRequest(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext);
|
||||
static inline otError otCoapSendRequest(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext)
|
||||
{
|
||||
return otCoapSendRequestWithParameters(aInstance, aMessage, aMessageInfo, aHandler, aContext, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function starts the CoAP server.
|
||||
@@ -767,6 +828,23 @@ void otCoapRemoveResource(otInstance *aInstance, otCoapResource *aResource);
|
||||
*/
|
||||
void otCoapSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandler, void *aContext);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP response from the server with custom transmission parameters.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aMessage A pointer to the CoAP response to send.
|
||||
* @param[in] aMessageInfo A pointer to the message info associated with @p aMessage.
|
||||
* @param[in] aTxParameters A pointer to transmission parameters for this response. Use NULL for defaults.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully enqueued the CoAP response message.
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response.
|
||||
*
|
||||
*/
|
||||
otError otCoapSendResponseWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
const otCoapTxParameters *aTxParameters);
|
||||
|
||||
/**
|
||||
* This function sends a CoAP response from the server.
|
||||
*
|
||||
@@ -778,7 +856,10 @@ void otCoapSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandle
|
||||
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response.
|
||||
*
|
||||
*/
|
||||
otError otCoapSendResponse(otInstance *aInstance, otMessage *aMessage, const otMessageInfo *aMessageInfo);
|
||||
static inline otError otCoapSendResponse(otInstance *aInstance, otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
{
|
||||
return otCoapSendResponseWithParameters(aInstance, aMessage, aMessageInfo, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
||||
@@ -57,6 +57,7 @@ coap response sent
|
||||
* [help](#help)
|
||||
* [delete](#delete-address-uri-path-type-payload)
|
||||
* [get](#get-address-uri-path-type)
|
||||
* [parameters](#parameters)
|
||||
* [post](#post-address-uri-path-type-payload)
|
||||
* [put](#put-address-uri-path-type-payload)
|
||||
* [resource](#resource-uri-path)
|
||||
@@ -72,6 +73,7 @@ coap response sent
|
||||
help
|
||||
delete
|
||||
get
|
||||
parameters
|
||||
post
|
||||
put
|
||||
resource
|
||||
@@ -105,6 +107,43 @@ Done
|
||||
Done
|
||||
```
|
||||
|
||||
### parameters \<type\> \["default"|<ack\_timeout\> <ack\_random\_factor\_numerator\> <ack\_random\_factor\_denominator\> <max\_retransmit\>\]
|
||||
|
||||
Sets transmission parameters for the following interactions.
|
||||
|
||||
* type: "request" for CoAP requests and "response" for CoAP responses.
|
||||
|
||||
If no more parameters are given, the command prints the current configuration:
|
||||
|
||||
```bash
|
||||
> coap parameters request
|
||||
Transmission parameters for request:
|
||||
ACK_TIMEOUT=1000 ms, ACK_RANDOM_FACTOR=255/254, MAX_RETRANSMIT=2
|
||||
Done
|
||||
```
|
||||
|
||||
If `"default"` is given, the command sets the default configuration for the transmission parameters.
|
||||
|
||||
```bash
|
||||
> coap parameters request default
|
||||
Transmission parameters for request:
|
||||
default
|
||||
Done
|
||||
```
|
||||
|
||||
Also, you can specify the transmission parameters in the command line:
|
||||
* ack\_timeout (0~UINT32\_MAX): RFC7252 ACK\_TIMEOUT, in milliseconds.
|
||||
* ack\_random\_factor\_numerator, ack\_random\_factor\_denominator (0~255):
|
||||
RFC7252 ACK\_RANDOM\_FACTOR=ack\_random\_factor\_numerator/ack\_random\_factor\_denominator.
|
||||
* max\_retransmit (0~255): RFC7252 MAX_RETRANSMIT.
|
||||
|
||||
```bash
|
||||
> coap parameters request 1000 255 254 2
|
||||
Transmission parameters for request:
|
||||
ACK_TIMEOUT=1000 ms, ACK_RANDOM_FACTOR=255/254, MAX_RETRANSMIT=2
|
||||
Done
|
||||
```
|
||||
|
||||
### post \<address\> \<uri-path\> \[type\] \[payload\]
|
||||
|
||||
* address: IPv6 address of the CoAP server.
|
||||
|
||||
+87
-6
@@ -45,13 +45,17 @@ namespace ot {
|
||||
namespace Cli {
|
||||
|
||||
const struct Coap::Command Coap::sCommands[] = {
|
||||
{"help", &Coap::ProcessHelp}, {"delete", &Coap::ProcessRequest}, {"get", &Coap::ProcessRequest},
|
||||
{"post", &Coap::ProcessRequest}, {"put", &Coap::ProcessRequest}, {"resource", &Coap::ProcessResource},
|
||||
{"start", &Coap::ProcessStart}, {"stop", &Coap::ProcessStop},
|
||||
{"help", &Coap::ProcessHelp}, {"delete", &Coap::ProcessRequest},
|
||||
{"get", &Coap::ProcessRequest}, {"parameters", &Coap::ProcessParameters},
|
||||
{"post", &Coap::ProcessRequest}, {"put", &Coap::ProcessRequest},
|
||||
{"resource", &Coap::ProcessResource}, {"start", &Coap::ProcessStart},
|
||||
{"stop", &Coap::ProcessStop},
|
||||
};
|
||||
|
||||
Coap::Coap(Interpreter &aInterpreter)
|
||||
: mInterpreter(aInterpreter)
|
||||
, mUseDefaultRequestTxParameters(true)
|
||||
, mUseDefaultResponseTxParameters(true)
|
||||
{
|
||||
memset(&mResource, 0, sizeof(mResource));
|
||||
}
|
||||
@@ -137,6 +141,80 @@ otError Coap::ProcessStop(int argc, char *argv[])
|
||||
return otCoapStop(mInterpreter.mInstance);
|
||||
}
|
||||
|
||||
otError Coap::ProcessParameters(int argc, char *argv[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(argc > 0, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
bool * defaultTxParameters;
|
||||
otCoapTxParameters *txParameters;
|
||||
|
||||
if (strcmp(argv[1], "request") == 0)
|
||||
{
|
||||
txParameters = &mRequestTxParameters;
|
||||
defaultTxParameters = &mUseDefaultRequestTxParameters;
|
||||
}
|
||||
else if (strcmp(argv[1], "response") == 0)
|
||||
{
|
||||
txParameters = &mResponseTxParameters;
|
||||
defaultTxParameters = &mUseDefaultResponseTxParameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_ARGS);
|
||||
}
|
||||
|
||||
if (argc > 2)
|
||||
{
|
||||
if (strcmp(argv[2], "default") == 0)
|
||||
{
|
||||
*defaultTxParameters = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
VerifyOrExit(argc >= 6, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[2], value));
|
||||
txParameters->mAckTimeout = static_cast<uint32_t>(value);
|
||||
|
||||
SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[3], value));
|
||||
VerifyOrExit(value <= 255, error = OT_ERROR_INVALID_ARGS);
|
||||
txParameters->mAckRandomFactorNumerator = static_cast<uint8_t>(value);
|
||||
|
||||
SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[4], value));
|
||||
VerifyOrExit(value <= 255, error = OT_ERROR_INVALID_ARGS);
|
||||
txParameters->mAckRandomFactorDenominator = static_cast<uint8_t>(value);
|
||||
|
||||
SuccessOrExit(error = mInterpreter.ParseUnsignedLong(argv[5], value));
|
||||
VerifyOrExit(value <= 255, error = OT_ERROR_INVALID_ARGS);
|
||||
txParameters->mMaxRetransmit = static_cast<uint8_t>(value);
|
||||
|
||||
VerifyOrExit(txParameters->mAckRandomFactorNumerator > txParameters->mAckRandomFactorDenominator,
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
*defaultTxParameters = false;
|
||||
}
|
||||
}
|
||||
|
||||
mInterpreter.mServer->OutputFormat("Transmission parameters for %s:\r\n", argv[1]);
|
||||
if (*defaultTxParameters)
|
||||
{
|
||||
mInterpreter.mServer->OutputFormat("default\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
mInterpreter.mServer->OutputFormat("ACK_TIMEOUT=%u ms, ACK_RANDOM_FACTOR=%u/%u, MAX_RETRANSMIT=%u\r\n",
|
||||
txParameters->mAckTimeout, txParameters->mAckRandomFactorNumerator,
|
||||
txParameters->mAckRandomFactorDenominator, txParameters->mMaxRetransmit);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Coap::ProcessRequest(int argc, char *argv[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
@@ -233,11 +311,13 @@ otError Coap::ProcessRequest(int argc, char *argv[])
|
||||
|
||||
if ((coapType == OT_COAP_TYPE_CONFIRMABLE) || (coapCode == OT_COAP_CODE_GET))
|
||||
{
|
||||
error = otCoapSendRequest(mInterpreter.mInstance, message, &messageInfo, &Coap::HandleResponse, this);
|
||||
error = otCoapSendRequestWithParameters(mInterpreter.mInstance, message, &messageInfo, &Coap::HandleResponse,
|
||||
this, GetRequestTxParameters());
|
||||
}
|
||||
else
|
||||
{
|
||||
error = otCoapSendRequest(mInterpreter.mInstance, message, &messageInfo, NULL, NULL);
|
||||
error = otCoapSendRequestWithParameters(mInterpreter.mInstance, message, &messageInfo, NULL, NULL,
|
||||
GetResponseTxParameters());
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -339,7 +419,8 @@ void Coap::HandleRequest(otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
SuccessOrExit(error = otMessageAppend(responseMessage, &responseContent, sizeof(responseContent)));
|
||||
}
|
||||
|
||||
SuccessOrExit(error = otCoapSendResponse(mInterpreter.mInstance, responseMessage, aMessageInfo));
|
||||
SuccessOrExit(error = otCoapSendResponseWithParameters(mInterpreter.mInstance, responseMessage, aMessageInfo,
|
||||
GetResponseTxParameters()));
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
@@ -85,6 +85,7 @@ private:
|
||||
void PrintPayload(otMessage *aMessage) const;
|
||||
|
||||
otError ProcessHelp(int argc, char *argv[]);
|
||||
otError ProcessParameters(int argc, char *argv[]);
|
||||
otError ProcessRequest(int argc, char *argv[]);
|
||||
otError ProcessResource(int argc, char *argv[]);
|
||||
otError ProcessStart(int argc, char *argv[]);
|
||||
@@ -96,9 +97,25 @@ private:
|
||||
static void HandleResponse(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError);
|
||||
void HandleResponse(otMessage *aMessage, const otMessageInfo *aMessageInfo, otError aError);
|
||||
|
||||
const otCoapTxParameters *GetRequestTxParameters(void) const
|
||||
{
|
||||
return mUseDefaultRequestTxParameters ? NULL : &mRequestTxParameters;
|
||||
}
|
||||
|
||||
const otCoapTxParameters *GetResponseTxParameters(void) const
|
||||
{
|
||||
return mUseDefaultResponseTxParameters ? NULL : &mResponseTxParameters;
|
||||
}
|
||||
|
||||
static const Command sCommands[];
|
||||
Interpreter & mInterpreter;
|
||||
|
||||
bool mUseDefaultRequestTxParameters;
|
||||
bool mUseDefaultResponseTxParameters;
|
||||
|
||||
otCoapTxParameters mRequestTxParameters;
|
||||
otCoapTxParameters mResponseTxParameters;
|
||||
|
||||
otCoapResource mResource;
|
||||
char mUriPath[kMaxUriLength];
|
||||
};
|
||||
|
||||
@@ -195,17 +195,18 @@ otError otCoapOptionIteratorGetOptionValue(otCoapOptionIterator *aIterator, void
|
||||
return static_cast<Coap::OptionIterator *>(aIterator)->GetOptionValue(aValue);
|
||||
}
|
||||
|
||||
otError otCoapSendRequest(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext)
|
||||
otError otCoapSendRequestWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext,
|
||||
const otCoapTxParameters *aTxParameters)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetApplicationCoap().SendMessage(*static_cast<Coap::Message *>(aMessage),
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo), aHandler,
|
||||
aContext);
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo),
|
||||
Coap::CoapTxParameters::From(aTxParameters), aHandler, aContext);
|
||||
}
|
||||
|
||||
otError otCoapStart(otInstance *aInstance, uint16_t aPort)
|
||||
@@ -243,12 +244,16 @@ void otCoapSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandle
|
||||
instance.GetApplicationCoap().SetDefaultHandler(aHandler, aContext);
|
||||
}
|
||||
|
||||
otError otCoapSendResponse(otInstance *aInstance, otMessage *aMessage, const otMessageInfo *aMessageInfo)
|
||||
otError otCoapSendResponseWithParameters(otInstance * aInstance,
|
||||
otMessage * aMessage,
|
||||
const otMessageInfo * aMessageInfo,
|
||||
const otCoapTxParameters *aTxParameters)
|
||||
{
|
||||
Instance &instance = *static_cast<Instance *>(aInstance);
|
||||
|
||||
return instance.GetApplicationCoap().SendMessage(*static_cast<Coap::Message *>(aMessage),
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
|
||||
*static_cast<const Ip6::MessageInfo *>(aMessageInfo),
|
||||
Coap::CoapTxParameters::From(aTxParameters), NULL, NULL);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
|
||||
|
||||
+53
-23
@@ -109,18 +109,18 @@ exit:
|
||||
|
||||
otError CoapBase::SendMessage(Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
const CoapTxParameters &aTxParameters,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext)
|
||||
{
|
||||
otError error;
|
||||
CoapMetadata coapMetadata;
|
||||
Message * storedCopy = NULL;
|
||||
uint16_t copyLength = 0;
|
||||
otError error;
|
||||
Message *storedCopy = NULL;
|
||||
uint16_t copyLength = 0;
|
||||
|
||||
switch (aMessage.GetType())
|
||||
{
|
||||
case OT_COAP_TYPE_ACKNOWLEDGMENT:
|
||||
mResponsesQueue.EnqueueResponse(aMessage, aMessageInfo);
|
||||
mResponsesQueue.EnqueueResponse(aMessage, aMessageInfo, aTxParameters);
|
||||
break;
|
||||
case OT_COAP_TYPE_RESET:
|
||||
assert(aMessage.GetCode() == OT_COAP_CODE_EMPTY);
|
||||
@@ -145,7 +145,8 @@ otError CoapBase::SendMessage(Message & aMessage,
|
||||
|
||||
if (copyLength > 0)
|
||||
{
|
||||
coapMetadata = CoapMetadata(aMessage.IsConfirmable(), aMessageInfo, aHandler, aContext);
|
||||
CoapMetadata coapMetadata =
|
||||
CoapMetadata(aMessage.IsConfirmable(), aMessageInfo, aHandler, aContext, aTxParameters);
|
||||
VerifyOrExit((storedCopy = CopyAndEnqueueMessage(aMessage, copyLength, coapMetadata)) != NULL,
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
}
|
||||
@@ -247,7 +248,7 @@ void CoapBase::HandleRetransmissionTimer(void)
|
||||
|
||||
if (now >= coapMetadata.mNextTimerShot)
|
||||
{
|
||||
if (!coapMetadata.mConfirmable || (coapMetadata.mRetransmissionCount >= kMaxRetransmit))
|
||||
if (!coapMetadata.mConfirmable || (coapMetadata.mRetransmissionsRemaining == 0))
|
||||
{
|
||||
// No expected response or acknowledgment.
|
||||
FinalizeCoapTransaction(*message, coapMetadata, NULL, NULL, OT_ERROR_RESPONSE_TIMEOUT);
|
||||
@@ -255,7 +256,7 @@ void CoapBase::HandleRetransmissionTimer(void)
|
||||
}
|
||||
|
||||
// Increment retransmission counter and timer.
|
||||
coapMetadata.mRetransmissionCount++;
|
||||
coapMetadata.mRetransmissionsRemaining--;
|
||||
coapMetadata.mRetransmissionTimeout *= 2;
|
||||
coapMetadata.mNextTimerShot = now + coapMetadata.mRetransmissionTimeout;
|
||||
coapMetadata.UpdateIn(*message);
|
||||
@@ -623,18 +624,16 @@ exit:
|
||||
CoapMetadata::CoapMetadata(bool aConfirmable,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext)
|
||||
void * aContext,
|
||||
const CoapTxParameters &aTxParameters)
|
||||
{
|
||||
mSourceAddress = aMessageInfo.GetSockAddr();
|
||||
mDestinationPort = aMessageInfo.GetPeerPort();
|
||||
mDestinationAddress = aMessageInfo.GetPeerAddr();
|
||||
mResponseHandler = aHandler;
|
||||
mResponseContext = aContext;
|
||||
mRetransmissionCount = 0;
|
||||
mRetransmissionTimeout = Time::SecToMsec(kAckTimeout);
|
||||
mRetransmissionTimeout += Random::NonCrypto::GetUint32InRange(
|
||||
0, Time::SecToMsec(kAckTimeout) * kAckRandomFactorNumerator / kAckRandomFactorDenominator -
|
||||
Time::SecToMsec(kAckTimeout) + 1);
|
||||
mSourceAddress = aMessageInfo.GetSockAddr();
|
||||
mDestinationPort = aMessageInfo.GetPeerPort();
|
||||
mDestinationAddress = aMessageInfo.GetPeerAddr();
|
||||
mResponseHandler = aHandler;
|
||||
mResponseContext = aContext;
|
||||
mRetransmissionsRemaining = aTxParameters.mMaxRetransmit;
|
||||
mRetransmissionTimeout = aTxParameters.CalculateInitialRetransmissionTimeout();
|
||||
|
||||
if (aConfirmable)
|
||||
{
|
||||
@@ -644,7 +643,7 @@ CoapMetadata::CoapMetadata(bool aConfirmable,
|
||||
else
|
||||
{
|
||||
// Set overall response timeout.
|
||||
mNextTimerShot = TimerMilli::GetNow() + Time::SecToMsec(kMaxTransmitWait);
|
||||
mNextTimerShot = TimerMilli::GetNow() + aTxParameters.CalculateMaxTransmitWait();
|
||||
}
|
||||
|
||||
mAcknowledged = false;
|
||||
@@ -711,13 +710,17 @@ exit:
|
||||
return matchedResponse;
|
||||
}
|
||||
|
||||
void ResponsesQueue::EnqueueResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
|
||||
void ResponsesQueue::EnqueueResponse(Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
const CoapTxParameters &aTxParameters)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
Message * responseCopy = NULL;
|
||||
EnqueuedResponseHeader enqueuedResponseHeader(aMessageInfo);
|
||||
uint16_t messageCount;
|
||||
uint16_t bufferCount;
|
||||
uint32_t exchangeLifetime = aTxParameters.CalculateExchangeLifetime();
|
||||
TimeMilli dequeueTime = TimerMilli::GetNow() + exchangeLifetime;
|
||||
EnqueuedResponseHeader enqueuedResponseHeader(dequeueTime, aMessageInfo);
|
||||
|
||||
// return success if matched response already exists in the cache
|
||||
VerifyOrExit(FindMatchedResponse(aMessage, aMessageInfo) == NULL);
|
||||
@@ -736,7 +739,7 @@ void ResponsesQueue::EnqueueResponse(Message &aMessage, const Ip6::MessageInfo &
|
||||
|
||||
if (!mTimer.IsRunning())
|
||||
{
|
||||
mTimer.Start(Time::SecToMsec(kExchangeLifetime));
|
||||
mTimer.Start(exchangeLifetime);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -809,6 +812,33 @@ uint32_t EnqueuedResponseHeader::GetRemainingTime(void) const
|
||||
return remainingTime;
|
||||
}
|
||||
|
||||
uint32_t CoapTxParameters::CalculateInitialRetransmissionTimeout(void) const
|
||||
{
|
||||
return Random::NonCrypto::GetUint32InRange(
|
||||
mAckTimeout, mAckTimeout * mAckRandomFactorNumerator / mAckRandomFactorDenominator + 1);
|
||||
}
|
||||
|
||||
uint32_t CoapTxParameters::CalculateExchangeLifetime(void) const
|
||||
{
|
||||
uint32_t maxTransmitSpan = static_cast<uint32_t>(mAckTimeout * ((1ULL << mMaxRetransmit) - 1) *
|
||||
mAckRandomFactorNumerator / mAckRandomFactorDenominator);
|
||||
uint32_t processingDelay = mAckTimeout;
|
||||
return maxTransmitSpan + 2 * kDefaultMaxLatency + processingDelay;
|
||||
}
|
||||
|
||||
uint32_t CoapTxParameters::CalculateMaxTransmitWait(void) const
|
||||
{
|
||||
return static_cast<uint32_t>(mAckTimeout * ((2ULL << mMaxRetransmit) - 1) * mAckRandomFactorNumerator /
|
||||
mAckRandomFactorDenominator);
|
||||
}
|
||||
|
||||
const otCoapTxParameters CoapTxParameters::kDefaultTxParameters = {
|
||||
kDefaultAckTimeout,
|
||||
kDefaultAckRandomFactorNumerator,
|
||||
kDefaultAckRandomFactorDenominator,
|
||||
kDefaultMaxRetransmit,
|
||||
};
|
||||
|
||||
Coap::Coap(Instance &aInstance)
|
||||
: CoapBase(aInstance, &Coap::Send)
|
||||
, mSocket(aInstance.Get<Ip6::Udp>())
|
||||
|
||||
+94
-43
@@ -59,30 +59,50 @@ namespace Coap {
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Protocol Constants (RFC 7252).
|
||||
*
|
||||
*/
|
||||
enum
|
||||
class CoapTxParameters : public otCoapTxParameters
|
||||
{
|
||||
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,
|
||||
public:
|
||||
/**
|
||||
* Protocol Constants (RFC 7252).
|
||||
*
|
||||
*/
|
||||
enum
|
||||
{
|
||||
kDefaultAckTimeout = OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT_MILLIS,
|
||||
kDefaultAckRandomFactorNumerator = OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_NUMERATOR,
|
||||
kDefaultAckRandomFactorDenominator = OPENTHREAD_CONFIG_COAP_ACK_RANDOM_FACTOR_DENOMINATOR,
|
||||
kDefaultMaxRetransmit = OPENTHREAD_CONFIG_COAP_MAX_RETRANSMIT,
|
||||
kDefaultNStart = 1,
|
||||
kDefaultLeisure = 5000, // in milliseconds
|
||||
kDefaultProbingRate = 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
|
||||
kDefaultMaxTransmitSpan = kDefaultAckTimeout * ((1ULL << kDefaultMaxRetransmit) - 1) *
|
||||
kDefaultAckRandomFactorNumerator / kDefaultAckRandomFactorDenominator,
|
||||
kDefaultMaxTransmitWait = kDefaultAckTimeout * ((2ULL << kDefaultMaxRetransmit) - 1) *
|
||||
kDefaultAckRandomFactorNumerator / kDefaultAckRandomFactorDenominator,
|
||||
kDefaultMaxLatency = 100000, // in milliseconds
|
||||
kDefaultProcessingDelay = kDefaultAckTimeout,
|
||||
kDefaultMaxRtt = 2 * kDefaultMaxLatency + kDefaultProcessingDelay,
|
||||
kDefaultExchangeLifetime = kDefaultMaxTransmitSpan + 2 * kDefaultMaxLatency + kDefaultProcessingDelay,
|
||||
kDefaultNonLifetime = kDefaultMaxTransmitSpan + kDefaultMaxLatency
|
||||
};
|
||||
|
||||
uint32_t CalculateInitialRetransmissionTimeout(void) const;
|
||||
uint32_t CalculateExchangeLifetime(void) const;
|
||||
uint32_t CalculateMaxTransmitWait(void) const;
|
||||
|
||||
static inline const CoapTxParameters &From(const otCoapTxParameters *aTxParameters)
|
||||
{
|
||||
return aTxParameters ? *static_cast<const CoapTxParameters *>(aTxParameters) : GetDefault();
|
||||
}
|
||||
|
||||
static inline const CoapTxParameters &GetDefault()
|
||||
{
|
||||
return *static_cast<const CoapTxParameters *>(&kDefaultTxParameters);
|
||||
}
|
||||
|
||||
private:
|
||||
static const otCoapTxParameters kDefaultTxParameters;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -104,23 +124,25 @@ public:
|
||||
, mResponseContext(NULL)
|
||||
, mNextTimerShot(0)
|
||||
, mRetransmissionTimeout(0)
|
||||
, mRetransmissionCount(0)
|
||||
, mRetransmissionsRemaining(0)
|
||||
, mAcknowledged(false)
|
||||
, mConfirmable(false){};
|
||||
|
||||
/**
|
||||
* This constructor initializes the object with specific values.
|
||||
*
|
||||
* @param[in] aConfirmable Information if the request is confirmable or not.
|
||||
* @param[in] aMessageInfo Addressing information.
|
||||
* @param[in] aHandler Pointer to a handler function for the response.
|
||||
* @param[in] aContext Context for the handler function.
|
||||
* @param[in] aConfirmable Information if the request is confirmable or not.
|
||||
* @param[in] aMessageInfo Addressing information.
|
||||
* @param[in] aHandler Pointer to a handler function for the response.
|
||||
* @param[in] aContext Context for the handler function.
|
||||
* @param[in] aTxParameters Transmission parameters.
|
||||
*
|
||||
*/
|
||||
CoapMetadata(bool aConfirmable,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
otCoapResponseHandler aHandler,
|
||||
void * aContext);
|
||||
void * aContext,
|
||||
const CoapTxParameters &aTxParameters);
|
||||
|
||||
/**
|
||||
* This method appends request data to the message.
|
||||
@@ -160,16 +182,16 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
Ip6::Address mSourceAddress; ///< IPv6 address of the message source.
|
||||
Ip6::Address mDestinationAddress; ///< IPv6 address of the message destination.
|
||||
uint16_t mDestinationPort; ///< UDP port of the message destination.
|
||||
otCoapResponseHandler mResponseHandler; ///< A function pointer that is called on response reception.
|
||||
void * mResponseContext; ///< A pointer to arbitrary context information.
|
||||
TimeMilli mNextTimerShot; ///< Time when the timer should shoot for this message.
|
||||
uint32_t mRetransmissionTimeout; ///< Delay that is applied to next retransmission.
|
||||
uint8_t mRetransmissionCount; ///< Number of retransmissions.
|
||||
bool mAcknowledged : 1; ///< Information that request was acknowledged.
|
||||
bool mConfirmable : 1; ///< Information that message is confirmable.
|
||||
Ip6::Address mSourceAddress; ///< IPv6 address of the message source.
|
||||
Ip6::Address mDestinationAddress; ///< IPv6 address of the message destination.
|
||||
uint16_t mDestinationPort; ///< UDP port of the message destination.
|
||||
otCoapResponseHandler mResponseHandler; ///< A function pointer that is called on response reception.
|
||||
void * mResponseContext; ///< A pointer to arbitrary context information.
|
||||
TimeMilli mNextTimerShot; ///< Time when the timer should shoot for this message.
|
||||
uint32_t mRetransmissionTimeout; ///< Delay that is applied to next retransmission.
|
||||
uint8_t mRetransmissionsRemaining; ///< Number of retransmissions remaining.
|
||||
bool mAcknowledged : 1; ///< Information that request was acknowledged.
|
||||
bool mConfirmable : 1; ///< Information that message is confirmable.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -241,8 +263,8 @@ public:
|
||||
* @param[in] aMessageInfo The message info containing source endpoint identification.
|
||||
*
|
||||
*/
|
||||
explicit EnqueuedResponseHeader(const Ip6::MessageInfo &aMessageInfo)
|
||||
: mDequeueTime(TimerMilli::GetNow() + Time::SecToMsec(kExchangeLifetime))
|
||||
explicit EnqueuedResponseHeader(TimeMilli aDequeueTime, const Ip6::MessageInfo &aMessageInfo)
|
||||
: mDequeueTime(aDequeueTime)
|
||||
, mMessageInfo(aMessageInfo)
|
||||
{
|
||||
}
|
||||
@@ -316,9 +338,12 @@ public:
|
||||
*
|
||||
* @param[in] aMessage The CoAP response to add to the cache.
|
||||
* @param[in] aMessageInfo The message info corresponding to @p aMessage.
|
||||
* @param[in] aTxParameters Transmission parameters.
|
||||
*
|
||||
*/
|
||||
void EnqueueResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
|
||||
void EnqueueResponse(Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
const CoapTxParameters &aTxParameters);
|
||||
|
||||
/**
|
||||
* This method removes the oldest response from the cache.
|
||||
@@ -469,7 +494,30 @@ public:
|
||||
Message *NewMessage(const otMessageSettings *aSettings = NULL);
|
||||
|
||||
/**
|
||||
* This method sends a CoAP message.
|
||||
* This method sends a CoAP message with custom transmission parameters.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
* If Message Id was not set in the header (equal to 0), this function will assign unique Message Id to the message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message to send.
|
||||
* @param[in] aMessageInfo A reference to the message info associated with @p aMessage.
|
||||
* @param[in] aTxParameters A reference to transmission parameters for this message.
|
||||
* @param[in] aHandler A function pointer that shall be called on response reception or time-out.
|
||||
* @param[in] aContext A pointer to arbitrary context information.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully sent CoAP message.
|
||||
* @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data.
|
||||
*
|
||||
*/
|
||||
otError SendMessage(Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
const CoapTxParameters &aTxParameters,
|
||||
otCoapResponseHandler aHandler = NULL,
|
||||
void * aContext = NULL);
|
||||
|
||||
/**
|
||||
* This method sends a CoAP message with default transmission parameters.
|
||||
*
|
||||
* If a response for a request is expected, respective function and context information should be provided.
|
||||
* If no response is expected, these arguments should be NULL pointers.
|
||||
@@ -487,7 +535,10 @@ public:
|
||||
otError SendMessage(Message & aMessage,
|
||||
const Ip6::MessageInfo &aMessageInfo,
|
||||
otCoapResponseHandler aHandler = NULL,
|
||||
void * aContext = NULL);
|
||||
void * aContext = NULL)
|
||||
{
|
||||
return SendMessage(aMessage, aMessageInfo, CoapTxParameters::GetDefault(), aHandler, aContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sends a CoAP reset message.
|
||||
|
||||
@@ -36,13 +36,14 @@
|
||||
#define CONFIG_COAP_H_
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT
|
||||
* @def OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT_MILLIS
|
||||
*
|
||||
* Minimum spacing before first retransmission when ACK is not received (RFC7252 default value is 2).
|
||||
* Minimum spacing before first retransmission when ACK is not received, in milliseconds (RFC7252 default value
|
||||
* is 2000).
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT
|
||||
#define OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT 2
|
||||
#ifndef OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT_MILLIS
|
||||
#define OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT_MILLIS 2000
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
@@ -463,4 +463,9 @@
|
||||
#error "OPENTHREAD_CONFIG_INITIAL_LOG_LEVEL was replaced by OPENTHREAD_CONFIG_LOG_LEVEL_INIT."
|
||||
#endif
|
||||
|
||||
#ifdef OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT
|
||||
#error \
|
||||
"OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT (in seconds) was replaced by OPENTHREAD_CONFIG_COAP_ACK_TIMEOUT_MILLIS (in milliseconds)"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CORE_CONFIG_CHECK_H_
|
||||
|
||||
Reference in New Issue
Block a user