Serdar Gökay created CAMEL-26349:
------------------------------------

             Summary: camel-paho-mqtt5 - a CamelPahoMqtt5MsgProperties header 
shared by several publishes (split, multicast, loop) gets a topic alias written 
into it by Paho, so messages arrive on the wrong topic
                 Key: CAMEL-26349
                 URL: https://issues.apache.org/jira/browse/CAMEL-26349
             Project: Camel
          Issue Type: Bug
          Components: camel-paho-mqtt5
    Affects Versions: 4.23.0
         Environment: Camel 4.23.0, Eclipse Paho mqttv5 client 1.2.5, Mosquitto 
2.0.22 (default max_topic_alias 10), JDK 25
            Reporter: Serdar Gökay


An MQTT-to-MQTT route that consumes from {{paho-mqtt5}}, splits each message 
and publishes every part to its own topic with {{CamelPahoMqtt5OverrideTopic}} 
delivers some payloads on the wrong topic, with no error and no log line.

The cause is one {{MqttProperties}} object used by several publishes:
# The consumer puts the received message's {{MqttProperties}} object in the 
{{CamelPahoMqtt5MsgProperties}} header ({{PahoMqtt5Consumer.createExchange}}).
# Split, multicast, recipient list, loop and wire tap copy header references, 
so every publish of the exchange tree sees the same object.
# The producer passes the object from that header to 
{{MqttMessage.setProperties}} without copying it 
({{PahoMqtt5Producer.process}}).
# Paho 1.2.5 keeps the caller's object ({{MqttAsyncClient.publish}} creates 
{{new MqttPublish(topic, message, message.getProperties())}}) and 
{{ClientState.send}} writes the outgoing topic alias into it.
# Once the connection has used the Topic Alias Maximum the broker granted in 
CONNACK (mosquitto default 10), {{ClientState.send}} assigns no alias for a new 
topic but does not clear the alias left by the previous publish. The packet 
goes out with the new topic name and that alias, the broker maps the alias to 
the new topic, and later alias-only publishes for the old topic are delivered 
on the new topic.

A route that publishes once per received message is not affected, because each 
received message has its own properties object.

Reproducer (Camel JBang 4.23.0, mosquitto 2.0.22 with its default configuration 
on port 18883), repro.camel.yaml:
{noformat}
- route:
    id: trigger
    from:
      uri: timer:trigger
      parameters: {period: 1000, repeatCount: 5, delay: 3000}
      steps:
        - setBody: {constant: "{{items}}"}
        - to:
            uri: "paho-mqtt5:{{root}}/in/x"
            parameters: {brokerUrl: "tcp://127.0.0.1:18883"}
- route:
    id: relay
    from:
      uri: "paho-mqtt5:{{root}}/in/x"
      parameters: {brokerUrl: "tcp://127.0.0.1:18883"}
      steps:
        - convertBodyTo: {type: java.lang.String}
        - choice:
            when:
              - simple: "{{strip}} == true"
                steps:
                  - removeHeader: {name: CamelPahoMqtt5MsgProperties}
        - split:
            tokenize: ","
            steps:
              - setHeader:
                  name: CamelPahoMqtt5OverrideTopic
                  simple: "{{root}}/out/${body}"
              - to:
                  uri: "paho-mqtt5:{{root}}/out/unrouted"
                  parameters: {brokerUrl: "tcp://127.0.0.1:18883"}
- route:
    id: check
    from:
      uri: "paho-mqtt5:{{root}}/out/#"
      parameters: {brokerUrl: "tcp://127.0.0.1:18883"}
      steps:
        - convertBodyTo: {type: java.lang.String}
        - choice:
            when:
              - simple: "${header.CamelMqttTopic} == '{{root}}/out/${body}'"
                steps:
                  - log: "RESULT OK topic=${header.CamelMqttTopic} body=${body}"
            otherwise:
              steps:
                - log: "RESULT MISMATCH topic=${header.CamelMqttTopic} 
body=${body}"
{noformat}
{noformat}
camel run repro.camel.yaml --max-seconds=20 --prop root=check30 --prop 
items=1,2,3,...,30 --prop strip=false
{noformat}
Results (5 batches each; a mismatch is a payload delivered on another item's 
topic):
||Items per message||CamelPahoMqtt5MsgProperties||Broker 
max_topic_alias||Correct||Wrong topic||
|30|kept|10 (default)|146|4|
|30|removed before split|10 (default)|150|0|
|10|kept|10 (default)|50|0|
|11|kept|10 (default)|51|4|
|30|kept|0|150|0|
With 30 items, from the second batch on the payload for out/10 arrives on 
out/30, the last topic that alias 10 was mapped to.

Affected: 4.7.0 (CAMEL-20754) up to 4.23.0 and main.

Suggested fix: the producer builds a new {{MqttProperties}} with only the 
publish properties from the header (payload format indicator, message expiry 
interval, content type, response topic, correlation data, user properties) and 
leaves out the topic alias, which belongs to one connection, and subscription 
identifiers, which a client must not send (MQTT 5 section 3.3.4). 
{{MqttProperties}} has no copy constructor, so the copy is field by field.

Workaround: remove the {{CamelPahoMqtt5MsgProperties}} header before 
publishing, or disable topic aliases on the broker.




--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to