2424import com .hivemq .client .internal .mqtt .handler .disconnect .MqttDisconnectUtil ;
2525import com .hivemq .client .internal .mqtt .ioc .ClientScope ;
2626import com .hivemq .client .internal .mqtt .message .MqttMessage ;
27- import com .hivemq .client .internal .mqtt .message .publish .MqttStatefulPublish ;
27+ import com .hivemq .client .internal .mqtt .message .publish .MqttStatefulIncomingPublish ;
2828import com .hivemq .client .internal .mqtt .message .publish .puback .MqttPubAck ;
2929import com .hivemq .client .internal .mqtt .message .publish .puback .MqttPubAckBuilder ;
3030import com .hivemq .client .internal .mqtt .message .publish .pubcomp .MqttPubComp ;
@@ -62,10 +62,11 @@ public class MqttIncomingQosHandler extends MqttSessionAwareHandler
6262
6363 // valid for session
6464 private final @ NotNull IntIndex <MqttMessage .WithId > messages = new IntIndex <>(INDEX_SPEC );
65- // contains StatefulPublish with AT_LEAST_ONCE/EXACTLY_ONCE, MqttPubAck or MqttPubRec
65+ // contains MqttStatefulIncomingPublish with AT_LEAST_ONCE/EXACTLY_ONCE, MqttPubAck or MqttPubRec
6666
6767 // valid for connection
6868 private int receiveMaximum ;
69+ private long connectionIndex ;
6970
7071 @ Inject
7172 MqttIncomingQosHandler (
@@ -81,21 +82,24 @@ public void onSessionStartOrResume(
8182 final @ NotNull MqttClientConnectionConfig connectionConfig , final @ NotNull EventLoop eventLoop ) {
8283
8384 receiveMaximum = connectionConfig .getReceiveMaximum ();
85+ connectionIndex ++;
8486 super .onSessionStartOrResume (connectionConfig , eventLoop );
8587 }
8688
8789 @ Override
8890 public void channelRead (final @ NotNull ChannelHandlerContext ctx , final @ NotNull Object msg ) {
89- if (msg instanceof MqttStatefulPublish ) {
90- readPublish (ctx , (MqttStatefulPublish ) msg );
91+ if (msg instanceof MqttStatefulIncomingPublish ) {
92+ readPublish (ctx , (MqttStatefulIncomingPublish ) msg );
9193 } else if (msg instanceof MqttPubRel ) {
9294 readPubRel (ctx , (MqttPubRel ) msg );
9395 } else {
9496 ctx .fireChannelRead (msg );
9597 }
9698 }
9799
98- private void readPublish (final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulPublish publish ) {
100+ private void readPublish (
101+ final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulIncomingPublish publish ) {
102+
99103 switch (publish .stateless ().getQos ()) {
100104 case AT_MOST_ONCE :
101105 readPublishQos0 (publish );
@@ -109,46 +113,62 @@ private void readPublish(final @NotNull ChannelHandlerContext ctx, final @NotNul
109113 }
110114 }
111115
112- private void readPublishQos0 (final @ NotNull MqttStatefulPublish publish ) {
116+ private void readPublishQos0 (final @ NotNull MqttStatefulIncomingPublish publish ) {
113117 incomingPublishService .onPublishQos0 (publish , receiveMaximum );
114118 }
115119
116- private void readPublishQos1 (final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulPublish publish ) {
120+ private void readPublishQos1 (
121+ final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulIncomingPublish publish ) {
122+
117123 final MqttMessage .WithId prevMessage = messages .putIfAbsent (publish );
118- if (prevMessage == null ) { // new message
124+ if (prevMessage == null ) {
125+ // new message
126+ publish .setConnectionIndex (connectionIndex );
119127 readNewPublishQos1Or2 (ctx , publish );
120- } else if ((prevMessage instanceof MqttStatefulPublish ) &&
121- (((MqttStatefulPublish ) prevMessage ).stateless ().getQos () == MqttQos .AT_LEAST_ONCE )) { // resent message
128+ } else if ((prevMessage instanceof MqttStatefulIncomingPublish ) &&
129+ (((MqttStatefulIncomingPublish ) prevMessage ).stateless ().getQos () == MqttQos .AT_LEAST_ONCE )) {
130+ // resent message
131+ ((MqttStatefulIncomingPublish ) prevMessage ).setConnectionIndex (connectionIndex );
122132 checkDupFlagSet (ctx , publish );
123- } else if (prevMessage instanceof MqttPubAck ) { // resent message and already acknowledged
133+ } else if (prevMessage instanceof MqttPubAck ) {
134+ // resent message and already acknowledged
124135 if (checkDupFlagSet (ctx , publish )) {
125136 writePubAck (ctx , (MqttPubAck ) prevMessage );
126137 }
127- } else { // EXACTLY_ONCE or MqttPubRec
138+ } else {
139+ // EXACTLY_ONCE or MqttPubRec
128140 MqttDisconnectUtil .disconnect (ctx .channel (), Mqtt5DisconnectReasonCode .PROTOCOL_ERROR ,
129141 "QoS 1 PUBLISH must not be received with the same packet identifier as a QoS 2 PUBLISH" );
130142 }
131143 }
132144
133- private void readPublishQos2 (final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulPublish publish ) {
145+ private void readPublishQos2 (
146+ final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulIncomingPublish publish ) {
147+
134148 final MqttMessage .WithId prevMessage = messages .putIfAbsent (publish );
135- if (prevMessage == null ) { // new message
149+ if (prevMessage == null ) {
150+ // new message
151+ publish .setConnectionIndex (connectionIndex );
136152 readNewPublishQos1Or2 (ctx , publish );
137- } else if ((prevMessage instanceof MqttStatefulPublish ) &&
138- (((MqttStatefulPublish ) prevMessage ).stateless ().getQos () == MqttQos .EXACTLY_ONCE )) { // resent message
153+ } else if ((prevMessage instanceof MqttStatefulIncomingPublish ) &&
154+ (((MqttStatefulIncomingPublish ) prevMessage ).stateless ().getQos () == MqttQos .EXACTLY_ONCE )) {
155+ // resent message
156+ ((MqttStatefulIncomingPublish ) prevMessage ).setConnectionIndex (connectionIndex );
139157 checkDupFlagSet (ctx , publish );
140- } else if (prevMessage instanceof MqttPubRec ) { // resent message and already acknowledged
158+ } else if (prevMessage instanceof MqttPubRec ) {
159+ // resent message and already acknowledged
141160 if (checkDupFlagSet (ctx , publish )) {
142161 writePubRec (ctx , (MqttPubRec ) prevMessage );
143162 }
144- } else { // AT_LEAST_ONCE or MqttPubAck
163+ } else {
164+ // AT_LEAST_ONCE or MqttPubAck
145165 MqttDisconnectUtil .disconnect (ctx .channel (), Mqtt5DisconnectReasonCode .PROTOCOL_ERROR ,
146166 "QoS 2 PUBLISH must not be received with the same packet identifier as a QoS 1 PUBLISH" );
147167 }
148168 }
149169
150170 private void readNewPublishQos1Or2 (
151- final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulPublish publish ) {
171+ final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulIncomingPublish publish ) {
152172
153173 if (!incomingPublishService .onPublishQos1Or2 (publish , receiveMaximum )) {
154174 MqttDisconnectUtil .disconnect (ctx .channel (), Mqtt5DisconnectReasonCode .RECEIVE_MAXIMUM_EXCEEDED ,
@@ -157,7 +177,7 @@ private void readNewPublishQos1Or2(
157177 }
158178
159179 private boolean checkDupFlagSet (
160- final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulPublish publish ) {
180+ final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttStatefulIncomingPublish publish ) {
161181
162182 if (!publish .isDup ()) {
163183 MqttDisconnectUtil .disconnect (ctx .channel (), Mqtt5DisconnectReasonCode .PROTOCOL_ERROR ,
@@ -168,25 +188,39 @@ private boolean checkDupFlagSet(
168188 }
169189
170190 @ CallByThread ("Netty EventLoop" )
171- void ack (final @ NotNull MqttStatefulPublish publish ) {
191+ void ack (final @ NotNull MqttStatefulIncomingPublish publish ) {
172192 switch (publish .stateless ().getQos ()) {
173193 case AT_LEAST_ONCE :
174194 final MqttPubAck pubAck = buildPubAck (new MqttPubAckBuilder (publish ));
175- messages .put (pubAck );
176- if (ctx != null ) {
195+ if (ack (publish , pubAck ) && (ctx != null )) {
177196 writePubAck (ctx , pubAck );
178197 }
179198 break ;
180199 case EXACTLY_ONCE :
181200 final MqttPubRec pubRec = buildPubRec (new MqttPubRecBuilder (publish ));
182- messages .put (pubRec );
183- if (ctx != null ) {
201+ if (ack (publish , pubRec ) && (ctx != null )) {
184202 writePubRec (ctx , pubRec );
185203 }
186204 break ;
187205 }
188206 }
189207
208+ private boolean ack (
209+ final @ NotNull MqttStatefulIncomingPublish publish , final @ NotNull MqttMessage .WithId pubAckOrRec ) {
210+
211+ final MqttMessage .WithId prevMessage = messages .put (pubAckOrRec );
212+ if (prevMessage != publish ) {
213+ // message has been overwritten by a new message because session state on server differs
214+ if (prevMessage == null ) {
215+ messages .remove (pubAckOrRec .getPacketIdentifier ());
216+ } else {
217+ messages .put (prevMessage );
218+ }
219+ return false ;
220+ }
221+ return publish .getConnectionIndex () == connectionIndex ;
222+ }
223+
190224 private void writePubAck (final @ NotNull ChannelHandlerContext ctx , final @ NotNull MqttPubAck pubAck ) {
191225 ctx .writeAndFlush (pubAck , new DefaultContextPromise <>(ctx .channel (), pubAck )).addListener (this );
192226 }
@@ -216,8 +250,8 @@ private void readPubRel(final @NotNull ChannelHandlerContext ctx, final @NotNull
216250 writePubComp (
217251 ctx , buildPubComp (new MqttPubCompBuilder (pubRel ).reasonCode (
218252 Mqtt5PubCompReasonCode .PACKET_IDENTIFIER_NOT_FOUND )));
219- } else if ((prevMessage instanceof MqttStatefulPublish ) &&
220- (((MqttStatefulPublish ) prevMessage ).stateless ().getQos () ==
253+ } else if ((prevMessage instanceof MqttStatefulIncomingPublish ) &&
254+ (((MqttStatefulIncomingPublish ) prevMessage ).stateless ().getQos () ==
221255 MqttQos .EXACTLY_ONCE )) { // PubRec not sent yet
222256 messages .put (prevMessage ); // revert
223257 MqttDisconnectUtil .disconnect (ctx .channel (), Mqtt5DisconnectReasonCode .PROTOCOL_ERROR ,
0 commit comments