Skip to content

Commit e5b516f

Browse files
committed
handle some more edge cases, code style, add todos
1 parent 5c09dcd commit e5b516f

File tree

1 file changed

+50
-42
lines changed

1 file changed

+50
-42
lines changed

index.js

Lines changed: 50 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,9 @@ var string2compact = require('string2compact')
1313
var dgram = require('dgram')
1414
var parseUrl = require('url').parse
1515

16-
var CONNECTION_ID = Buffer.concat([toUInt32(0x417), toUInt32(0x27101980)])
17-
var CONNECT = toUInt32(0)
18-
var ANNOUNCE = toUInt32(1)
19-
var EVENTS = {
20-
completed: 1,
21-
started: 2,
22-
stopped: 3
23-
}
16+
var CONNECTION_ID = Buffer.concat([ toUInt32(0x417), toUInt32(0x27101980) ])
17+
var ACTIONS = { CONNECT: 0, ANNOUNCE: 1 }
18+
var EVENTS = { completed: 1, started: 2, stopped: 3 }
2419

2520
inherits(Client, EventEmitter)
2621

@@ -31,9 +26,13 @@ function Client (peerId, port, torrent, opts) {
3126
self._opts = opts || {}
3227

3328
// required
34-
self._peerId = peerId
29+
self._peerId = Buffer.isBuffer(peerId)
30+
? peerId
31+
: new Buffer(torrent.infoHash, 'utf8')
3532
self._port = port
36-
self._infoHash = torrent.infoHash
33+
self._infoHash = Buffer.isBuffer(torrent.infoHash)
34+
? torrent.infoHash
35+
: new Buffer(torrent.infoHash, 'hex')
3736
self._torrentLength = torrent.length
3837
self._announce = torrent.announce
3938

@@ -142,21 +141,26 @@ Client.prototype._requestHttp = function (announceUrl, opts) {
142141
}
143142

144143
Client.prototype._requestUdp = function (announceUrl, opts) {
145-
var parsed = parseUrl(announceUrl)
146-
var socket = dgram.createSocket('udp4')
147144
var self = this
145+
var parsedUrl = parseUrl(announceUrl)
146+
var socket = dgram.createSocket('udp4')
147+
var transactionId = new Buffer(hat(32), 'hex')
148148

149-
var timeout = setTimeout(function() {
149+
var timeout = setTimeout(function () {
150150
socket.close()
151151
}, 5000)
152152

153-
socket.on('error', function(err) {
153+
socket.on('error', function (err) {
154154
self.emit('error', err)
155155
})
156156

157-
socket.on('message', function(message, rinfo) {
158-
var action = message.readUInt32BE(0)
157+
socket.on('message', function (message, rinfo) {
158+
159+
if (message.length < 8 || message.readUInt32BE(4) !== transactionId.readUInt32BE(0)) {
160+
return self.emit('error', new Error('tracker sent back invalid transaction id'))
161+
}
159162

163+
var action = message.readUInt32BE(0)
160164
switch (action) {
161165
case 0:
162166
if (message.length < 16) {
@@ -170,49 +174,58 @@ Client.prototype._requestUdp = function (announceUrl, opts) {
170174
return self.emit('error', new Error('invalid announce message'))
171175
}
172176

177+
// TODO: this should be stored per tracker, not globally for all trackers
178+
var interval = message.readUInt32BE(8)
179+
if (interval && !self._opts.interval && self._intervalMs !== 0) {
180+
// use the interval the tracker recommends, UNLESS the user manually specifies an
181+
// interval they want to use
182+
self.setInterval(interval * 1000)
183+
}
184+
173185
self.emit('update', {
174186
announce: announceUrl,
175187
complete: message.readUInt32BE(16),
176188
incomplete: message.readUInt32BE(12)
177189
})
178190

179-
for (var i = 20; i < message.length; i += 6) {
180-
self.emit('peer', compact2string(message.slice(i, i+6)))
181-
}
191+
compact2string.multi(message.slice(20)).forEach(function (addr) {
192+
self.emit('peer', addr)
193+
})
182194

183195
clearTimeout(timeout)
184196
socket.close()
185197
}
186198
})
187199

200+
function send (message) {
201+
socket.send(message, 0, message.length, parsedUrl.port, parsedUrl.hostname)
202+
}
203+
188204
function announce (connectionId, opts) {
189205
opts = opts || {}
206+
transactionId = new Buffer(hat(32), 'hex')
190207

191208
send(Buffer.concat([
192209
connectionId,
193-
ANNOUNCE,
194-
new Buffer(hat(32), 'hex'),
195-
new Buffer(self._infoHash, 'hex'),
196-
new Buffer(self._peerId, 'utf-8'),
197-
toUInt32(0), toUInt32(opts.downloaded || 0), // fromUint32(0) to expand this to 64bit
198-
toUInt32(0), toUInt32(opts.left || 0),
199-
toUInt32(0), toUInt32(opts.uploaded || 0),
210+
toUInt32(ACTIONS.ANNOUNCE),
211+
transactionId,
212+
self._infoHash,
213+
self._peerId,
214+
toUInt32(0), toUInt32(opts.downloaded || 0), // 64bit
215+
toUInt32(0), toUInt32(opts.left || 0), // 64bit
216+
toUInt32(0), toUInt32(opts.uploaded || 0), // 64bit
200217
toUInt32(EVENTS[opts.event] || 0),
201-
toUInt32(0),
202-
toUInt32(0),
218+
toUInt32(0), // ip address (optional)
219+
toUInt32(0), // key (optional)
203220
toUInt32(self._numWant),
204221
toUInt16(self._port || 0)
205222
]))
206223
}
207224

208-
function send (message) {
209-
socket.send(message, 0, message.length, parsed.port, parsed.hostname)
210-
}
211-
212225
send(Buffer.concat([
213226
CONNECTION_ID,
214-
CONNECT,
215-
new Buffer(hat(32), 'hex')
227+
toUInt32(ACTIONS.CONNECT),
228+
transactionId
216229
]))
217230
}
218231

@@ -234,13 +247,15 @@ Client.prototype._handleResponse = function (data, announceUrl) {
234247
self.emit('warning', warning);
235248
}
236249

250+
// TODO: this should be stored per tracker, not globally for all trackers
237251
var interval = data.interval || data['min interval']
238252
if (interval && !self._opts.interval && self._intervalMs !== 0) {
239253
// use the interval the tracker recommends, UNLESS the user manually specifies an
240254
// interval they want to use
241255
self.setInterval(interval * 1000)
242256
}
243257

258+
// TODO: this should be stored per tracker, not globally for all trackers
244259
var trackerId = data['tracker id']
245260
if (trackerId) {
246261
// If absent, do not discard previous trackerId value
@@ -255,8 +270,7 @@ Client.prototype._handleResponse = function (data, announceUrl) {
255270

256271
if (Buffer.isBuffer(data.peers)) {
257272
// tracker returned compact response
258-
var addrs = compact2string.multi(data.peers)
259-
addrs.forEach(function (addr) {
273+
compact2string.multi(data.peers).forEach(function (addr) {
260274
self.emit('peer', addr)
261275
})
262276
} else if (Array.isArray(data.peers)) {
@@ -463,15 +477,9 @@ function toUInt32 (n) {
463477
}
464478

465479
function bytewiseEncodeURIComponent (buf) {
466-
if (!Buffer.isBuffer(buf)) {
467-
buf = new Buffer(buf, 'hex')
468-
}
469480
return encodeURIComponent(buf.toString('binary'))
470481
}
471482

472483
function bytewiseDecodeURIComponent (str) {
473-
if (Buffer.isBuffer(str)) {
474-
str = str.toString('utf8')
475-
}
476484
return (new Buffer(decodeURIComponent(str), 'binary').toString('hex'))
477485
}

0 commit comments

Comments
 (0)