net: mqtt: Reset client state before notifying MQTT_EVT_DISCONNECT

MQTT client state is protected using mutex. That mutex however is
temporarily unlocked when calling event callbacks. This means that in
client_disconnect() transport can already be disconnected, but without
marking it as such in client->internal.state.

When mutex is unlocked in event_notify() function, then there are two
possible paths of failure:

1) First possibility is when RX and TX are called from two separate
   threads, so that the other thread gets resumed and functions like
   verify_tx_state() (e.g. in mqtt_publish()) allow to continue
   communication over disconnected medium.
2) Another possibility is that user calls mqtt_abort() or
   mqtt_disconnect() in event handler.

In both cases MQTT library tries to send or receive data, possibly
followed by second close() of underlying file descriptor.

Prevent using disconnected transport by clearing MQTT client state right
after calling mqtt_transport_disconnect(), without releasing mutex, even
for a while.

Signed-off-by: Marcin Niestroj <m.niestroj@grinn-global.com>
This commit is contained in:
Marcin Niestroj 2020-09-29 16:09:16 +02:00 committed by Jukka Rissanen
parent 5fd53dcd8a
commit 9a791dd6bb

View file

@ -56,6 +56,9 @@ static void client_disconnect(struct mqtt_client *client, int result,
MQTT_ERR("Failed to disconnect transport!");
}
/* Reset internal state. */
client_reset(client);
if (notify) {
struct mqtt_evt evt = {
.type = MQTT_EVT_DISCONNECT,
@ -65,9 +68,6 @@ static void client_disconnect(struct mqtt_client *client, int result,
/* Notify application. */
event_notify(client, &evt);
}
/* Reset internal state. */
client_reset(client);
}
static int client_connect(struct mqtt_client *client)