New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Retain bit not set on messages published to bridges (protocol level 131) #1223
Comments
Hi @trarbr Thanks for the detailed write-up - we'll take a look as soon as possible! |
Hi @larshesel Thanks for the quick response. I just tested it out. Unfortunately, it does not solve the issue. Retained messages forwarded from VerneMQ to the Mosquitto bridge client still do not have the retain bit set to 1. It seems like the changes in the PR relate to vmq_bridge, which I assume is only relevant when VerneMQ is a bridge client. Fixing that sounds like a good idea as well, but in our situation, VerneMQ is the central broker that the Mosquitto bridge client is connecting to. |
I noticed that bridging is actually incorporated in MQTT v5, so I guess the features needed might already be in your MQTT v5 handler? This is mentioned in the Subscription Options part of the MQTT v5 spec. To quote:
I dived into the codebase a bit, and found this which handles the "retain as published" flag. I wonder if it might be possible to set this "retain as published" flag in the subscriber info for connections using protocol 131? I guess that should just fix it? (OK, I bet it's not simply, but hopefully food for thought...) If not, we will just have to wait until Mosquitto's bridge can connect using MQTT v5 😄 |
Digging into it a little more... The Would it be acceptable to either add a special case to connected(#mqtt_subscribe{message_id=MessageId, topics=Topics}, State) ->
...
SubTopics = subtopics(MaybeChangedTopics, map:get(proto, State))
...
.
%% Internal functions
subtopics(Topics, 131 = _proto) ->
SubTopics = vmq_mqtt_fsm_util:to_vmq_subtopics(MaybeChangedTopics, undefined)
lists:map(fun({T, QoS}) -> {T, #{rap => true}} end);
subtopics(Topics, _proto) ->
vmq_mqtt_fsm_util:to_vmq_subtopics(MaybeChangedTopics, undefined). (Please excuse my bad pseudo-erlang) |
Hi @trarbr sorry for me confusing the issue - I'd taken a quick look and noticed that the VerneMQ bridge didn't forward/handle the retained flag at all, which was wrong and then I assumed this was the problem... So, I just looked at the MQTT (3.1.1) spec to see how the retain bit is handled, and the relevant snippet is this:
I'm pretty sure VerneMQ forwards the bit like this: when a retained message is published and a subscription already existed the retain flag is 0 and it is only set to 1 when the subscription is made an an retained message is already stored. Does this make sense? Perhaps the tests you did didn't take this into account? |
Hi @larshesel, no problem - the bridge terminology is quite confusing to me as well. Yes, VerneMQ's current handling of the retain bit is exactly what is described in MQTT 3.1.1. This matches our observations. And this is great in the majority of cases, except when the clients connect with the try_private protocol (131). The reason protocol 131 exists is exactly to change the handling of retained bits (and to do loop detection). And both of these features were added to MQTT 5 as part of the subscription options (bits 2 and 3), in order to make bridges first-class citizens. So while VerneMQ currently accepts connections with protocol 131, it doesn't actually implement these changes to the MQTT protocol. Since the logic for Retain as Published (and no-local I assume) is already implemented for MQTT 5, I imagine VerneMQ could implement protocol 131 by piggybacking on the logic you implemented for MQTT 5. |
I just built VerneMQ from master and went through the steps outlined above - and I am happy to say that the issue with retained bits has been fixed 👏 Thank you so much for your work on VerneMQ 🍰 |
Environment
Expected behavior
Imagine the following setup
The Mosquitto broker is connected to the VerneMQ broker as a bridge client, using the private bridge protocol (131). When Client A publishes a message to the VerneMQ broker with Retain set to 1, the Mosquitto bridge should receive the message with Retain set to 1.
Actual behaviour
In the above scenario, the Retain bit is currently set to 0 when sent from VerneMQ broker to Mosquitto bridge. Also, if Client B publishes a message to the Mosquitto bridge with Retain set to 1, VerneMQ receives the message with Retain set to 1 (as expected). So it looks like this:
But it should look like this (only thing changed is the Retain bit from VerneMQ to Mosquitto):
In fact, if the VerneMQ broker is swapped with a Mosquitto broker, the Retain bit is propagated as expected.
The following steps first reproduce the expected behaviour using Mosquitto, and then the behaviour with VerneMQ:
First create two configuration files for the Mosquitto brokers:
Start the mosq-central broker:
/usr/local/sbin/mosquitto -c mosq-central.conf
Start the mosq-bridge broker:
/usr/local/sbin/mosquitto -c mosq-bridge.conf
Start a client A that subscribes to mosq-central:
mosquitto_sub -p 1883 -t '#' -F 'topic="%t" payload="%p" retained="%r"'
Start a client B that subscribes to mosq-bridge:
mosquitto_sub -p 11883 -t '#' -F 'topic="%t" payload="%p" retained="%r"'
Publish a retained message to mosq-central on a bridged topic:
mosquitto_pub -p 1883 -t 'to/bridge/central-says' -m '1' -r
Client A prints (as expected)
topic="to/bridge/central-says" payload="1" retained="0"
Client B prints (as expected)
topic="from/central/central-says" payload="1" retained="0"
Now disconnect client A and reconnect it. Client A prints (as expected)
topic="to/bridge/central-says" payload="1" retained="1"
Now disconnect client B and reconnect it. Client B prints (as expected)
topic="from/central/central-says" payload="1" retained="1"
Stop the mosq-central broker and start a VMQ broker instead:
docker run -e "DOCKER_VERNEMQ_ALLOW_ANONYMOUS=on" -p 1883:1883 erlio/docker-vernemq:1.8.0-alpine
. Go through steps 2-7. Everything will be the same, except step 7: When reconnected, Client B does not receive the retained message (as the Mosquitto bridge did not receive the message with the Retain bit set to 1).The text was updated successfully, but these errors were encountered: