Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
gazsiazasz opened this issue Oct 16, 2021 · 1 comment

Comments

@gazsiazasz
Copy link

gazsiazasz commented Oct 16, 2021

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:

stream.write(protocol.CONNECT_HEADER)
// Generate length
writeVarByteInt(stream, length)
// Generate protocol ID
writeStringOrBuffer(stream, protocolId)
if (settings.bridgeMode) {
protocolVersion += 128
}
stream.write(
protocolVersion === 131
? protocol.VERSION131
: protocolVersion === 132
? protocol.VERSION132
: protocolVersion === 4
? protocol.VERSION4
: protocolVersion === 5
? protocol.VERSION5
: protocol.VERSION3
)
// Connect flags
let flags = 0
flags |= (username != null) ? protocol.USERNAME_MASK : 0
flags |= (password != null) ? protocol.PASSWORD_MASK : 0
flags |= (will && will.retain) ? protocol.WILL_RETAIN_MASK : 0
flags |= (will && will.qos) ? will.qos << protocol.WILL_QOS_SHIFT : 0
flags |= will ? protocol.WILL_FLAG_MASK : 0
flags |= clean ? protocol.CLEAN_SESSION_MASK : 0
stream.write(Buffer.from([flags]))
// Keepalive
writeNumber(stream, keepalive)
// Properties
if (protocolVersion === 5) {
propertiesData.write()
}
// Client ID
writeStringOrBuffer(stream, clientId)
// Will
if (will) {
if (protocolVersion === 5) {
willProperties.write()
}
writeString(stream, will.topic)
writeStringOrBuffer(stream, will.payload)
}
// Username and password
if (username != null) {
writeStringOrBuffer(stream, username)
}
if (password != null) {
writeStringOrBuffer(stream, password)
}

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
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant