Fix parsing of IPC packets with multiple or partial messages#176
Open
mpoc wants to merge 3 commits intodiscordjs:masterfrom
Open
Fix parsing of IPC packets with multiple or partial messages#176mpoc wants to merge 3 commits intodiscordjs:masterfrom
mpoc wants to merge 3 commits intodiscordjs:masterfrom
Conversation
SpaceEEC
requested changes
Aug 18, 2023
Member
SpaceEEC
left a comment
There was a problem hiding this comment.
Do you have a way for me to reproduce your issue?
I couldn't come up with something that yielded me more than one payload in a message. 😅
This and the requested change aside, this looks fine to me.
Author
|
Here's a reproducible example: const RPC = require('discord-rpc')
;(async () => {
const client = new RPC.Client({ transport: 'ipc' })
await client.login({
clientId: '',
clientSecret: '',
redirectUri: '',
scopes: ['rpc', 'rpc.voice.read', 'rpc.voice.write'],
})
client.subscribe('VOICE_SETTINGS_UPDATE')
client.setVoiceSettings({ input: { volume: 100 } })
client.setVoiceSettings({ output: { volume: 100 } })
})()The sixth received packet will always have two payloads. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Observed bug
Sometimes creating subscriptions or sending commands through IPC would result in the promise never resolving, i.e. the message with the expected nonce never getting received.
Reason
The original code to parse the received IPC packets:
RPC/src/transports/ipc.js
Lines 82 to 100 in 9e7de2a
The code assumes that a packet will contain at most one message.
The code will skip the processing of a message if a packet contains:
Practically speaking, we've only seen scenario 1 happen, but theoretically scenario 2 can happen as well.
Scenario 1: A packet contains two complete messages
The packet buffer gets cropped to only contain the message:
RPC/src/transports/ipc.js
Line 85 in 9e7de2a
The rest of the buffer (which contains the second message) gets discarded. The second message never gets decoded.
Scenario 2: A packet contains the tail of one message and the head or entirety of the next message
working.fullalready contains a part of the message from the previous packet.This line assumes that the current packet will contain the tail of the message stored in
working.full:RPC/src/transports/ipc.js
Line 87 in 9e7de2a
However, because it contains the beginning or entirety of the next message, the parsing of the message fails on line 91, resulting in
working.fullcontaining one full message and at least partially a second message because of the concatenation on line 96:RPC/src/transports/ipc.js
Lines 90 to 97 in 9e7de2a
Because
working.fullis now malformed, it will also affect the decoding of any subsequent messages, causing the packet data to continually be added toworking.full.Fix
Store the expected length of the current payload (link)
Treat all received packets as a stream of bytes
Concatenate all received packets (link)
Read a number of bytes according to the received message length (link)
Keep the remainder of a packet for decoding of next message (link)
Keep processing the same packet if there's bytes left over after reading the length of the first complete message (link)