rubytorrent 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,536 @@
1
+ ## peer.rb -- bitttorrent peer ("wire") protocol.
2
+ ## Copyright 2004 William Morgan.
3
+ ##
4
+ ## This file is part of RubyTorrent. RubyTorrent is free software;
5
+ ## you can redistribute it and/or modify it under the terms of version
6
+ ## 2 of the GNU General Public License as published by the Free
7
+ ## Software Foundation.
8
+ ##
9
+ ## RubyTorrent is distributed in the hope that it will be useful, but
10
+ ## WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ ## General Public License (in the file COPYING) for more details.
13
+
14
+ require 'socket'
15
+ require 'thread'
16
+ require "rubytorrent/message"
17
+
18
+ module RubyTorrent
19
+
20
+ module ArrayToBitstring
21
+ def to_bitstring
22
+ ret = "\0"
23
+ bit = 7
24
+ map do |b|
25
+ if bit == -1
26
+ ret += "\0"
27
+ bit = 7
28
+ end
29
+ ret[ret.length - 1] |= (1 << bit) if b
30
+ bit -= 1
31
+ end
32
+ ret
33
+ end
34
+ end
35
+
36
+ module ArrayDelete2
37
+ ## just like delete but returns the *array* element deleted rather
38
+ ## than the argument. someone should file an rcr.
39
+ def delete2(el)
40
+ i = index el
41
+ unless i.nil?
42
+ ret = self[i]
43
+ delete_at i
44
+ ret
45
+ else
46
+ nil
47
+ end
48
+ end
49
+ end
50
+
51
+ module StringToBarray
52
+ include StringMapBytes
53
+ def to_barray
54
+ self.map_bytes do |b|
55
+ (0 .. 7).map { |i| (b & (1 << (7 - i))) != 0 }
56
+ end.flatten
57
+ end
58
+ end
59
+
60
+ ## estimate a rate. basically copied from bram's code.
61
+ class RateMeter
62
+ attr_reader :amt
63
+
64
+ def initialize(window=20)
65
+ @window = window.to_f
66
+ @amt = 0
67
+ @rate = 0
68
+ @last = @since = Time.now - 1
69
+ @m = Mutex.new
70
+ end
71
+
72
+ def add(new_amt)
73
+ now = Time.now
74
+ @m.synchronize do
75
+ @amt += new_amt
76
+ @rate = ((@rate * (@last - @since)) + new_amt).to_f / (now - @since)
77
+ @last = now
78
+ @since = [@since, now - @window].max
79
+ end
80
+ end
81
+
82
+ def rate
83
+ (@rate * (@last - @since)).to_f / (Time.now - @since)
84
+ end
85
+
86
+ def bytes_until(new_rate)
87
+ [(new_rate.to_f * (Time.now - @since)) - (@rate * (@last - @since)), 0].max
88
+ end
89
+ end
90
+
91
+ class ProtocolError < StandardError; end
92
+
93
+ ## The PeerConnection object deals with all the protocol issues. It
94
+ ## keeps state information as to the connection and the peer. It is
95
+ ## tightly integrated with the Controller object.
96
+ ##
97
+ ## Remember to be "strict in what you send, lenient in what you
98
+ ## accept".
99
+ class PeerConnection
100
+ extend AttrReaderQ
101
+ include EventSource
102
+
103
+ attr_reader :peer_pieces, :name
104
+ attr_reader_q :running, :choking, :interested, :peer_choking,
105
+ :peer_interested, :snubbing
106
+ event :peer_has_piece, :peer_has_pieces, :received_block, :sent_block,
107
+ :requested_block
108
+
109
+ BUFSIZE = 8192
110
+ MAX_PEER_REQUESTS = 5 # how many peer requests to keep queued
111
+ MAX_REQUESTS = 5 # how many requests for blocks to keep current
112
+ MIN_REQUESTS = 1 # get more blocks from controller when this limit is reached
113
+ REQUEST_TIMEOUT = 60 # number of seconds after sending a request before we
114
+ # decide it's been forgotten
115
+
116
+ def initialize(name, controller, socket, package)
117
+ @name = name
118
+ @controller = controller
119
+ @socket = socket
120
+ @package = package
121
+ @running = false
122
+
123
+ ## my state
124
+ @want_blocks = [].extend(ArrayDelete2) # blocks i want
125
+ @want_blocks_m = Mutex.new
126
+ @choking = true
127
+ @interested = false
128
+ @snubbing = false
129
+
130
+ ## peer's state
131
+ @peer_want_blocks = [].extend(ArrayDelete2)
132
+ @peer_choking = true # assumption of initial condition
133
+ @peer_interested = false # ditto
134
+ @peer_pieces = Array.new(@package.num_pieces, false) # ditto
135
+ @peer_virgin = true # does the peer have any pieces at all?
136
+
137
+ ## connection stats
138
+ @dlmeter = RateMeter.new
139
+ @ulmeter = RateMeter.new
140
+
141
+ @send_q = Queue.new # output thread takes messages from here and
142
+ # puts them on the wire
143
+ end
144
+
145
+ def pending_recv; @want_blocks.find_all { |b| b.requested? }.length; end
146
+ def pending_send; @peer_want_blocks.length; end
147
+
148
+ def start
149
+ @running = true
150
+ @time = {:start => Time.now}
151
+
152
+ Thread.new do # start input thread
153
+ begin
154
+ while @running; input_thread_step; end
155
+ rescue SystemCallError, IOError, ProtocolError => e
156
+ rt_debug "#{self} (input): #{e.message}, releasing #{@want_blocks.length} claimed blocks and dying"
157
+ # rt_debug e.backtrace.join("\n")
158
+ @running = false
159
+ @controller.forget_blocks @want_blocks
160
+ end
161
+ end
162
+
163
+ Thread.new do # start output thread
164
+ begin
165
+ while @running; output_thread_step; end
166
+ rescue SystemCallError, IOError, ProtocolError => e
167
+ rt_debug "#{self} (output): #{e.message}, releasing #{@want_blocks.length} claimed blocks and dying"
168
+ # rt_debug e.backtrace.join("\n")
169
+ @running = false
170
+ @controller.forget_blocks @want_blocks
171
+ end
172
+ end
173
+
174
+ ## queue the initial messages
175
+ queue_message(:bitfield, {:bitfield => @package.pieces.map { |p| p.complete? }.extend(ArrayToBitstring).to_bitstring})
176
+
177
+ ## and that's it. if peer sends a bitfield, we'll send an
178
+ ## interested and start requesting blocks at that point. if they
179
+ ## don't, it means they don't have any pieces, so we can just sit
180
+ ## tight.
181
+ self
182
+ end
183
+
184
+ ## the Controller calls this from heartbeat thread to tell us
185
+ ## whether to choke or not.
186
+ def choke=(now_choke)
187
+ queue_message(now_choke ? :choke : :unchoke) unless @choking == now_choke
188
+ @choking = now_choke
189
+ end
190
+
191
+ ## the Controller calls this from heartbeat thread to tell us
192
+ ## whether to snub or not.
193
+ def snub=(now_snub)
194
+ unless @snubbing = now_snub
195
+ @snubbing = now_snub
196
+ choke = true if @snubbing
197
+ end
198
+ end
199
+
200
+ def peer_complete?; @peer_pieces.all?; end
201
+ def last_send_time; @time[:send]; end
202
+ def last_recv_time; @time[:recv]; end
203
+ def last_send_block_time; @time[:send_block]; end
204
+ def last_recv_block_time; @time[:recv_block]; end
205
+ def start_time; @time[:start]; end
206
+ def dlrate; @dlmeter.rate; end
207
+ def ulrate; @ulmeter.rate; end
208
+ def dlamt; @dlmeter.amt; end
209
+ def ulamt; @ulmeter.amt; end
210
+ def piece_available?(index); @peer_pieces[index]; end
211
+ def to_s; "<peer: #@name>"; end
212
+
213
+ ## called by Controller in the event that a request needs to be
214
+ ## rescinded.
215
+ def cancel(block)
216
+ wblock = @want_blocks_m.synchronize { @want_blocks.delete2 block }
217
+ unless wblock.nil? || !wblock.requested?
218
+ rt_debug "#{self}: sending cancel for #{wblock}"
219
+ queue_message(:cancel, {:index => wblock.pindex, :begin => wblock.begin,
220
+ :length => wblock.length})
221
+ end
222
+ get_want_blocks unless wblock.nil?
223
+ end
224
+
225
+ def shutdown
226
+ rt_debug "#{self.to_s}: shutting down"
227
+ @running = false
228
+ @socket.close rescue nil
229
+ end
230
+
231
+ ## Controller calls this to tell us that a complete piece has been
232
+ ## received.
233
+ def have_piece(piece)
234
+ queue_message(:have, {:index => piece.index})
235
+ end
236
+
237
+ ## Controller calls this to tell us to send a keepalive
238
+ def send_keepalive
239
+ # rt_debug "* sending keepalive!"
240
+ queue_message(:keepalive)
241
+ end
242
+
243
+ ## this is called both by input_thread_step and by the controller's
244
+ ## heartbeat thread. it sends as many pending blocks as it can while
245
+ ## keeping the amount below 'ullim', and sends as many requests as
246
+ ## it can while keeping the amount below 'dllim'.
247
+ ##
248
+ ## returns the number of bytes requested and sent
249
+ def send_blocks_and_reqs(dllim=nil, ullim=nil)
250
+ sent_bytes = 0
251
+ reqd_bytes = 0
252
+
253
+ @want_blocks_m.synchronize do
254
+ @want_blocks.each do |b|
255
+ # puts "[][] #{self}: #{b} is #{b.requested? ? 'requested' : 'NOT requested'} and has time_elapsed of #{b.requested? ? b.time_elapsed.round : 'n/a'}s"
256
+ if b.requested? && (b.time_elapsed > REQUEST_TIMEOUT)
257
+ rt_warning "#{self}: for block #{b}, time elapsed since request is #{b.time_elapsed} > #{REQUEST_TIMEOUT}, assuming peer forgot about it"
258
+ @want_blocks.delete b
259
+ @controller.forget_blocks [b]
260
+ end
261
+ end
262
+ end
263
+
264
+ ## send :requests
265
+ unless @peer_choking || !@interested
266
+ @want_blocks_m.synchronize do
267
+ @want_blocks.each do |b|
268
+ break if dllim && (reqd_bytes >= dllim)
269
+ next if b.requested?
270
+
271
+ if @package.pieces[b.pindex].complete?
272
+ # not sure that this will ever happen, but...
273
+ rt_warning "#{self}: deleting scheduled block for already-complete piece #{b}"
274
+ @want_blocks.delete b
275
+ next
276
+ end
277
+
278
+ queue_message(:request, {:index => b.pindex, :begin => b.begin,
279
+ :length => b.length})
280
+ reqd_bytes += b.length
281
+ b.requested = true
282
+ b.mark_time
283
+ send_event(:requested_block, b)
284
+ end
285
+ end
286
+ end
287
+
288
+ ## send blocks
289
+ # rt_debug "sending blocks. choking? #@choking, choked? #@peer_choking, ul rate #{ulrate}b/s, limit #@ulmeterlim" unless @peer_want_blocks.empty?
290
+ unless @choking || !@peer_interested
291
+ while !@peer_want_blocks.empty?
292
+ break if ullim && (sent_bytes >= ullim)
293
+ if (b = @peer_want_blocks.shift)
294
+ sent_bytes += b.length
295
+ @send_q.push b
296
+ @time[:send_block] = Time.now
297
+ send_event(:sent_block, b)
298
+ end
299
+ end
300
+ end
301
+
302
+ get_want_blocks
303
+
304
+ [reqd_bytes, sent_bytes]
305
+ end
306
+
307
+ private
308
+
309
+ ## re-calculate whether we're interested or not. triggered by
310
+ ## received :have and :bitfield messages.
311
+ def recalc_interested
312
+ show_interest = !@peer_virgin || (@package.pieces.detect do |p|
313
+ !p.complete? && @peer_pieces[p.index]
314
+ end) != nil
315
+
316
+ queue_message(show_interest ? :interested : :uninterested) unless show_interest == @interested
317
+ if ((@interested = show_interest) == false)
318
+ @want_blocks_m.synchronize do
319
+ @controller.forget_blocks @want_blocks
320
+ @want_blocks.clear
321
+ end
322
+ end
323
+ end
324
+
325
+ ## take a message/block from the send_q and place it on the wire. blocking.
326
+ def output_thread_step
327
+ obj = @send_q.deq
328
+ case obj
329
+ when Message
330
+ # rt_debug "output: sending message #{obj}" + (obj.id == :request ? " (request queue size #{@want_blocks.length})" : "")
331
+ send_bytes obj.to_wire_form
332
+ @time[:send] = Time.now
333
+ when Block
334
+ # rt_debug "output: sending block #{obj}"
335
+ send_bytes Message.new(:piece, {:length => obj.length, :index => obj.pindex, :begin => obj.begin}).to_wire_form
336
+ obj.each_chunk(BUFSIZE) { |c| send_bytes c }
337
+ @time[:send] = Time.now
338
+ @ulmeter.add obj.length
339
+ # rt_debug "sent block #{obj} ul rate now #{(ulrate / 1024.0).round}kb/s"
340
+ else
341
+ raise "don't know what to do with #{obj}"
342
+ end
343
+ end
344
+
345
+ ## take bits from the wire and respond to them. blocking.
346
+ def input_thread_step
347
+ case (obj = read_from_wire)
348
+ when Block
349
+ handle_block obj
350
+ when Message
351
+ handle_message obj
352
+ else
353
+ raise "don't know what to do with #{obj.inspect}"
354
+ end
355
+
356
+ ## to enable immediate response, if there are no rate limits,
357
+ ## we'll send the blocks and reqs right here. otherwise, the
358
+ ## controller will call this at intervals.
359
+ send_blocks_and_reqs if @controller.dlratelim.nil? && @controller.ulratelim.nil?
360
+ end
361
+
362
+ ## take bits from the wire and make a message/block out of them. blocking.
363
+ def read_from_wire
364
+ len = nil
365
+ while (len = recv_bytes(4).from_fbbe) == 0
366
+ @time[:recv] = Time.now
367
+ # rt_debug "* hey, a keepalive!"
368
+ end
369
+
370
+ id = recv_bytes(1)[0]
371
+
372
+ if Message::WIRE_IDS[id] == :piece # add a block
373
+ len -= 9
374
+ m = Message.from_wire_form(id, recv_bytes(8))
375
+ b = Block.new(m.index, m.begin, len)
376
+ while len > 0
377
+ thislen = [BUFSIZE, len].min
378
+ b.add_chunk recv_bytes(thislen)
379
+ len -= thislen
380
+ end
381
+ @time[:recv] = @time[:recv_block] = Time.now
382
+ b
383
+ else # add a message
384
+ m = Message.from_wire_form(id, recv_bytes(len - 1))
385
+ # rt_debug "input: read message #{m}"
386
+ @time[:recv] = Time.now
387
+ m
388
+ end
389
+ end
390
+
391
+ def handle_block(block)
392
+ wblock = @want_blocks_m.synchronize { @want_blocks.delete2 block }
393
+
394
+ return rt_warning("#{self}: peer sent unrequested (possibly cancelled) block #{block}") if wblock.nil? || !wblock.requested?
395
+
396
+ @dlmeter.add block.have_length
397
+ # rt_debug "received block #{block}, dl rate now #{(dlrate / 1024.0).round}kb/s"
398
+
399
+ piece = @package.pieces[block.pindex] # find corresponding piece
400
+ piece.add_block block
401
+ send_event(:received_block, block)
402
+ get_want_blocks
403
+ end
404
+
405
+ def send_bytes(s)
406
+ if s.nil?
407
+ raise "can't send nil"
408
+ elsif s.length > 0
409
+ @socket.send(s, 0)
410
+ end
411
+ end
412
+
413
+ def recv_bytes(len)
414
+ if len < 0
415
+ raise "can't recv negative bytes"
416
+ elsif len == 0
417
+ ""
418
+ elsif len > 512 * 1024 # 512k
419
+ raise ProtocolError, "read size too big."
420
+ else
421
+ r = ""
422
+ zeros = 0
423
+ while r.length < len
424
+ x = @socket.recv(len - r.length)
425
+ raise IOError, "zero bytes received" if x.length == 0
426
+ r += x
427
+ end
428
+ r
429
+ end
430
+ end
431
+
432
+ def handle_message(m)
433
+ case m.id
434
+ when :choke
435
+ # rt_debug "#{self}: peer choking (was #{@peer_choking})"
436
+ @peer_choking = true
437
+ @want_blocks_m.synchronize do
438
+ @controller.forget_blocks @want_blocks
439
+ @want_blocks.clear
440
+ end
441
+
442
+ when :unchoke
443
+ # rt_debug "#{self}: peer not choking (was #{@peer_choking})"
444
+ @peer_choking = false
445
+
446
+ when :interested
447
+ # rt_debug "peer interested (was #{@peer_interested})"
448
+ @peer_interested = true
449
+
450
+ when :uninterested
451
+ # rt_debug "peer not interested (was #{@peer_interested})"
452
+ @peer_interested = false
453
+
454
+ when :have
455
+ # rt_debug "peer has piece #{m.index}"
456
+ rt_warning "#{self}: peer already has piece #{m.index}" if @peer_pieces[m.index]
457
+ @peer_pieces[m.index] = true
458
+ @peer_virgin = false
459
+ send_event(:peer_has_piece, m)
460
+ recalc_interested
461
+
462
+ when :bitfield
463
+ # rt_debug "peer reports bitfield #{m.bitfield.inspect}"
464
+ barray = m.bitfield.extend(StringToBarray).to_barray
465
+
466
+ expected_pieces = @package.num_pieces - (@package.num_pieces % 8) + ((@package.num_pieces % 8) == 0 ? 0 : 8)
467
+ raise ProtocolError, "invalid length in bitfield message (package has #{@package.num_pieces} pieces; bitfield should be size #{expected_pieces} but is #{barray.length} pieces)" unless barray.length == expected_pieces
468
+
469
+ @peer_pieces.each_index { |i| @peer_pieces[i] = barray[i] }
470
+ @peer_virgin = false
471
+ send_event(:peer_has_pieces, barray)
472
+ recalc_interested
473
+ get_want_blocks
474
+
475
+ when :request
476
+ return rt_warning("#{self}: peer requests invalid piece #{m.index}") unless m.index < @package.num_pieces
477
+ return rt_warning("#{self}: peer requests a block but we're choking") if @choking
478
+ return rt_warning("#{self}: peer requests a block but isn't interested") unless @peer_interested
479
+ return rt_warning("#{self}: peer requested too many blocks, ignoring") if @peer_want_blocks.length > MAX_PEER_REQUESTS
480
+
481
+ piece = @package.pieces[m.index]
482
+ return rt_warning("#{self}: peer requests unavailable block from piece #{piece}") unless piece.complete?
483
+
484
+ @peer_want_blocks.push piece.get_complete_block(m.begin, m.length)
485
+
486
+ when :piece
487
+ raise "can't handle piece here"
488
+
489
+ when :cancel
490
+ b = Block.new(m.index, m.begin, m.length)
491
+ # rt_debug "peer cancels #{b}"
492
+ if @peer_want_blocks.delete2(b) == nil
493
+ rt_warning "#{self}: peer wants to cancel unrequested block #{b}"
494
+ end
495
+
496
+ else
497
+ raise "unknown message #{type}"
498
+ end
499
+ end
500
+
501
+ ## queues a message for delivery. (for :piece messages, this
502
+ ## transmits everything but the piece itself)
503
+ def queue_message(id, args=nil)
504
+ @send_q.push Message.new(id, args)
505
+ end
506
+
507
+ ## talks to Controller and get some new blocks to request. could be
508
+ ## slow. this is presumably called whenever the queue of requests is
509
+ ## too small.
510
+ def get_want_blocks
511
+ return if (@want_blocks.length >= MIN_REQUESTS) || @peer_virgin || @peer_choking || !@interested
512
+
513
+ rej_count = 0
514
+ acc_count = 0
515
+ @controller.claim_blocks do |b|
516
+ break if @want_blocks.length >= MAX_REQUESTS
517
+ if @peer_pieces[b.pindex] && !@want_blocks.member?(b)
518
+ rt_debug "! #{self}: starting new piece #{@package.pieces[b.pindex]}" unless @package.pieces[b.pindex].started?
519
+
520
+ # rt_debug "#{self}: added to queue block #{b}"
521
+ # puts "#{self}: claimed block #{b}"
522
+ @want_blocks.push b
523
+ acc_count += 1
524
+ true
525
+ else
526
+ # puts "#{self}: cont offers block #{b} but peer has? #{@peer_pieces[b.pindex]} i already want? #{@want_blocks.member? b}" if rej_count < 10
527
+ rej_count += 1
528
+ false
529
+ end
530
+ end
531
+ # puts "#{self}: ... and #{rej_count} more (peer has #{@peer_pieces.inject(0) { |s, p| s + (p ? 1 : 0) }} pieces)... " if rej_count >= 10
532
+ # puts "#{self}: accepted #{acc_count} blocks, rejected #{rej_count} blocks"
533
+ end
534
+ end
535
+
536
+ end