Skip to content

Commit

Permalink
KeepAlive: Better session cleanup after KeepAlive failure
Browse files Browse the repository at this point in the history
  • Loading branch information
mrdeep1 committed Feb 13, 2025
1 parent 238694f commit 60fbbd3
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 24 deletions.
2 changes: 1 addition & 1 deletion examples/coap-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -2101,7 +2101,7 @@ main(int argc, char **argv) {
obs_ms -= result;
}
}
if (ready && repeat_count) {
if ((ready || obs_ms) && repeat_count) {
/* Send off next request if appropriate */
if (repeat_ms > (unsigned)result) {
repeat_ms -= (unsigned)result;
Expand Down
10 changes: 10 additions & 0 deletions include/coap3/coap_session_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
12 changes: 12 additions & 0 deletions include/coap3/coap_subscribe_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 1 addition & 10 deletions src/coap_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
12 changes: 9 additions & 3 deletions src/coap_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
25 changes: 15 additions & 10 deletions src/coap_resource.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -1005,26 +999,37 @@ coap_delete_observer_internal(coap_resource_t *resource, coap_session_t *session
if (coap_get_log_level() >= COAP_LOG_DEBUG) {
char outbuf[2 * 8 + 1] = "";
unsigned int i;
coap_string_t *uri_path;
coap_string_t *uri_query;

for (i = 0; i < s->pdu->actual_token.length; i++) {
size_t size = strlen(outbuf);

snprintf(&outbuf[size], sizeof(outbuf)-size, "%02x",
s->pdu->actual_token.s[i]);
}
coap_log_debug("removed subscription %p with token '%s' key 0x%02x%02x%02x%02x\n",
uri_path = coap_get_uri_path(s->pdu);
uri_query = coap_get_query(s->pdu);
coap_log_debug("removed subscription '/%*.*s%s%*.*s' (%p) with token '%s' key 0x%02x%02x%02x%02x\n",
uri_path ? (int)uri_path->length : 0, uri_path ? (int)uri_path->length : 0,
uri_path ? (char *)uri_path->s : "",
uri_query ? "?" : "",
uri_query ? (int)uri_query->length : 0, uri_query ? (int)uri_query->length : 0,
uri_query ? (char *)uri_query->s : "",
(void *)s, outbuf, s->cache_key->key[0], s->cache_key->key[1],
s->cache_key->key[2], s-> cache_key->key[3]);
coap_delete_string(uri_path);
coap_delete_string(uri_query);
}
if (session->context->observe_deleted)
session->context->observe_deleted(session, s,
session->context->observe_user_data);

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);
Expand Down
29 changes: 29 additions & 0 deletions src/coap_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,35 @@ 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_session_reference_lkd(session);
coap_handle_event_lkd(session->context, COAP_EVENT_KEEPALIVE_FAILURE, session);
coap_cancel_all_messages(session->context, session, NULL);
RESOURCES_ITER(session->context->resources, r) {
int i;

/* In case code is broken somewhere */
for (i = 0; i < 1000; i++) {
if (!coap_delete_observer(r, session, NULL))
break;
}
}
while (session->delayqueue) {
coap_queue_t *q = session->delayqueue;

session->delayqueue = q->next;
coap_delete_node_lkd(q);
}
/* Force session to go away */
coap_session_set_type_client_lkd(session);
coap_session_release_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) {
Expand Down

0 comments on commit 60fbbd3

Please sign in to comment.