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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "bittorrent-tracker",
"description": "Simple, robust, BitTorrent tracker (client & server) implementation",
"version": "9.15.0",
"version": "9.16.0",
"author": {
"name": "WebTorrent LLC",
"email": "[email protected]",
Expand Down
57 changes: 33 additions & 24 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ const hasOwnProperty = Object.prototype.hasOwnProperty
* metrics from clients that help the tracker keep overall statistics about the torrent.
* Responses include a peer list that helps the client participate in the torrent.
*
* @param {Object} opts options object
* @param {Number} opts.interval tell clients to announce on this interval (ms)
* @param {Number} opts.trustProxy trust 'x-forwarded-for' header from reverse proxy
* @param {boolean} opts.http start an http server? (default: true)
* @param {boolean} opts.udp start a udp server? (default: true)
* @param {boolean} opts.ws start a websocket server? (default: true)
* @param {boolean} opts.stats enable web-based statistics? (default: true)
* @param {function} opts.filter black/whitelist fn for disallowing/allowing torrents
* @param {Object} opts options object
* @param {Number} opts.interval tell clients to announce on this interval (ms)
* @param {Number} opts.trustProxy trust 'x-forwarded-for' header from reverse proxy
* @param {boolean|Object} opts.http start an http server?, or options for http.createServer (default: true)
* @param {boolean|Object} opts.udp start a udp server?, or extra options for dgram.createSocket (default: true)
* @param {boolean|Object} opts.ws start a websocket server?, or extra options for new WebSocketServer (default: true)
* @param {boolean} opts.stats enable web-based statistics? (default: true)
* @param {function} opts.filter black/whitelist fn for disallowing/allowing torrents
*/
class Server extends EventEmitter {
constructor (opts = {}) {
Expand Down Expand Up @@ -59,7 +59,7 @@ class Server extends EventEmitter {

// start an http tracker unless the user explictly says no
if (opts.http !== false) {
this.http = http.createServer()
this.http = http.createServer(isObject(opts.http) ? opts.http : undefined)
this.http.on('error', err => { this._onError(err) })
this.http.on('listening', onListening)

Expand All @@ -75,26 +75,29 @@ class Server extends EventEmitter {

// start a udp tracker unless the user explicitly says no
if (opts.udp !== false) {
const isNode10 = /^v0.10./.test(process.version)

this.udp4 = this.udp = dgram.createSocket(
isNode10 ? 'udp4' : { type: 'udp4', reuseAddr: true }
)
this.udp4 = this.udp = dgram.createSocket({
type: 'udp4',
reuseAddr: true,
...(isObject(opts.udp) ? opts.udp : undefined)
})
this.udp4.on('message', (msg, rinfo) => { this.onUdpRequest(msg, rinfo) })
this.udp4.on('error', err => { this._onError(err) })
this.udp4.on('listening', onListening)

this.udp6 = dgram.createSocket(
isNode10 ? 'udp6' : { type: 'udp6', reuseAddr: true }
)
this.udp6 = dgram.createSocket({
type: 'udp6',
reuseAddr: true,
...(isObject(opts.udp) ? opts.udp : undefined)
})
this.udp6.on('message', (msg, rinfo) => { this.onUdpRequest(msg, rinfo) })
this.udp6.on('error', err => { this._onError(err) })
this.udp6.on('listening', onListening)
}

// start a websocket tracker (for WebTorrent) unless the user explicitly says no
if (opts.ws !== false) {
if (!this.http) {
const noServer = isObject(opts.ws) && opts.ws.noServer
if (!this.http && !noServer) {
this.http = http.createServer()
this.http.on('error', err => { this._onError(err) })
this.http.on('listening', onListening)
Expand All @@ -112,13 +115,19 @@ class Server extends EventEmitter {
})
}
this.ws = new WebSocketServer({
server: this.http,
server: noServer ? undefined : this.http,
perMessageDeflate: false,
clientTracking: false
clientTracking: false,
...(isObject(opts.ws) ? opts.ws : undefined)
})

this.ws.address = () => {
if (noServer) {
throw new Error('address() unavailable with { noServer: true }')
}
return this.http.address()
}

this.ws.on('error', err => { this._onError(err) })
this.ws.on('connection', (socket, req) => {
// Note: socket.upgradeReq was removed in [email protected], so re-add it.
Expand Down Expand Up @@ -297,10 +306,6 @@ class Server extends EventEmitter {

debug('listen (port: %o hostname: %o)', port, hostname)

function isObject (obj) {
return typeof obj === 'object' && obj !== null
}

const httpPort = isObject(port) ? (port.http || 0) : port
const udpPort = isObject(port) ? (port.udp || 0) : port

Expand Down Expand Up @@ -801,6 +806,10 @@ function makeUdpPacket (params) {
return packet
}

function isObject (obj) {
return typeof obj === 'object' && obj !== null
}

function toNumber (x) {
x = Number(x)
return x >= 0 ? x : false
Expand Down