Skip to content

Commit

Permalink
fix: infinite loop when an allowed-fast request is pending on choke (#88
Browse files Browse the repository at this point in the history
)

* Added test case for allowed-fast peer request on choke

* Fixed allowed-fast peer request handling on choke
  • Loading branch information
paullouisageneau committed Apr 22, 2022
1 parent 83ae7ed commit a3d28da
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 4 deletions.
11 changes: 7 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,13 @@ class Wire extends stream.Duplex {
if (this.hasFast) {
// BEP6: If a peer sends a choke, it MUST reject all requests from the peer to whom the choke
// was sent except it SHOULD NOT reject requests for pieces that are in the allowed fast set.
while (this.peerRequests.length) {
const request = this.peerRequests[0]
if (!this.allowedFastSet.includes(request.piece)) {
this.reject(request.piece, request.offset, request.length)
let allowedCount = 0
while (this.peerRequests.length > allowedCount) { // until only allowed requests are left
const request = this.peerRequests[allowedCount] // first non-allowed request
if (this.allowedFastSet.includes(request.piece)) {
++allowedCount // count request as allowed
} else {
this.reject(request.piece, request.offset, request.length) // removes from this.peerRequests
}
}
} else {
Expand Down
37 changes: 37 additions & 0 deletions test/protocol.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,43 @@ test('Fast Extension: reject on choke', t => {
wire.handshake(Buffer.from('01234567890123456789'), Buffer.from('12345678901234567890'), { fast: true })
})

test('Fast Extension: don\'t reject allowed-fast on choke', t => {
t.plan(11)

const wire = new Protocol()
wire.on('error', err => { t.fail(err) })
wire.pipe(wire)

wire.once('handshake', (infoHash, peerId, extensions) => {
t.equal(wire.extensions.fast, true)
t.equal(wire.peerExtensions.fast, true)
t.equal(wire.hasFast, true)
wire.allowedFast(6)
wire.unchoke()
})

wire.once('unchoke', () => {
t.equal(wire.requests.length, 0)
wire.request(6, 66, 666, (err, buffer) => {
t.fail(err)
})
t.equal(wire.requests.length, 1)
t.equal(wire.peerRequests.length, 0)
})

wire.on('request', (i, offset, length, callback) => {
t.equal(wire.peerRequests.length, 1)
t.equal(i, 6)
t.equal(offset, 66)
t.equal(length, 666)

wire.choke()
t.equal(wire.peerRequests.length, 1) // NOT rejected
})

wire.handshake(Buffer.from('01234567890123456789'), Buffer.from('12345678901234567890'), { fast: true })
})

test('Fast Extension: reject on error', t => {
t.plan(12)

Expand Down

0 comments on commit a3d28da

Please sign in to comment.