Simple, robust, BitTorrent peer wire protocol implementation


Node.js implementation of the BitTorrent peer wire protocol. The protocol is the main communication layer for BitTorrent file transfer.

Also works in the browser with browserify! This module is used by WebTorrent.

npm install bittorrent-protocol

The protocol is implemented as a duplex stream, so all you have to do is pipe to and from it.

duplex streamsa.pipe(b).pipe(a)

(Images from the "harnessing streams" talk by substack.)

var Protocol = require('bittorrent-protocol')
var net = require('net')
net.createServer(function (socket) {
    var wire = new Protocol()
    // pipe to and from the protocol 
    wire.on('handshake', function (infoHashpeerId) {
        // lets emit a handshake of our own as well 
        wire.handshake(new Buffer('my info hash'), new Buffer('my peer id'))
    wire.on('unchoke', function () {
        console.log('peer is no longer choking us: ' + wire.peerChoking)

Send and receive a handshake from the peer. This is the first message.

// send a handshake to the peer 
wire.handshake(infoHash, peerId, { dht: true })
wire.on('handshake', function (infoHashpeerIdextensions) {
    // receive a handshake 
  console.log(extensions.dht) // supports DHT (BEP-0005) 
  console.log(extensions.extended) // supports extension protocol (BEP-0010) 

Both the infoHash and the peerId should be 20 bytes (Buffer or hex-encoded string).

Check if you or the peer is choking.

wire.peerChoking // is the peer choking us? 
wire.amChoking // are we choking the peer? 
wire.on('choke', function () {
    // the peer is now choking us 
wire.on('unchoke', function () {
    // peer is no longer choking us 

See if you or the peer is interested.

wire.peerInterested // is the peer interested in us? 
wire.amInterested // are we interested in the peer? 
wire.on('interested', function () {
    // peer is now interested 
wire.on('uninterested', function () {
    // peer is no longer interested 

Exchange piece information with the peer.

// send a bitfield to the peer 
wire.on('bitfield', function (bitfield) {
    // bitfield received from the peer 
// send a have message indicating that you have a piece 
wire.on('have', function (pieceIndex) {
    // peer has sent you a have message 

You can always see which pieces the peer has

wire.peerPieces.get(i) // returns true if peer has piece i 

wire.peerPieces is a BitField, see docs.

Send and respond to requests for pieces.

// request a block from a peer 
wire.request(pieceIndex, offset, length, function (errblock) {
    if (err) {
        // there was an error (peer has started choking us etc) 
    // got block 
// cancel a request to a peer 
wire.cancel(pieceIndex, offset, length)
// receive a request from a peer 
wire.on('request', function (pieceIndexoffsetlengthcallback) {
    // ... read block ... 
    callback(null, block) // respond back to the peer 
wire.requests     // list of requests we currently have pending {piece, offset, length} 
wire.peerRequests // list of requests the peer currently have pending {piece, offset, length} 

You can set a request timeout if you want to.

wire.setTimeout(5000) // head request should take a most 5s to finish 

If the timeout is triggered the request callback is called with an error and a timeout event is emitted.

You can set the extensions flag dht in the handshake to true if you participate in the torrent dht. Afterwards you can send your dht port.

// send your port to the peer 
wire.on('port', function (dhtPort) {
    // peer has sent a port to us 

You can check to see if the peer supports extensions.

wire.peerExtensions.dht // supports DHT (bep_0005) 
wire.peerExtensions.extended // supports extended messages (bep_0005) 

You can enable the keep-alive ping (triggered every 60s).

// starts the keep alive 
wire.on('keep-alive', function () {
    // peer sent a keep alive - just ignore it 

This module has built-in support for the BitTorrent Extension Protocol (BEP 10).

The intention of BEP 10 is to provide a simple and thin transport for extensions to the bittorrent protocol. Most extensions to the protocol use BEP 10 so they can add new features to the protocol without interfering with the standard bittorrent protocol or clients that don't support the new extension.

An example of a BitTorrent extension that uses BEP 10 is ut_metadata (BEP 9), the extension that allows magnet uris to work.

wire.extended(code, buffer)

This package, bittorrent-protocol, also provides an extension API to make it easy to add extensions to this module using the "extension protocol" (BEP 10). For example, to support ut_metadata (BEP 9), you need only install the ut_metadata npm module and call wire.use(). See the Extension API section for more information.

Check how many bytes you have uploaded and download, and current speed

wire.uploaded // number of bytes uploaded 
wire.downloaded // number of bytes downloaded 
wire.uploadSpeed() // upload speed - bytes per second 
wire.downloadSpeed() // download speed - bytes per second 
wire.on('download', function (numberOfBytes) {
wire.on('upload', function (numberOfBytes) {

This package supports a simple extension API so you can extend the default protocol functionality with common protocol extensions like ut_metadata (magnet uris).

Here are the bittorrent-protocol extensions that we know about:

  • ut_metadata - Extension for Peers to Send Metadata Files (BEP 9)
  • ut_pex - Extension for Peer Discovery (PEX)
  • Add yours here! Send a pull request!

In short, an extension can register itself with at a certain name, which will be added to the extended protocol handshake sent to the remote peer. Extensions can also hook events like 'handshake' and 'extended'. To use an extension, simply require it and call wire.use().

Here is an example of the ut_metadata extension being used with bittorrent-protocol:

var Protocol = require('bittorrent-protocol')
var net = require('net')
var ut_metadata = require('ut_metadata')
net.createServer(function (socket) {
  var wire = new Protocol()
  // initialize the extension 
  // all `ut_metadata` functionality can now be accessed at wire.ut_metadata 
  // ask the peer to send us metadata 
  // 'metadata' event will fire when the metadata arrives and is verified to be correct! 
  wire.ut_metadata.on('metadata', function (metadata) {
    // got metadata! 
    // Note: the event will not fire if the peer does not support ut_metadata, if they 
    // don't have metadata yet either, if they repeatedly send invalid data, or if they 
    // simply don't respond. 
  // optionally, listen to the 'warning' event if you want to know that metadata is 
  // probably not going to arrive for one of the above reasons. 
  wire.ut_metadata.on('warning', function (err) {
  // handle handshake 
  wire.on('handshake', function (infoHashpeerId) {
    wire.handshake(new Buffer('my info hash'), new Buffer('my peer id'))

If you want to write your own extension, take a look at the ut_metadata index.js file to see how it's done.

MIT. Copyright (c) Feross Aboukhadijeh.

Includes code from peer-wire-protocol by mafintosh, which is also MIT.