Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lib/parse_http.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
module.exports = parseHttpRequest

var common = require('./common')

var REMOVE_IPV6_RE = /^::ffff:/

module.exports = parseHttpRequest

function parseHttpRequest (req, options) {
var s = req.url.split('?')
var params = common.querystringParse(s[1])

if (s[0] === '/announce') {
params.action = common.ACTIONS.ANNOUNCE

params.peer_id = typeof params.peer_id === 'string' && common.binaryToUtf8(params.peer_id)
params.port = Number(params.port)

Expand Down
7 changes: 3 additions & 4 deletions lib/parse_udp.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
module.exports = parseUdpRequest

var bufferEqual = require('buffer-equal')
var ipLib = require('ip')
var common = require('./common')


module.exports = parseUdpRequest

function parseUdpRequest (msg, rinfo) {
if (msg.length < 16) {
throw new Error('received packet is too short')
Expand All @@ -20,7 +19,7 @@ function parseUdpRequest (msg, rinfo) {
transactionId: msg.readUInt32BE(12)
}

// TODO: randomize:
// TODO: randomize
if (!bufferEqual(params.connectionId, common.CONNECTION_ID)) {
throw new Error('received packet with invalid connection id')
}
Expand Down
49 changes: 20 additions & 29 deletions lib/swarm.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
var debug = require('debug')('bittorrent-tracker')

module.exports = Swarm

var debug = require('debug')('bittorrent-tracker')

// Regard this as the default implementation of an interface that you
// need to support when overriding Server.getSwarm()
function Swarm (infoHash, server) {
Expand All @@ -19,30 +19,27 @@ Swarm.prototype.announce = function (params, cb) {
if (!params.event || params.event === 'empty') params.event = 'update'
var fn = '_onAnnounce_' + params.event
if (self[fn]) {
self[fn](params, peer, function (err) {
// event processed, prepare response:
self[fn](params, peer) // process event

if (params.left === 0 && peer) peer.complete = true
if (params.left === 0 && peer) peer.complete = true

// send peers
var peers = self._getPeers(params.numwant)

cb(null, {
complete: self.complete,
incomplete: self.incomplete,
peers: peers
})
cb(null, {
complete: self.complete,
incomplete: self.incomplete,
peers: self._getPeers(params.numwant)
})

} else {
cb(new Error('invalid event'))
}
}

Swarm.prototype._onAnnounce_started = function (params, peer, cb) {
Swarm.prototype._onAnnounce_started = function (params, peer) {
if (peer) {
debug('unexpected `started` event from peer that is already in swarm')
return this._onAnnounce_update() // treat as an update
return this._onAnnounce_update(params, peer) // treat as an update
}

if (params.left === 0) this.complete += 1
else this.incomplete += 1
peer = this.peers[params.addr] = {
Expand All @@ -51,48 +48,42 @@ Swarm.prototype._onAnnounce_started = function (params, peer, cb) {
peerId: params.peer_id
}
this.emit('start', params.addr)

cb()
}

Swarm.prototype._onAnnounce_stopped = function (params, peer, cb) {
Swarm.prototype._onAnnounce_stopped = function (params, peer) {
if (!peer) {
debug('unexpected `stopped` event from peer that is not in swarm')
return // do nothing
}

if (peer.complete) this.complete -= 1
else this.incomplete -= 1
this.peers[params.addr] = null
this.emit('stop', params.addr)

cb()
}

Swarm.prototype._onAnnounce_completed = function (params, peer, cb) {
Swarm.prototype._onAnnounce_completed = function (params, peer) {
if (!peer) {
debug('unexpected `completed` event from peer that is not in swarm')
return start() // treat as a start
return this._onAnnounce_started(params, peer) // treat as a start
}
if (peer.complete) {
debug('unexpected `completed` event from peer that is already marked as completed')
return // do nothing
}

this.complete += 1
this.incomplete -= 1
peer.complete = true
this.emit('complete', params.addr)

cb()
}

Swarm.prototype._onAnnounce_update = function (params, peer, cb) {
Swarm.prototype._onAnnounce_update = function (params, peer) {
if (!peer) {
debug('unexpected `update` event from peer that is not in swarm')
return start() // treat as a start
return this._onAnnounce_started(params, peer) // treat as a start
}
this.emit('update', params.addr)

cb()
}

Swarm.prototype._getPeers = function (numwant) {
Expand All @@ -110,7 +101,7 @@ Swarm.prototype._getPeers = function (numwant) {
return peers
}

Swarm.prototype.scrape = function (infoHash, params, cb) {
Swarm.prototype.scrape = function (params, cb) {
cb(null, {
complete: this.complete,
incomplete: this.incomplete
Expand Down
13 changes: 6 additions & 7 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ Server.prototype._onHttpRequest = function (req, res) {
// even though it's an error for the client, it's just a warning for the server.
// don't crash the server because a client sent bad data :)
self.emit('warning', error)

return
}

Expand Down Expand Up @@ -185,7 +185,7 @@ Server.prototype._onUdpRequest = function (msg, rinfo) {
'failure reason': err.message
}
}

var socket = dgram.createSocket('udp4')
response.transactionId = params.transactionId
response.connectionId = params.connectionId
Expand All @@ -199,7 +199,6 @@ Server.prototype._onUdpRequest = function (msg, rinfo) {
}

Server.prototype._onRequest = function (params, cb) {
var response
if (params && params.action === common.ACTIONS.CONNECT) {
cb(null, { action: common.ACTIONS.CONNECT })
} else if (params && params.action === common.ACTIONS.ANNOUNCE) {
Expand Down Expand Up @@ -230,21 +229,21 @@ Server.prototype._onAnnounce = function (params, cb) {

Server.prototype._onScrape = function (params, cb) {
var self = this

if (typeof params.info_hash === 'string') {
params.info_hash = [ params.info_hash ]
} else if (params.info_hash == null) {
// if info_hash param is omitted, stats for all torrents are returned
// TODO: make this configurable!
params.info_hash = Object.keys(self.torrents)
}

if (!Array.isArray(params.info_hash)) {
var err = new Error('invalid info_hash')
self.emit('warning', err)
return cb(err)
}

var response = {
action: common.ACTIONS.SCRAPE,
files: {},
Expand All @@ -256,7 +255,7 @@ Server.prototype._onScrape = function (params, cb) {
series(params.info_hash.map(function (infoHash) {
var swarm = self.getSwarm(infoHash)
return function (cb) {
swarm.scrape(infoHash, params, function (err, scrapeInfo) {
swarm.scrape(params, function (err, scrapeInfo) {
cb(err, scrapeInfo && {
infoHash: infoHash,
complete: scrapeInfo.complete || 0,
Expand Down