net: lwm2m: Clean up context on stop

When lwm2m_rd_client_stop() was called and immediately
followed by lwm2m_rd_client_start() it leaked the file
handle for existing socket.

Problem can be fixed when rd_client_stop() does not
move state machine to IDLE, but instead DEREGISTER
and then allow state machine to move forward.

I added a blocking wait for rd_client_stop() because
it needs to wait for proper clean up.

I also move couple of lwm2m_engine_context_close() to
set_sm_state() event handler or similarly in lwm2m_engine.c
there was couple of places where context was not properly
cleaned.

Signed-off-by: Seppo Takalo <seppo.takalo@nordicsemi.no>
This commit is contained in:
Seppo Takalo 2022-03-30 15:24:37 +03:00 committed by Carles Cufí
commit 43c988d43e
2 changed files with 38 additions and 18 deletions

View file

@ -5591,8 +5591,9 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
{ {
socklen_t addr_len; socklen_t addr_len;
int flags; int flags;
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
int ret; int ret;
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
uint8_t tmp; uint8_t tmp;
if (client_ctx->load_credentials) { if (client_ctx->load_credentials) {
@ -5636,10 +5637,9 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
ret = setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST, ret = setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST,
tls_tag_list, sizeof(tls_tag_list)); tls_tag_list, sizeof(tls_tag_list));
if (ret < 0) { if (ret < 0) {
LOG_ERR("Failed to set TLS_SEC_TAG_LIST option: %d", ret = -errno;
errno); LOG_ERR("Failed to set TLS_SEC_TAG_LIST option: %d", ret);
lwm2m_engine_context_close(client_ctx); goto error;
return -errno;
} }
if (client_ctx->hostname_verify && (client_ctx->desthostname != NULL)) { if (client_ctx->hostname_verify && (client_ctx->desthostname != NULL)) {
@ -5656,9 +5656,9 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
/** restore character */ /** restore character */
client_ctx->desthostname[client_ctx->desthostnamelen] = tmp; client_ctx->desthostname[client_ctx->desthostnamelen] = tmp;
if (ret < 0) { if (ret < 0) {
LOG_ERR("Failed to set TLS_HOSTNAME option: %d", errno); ret = -errno;
lwm2m_engine_context_close(client_ctx); LOG_ERR("Failed to set TLS_HOSTNAME option: %d", ret);
return -errno; goto error;
} }
} }
} }
@ -5674,18 +5674,31 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
if (connect(client_ctx->sock_fd, &client_ctx->remote_addr, if (connect(client_ctx->sock_fd, &client_ctx->remote_addr,
addr_len) < 0) { addr_len) < 0) {
LOG_ERR("Cannot connect UDP (-%d)", errno); ret = -errno;
lwm2m_engine_context_close(client_ctx); LOG_ERR("Cannot connect UDP (%d)", ret);
return -errno; goto error;
} }
flags = fcntl(client_ctx->sock_fd, F_GETFL, 0); flags = fcntl(client_ctx->sock_fd, F_GETFL, 0);
if (flags == -1) { if (flags == -1) {
return -errno; ret = -errno;
LOG_ERR("fcntl(F_GETFL) failed (%d)", ret);
goto error;
} }
fcntl(client_ctx->sock_fd, F_SETFL, flags | O_NONBLOCK); ret = fcntl(client_ctx->sock_fd, F_SETFL, flags | O_NONBLOCK);
if (ret == -1) {
ret = -errno;
LOG_ERR("fcntl(F_SETFL) failed (%d)", ret);
goto error;
}
LOG_INF("Connected, sock id %d", client_ctx->sock_fd);
return lwm2m_socket_add(client_ctx); return lwm2m_socket_add(client_ctx);
error:
lwm2m_engine_context_close(client_ctx);
return ret;
} }
int lwm2m_parse_peerinfo(char *url, struct lwm2m_ctx *client_ctx, bool is_firmware_uri) int lwm2m_parse_peerinfo(char *url, struct lwm2m_ctx *client_ctx, bool is_firmware_uri)

View file

@ -155,8 +155,10 @@ static void set_sm_state(uint8_t sm_state)
sm_state == ENGINE_DEREGISTERED) && sm_state == ENGINE_DEREGISTERED) &&
(client.engine_state >= ENGINE_DO_REGISTRATION && (client.engine_state >= ENGINE_DO_REGISTRATION &&
client.engine_state <= ENGINE_DEREGISTER_SENT)) { client.engine_state <= ENGINE_DEREGISTER_SENT)) {
lwm2m_engine_context_close(client.ctx);
event = LWM2M_RD_CLIENT_EVENT_DISCONNECT; event = LWM2M_RD_CLIENT_EVENT_DISCONNECT;
} else if (sm_state == ENGINE_NETWORK_ERROR) { } else if (sm_state == ENGINE_NETWORK_ERROR) {
lwm2m_engine_context_close(client.ctx);
client.retry_delay = 1 << client.retries; client.retry_delay = 1 << client.retries;
client.retries++; client.retries++;
if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) { if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) {
@ -231,6 +233,7 @@ static void sm_handle_failure_state(enum sm_engine_state sm_state)
event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE; event = LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE;
} }
lwm2m_engine_context_close(client.ctx);
set_sm_state(sm_state); set_sm_state(sm_state);
if (event > LWM2M_RD_CLIENT_EVENT_NONE && client.event_cb) { if (event > LWM2M_RD_CLIENT_EVENT_NONE && client.event_cb) {
@ -456,7 +459,6 @@ static int do_deregister_reply_cb(const struct coap_packet *response,
if (code == COAP_RESPONSE_CODE_DELETED) { if (code == COAP_RESPONSE_CODE_DELETED) {
LOG_INF("Deregistration success"); LOG_INF("Deregistration success");
lwm2m_engine_context_close(client.ctx);
set_sm_state(ENGINE_DEREGISTERED); set_sm_state(ENGINE_DEREGISTERED);
return 0; return 0;
} }
@ -678,7 +680,6 @@ static int sm_do_bootstrap_reg(void)
set_sm_state(ENGINE_BOOTSTRAP_REG_SENT); set_sm_state(ENGINE_BOOTSTRAP_REG_SENT);
} else { } else {
LOG_ERR("Bootstrap registration err: %d", ret); LOG_ERR("Bootstrap registration err: %d", ret);
lwm2m_engine_context_close(client.ctx);
set_sm_state(ENGINE_NETWORK_ERROR); set_sm_state(ENGINE_NETWORK_ERROR);
} }
@ -896,7 +897,6 @@ static int sm_do_registration(void)
set_sm_state(ENGINE_REGISTRATION_SENT); set_sm_state(ENGINE_REGISTRATION_SENT);
} else { } else {
LOG_ERR("Registration err: %d", ret); LOG_ERR("Registration err: %d", ret);
lwm2m_engine_context_close(client.ctx);
set_sm_state(ENGINE_NETWORK_ERROR); set_sm_state(ENGINE_NETWORK_ERROR);
} }
@ -951,7 +951,8 @@ static int sm_do_deregister(void)
msg = lwm2m_get_message(client.ctx); msg = lwm2m_get_message(client.ctx);
if (!msg) { if (!msg) {
LOG_ERR("Unable to get a lwm2m message!"); LOG_ERR("Unable to get a lwm2m message!");
return -ENOMEM; ret = -ENOMEM;
goto close_ctx;
} }
msg->type = COAP_TYPE_CON; msg->type = COAP_TYPE_CON;
@ -992,7 +993,9 @@ static int sm_do_deregister(void)
cleanup: cleanup:
lwm2m_reset_message(msg, true); lwm2m_reset_message(msg, true);
close_ctx:
lwm2m_engine_context_close(client.ctx); lwm2m_engine_context_close(client.ctx);
set_sm_state(ENGINE_DEREGISTERED);
return ret; return ret;
} }
@ -1129,12 +1132,16 @@ void lwm2m_rd_client_stop(struct lwm2m_ctx *client_ctx,
if (sm_is_registered() && deregister) { if (sm_is_registered() && deregister) {
set_sm_state(ENGINE_DEREGISTER); set_sm_state(ENGINE_DEREGISTER);
} else { } else {
set_sm_state(ENGINE_IDLE); set_sm_state(ENGINE_DEREGISTERED);
} }
LOG_INF("Stop LWM2M Client: %s", log_strdup(client.ep_name)); LOG_INF("Stop LWM2M Client: %s", log_strdup(client.ep_name));
k_mutex_unlock(&client.mutex); k_mutex_unlock(&client.mutex);
while (get_sm_state() != ENGINE_IDLE) {
k_sleep(K_MSEC(STATE_MACHINE_UPDATE_INTERVAL_MS / 2));
}
} }
void lwm2m_rd_client_update(void) void lwm2m_rd_client_update(void)