class QuartzTorrent::UdpTrackerDriver
A tracker driver that uses the UDP protocol as defined by xbtt.sourceforge.net/udp_tracker_protocol.html
Constants
- ReceiveLength
Set UDP receive length to a value that allows up to 100 peers to be returned in an announce.
Public Class Methods
new(announceUrl, infoHash, timeout = 2)
click to toggle source
Calls superclass method
QuartzTorrent::TrackerDriver::new
# File lib/quartz_torrent/udptrackerdriver.rb, line 6 def initialize(announceUrl, infoHash, timeout = 2) super() @announceUrl = announceUrl @infoHash = infoHash @timeout = timeout @logger = LogManager.getLogger("udp_tracker_client") if @announceUrl =~ /udp:\/\/([^:]+):(\d+)/ @host = $1 @trackerPort = $2 else throw "UDP Tracker announce URL is invalid: #{announceUrl}" end end
Public Instance Methods
request(event = nil)
click to toggle source
# File lib/quartz_torrent/udptrackerdriver.rb, line 20 def request(event = nil) if event == :started event = UdpTrackerMessage::EventStarted elsif event == :stopped event = UdpTrackerMessage::EventStopped elsif event == :completed event = UdpTrackerMessage::EventCompleted else event = UdpTrackerMessage::EventNone end socket = UDPSocket.new result = nil begin socket.connect @host, @trackerPort @logger.debug "Sending UDP tracker request to #{@host}:#{@trackerPort}" # Send connect request req = UdpTrackerConnectRequest.new socket.send req.serialize, 0 resp = UdpTrackerConnectResponse.unserialize(readWithTimeout(socket,ReceiveLength,@timeout)) @logger.debug "Connect response: #{resp.inspect}" raise "Invalid connect response: response transaction id is different from the request transaction id" if resp.transactionId != req.transactionId connectionId = resp.connectionId dynamicParams = @dynamicRequestParamsBuilder.call # Send announce request req = UdpTrackerAnnounceRequest.new(connectionId) req.peerId = dynamicParams.peerId req.infoHash = @infoHash req.downloaded = dynamicParams.downloaded req.left = dynamicParams.left req.uploaded = dynamicParams.uploaded req.event = event #req.port = socket.addr[1] req.port = dynamicParams.port socket.send req.serialize, 0 resp = UdpTrackerAnnounceResponse.unserialize(readWithTimeout(socket,ReceiveLength,@timeout)) @logger.debug "Announce response: #{resp.inspect}" peers = [] resp.ips.length.times do |i| ip = resp.ips[i].unpack("CCCC").join('.') port = resp.ports[i].unpack("n").first peers.push TrackerPeer.new ip, port end peers result = TrackerResponse.new(true, nil, peers) result.interval = resp.interval if resp.interval rescue result = TrackerResponse.new(false, $!, []) ensure socket.close if ! socket.closed? end result end
Private Instance Methods
readWithTimeout(socket, length, timeout)
click to toggle source
Throws exception if timeout occurs
# File lib/quartz_torrent/udptrackerdriver.rb, line 82 def readWithTimeout(socket, length, timeout) rc = IO.select([socket], nil, nil, timeout) if ! rc raise "Waiting for response from UDP tracker #{@host}:#{@trackerPort} timed out after #{@timeout} seconds" elsif rc[0].size > 0 socket.recvfrom(length)[0] else raise "Error receiving response from UDP tracker #{@host}:#{@trackerPort}" end end