eclipse-paho / eclipse-paho/paho.mqtt.java

Deadlock occurs if QoS0 publication fails due to connection failure

Open
#812 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
2.3k
Forks
919
PR merge metrics
No merged PRs in 30d

Description

Please fill out the form below before submitting, thank you!

- [X] Bug exists Release Version 1.2.5 ( Master Branch)
- [X] Bug exists in MQTTv3 Client on Snapshot Version 1.2.6-SNAPSHOT (Develop Branch)
- [ ] Bug exists in MQTTv5 Client on Snapshot Version 1.2.6-SNAPSHOT (Develop Branch)

MqttToken may not be signaled for QoS0 publications, when a connection error is encountered.
I was originally using Paho MQTT v1.2.1, but it is still present as of v1.2.5 (inclusive of the v1.2.6 under development).

I do not know if it affects the MQTTv5 client, as I do not use MQTTv5.

This glitch occurs because ClientState.send() does not set the MqttToken into the tokenStore for QoS0.
```
switch(innerMessage.getQos()) {
case 2:
outboundQoS2.put( Integer.valueOf(message.getMessageId()), message);
persistence.put(getSendPersistenceKey(message), (MqttPublish) message);
tokenStore.saveToken(token, message);
break;
case 1:
outboundQoS1.put( Integer.valueOf(message.getMessageId()), message);
persistence.put(getSendPersistenceKey(message), (MqttPublish) message);
tokenStore.saveToken(token, message);
break;
case 0: // <-- Currently missing. Save the token, for possibly notifying listeners of failure.
tokenStore.saveToken(token, message);
break;
}
```

When a connection error is encountered, ClientComms.handleOldTokens() fails to notify any listeners for QoS0 publication completion, as tokenStore remains empty.

I think ClientState.send() should call tokenStore.saveToken() for QoS0, as ClientState.notifySent() calls tokenStore.removeToken() for QoS0 - but this call does not remove anything since no tokens are saved.
```
else if (message instanceof MqttPublish) {
if (((MqttPublish)message).getMessage().getQos() == 0) {
// once a QoS 0 message is sent we can clean up its records straight away as
// we won't be hearing about it again
token.internalTok.markComplete(null, null);
callback.asyncOperationComplete(token);
decrementInFlight();
releaseMessageId(message.getMessageId());
tokenStore.removeToken(message);
checkQuiesceLock();
}
}
}
```

I'll be raising a PR to solve this, soon.

Contributor guide

Open the contributing guide

Research direction

Start in ClientState.send(), where the issue identifies the missing QoS0 token handling, then inspect ClientState.notifySent() and ClientComms.handleOldTokens(). Confirm that a QoS0 publication token is available when a connection error occurs and that the failure is delivered to listeners without breaking normal completion cleanup.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
networking
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.