[coap] add otCoapSetResponseFallback to process unmatched responses (#11583)

Adding two extensions:
1. Add an api function to configure a response fallback callback with
`otCoapSetResponseFallback`.
2. Enable fire and forget for NON requests, supporting requests which
do not expect a response.
This commit is contained in:
Lucien Zürcher
2025-08-29 13:21:32 -07:00
committed by GitHub
parent 853bbd1f43
commit c007599107
6 changed files with 82 additions and 6 deletions
+22
View File
@@ -352,6 +352,18 @@ typedef void (*otCoapResponseHandler)(void *aContext,
*/
typedef void (*otCoapRequestHandler)(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
/**
* Pointer is called as a fallback if a response did not match a stored CoAP request.
*
* @param[in] aContext A pointer to arbitrary context information.
* @param[in] aMessage A pointer to the message.
* @param[in] aMessageInfo A pointer to the message info for @p aMessage.
*
* @retval TRUE The fallback handled the response.
* @retval FALSE OpenThread takes default actions for response.
*/
typedef bool (*otCoapResponseFallback)(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
/**
* Pointer is called when a CoAP message with a block-wise transfer option is received.
*
@@ -1012,6 +1024,16 @@ void otCoapRemoveBlockWiseResource(otInstance *aInstance, otCoapBlockwiseResourc
*/
void otCoapSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandler, void *aContext);
/**
* Sets a fallback handler for CoAP responses not matching any active/pending request.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aHandler A function pointer that shall be called as a fallback for responses without matching
* active/pending CoAP requests.
* @param[in] aContext A pointer to arbitrary context information. May be NULL if not used.
*/
void otCoapSetResponseFallback(otInstance *aInstance, otCoapResponseFallback aHandler, void *aContext);
/**
* Sends a CoAP response from the server with custom transmission parameters.
*
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (530)
#define OPENTHREAD_API_VERSION (531)
/**
* @addtogroup api-instance
+5
View File
@@ -287,6 +287,11 @@ void otCoapSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandle
AsCoreType(aInstance).Get<Coap::ApplicationCoap>().SetDefaultHandler(aHandler, aContext);
}
void otCoapSetResponseFallback(otInstance *aInstance, otCoapResponseFallback aHandler, void *aContext)
{
AsCoreType(aInstance).Get<Coap::ApplicationCoap>().SetResponseFallback(aHandler, aContext);
}
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
otError otCoapSendResponseBlockWiseWithParameters(otInstance *aInstance,
otMessage *aMessage,
+14 -3
View File
@@ -209,6 +209,12 @@ Error CoapBase::SendMessage(Message &aMessage,
bool moreBlocks = false;
#endif
// fire and forget (mAckTimeout=0) is only allowed for Non-confirmable (NON) messages
if (aTxParameters.mAckTimeout == 0)
{
VerifyOrExit(aMessage.IsNonConfirmable(), error = kErrorInvalidArgs);
}
switch (aMessage.GetType())
{
case kTypeAck:
@@ -1287,7 +1293,7 @@ exit:
if (error == kErrorNone && request == nullptr)
{
if (aMessage.IsConfirmable() || aMessage.IsNonConfirmable())
if (!InvokeResponseFallback(aMessage, aMessageInfo) && aMessage.RequireResetOnError())
{
// Successfully parsed a header but no matching request was
// found - reject the message by sending reset.
@@ -1626,8 +1632,13 @@ bool TxParameters::IsValid(void) const
{
bool rval = false;
if ((mAckRandomFactorDenominator > 0) && (mAckRandomFactorNumerator >= mAckRandomFactorDenominator) &&
(mAckTimeout >= OT_COAP_MIN_ACK_TIMEOUT) && (mMaxRetransmit <= OT_COAP_MAX_RETRANSMIT))
// support fire and forget requests
if (mAckTimeout == 0)
{
rval = true;
}
else if ((mAckRandomFactorDenominator > 0) && (mAckRandomFactorNumerator >= mAckRandomFactorDenominator) &&
(mAckTimeout >= OT_COAP_MIN_ACK_TIMEOUT) && (mMaxRetransmit <= OT_COAP_MAX_RETRANSMIT))
{
// Calculate exchange lifetime step by step and verify no overflow.
uint32_t tmp = Multiply(mAckTimeout, (1U << (mMaxRetransmit + 1)) - 1);
+29 -2
View File
@@ -77,6 +77,13 @@ typedef otCoapResponseHandler ResponseHandler;
*/
typedef otCoapRequestHandler RequestHandler;
/**
* Represents a function pointer which is called when a CoAP response is not associated with a sent request.
*
* Please see otCoapResponseFallback for details.
*/
typedef otCoapResponseFallback ResponseFallback;
/**
* Represents the CoAP transmission parameters.
*/
@@ -400,13 +407,23 @@ public:
*/
void RemoveResource(Resource &aResource);
/* Sets the default handler for unhandled CoAP requests.
/**
* Sets the default handler for unhandled CoAP requests.
*
* @param[in] aHandler A function pointer that shall be called when an unhandled request arrives.
* @param[in] aContext A pointer to arbitrary context information. May be `nullptr` if not used.
*/
void SetDefaultHandler(RequestHandler aHandler, void *aContext) { mDefaultHandler.Set(aHandler, aContext); }
/**
* Sets a fallback handler for CoAP responses not matching any active/pending request.
*
* @param[in] aHandler A function pointer that shall be called as a fallback for responses that do not match any
* pending request.
* @param[in] aContext A pointer to arbitrary context information. May be `nullptr` if not used.
*/
void SetResponseFallback(ResponseFallback aHandler, void *aContext) { mResponseFallback.Set(aHandler, aContext); }
/**
* Allocates a new message with a CoAP header.
*
@@ -831,6 +848,15 @@ private:
const Ip6::MessageInfo *aMessageInfo,
Error aResult);
inline bool InvokeResponseFallback(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
if (mResponseFallback.IsSet())
{
return mResponseFallback.Invoke(&aMessage, &aMessageInfo);
}
return false;
}
#if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
void FreeLastBlockResponse(void);
Error CacheLastBlockResponse(Message *aResponse);
@@ -877,7 +903,8 @@ private:
Callback<Interceptor> mInterceptor;
ResponsesQueue mResponsesQueue;
Callback<RequestHandler> mDefaultHandler;
Callback<RequestHandler> mDefaultHandler;
Callback<ResponseFallback> mResponseFallback;
ResourceHandler mResourceHandler;
+11
View File
@@ -734,6 +734,17 @@ public:
*/
bool IsNonConfirmablePostRequest(void) const;
/**
* Checks if the message requires an reset response if an error during low level CoAP processing occurred.
*
* A reset message is expected to be sent for NON and CON messages if the message can not be processed or a
* duplicated message has been received.
*
* @retval TRUE Expect to respond with CoAP reset message on error.
* @retval FALSE No CoAP reset message should be sent on error.
*/
bool RequireResetOnError(void) { return IsConfirmable() || IsNonConfirmable(); }
/**
* Creates a copy of this CoAP message.
*