I'm building a Bittorrent client using Node.js and am failing at getting answer from peers over the PWP metadata extension (BEP 0009)
I get peers from the DHT (BEP 0005) (where i announce), then send Handshake and Extended Handshake over PWP using a net Socket.
buildHandshake = (torrent, ext) => { // torrent contains mainly infoHash
const buf = Buffer.alloc(68)
buf.writeUInt8(19, 0)
buf.write('BitTorrent protocol', 1)
if (ext) {
const big = new Uint64BE(1048576)
big.toBuffer().copy(buf, 20)
} else {
buf.writeUInt32BE(0, 20)
buf.writeUInt32BE(0, 24)
}
torrent.infoHashBuffer.copy(buf, 28)
anon.nodeId().copy(buf, 48) // tool that generates a nodeId once.
return buf
}
buildExtRequest = (id, msg) => {
const size = msg.length + 1
const buf = Buffer.alloc(size + 5)
buf.writeUInt32BE(size, 0)
buf.writeUInt8(20, 4)
buf.writeUInt8(id, 5)
msg.copy(buf, 6)
return buf
}
const client = new net.Socket()
client.connect(peer.port, peer.ip, () => {
client.write(buildHandshake(torrent, true))
const extHandshake = bencode.encode({
m: {
ut_metadata: 2,
},
metadata_size: self.metaDataSize, // 0 by default
p: client.localPort,
v: Buffer.from('Hypertube 0.1')
})
client.write(buildExtRequest(0, extHandshake))
})
From here, i get Handshakes and extended Hanshakes back (and sometimes Bitfields), then i require metadata pieces:
const req = bencode.encode({ msg_type: 0, piece: 0 })
// utMetadata is from extended Handshake dictionary m.ut_metadata
client.write(message.buildExtRequest(utMetadata, req))
After what, i don't hear from the peer anymore. After 2mins without keeping alive, connection timeouts.
Has anybody got an idea why i don't get answered back ?
BitTorrent protocol message formating can be unclear if you're a first timer, like me.
message structure is always as follows (except for handshake):
where len is a UInt32 big endian of value message.length, message is whatever you're sending except handshake.
For example:
Extended protocol piece request: ut_metadata piece message
where:
ut_metadata dict is a bencoded dictionary:
{ 'msg_type': 0, 'piece': 0 }
d8:msg_typei0e5:piecei0ee
(here is on the first line the object - the dictionary - and on the second line is the same object once bencoded)
msg_type is 0 (it's the request message indicator for BEP 0009 piece request.
piece is the index of the piece you request (0 would be the first piece)
In general:
Not giving the right value to
<len>
will result in messages badly interpreted by peer, and therefore not getting the right answers, not getting any answer and eventually connection being closed (by the peer or through your own messages)