From 72691daec2a75d40f58d74a92467551ae40c8ebf Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Thu, 10 Apr 2025 17:07:48 +0100 Subject: [PATCH] coap_pdu.c: Support incrementing reference count on const coap_pdu_t parameters const coap_pdu_t * parameters are passed into application (call-back handler) code. If the application code then calls a libcoap API with a const coap_pdu_t * parameter, it is not possible to increment the reference counter so that multiple entities can reference the same PDU and an entity's call to coap_delete_pdu() does not prematurely remove the PDU until all the entities have finished. This code allows the (const) PDU's reference counter to be incremented. --- include/coap3/coap_pdu_internal.h | 18 ++++++++++++++++++ src/coap_pdu.c | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/include/coap3/coap_pdu_internal.h b/include/coap3/coap_pdu_internal.h index 46cf8d5c..26cdb31c 100644 --- a/include/coap3/coap_pdu_internal.h +++ b/include/coap3/coap_pdu_internal.h @@ -426,6 +426,24 @@ coap_pdu_t *coap_pdu_duplicate_lkd(const coap_pdu_t *old_pdu, * @return same as PDU */ coap_pdu_t *coap_pdu_reference_lkd(coap_pdu_t *pdu); + +/** + * Increment reference counter on a const pdu to stop it prematurely getting freed + * off when coap_delete_pdu() is called. + * + * In other words, if coap_const_pdu_reference_lkd() is called once, then the first + * call to coap_delete_pdu() will decrement the reference counter, but not delete + * the PDU and the second call to coap_delete_pdu() then actually deletes the PDU. + * + * Needed when const coap_pdu_t* is passed from application handlers. + * + * Note: This function must be called in the locked state. + * + * @param pdu The CoAP PDU. + * @return non const version of PDU. + */ +coap_pdu_t *coap_const_pdu_reference_lkd(const coap_pdu_t *pdu); + /** @} */ #endif /* COAP_COAP_PDU_INTERNAL_H_ */ diff --git a/src/coap_pdu.c b/src/coap_pdu.c index 20f706d6..94a609b3 100644 --- a/src/coap_pdu.c +++ b/src/coap_pdu.c @@ -1626,3 +1626,16 @@ coap_pdu_reference_lkd(coap_pdu_t *pdu) { } return pdu; } + +coap_pdu_t * +coap_const_pdu_reference_lkd(const coap_pdu_t *pdu) { + coap_pdu_t *pdu_rw = NULL; + + if (pdu != NULL) { + + /* Need to do this to not get a compiler warning about const parameters */ + memcpy(&pdu_rw, &pdu, sizeof(pdu_rw)); + ++pdu_rw->ref; + } + return pdu_rw; +}