diff --git a/include/coap3/coap_session_internal.h b/include/coap3/coap_session_internal.h index f284864c75..e5519ece30 100644 --- a/include/coap3/coap_session_internal.h +++ b/include/coap3/coap_session_internal.h @@ -604,6 +604,16 @@ coap_session_t *coap_new_client_session_psk2_lkd(coap_context_t *ctx, coap_session_t *coap_session_new_dtls_session(coap_session_t *session, coap_tick_t now); +/** + * Clear down a session following a keepalive failure. + * The event handler will get notified of the failure. + * Note: the @p session cannot be used after this function is called. + * + * @param session Session to clear down. + * + */ +void coap_session_server_keepalive_failed(coap_session_t *session); + void coap_session_free(coap_session_t *session); void coap_session_mfree(coap_session_t *session); diff --git a/include/coap3/coap_subscribe_internal.h b/include/coap3/coap_subscribe_internal.h index c9cceed6f4..68a2372e23 100644 --- a/include/coap3/coap_subscribe_internal.h +++ b/include/coap3/coap_subscribe_internal.h @@ -167,6 +167,18 @@ int coap_delete_observer_request(coap_resource_t *resource, */ void coap_delete_observers(coap_context_t *context, coap_session_t *session); +/** + * Removes specific subscription for @p session for @p resource and releases + * the allocated storage. + * + * @param resource The resource + * @param session The observer's session. + * @param subscription The observer's subscription. + */ +void coap_delete_observer_internal(coap_resource_t *resource, + coap_session_t *session, + coap_subscription_t *subscription); + /** * Initiate the sending of an Observe packet for all observers of @p resource, * optionally matching @p query if not NULL diff --git a/src/coap_io.c b/src/coap_io.c index e940ec9954..62a3889337 100644 --- a/src/coap_io.c +++ b/src/coap_io.c @@ -1490,16 +1490,7 @@ coap_io_prepare_io_lkd(coap_context_t *ctx, /* Some issue - not safe to continue processing */ continue; if (s->last_ping > 0 && s->last_pong < s->last_ping) { - coap_handle_event_lkd(s->context, COAP_EVENT_KEEPALIVE_FAILURE, s); - coap_session_reference_lkd(s); - RESOURCES_ITER(s->context->resources, r) { - coap_cancel_all_messages(s->context, s, NULL); - coap_delete_observer(r, s, NULL); - } - coap_session_release_lkd(s); - /* Force session to go away */ - coap_session_set_type_client_lkd(s); - coap_session_release_lkd(s); + coap_session_server_keepalive_failed(s); /* check the next session */ continue; } diff --git a/src/coap_net.c b/src/coap_net.c index 816b65c111..815196ca58 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -763,9 +763,9 @@ coap_free_context_lkd(coap_context_t *context) { #endif /* COAP_SERVER_SUPPORT */ coap_delete_all(context->sendqueue); + context->sendqueue = NULL; #ifdef WITH_LWIP - context->sendqueue = NULL; if (context->timer_configured) { LOCK_TCPIP_CORE(); sys_untimeout(coap_io_process_timeout, (void *)context); @@ -2167,8 +2167,14 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { #if COAP_SERVER_SUPPORT /* Check if subscriptions exist that should be canceled after COAP_OBS_MAX_FAIL */ - if (COAP_RESPONSE_CLASS(node->pdu->code) >= 2) { - coap_handle_failed_notify(context, node->session, &node->pdu->actual_token); + if (COAP_RESPONSE_CLASS(node->pdu->code) >= 2 && node->session->ref_subscriptions) { + if (context->ping_timeout) { + coap_session_server_keepalive_failed(node->session); + coap_delete_node_lkd(node); + return COAP_INVALID_MID; + } else { + coap_handle_failed_notify(context, node->session, &node->pdu->actual_token); + } } #endif /* COAP_SERVER_SUPPORT */ if (node->session->con_active) { diff --git a/src/coap_resource.c b/src/coap_resource.c index 24401bb1da..cfa26789d0 100644 --- a/src/coap_resource.c +++ b/src/coap_resource.c @@ -513,13 +513,7 @@ coap_free_resource(coap_resource_t *resource) { /* free all elements from resource->subscribers */ LL_FOREACH_SAFE(resource->subscribers, obs, otmp) { - if (resource->context->observe_deleted) - resource->context->observe_deleted(obs->session, obs, - resource->context->observe_user_data); - coap_session_release_lkd(obs->session); - coap_delete_pdu_lkd(obs->pdu); - coap_delete_cache_key(obs->cache_key); - coap_free_type(COAP_SUBSCRIPTION, obs); + coap_delete_observer_internal(resource, obs->session, obs); } if (resource->proxy_name_count && resource->proxy_name_list) { size_t i; @@ -996,7 +990,7 @@ coap_touch_observer(coap_context_t *context, coap_session_t *session, } } -static void +void coap_delete_observer_internal(coap_resource_t *resource, coap_session_t *session, coap_subscription_t *s) { if (!s) @@ -1022,9 +1016,9 @@ coap_delete_observer_internal(coap_resource_t *resource, coap_session_t *session if (resource->subscribers) { LL_DELETE(resource->subscribers, s); - coap_session_release_lkd(session); assert(session->ref_subscriptions > 0); session->ref_subscriptions--; + coap_session_release_lkd(session); coap_delete_pdu_lkd(s->pdu); coap_delete_cache_key(s->cache_key); coap_free_type(COAP_SUBSCRIPTION, s); diff --git a/src/coap_session.c b/src/coap_session.c index 207416e4c4..f74e17c1b1 100644 --- a/src/coap_session.c +++ b/src/coap_session.c @@ -601,6 +601,28 @@ coap_session_free(coap_session_t *session) { coap_free_type(COAP_SESSION, session); } +#if COAP_SERVER_SUPPORT +void +coap_session_server_keepalive_failed(coap_session_t *session) { + coap_handle_event_lkd(session->context, COAP_EVENT_KEEPALIVE_FAILURE, session); + coap_session_reference_lkd(session); + coap_cancel_all_messages(session->context, session, NULL); + RESOURCES_ITER(session->context->resources, r) { + coap_delete_observer(r, session, NULL); + } + while (session->delayqueue) { + coap_queue_t *q = session->delayqueue; + + session->delayqueue = q->next; + coap_delete_node_lkd(q); + } + coap_session_release_lkd(session); + /* Force session to go away */ + coap_session_set_type_client_lkd(session); + coap_session_release_lkd(session); +} +#endif /* COAP_SERVER_SUPPORT */ + static size_t coap_session_max_pdu_size_internal(const coap_session_t *session, size_t max_with_header) {