diff --git a/lib/parse_http.js b/lib/parse_http.js index 85e3519..c6b67d7 100644 --- a/lib/parse_http.js +++ b/lib/parse_http.js @@ -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) diff --git a/lib/parse_udp.js b/lib/parse_udp.js index 7e5ccdf..2122d96 100644 --- a/lib/parse_udp.js +++ b/lib/parse_udp.js @@ -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') @@ -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') } diff --git a/lib/swarm.js b/lib/swarm.js index 40e4577..b7c2baa 100644 --- a/lib/swarm.js +++ b/lib/swarm.js @@ -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) { @@ -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] = { @@ -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) { @@ -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 diff --git a/server.js b/server.js index ed1a229..af1dd49 100644 --- a/server.js +++ b/server.js @@ -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 } @@ -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 @@ -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) { @@ -230,7 +229,7 @@ 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) { @@ -238,13 +237,13 @@ Server.prototype._onScrape = function (params, cb) { // 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: {}, @@ -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,