eclipse-paho / eclipse-paho/paho.mqtt.java
Deadlock occurs if QoS0 publication fails due to connection failure
- 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
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