Module: QuartzTorrent

Defined in:
lib/quartz_torrent/metainfopiecestate.rb,
lib/quartz_torrent/log.rb,
lib/quartz_torrent/peer.rb,
lib/quartz_torrent/rate.rb,
lib/quartz_torrent/util.rb,
lib/quartz_torrent/alarm.rb,
lib/quartz_torrent/magnet.rb,
lib/quartz_torrent/peermsg.rb,
lib/quartz_torrent/reactor.rb,
lib/quartz_torrent/bitfield.rb,
lib/quartz_torrent/metainfo.rb,
lib/quartz_torrent/extension.rb,
lib/quartz_torrent/formatter.rb,
lib/quartz_torrent/ratelimit.rb,
lib/quartz_torrent/regionmap.rb,
lib/quartz_torrent/blockstate.rb,
lib/quartz_torrent/peerclient.rb,
lib/quartz_torrent/peerholder.rb,
lib/quartz_torrent/filemanager.rb,
lib/quartz_torrent/memprofiler.rb,
lib/quartz_torrent/peermanager.rb,
lib/quartz_torrent/timermanager.rb,
lib/quartz_torrent/torrentqueue.rb,
lib/quartz_torrent/udptrackermsg.rb,
lib/quartz_torrent/classifiedpeers.rb,
lib/quartz_torrent/udptrackerdriver.rb,
lib/quartz_torrent/httptrackerdriver.rb,
lib/quartz_torrent/interruptiblesleep.rb,
lib/quartz_torrent/peermsgserialization.rb,
lib/quartz_torrent/piecemanagerrequestmetadata.rb

Overview

This class is used when we don’t have the info struct for the torrent (no .torrent file) and must download it piece by piece from peers. It keeps track of the pieces we have.

When a piece is requested from a peer and that peer responds with a reject saying it doesn’t have that metainfo piece, we take a simple approach and mark that peer as bad, and don’t request any more pieces from that peer even though they may have other pieces. This simplifies the code.

Defined Under Namespace

Classes: Alarm, Alarms, Bitfield, BitfieldMessage, BlockInfo, BlockState, Cancel, Choke, ClassifiedPeers, EmptyBitfield, Extended, ExtendedHandshake, ExtendedMetaInfo, Extension, FileRegion, Formatter, Handler, Have, HttpTrackerDriver, IOInfo, IOManager, IncompletePiece, Interested, InterruptibleSleep, IoFacade, KeepAlive, LogManager, MagnetURI, ManagePeersResult, MemProfiler, Metainfo, MetainfoPieceState, OutputBuffer, Peer, PeerClient, PeerClientHandler, PeerHandshake, PeerHolder, PeerManager, PeerRequest, PeerWireMessage, PeerWireMessageSerializer, Piece, PieceIO, PieceManager, PieceManagerRequestMetadata, PieceMapper, Rate, RateLimit, Reactor, ReadRequestMetadata, RegionMap, Request, RequestedBlock, TimerManager, TorrentData, TorrentDataDelegate, TorrentQueue, TrackerClient, TrackerDriver, UdpTrackerAnnounceRequest, UdpTrackerAnnounceResponse, UdpTrackerConnectRequest, UdpTrackerConnectResponse, UdpTrackerDriver, UdpTrackerMessage, UdpTrackerRequest, UdpTrackerResponse, Unchoke, Uninterested, WriteOnlyIoFacade

Constant Summary collapse

SYSCALL_GETTID =

This is Linux specific: system call number for gettid

224

Class Method Summary collapse

Class Method Details

.arrayShuffleRange!(array, start, length) ⇒ Object

Shuffle the subset of elements in the given array between start and start+length-1 inclusive.



36
37
38
39
40
41
42
43
44
# File 'lib/quartz_torrent/util.rb', line 36

def self.arrayShuffleRange!(array, start, length)
  raise "Invalid range" if start + length > array.size

  (start+length).downto(start+1) do |i|
    r = start + rand(i-start)
    array[r], array[i-1] = array[i-1], array[r]
  end
  true
end

.bytesToHex(v, addSpaces = nil) ⇒ Object

Return a hex string representing the bytes in the passed string.



19
20
21
22
23
24
25
26
27
28
# File 'lib/quartz_torrent/util.rb', line 19

def self.bytesToHex(v, addSpaces = nil)
  s = ""
  v.each_byte{ |b|
    hex = b.to_s(16)
    hex = "0" + hex if hex.length == 1
    s << hex
    s << " " if addSpaces == :add_spaces
  }
  s
end

.hexToBytes(v) ⇒ Object

Given a hex string representing a sequence of bytes, convert it the the original bytes. Inverse of bytesToHex.



31
32
33
# File 'lib/quartz_torrent/util.rb', line 31

def self.hexToBytes(v)
  [v].pack "H*"
end

.initThread(name) ⇒ Object

Method to set a few thread-local variables useful in debugging. Threads should call this when started.



95
96
97
# File 'lib/quartz_torrent/util.rb', line 95

def self.initThread(name)
  Thread.current[:name] = name
end

.logBacktraces(io = nil) ⇒ Object

Log backtraces of all threads currently running. The threads are logged to the passed io, or if that’s nil they are written to the logger named ‘util’ at error level.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/quartz_torrent/util.rb', line 74

def self.logBacktraces(io = nil)
  logger = nil
  logger = LogManager.getLogger("util") if ! io
  isLinux = RUBY_PLATFORM.downcase.include?("linux")

  Thread.list.each do |thread|
    lwpid = ""

    setThreadLwpid thread if ! thread[:lwpid] && isLinux
    lwpid = " [lwpid #{thread[:lwpid]}]" if thread[:lwpid]

    msg = "Thread #{thread[:name]} #{thread.object_id}#{lwpid}: #{thread.status}\n  " + (thread.backtrace ? thread.backtrace.join("\n  ") : "no backtrace")
    if io
      io.puts msg
    else
      logger.error msg
    end
  end
end

.setThreadLwpid(thread = nil) ⇒ Object

Store Linux Lightweight process ids (LWPID) on each thread. If this is called a while before logBacktraces the backtraces will include lwpids.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/quartz_torrent/util.rb', line 49

def self.setThreadLwpid(thread = nil)
  # This function works by calling the GETTID system call in Linux. That
  # system call must be called in the thread that we want to get the lwpid of,
  # but the user may not have created those threads and so can't call the system call
  # in those threads (think Sinatra). To get around this this function runs code in the
  # thread by adding a trace function to the thread, and on the first traced operation
  # stores the LWPID on the thread and unregisters itself.    

  isLinux = RUBY_PLATFORM.downcase.include?("linux")
  return if !isLinux

  tracer = Proc.new do
    Thread.current[:lwpid] = syscall(SYSCALL_GETTID) if ! Thread.current[:lwpid] && isLinux
    Thread.current.set_trace_func(nil)
  end
  
  if thread
    thread.set_trace_func(tracer)
  else
    Thread.list.each { |thread| thread.set_trace_func(tracer) }
  end
end