mqttjs / mqtt-packet

Parse and generate MQTT packets like a breeze in JS
Other
206 stars 93 forks source link

Cannot connect to some MQTT server when the connect packet sent in chunk instead of full packet at once #123

Open gazsiazasz opened 3 years ago

gazsiazasz commented 3 years ago

I am trying to connect to an MQTT server over websocket(was actually, but I think it doesn't matter). But the connection attempt fails, because the client sends the connect packet in little chunks: https://github.com/mqttjs/mqtt-packet/blob/23774e79e0ca83a718b95d254414964e7a421b1f/writeToStream.js#L216-L277

I tried to connect with replacing the whole packet generation with a hardcoded one, and it immediately succeeds to connect:

conbuf = Buffer.from([0x10, 0x38, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54, 0x04, 0xc2, 0x00, 0x1e, 0x00, 0x20, 0x36, 0x37, 0x61, 0x64, 0x33, 0x63, 0x63, 0x35, 0x63, 0x31, 0x31, 0x33, 0x34, 0x35, 0x63, 0x31, 0x39, 0x37, 0x64, 0x38, 0x33, 0x36, 0x31, 0x39, 0x61, 0x63, 0x64, 0x37, 0x30, 0x66, 0x31, 0x63, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74]) stream.write(conbuf)

The same problem appears with the subscribe command.

gazsiazasz commented 3 years ago

Yes, changing the packet creations to this:

let connpacket = Buffer.concat(
    [
      protocol.CONNECT_HEADER,
      Buffer.from([length]),
      Buffer.from([0x00, 0x04]),
      new TextEncoder().encode(protocolId),
      protocol.VERSION4,
      Buffer.from([flags, 0x00, keepalive]),
      Buffer.from([0x00, 0x20]),
      new TextEncoder().encode(clientId),
      Buffer.from([0x00, 0x04]),
      new TextEncoder().encode(username),
      Buffer.from([0x00, 0x04]),
      new TextEncoder().encode(password),
    ]
);
stream.write(connpacket)

and this:

let bid = Buffer.allocUnsafe(2)
bid.writeUInt16BE(id, 0, 2)
let subpacket = Buffer.concat(
    [
      protocol.SUBSCRIBE_HEADER[1][dup ? 1 : 0][0],
      Buffer.from([length]),
      bid,
      Buffer.concat(subs.map(s => {
        let tstrb = new TextEncoder().encode(s.topic)
        let len = Buffer.allocUnsafe(2)
        len.writeUInt16BE(tstrb.length, 0, 2)
        return Buffer.concat([len, tstrb, Buffer.from([s.qos])])
      }))
    ]
)
result = stream.write(subpacket)

definitely makes it working. I know that maybe this is not the optimum solution, there should be a solution where the writable stream does not write until some signal, but I am not familiar with it unfortunately.