From df665114c68b8224e5b1b1748a8fb71cee5142b6 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Thu, 19 Jul 2018 10:45:27 +0100 Subject: [PATCH] src/resource.c: Handle subscriber leak if app is not handling duplicates If multiple GET requests for the same URI + QUERY with different tokens and Observe =0 is set, then for each GET there is an increment of the subscriptions. Currently, if the application is not clearing out the duplicate subscribers, then the subscriber list gets large and eventually runs out of memory. This fix stops duplicate subscriptions for the same session with the same URI + QUERY, deleting the original entry and replacing it with a new subscription. --- src/resource.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/resource.c b/src/resource.c index 64dcd0d5..571bcf1d 100644 --- a/src/resource.c +++ b/src/resource.c @@ -600,6 +600,24 @@ coap_find_observer(coap_resource_t *resource, coap_session_t *session, return NULL; } +static coap_subscription_t * +coap_find_observer_query(coap_resource_t *resource, coap_session_t *session, + const coap_string_t *query) { + coap_subscription_t *s; + + assert(resource); + assert(session); + + LL_FOREACH(resource->subscribers, s) { + if (s->session == session + && ((!query && !s->query) + || (query && s->query && coap_string_equal(query, s->query)))) + return s; + } + + return NULL; +} + coap_subscription_t * coap_add_observer(coap_resource_t *resource, coap_session_t *session, @@ -611,6 +629,20 @@ coap_add_observer(coap_resource_t *resource, /* Check if there is already a subscription for this peer. */ s = coap_find_observer(resource, session, token); + if (!s) { + /* + * Cannot allow a duplicate to be created for the same query as application + * may not be cleaning up duplicates. If duplicate found, then original + * observer is deleted and a new one created with the new token + */ + s = coap_find_observer_query(resource, session, query); + if (s) { + /* Delete old entry with old token */ + coap_string_t tmp_token = { s->token_length, s->token }; + coap_delete_observer(resource, session, &tmp_token); + s = NULL; + } + } /* We are done if subscription was found. */ if (s) {