Skip to content

Commit 2265e59

Browse files
authored
fix: revert WebRTC message size increase (#2679)
go-libp2p and rust-libp2p close incoming streams when the message size is greater than 16KiB so reset to the previous limit.
1 parent 1675ade commit 2265e59

File tree

3 files changed

+36
-12
lines changed

3 files changed

+36
-12
lines changed

packages/transport-webrtc/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"protons-runtime": "^5.4.0",
7373
"race-signal": "^1.0.2",
7474
"react-native-webrtc": "^118.0.7",
75+
"uint8-varint": "^2.0.4",
7576
"uint8arraylist": "^2.4.8",
7677
"uint8arrays": "^5.1.0"
7778
},

packages/transport-webrtc/src/stream.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import pDefer from 'p-defer'
66
import { pEvent, TimeoutError } from 'p-event'
77
import pTimeout from 'p-timeout'
88
import { raceSignal } from 'race-signal'
9+
import { encodingLength } from 'uint8-varint'
910
import { Uint8ArrayList } from 'uint8arraylist'
1011
import { Message } from './pb/message.js'
1112
import type { DataChannelOptions } from './index.js'
@@ -35,22 +36,40 @@ export const MAX_BUFFERED_AMOUNT = 2 * 1024 * 1024
3536
export const BUFFERED_AMOUNT_LOW_TIMEOUT = 30 * 1000
3637

3738
/**
38-
* protobuf field definition overhead + length encoding prefix length
39+
* Max message size that can be sent to the DataChannel. In browsers this is
40+
* 256KiB but go-libp2p and rust-libp2p only support 16KiB at the time of
41+
* writing.
42+
*
43+
* @see https://blog.mozilla.org/webrtc/large-data-channel-messages/
44+
* @see https://issues.webrtc.org/issues/40644524
3945
*/
40-
export const PROTOBUF_OVERHEAD = 7
46+
export const MAX_MESSAGE_SIZE = 16 * 1024
4147

4248
/**
43-
* Length of varint, in bytes
49+
* max protobuf overhead:
50+
*
51+
* ```
52+
* [message-length][flag-field-id+type][flag-field-length][flag-field][message-field-id+type][message-field-length][message-field]
53+
* ```
4454
*/
45-
export const VARINT_LENGTH = 2
55+
function calculateProtobufOverhead (maxMessageSize = MAX_MESSAGE_SIZE): number {
56+
// these have a fixed size
57+
const messageLength = encodingLength(maxMessageSize - encodingLength(maxMessageSize))
58+
const flagField = 1 + encodingLength(Object.keys(Message.Flag).length - 1) // id+type/value
59+
const messageFieldIdType = 1 // id+type
60+
const available = maxMessageSize - messageLength - flagField - messageFieldIdType
61+
62+
// let message-length/message-data fill the rest of the message
63+
const messageFieldLengthLength = encodingLength(available)
64+
65+
return messageLength + flagField + messageFieldIdType + messageFieldLengthLength
66+
}
4667

4768
/**
48-
* Max message size that can be sent to the DataChannel
49-
*
50-
* @see https://blog.mozilla.org/webrtc/large-data-channel-messages/
51-
* @see https://issues.webrtc.org/issues/40644524
69+
* The protobuf message overhead includes the maximum amount of all bytes in the
70+
* protobuf that aren't message field bytes
5271
*/
53-
export const MAX_MESSAGE_SIZE = 256 * 1024
72+
export const PROTOBUF_OVERHEAD = calculateProtobufOverhead()
5473

5574
/**
5675
* When closing streams we send a FIN then wait for the remote to
@@ -132,7 +151,7 @@ export class WebRTCStream extends AbstractStream {
132151
this.incomingData = pushable<Uint8Array>()
133152
this.bufferedAmountLowEventTimeout = init.bufferedAmountLowEventTimeout ?? BUFFERED_AMOUNT_LOW_TIMEOUT
134153
this.maxBufferedAmount = init.maxBufferedAmount ?? MAX_BUFFERED_AMOUNT
135-
this.maxMessageSize = (init.maxMessageSize ?? MAX_MESSAGE_SIZE) - PROTOBUF_OVERHEAD - VARINT_LENGTH
154+
this.maxMessageSize = (init.maxMessageSize ?? MAX_MESSAGE_SIZE) - PROTOBUF_OVERHEAD
136155
this.receiveFinAck = pDefer()
137156
this.finAckTimeout = init.closeTimeout ?? FIN_ACK_TIMEOUT
138157
this.openTimeout = init.openTimeout ?? OPEN_TIMEOUT

packages/transport-webrtc/test/stream.spec.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@ describe('Max message size', () => {
2626
}
2727
})
2828

29-
// Make sure that the data that ought to be sent will result in a message with exactly MAX_MESSAGE_SIZE
30-
const messageLengthEncoded = lengthPrefixed.encode.single(Message.encode({ message: data }))
29+
// Make sure that a message with all fields will be exactly MAX_MESSAGE_SIZE
30+
const messageLengthEncoded = lengthPrefixed.encode.single(Message.encode({
31+
flag: Message.Flag.STOP_SENDING,
32+
message: data
33+
}))
34+
3135
expect(messageLengthEncoded.length).eq(MAX_MESSAGE_SIZE)
3236
const webrtcStream = createStream({
3337
channel,

0 commit comments

Comments
 (0)