zevv / nmqtt

Native Nim MQTT client library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BUG: Messages is sent twice

ThomasTJdev opened this issue · comments

During the implementation of PR #9 , the subscribe() failed when using asyncCheck. Debugging the packages on the broker and using -d:dev on nmqtt shows, that the packages are sent twice (2).

To make a quick workaround, the commit 62e5d8f checks, that the SUBACK package received matches the msgId in the queue - due to deletion of the first send message, which would crash the program when trying to delete the same package again.

The problem is also shown on the publish - which might could be part of issue #7?

Subscribe

Broker

1584256896: Sending CONNACK to hallo (0, 0)
1584256897: Received PINGREQ from hallo
1584256897: Sending PINGRESP to hallo
1584256897: Received SUBSCRIBE from hallo # => HERE
1584256897: 	# (QoS 2)
1584256897: Sending SUBACK to hallo  # => Package received, and msgId removed
1584256897: Received SUBSCRIBE from hallo # => HERE
1584256897: 	# (QoS 2)
1584256897: Sending SUBACK to hallo  # => Crash due to msgId already deleted
1584256898: Received PINGREQ from hallo
1584256898: Sending PINGRESP to hallo
1584256899: Received PINGREQ from hallo

Client

tx> Subscribe(02): 00 01 00 01 23 02 
tx> Subscribe(02): 00 01 00 01 23 02 
rx> PingResp(00): 
rx> SubAck(00): 00 01 02  # => HERE
rx> SubAck(00): 00 01 02  # => HERE
tx> PingReq(00): 
rx> PingResp(00): 
tx> PingReq(00): 

Publish

Broker

1584257384: Received PUBLISH from hallo (d0, q2, r0, m1, 'test1', ... (5 bytes))
1584257384: Sending PUBREC to hallo (m1, rc0)
1584257384: Received PUBLISH from hallo (d0, q2, r0, m1, 'test1', ... (5 bytes))
1584257384: Sending PUBREC to hallo (m1, rc0)
1584257384: Received PUBREL from hallo (Mid: 1)
1584257384: Sending PUBCOMP to hallo (m1)
1584257384: Received PUBREL from hallo (Mid: 1)
1584257384: Sending PUBCOMP to hallo (m1)

Client

tx> Publish(04): 00 05 74 65 73 74 31 00 01 68 61 6C 6C 6F 
tx> Publish(04): 00 05 74 65 73 74 31 00 01 68 61 6C 6C 6F 
rx> PingResp(00): 
rx> PubRec(00): 00 01 
tx> PubRel(02): 00 01 
rx> PubRec(00): 00 01 
tx> PubRel(02): 00 01 
rx> PubComp(00): 00 01 
rx> PubComp(00): 00 01 

Using asyncCheck instead of await in send() eliminates the double sending.

  asyncCheck ctx.s.send(hdr[0].unsafeAddr, hdr.len)

  if len > 0:
    asyncCheck ctx.s.send(pkt.data[0].unsafeAddr, len)

My guess is that work() messes up its bookkeeping because it can be scheduled on async work while it is called again (for example, from the ping async proc) , and its current design is not safe for reentrancy.

This should be the simple fix for that: https://github.com/zevv/nmqtt/pull/new/zevv-inwork, making it safe to call work()

My guess is that work() messes up its bookkeeping because it can be scheduled on async work while it is called again (for example, from the ping async proc) , and its current design is not safe for reentrancy.

This should be the simple fix for that: https://github.com/zevv/nmqtt/pull/new/zevv-inwork, making it safe to call work()

That's a good solution.

Closing in relation to #13