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: 6 additions & 0 deletions lib/common-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var querystring = require('querystring')

exports.IPV4_RE = /^[\d\.]+$/
exports.IPV6_RE = /^[\da-fA-F:]+$/
exports.REMOVE_IPV4_MAPPED_IPV6_RE = /^::ffff:/

exports.CONNECTION_ID = Buffer.concat([ toUInt32(0x417), toUInt32(0x27101980) ])
exports.ACTIONS = { CONNECT: 0, ANNOUNCE: 1, SCRAPE: 2, ERROR: 3 }
Expand All @@ -23,6 +24,11 @@ exports.EVENT_NAMES = {
started: 'start',
stopped: 'stop'
}
exports.PEER_TYPES = {
http: 'http',
udp: 'udp',
websocket: 'ws'
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would rather just use strings directly for these. The strings are the same as the object keys anyway.


function toUInt32 (n) {
var buf = new Buffer(4)
Expand Down
7 changes: 4 additions & 3 deletions lib/server/parse-http.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ module.exports = parseHttpRequest

var common = require('../common')

var REMOVE_IPV4_MAPPED_IPV6_RE = /^::ffff:/

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

if (opts.action === 'announce' || s[0] === '/announce') {
params.action = common.ACTIONS.ANNOUNCE
params.type = common.PEER_TYPES.http
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going to move this out of the if-statement so it's set when the action is 'scrape', too.


if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
throw new Error('invalid info_hash')
Expand All @@ -34,8 +33,10 @@ function parseHttpRequest (req, opts) {

params.ip = opts.trustProxy
? req.headers['x-forwarded-for'] || req.connection.remoteAddress
: req.connection.remoteAddress.replace(REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
: req.connection.remoteAddress.replace(common.REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
params.addr = (common.IPV6_RE.test(params.ip) ? '[' + params.ip + ']' : params.ip) + ':' + params.port

params.headers = req.headers
} else if (opts.action === 'scrape' || s[0] === '/scrape') {
params.action = common.ACTIONS.SCRAPE

Expand Down
3 changes: 2 additions & 1 deletion lib/server/parse-udp.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ function parseUdpRequest (msg, rinfo) {
var params = {
connectionId: msg.slice(0, 8), // 64-bit
action: msg.readUInt32BE(8),
transactionId: msg.readUInt32BE(12)
transactionId: msg.readUInt32BE(12),
type: common.PEER_TYPES.udp
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that type is set when the action is 'scrape' in the UDP case.

}

if (!bufferEqual(params.connectionId, common.CONNECTION_ID)) {
Expand Down
14 changes: 13 additions & 1 deletion lib/server/parse-websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ module.exports = parseWebSocketRequest

var common = require('../common')

function parseWebSocketRequest (socket, params) {
function parseWebSocketRequest (socket, opts, params) {
if (!opts) opts = {}
params = JSON.parse(params) // may throw

params.action = common.ACTIONS.ANNOUNCE
params.type = common.PEER_TYPES.websocket
params.socket = socket

if (typeof params.info_hash !== 'string' || params.info_hash.length !== 20) {
Expand All @@ -32,5 +34,15 @@ function parseWebSocketRequest (socket, params) {
)
params.compact = -1 // return full peer objects (used for websocket responses)

params.ip = opts.trustProxy
? socket.upgradeReq.headers['x-forwarded-for'] || socket.upgradeReq.connection.remoteAddress
: socket.upgradeReq.connection.remoteAddress.replace(common.REMOVE_IPV4_MAPPED_IPV6_RE, '') // force ipv4
params.port = socket.upgradeReq.connection.remotePort
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not name this port since port means something entirely different for the http server. There it means the client's reported torrent client port. There's no torrent client port for webrtc peers.

if (params.port) {
params.addr = (common.IPV6_RE.test(params.ip) ? '[' + params.ip + ']' : params.ip) + ':' + params.port
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addr property will cause issues in lib/server/swarm.js here: https://github.com/feross/bittorrent-tracker/blob/7406750b747de119ce9025855f945cb6ff998344/lib/server/swarm.js#L16

The presence of addr will cause that to be used instead of peer_id for webrtc peers.

}

params.headers = socket.upgradeReq.headers

return params
}
10 changes: 7 additions & 3 deletions lib/server/swarm.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module.exports = Swarm

var debug = require('debug')('bittorrent-tracker')
var randomIterate = require('random-iterate')
var common = require('../common')

// Regard this as the default implementation of an interface that you
// need to support when overriding Server.createSwarm() and Server.getSwarm()
Expand All @@ -13,7 +14,8 @@ function Swarm (infoHash, server) {

Swarm.prototype.announce = function (params, cb) {
var self = this
var peer = self.peers[params.addr || params.peer_id]
var id = params.type === common.PEER_TYPES.websocket ? params.peer_id : params.addr
var peer = self.peers[id]

if (params.event === 'started') {
self._onAnnounceStarted(params, peer)
Expand Down Expand Up @@ -49,7 +51,8 @@ Swarm.prototype._onAnnounceStarted = function (params, peer) {

if (params.left === 0) this.complete += 1
else this.incomplete += 1
peer = this.peers[params.addr || params.peer_id] = {
var id = params.type === common.PEER_TYPES.websocket ? params.peer_id : params.addr
peer = this.peers[id] = {
complete: params.left === 0,
peerId: params.peer_id, // as hex
ip: params.ip, // only http, udp
Expand All @@ -66,7 +69,8 @@ Swarm.prototype._onAnnounceStopped = function (params, peer) {

if (peer.complete) this.complete -= 1
else this.incomplete -= 1
delete this.peers[params.addr || params.peer_id]
var id = params.type === common.PEER_TYPES.websocket ? params.peer_id : params.addr
delete this.peers[id]
}

Swarm.prototype._onAnnounceCompleted = function (params, peer) {
Expand Down
10 changes: 6 additions & 4 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,21 +294,23 @@ Server.prototype.onUdpRequest = function (msg, rinfo) {
})
}

Server.prototype.onWebSocketConnection = function (socket) {
Server.prototype.onWebSocketConnection = function (socket, opts) {
var self = this
if (!opts) opts = {}
opts.trustProxy = opts.trustProxy || self._trustProxy
socket.peerId = null // as hex
socket.infoHashes = []
socket.onSend = self._onWebSocketSend.bind(self, socket)
socket.on('message', self._onWebSocketRequest.bind(self, socket))
socket.on('message', self._onWebSocketRequest.bind(self, socket, opts))
socket.on('error', self._onWebSocketError.bind(self, socket))
socket.on('close', self._onWebSocketClose.bind(self, socket))
}

Server.prototype._onWebSocketRequest = function (socket, params) {
Server.prototype._onWebSocketRequest = function (socket, opts, params) {
var self = this

try {
params = parseWebSocketRequest(socket, params)
params = parseWebSocketRequest(socket, opts, params)
} catch (err) {
socket.send(JSON.stringify({
'failure reason': err.message
Expand Down