Skip to content

Commit

Permalink
webrtc: set sctp receive buffer size to 100kB (#2745)
Browse files Browse the repository at this point in the history
  • Loading branch information
sukunrt authored Mar 21, 2024
1 parent e416c52 commit 96e0780
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 15 deletions.
4 changes: 4 additions & 0 deletions p2p/test/transport/rcmgr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ func TestResourceManagerIsUsed(t *testing.T) {
}
return nil
})
if tc.Name == "WebRTC" {
// webrtc receive buffer is a fix sized buffer allocated up front
connScope.EXPECT().ReserveMemory(gomock.Any(), gomock.Any())
}
connScope.EXPECT().Done().MinTimes(1)

var allStreamsDone sync.WaitGroup
Expand Down
4 changes: 4 additions & 0 deletions p2p/transport/webrtc/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@ func (l *listener) setupConnection(
// in a release.
settingEngine.SetReceiveMTU(udpmux.ReceiveBufSize)
settingEngine.DetachDataChannels()
settingEngine.SetSCTPMaxReceiveBufferSize(sctpReceiveBufferSize)
if err := scope.ReserveMemory(sctpReceiveBufferSize, network.ReservationPriorityMedium); err != nil {
return nil, err
}

w, err = newWebRTCConnection(settingEngine, l.config)
if err != nil {
Expand Down
21 changes: 8 additions & 13 deletions p2p/transport/webrtc/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,19 @@ import (
const (
// maxMessageSize is the maximum message size of the Protobuf message we send / receive.
maxMessageSize = 16384
// Pion SCTP association has an internal receive buffer of 1MB (roughly, 1MB per connection).
// We can change this value in the SettingEngine before creating the peerconnection.
// https://github.com/pion/webrtc/blob/v3.1.49/sctptransport.go#L341
maxBufferedAmount = 2 * maxMessageSize
// maxSendBuffer is the maximum data we enqueue on the underlying data channel for writes.
// The underlying SCTP layer has an unbounded buffer for writes. We limit the amount enqueued
// per stream is limited to avoid a single stream monopolizing the entire connection.
maxSendBuffer = 2 * maxMessageSize
// sendBufferLowThreshold is the threshold below which we write more data on the underlying
// data channel. We want a notification as soon as we can write 1 full sized message.
sendBufferLowThreshold = maxSendBuffer - maxMessageSize
// maxTotalControlMessagesSize is the maximum total size of all control messages we will
// write on this stream.
// 4 control messages of size 10 bytes + 10 bytes buffer. This number doesn't need to be
// exact. In the worst case, we enqueue these many bytes more in the webrtc peer connection
// send queue.
maxTotalControlMessagesSize = 50
// bufferedAmountLowThreshold and maxBufferedAmount are bound
// to a stream but congestion control is done on the whole
// SCTP association. This means that a single stream can monopolize
// the complete congestion control window (cwnd) if it does not
// read stream data and it's remote continues to send. We can
// add messages to the send buffer once there is space for 1 full
// sized message.
bufferedAmountLowThreshold = maxBufferedAmount / 2

// Proto overhead assumption is 5 bytes
protoOverhead = 5
Expand Down Expand Up @@ -120,7 +115,7 @@ func newStream(
}
// released when the controlMessageReader goroutine exits
s.controlMessageReaderDone.Add(1)
s.dataChannel.SetBufferedAmountLowThreshold(bufferedAmountLowThreshold)
s.dataChannel.SetBufferedAmountLowThreshold(sendBufferLowThreshold)
s.dataChannel.OnBufferedAmountLow(func() {
s.notifyWriteStateChanged()

Expand Down
4 changes: 2 additions & 2 deletions p2p/transport/webrtc/stream_write.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ func (s *stream) SetWriteDeadline(t time.Time) error {

func (s *stream) availableSendSpace() int {
buffered := int(s.dataChannel.BufferedAmount())
availableSpace := maxBufferedAmount - buffered
availableSpace := maxSendBuffer - buffered
if availableSpace+maxTotalControlMessagesSize < 0 { // this should never happen, but better check
log.Errorw("data channel buffered more data than the maximum amount", "max", maxBufferedAmount, "buffered", buffered)
log.Errorw("data channel buffered more data than the maximum amount", "max", maxSendBuffer, "buffered", buffered)
}
return availableSpace
}
Expand Down
6 changes: 6 additions & 0 deletions p2p/transport/webrtc/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ const (
DefaultDisconnectedTimeout = 20 * time.Second
DefaultFailedTimeout = 30 * time.Second
DefaultKeepaliveTimeout = 15 * time.Second

sctpReceiveBufferSize = 100_000
)

type WebRTCTransport struct {
Expand Down Expand Up @@ -314,6 +316,10 @@ func (t *WebRTCTransport) dial(ctx context.Context, scope network.ConnManagement
// If you run pion on a system with only the loopback interface UP,
// it will not connect to anything.
settingEngine.SetIncludeLoopbackCandidate(true)
settingEngine.SetSCTPMaxReceiveBufferSize(sctpReceiveBufferSize)
if err := scope.ReserveMemory(sctpReceiveBufferSize, network.ReservationPriorityMedium); err != nil {
return nil, err
}

w, err = newWebRTCConnection(settingEngine, t.webrtcConfig)
if err != nil {
Expand Down

0 comments on commit 96e0780

Please sign in to comment.