@@ -3281,7 +3281,7 @@ func TestMQTTRetainedMsgNetworkUpdates(t *testing.T) {
32813281 for _ , a := range test .order {
32823282 if a .add {
32833283 rf := & mqttRetainedMsgRef {sseq : a .seq }
3284- asm .handleRetainedMsg (test .subject , rf , nil , false )
3284+ asm .handleRetainedMsg (test .subject , rf , nil )
32853285 } else {
32863286 asm .handleRetainedMsgDel (test .subject , a .seq )
32873287 }
@@ -3294,7 +3294,7 @@ func TestMQTTRetainedMsgNetworkUpdates(t *testing.T) {
32943294 t .Run ("clear_" + subject , func (t * testing.T ) {
32953295 // Now add a new message, which should clear the floor.
32963296 rf := & mqttRetainedMsgRef {sseq : 3 }
3297- asm .handleRetainedMsg (subject , rf , nil , false )
3297+ asm .handleRetainedMsg (subject , rf , nil )
32983298 check (t , subject , true , 3 , 0 )
32993299 // Now do a non network delete and make sure it is gone.
33003300 asm .handleRetainedMsgDel (subject , 0 )
@@ -3315,7 +3315,7 @@ func TestMQTTRetainedMsgDel(t *testing.T) {
33153315 var i uint64
33163316 for i = 0 ; i < 3 ; i ++ {
33173317 rf := & mqttRetainedMsgRef {sseq : i }
3318- asm .handleRetainedMsg ("subject" , rf , nil , false )
3318+ asm .handleRetainedMsg ("subject" , rf , nil )
33193319 }
33203320 asm .handleRetainedMsgDel ("subject" , 2 )
33213321 if asm .sl .count > 0 {
@@ -3406,6 +3406,102 @@ func TestMQTTRetainedMsgMigration(t *testing.T) {
34063406 }
34073407}
34083408
3409+ func TestMQTTRetainedNoMsgBodyCorruption (t * testing.T ) {
3410+ f := func () {
3411+ o := testMQTTDefaultOptions ()
3412+ s := testMQTTRunServer (t , o )
3413+ defer testMQTTShutdownServer (s )
3414+
3415+ // Send a retained message.
3416+ c , r := testMQTTConnect (t , & mqttConnInfo {cleanSess : true }, o .MQTT .Host , o .MQTT .Port )
3417+ defer c .Close ()
3418+ testMQTTCheckConnAck (t , r , mqttConnAckRCConnectionAccepted , false )
3419+ testMQTTPublish (t , c , r , 0 , false , true , "foo/bar" , 0 , []byte ("retained 1" ))
3420+ testMQTTFlush (t , c , nil , r )
3421+
3422+ checkRetained := func (msg string ) {
3423+ t .Helper ()
3424+ c , r := testMQTTConnect (t , & mqttConnInfo {cleanSess : true }, o .MQTT .Host , o .MQTT .Port )
3425+ defer c .Close ()
3426+ testMQTTCheckConnAck (t , r , mqttConnAckRCConnectionAccepted , false )
3427+ testMQTTSub (t , 1 , c , r , []* mqttFilter {{filter : "foo/#" , qos : 0 }}, []byte {0 })
3428+ testMQTTCheckPubMsg (t , c , r , "foo/bar" , mqttPubFlagRetain , []byte (msg ))
3429+ }
3430+ // Subscribe to make it load into the cache.
3431+ checkRetained ("retained 1" )
3432+
3433+ // Now send another one.
3434+ testMQTTPublish (t , c , r , 0 , false , true , "foo/bar" , 0 , []byte ("retained 2" ))
3435+ testMQTTFlush (t , c , nil , r )
3436+
3437+ // Check it is updated
3438+ checkRetained ("retained 2" )
3439+
3440+ // Now we will simulate an update coming from another server
3441+ // if we were in cluster mode.
3442+ nc := natsConnect (t , s .ClientURL ())
3443+ defer nc .Close ()
3444+
3445+ msg := nats .NewMsg ("$MQTT.rmsgs.foo.bar" )
3446+ msg .Header .Set (mqttNatsRetainedMessageOrigin , "XXXXXXXX" )
3447+ msg .Header .Set (mqttNatsRetainedMessageTopic , "foo/bar" )
3448+ msg .Header .Set (mqttNatsRetainedMessageFlags , "1" )
3449+ msg .Data = []byte ("retained 3" )
3450+
3451+ // Have a continuous flow of updates coming in
3452+ wg := sync.WaitGroup {}
3453+ wg .Add (1 )
3454+ ch := make (chan struct {})
3455+ go func () {
3456+ defer wg .Done ()
3457+ for {
3458+ nc .PublishMsg (msg )
3459+ select {
3460+ case <- ch :
3461+ return
3462+ default :
3463+ }
3464+ }
3465+ }()
3466+
3467+ s .mu .RLock ()
3468+ sm := & s .mqtt .sessmgr
3469+ s .mu .RUnlock ()
3470+ sm .mu .RLock ()
3471+ as := sm .sessions [globalAccountName ]
3472+ sm .mu .RUnlock ()
3473+ require_True (t , as != nil )
3474+ as .mu .RLock ()
3475+ cache := as .rmsCache
3476+ as .mu .RUnlock ()
3477+
3478+ // Wait to make sure at least the first update occurs
3479+ checkFor (t , time .Second , 10 * time .Millisecond , func () error {
3480+ v , ok := cache .Load ("foo.bar" )
3481+ if ! ok {
3482+ return errors .New ("not in the cache" )
3483+ }
3484+ rm := v .(* mqttRetainedMsg )
3485+ if ! bytes .Equal (rm .Msg , []byte ("retained 3" )) {
3486+ return fmt .Errorf ("Retained message not updated, got %q" , rm .Msg )
3487+ }
3488+ return nil
3489+ })
3490+ // Repeat starting a subscription to check the retained message and
3491+ // make sure it is not corrupted. With the bug, the payload will at
3492+ // the very least contain trailing "\r\n" and possibly be corrupted
3493+ // (and the race detector would report a race).
3494+ for range 50 {
3495+ checkRetained ("retained 3" )
3496+ }
3497+ close (ch )
3498+ wg .Wait ()
3499+ }
3500+ for range 5 {
3501+ f ()
3502+ }
3503+ }
3504+
34093505func TestMQTTClusterReplicasCount (t * testing.T ) {
34103506 for _ , test := range []struct {
34113507 size int
0 commit comments