Skip to content

Commit d436993

Browse files
authored
fix: Use buffered reader in peer to fix ShortBuffer (#303)
This prevents a io.ErrShortBuffer from occurring when the byte slice being read is smaller than the chunks sent from the opposite pipe. This makes sense for unordered connections, where transmission is not guaranteed, but does not make sense for TCP-like connections. We use a bufio.Reader when ordered to ensure data isn't lost.
1 parent deb7170 commit d436993

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"tfexec",
5858
"tfstate",
5959
"unconvert",
60+
"webrtc",
6061
"xerrors",
6162
"yamux"
6263
]

peer/channel.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package peer
22

33
import (
4+
"bufio"
45
"context"
56
"io"
67
"net"
@@ -78,7 +79,8 @@ type Channel struct {
7879
dc *webrtc.DataChannel
7980
// This field can be nil. It becomes set after the DataChannel
8081
// has been opened and is detached.
81-
rwc datachannel.ReadWriteCloser
82+
rwc datachannel.ReadWriteCloser
83+
reader io.Reader
8284

8385
closed chan struct{}
8486
closeMutex sync.Mutex
@@ -130,6 +132,21 @@ func (c *Channel) init() {
130132
_ = c.closeWithError(xerrors.Errorf("detach: %w", err))
131133
return
132134
}
135+
// pion/webrtc will return an io.ErrShortBuffer when a read
136+
// is triggerred with a buffer size less than the chunks written.
137+
//
138+
// This makes sense when considering UDP connections, because
139+
// bufferring of data that has no transmit guarantees is likely
140+
// to cause unexpected behavior.
141+
//
142+
// When ordered, this adds a bufio.Reader. This ensures additional
143+
// data on TCP-like connections can be read in parts, while still
144+
// being bufferred.
145+
if c.opts.Unordered {
146+
c.reader = c.rwc
147+
} else {
148+
c.reader = bufio.NewReader(c.rwc)
149+
}
133150
close(c.opened)
134151
})
135152

@@ -181,7 +198,7 @@ func (c *Channel) Read(bytes []byte) (int, error) {
181198
}
182199
}
183200

184-
bytesRead, err := c.rwc.Read(bytes)
201+
bytesRead, err := c.reader.Read(bytes)
185202
if err != nil {
186203
if c.isClosed() {
187204
return 0, c.closeError

peer/conn_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,27 @@ func TestConn(t *testing.T) {
267267
_, err := client.Ping()
268268
require.NoError(t, err)
269269
})
270+
271+
t.Run("ShortBuffer", func(t *testing.T) {
272+
t.Parallel()
273+
client, server, _ := createPair(t)
274+
exchange(client, server)
275+
go func() {
276+
channel, err := client.Dial(context.Background(), "test", nil)
277+
require.NoError(t, err)
278+
_, err = channel.Write([]byte{1, 2})
279+
require.NoError(t, err)
280+
}()
281+
channel, err := server.Accept(context.Background())
282+
require.NoError(t, err)
283+
data := make([]byte, 1)
284+
_, err = channel.Read(data)
285+
require.NoError(t, err)
286+
require.Equal(t, uint8(0x1), data[0])
287+
_, err = channel.Read(data)
288+
require.NoError(t, err)
289+
require.Equal(t, uint8(0x2), data[0])
290+
})
270291
}
271292

272293
func createPair(t *testing.T) (client *peer.Conn, server *peer.Conn, wan *vnet.Router) {

0 commit comments

Comments
 (0)