def got_proxy_unhave(self, permid, selversion, aggregated_string): """ Take the list of pieces the proxy sent and combine it with the numhaves in the piece picker @param permid: The permid of the node sending the message @param selversion: selected Overlay protocol version @param aggregated_string: a bitstring of available pieces built by the proxy based on UNHAVE messages it received """ if DEBUG: print >> sys.stderr, "doe: received a PROXY_UNHAVE message from", show_permid_short( permid) # TODO: make this test using a different approach # if len(aggregated_string) != self.num_pieces: # print >> sys.stderr, "doe: got_proxy_have: invalid payload in received PROXY_HAVE message. self.num_pieces=", self.num_pieces, "len(aggregated_string)=", len(aggregated_string) # Search for the SingleDownload object that has the connection with this peer if DEBUG: debug_found_connection = False for single_dl in self.proxydownloader.downloads: if permid == single_dl.proxy_permid: # If the connection is found, add the piece_list information to the d.have information single_dl.proxy_have = Bitfield( length=self.btdownloader.numpieces, bitstring=aggregated_string) if DEBUG: debug_found_connection = True break if DEBUG: if debug_found_connection: print >> sys.stderr, "doe: got_proxy_unhave: found a data connection for the received PROXY_UNHAVE" else: print >> sys.stderr, "doe: got_proxy_unhave: no data connection for the received PROXY_UNHAVE has been found"
def __init__(self, downloader, connection): self.downloader = downloader self.connection = connection self.choked = True self.interested = False self.active_requests = [] self.measure = Measure(downloader.max_rate_period) self.peermeasure = Measure(downloader.max_rate_period) self.have = Bitfield(downloader.numpieces) self.last = -1000 self.last2 = -1000 self.example_interest = None self.backlog = 2 self.ip = connection.get_ip() self.guard = BadDataGuard(self) # boudewijn: VOD needs a download measurement that is not # averaged over a 'long' period. downloader.max_rate_period is # (by default) 20 seconds because this matches the unchoke # policy. self.short_term_measure = Measure(5) # boudewijn: each download maintains a counter for the number # of high priority piece requests that did not get any # responce within x seconds. self.bad_performance_counter = 0
def live_invalidate_ranges(self, toinvalidateranges, toinvalidateset): """ STBPEED: Faster version of live_invalidate that copies have arrays rather than iterate over them for clearing """ if len(toinvalidateranges) == 1: (s, e) = toinvalidateranges[0] emptyrange = [False for piece in xrange(s, e + 1)] assert len(emptyrange) == e + 1 - s for d in self.downloads: newhave = d.have[0:s] + emptyrange + d.have[e + 1:] #oldhave = d.have d.have = Bitfield(length=len(newhave), fromarray=newhave) #assert oldhave.tostring() == d.have.tostring() """ for piece in toinvalidateset: d.have[piece] = False print >>sys.stderr,"d len",len(d.have) print >>sys.stderr,"new len",len(newhave) for i in xrange(0,len(newhave)): if d.have[i] != newhave[i]: print >>sys.stderr,"newhave diff",i assert False """ else: (s1, e1) = toinvalidateranges[0] (s2, e2) = toinvalidateranges[1] emptyrange1 = [False for piece in xrange(s1, e1 + 1)] emptyrange2 = [False for piece in xrange(s2, e2 + 1)] assert len(emptyrange1) == e1 + 1 - s1 assert len(emptyrange2) == e2 + 1 - s2 for d in self.downloads: newhave = emptyrange1 + d.have[e1 + 1:s2] + emptyrange2 #oldhave = d.have d.have = Bitfield(length=len(newhave), fromarray=newhave) #assert oldhave.tostring() == d.have.tostring() """
def subtest_connect2downloader(self): print >> sys.stderr, "test: verifier: Connecting to seeder to check bitfield" infohash = self.tdef.get_infohash() s = BTConnection('localhost', self.mylistenport, user_infohash=infohash) s.read_handshake_medium_rare() try: s.s.settimeout(10.0) resp = s.recv() self.assert_(len(resp) > 0) print >> sys.stderr, "test: verifier: Got message", getMessageName( resp[0]) self.assert_(resp[0] == EXTEND) resp = s.recv() self.assert_(len(resp) > 0) print >> sys.stderr, "test: verifier: Got 2nd message", getMessageName( resp[0]) self.assert_(resp[0] == BITFIELD) b = Bitfield(self.npieces, resp[1:]) print >> sys.stderr, "test: verifier: Bitfield is", ` b.toboollist( ) ` b2 = Bitfield(self.npieces) b2[0] = True msg = BITFIELD + b2.tostring() s.send(msg) time.sleep(5) except socket.timeout: print >> sys.stderr, "test: verifier: Timeout, peer didn't reply" self.assert_(False) s.close()
def __init__(self, proxydownloader, proxy_permid): self.downloader = proxydownloader self.proxy_permid = proxy_permid self.connection = None self.measure = Measure(self.downloader.max_rate_period) self.active_requests = { } # dictionary with all indexes currently being downloaded. Key: index, value: timestamp (the moment when the piece was requested) self.piece_size = self.downloader.storage._piecelen(0) self.total_len = self.downloader.storage.total_length self.requests = { } # dictionary of lists: requests[index] contains a list of all reserved chunks self.request_size = {} # dictionary of piece sizes self.received_data = {} # a dictionary of piece data self.endflag = False self.error = None self.retry_period = 0 #30 self._retry_period = None self.errorcount = 0 self.active = False self.cancelled = False self.numpieces = self.downloader.numpieces self.proxy_have = Bitfield(self.downloader.numpieces) self.first_piece_request = True # boudewijn: VOD needs a download measurement that is not # averaged over a 'long' period. downloader.max_rate_period is # (by default) 20 seconds because this matches the unchoke # policy. self.short_term_measure = Measure(SHORT_TERM_MEASURE_INTERVAL) # boudewijn: each download maintains a counter for the number # of high priority piece requests that did not get any # responce within x seconds. self.bad_performance_counter = 0 # HTTP Video Support self.request_lock = Lock() self.video_support_policy = False # TODO : get from constructor parameters self.video_support_enabled = False # Don't start immediately with support self.video_support_speed = 0.0 # Start with the faster rescheduling speed self.video_support_slow_start = False # If enabled delay the first request (give chance to peers to give bandwidth) # Arno, 2010-04-07: Wait 1 second before using HTTP seed. TODO good policy # If Video Support policy is not eneabled then use Http seed normaly if not self.video_support_policy: self.resched(1)
def __init__(self, downloader, connection): # 2fastbt_ SingleDownloadHelperInterface.__init__(self) # _2fastbt self.downloader = downloader self.connection = connection self.choked = True self.interested = False self.active_requests = [] self.measure = Measure(downloader.max_rate_period) self.peermeasure = Measure(downloader.max_rate_period) self.have = Bitfield(downloader.numpieces) self.last = -1000 self.last2 = -1000 self.example_interest = None self.backlog = 2 self.ip = connection.get_ip() self.guard = BadDataGuard(self) # 2fastbt_ self.helper = downloader.picker.helper
def got_have_bitfield(self, have): if self.downloader.picker.am_I_complete() and have.complete(): # Arno: If we're both seeds if self.downloader.super_seeding: self.connection.send_bitfield( have.tostring()) # be nice, show you're a seed too self.connection.close() self.downloader.add_disconnected_seed( self.connection.get_readable_id()) return #print >>sys.stderr,"Downloader: got_have_bitfield: VVV#############################################################################################VVVVVVVVVVVVVVVVVVVVVVVVV valid",self.downloader.picker.get_valid_range_iterator(),"len",self.downloader.numpieces #print >>sys.stderr,"Downloader: got_have_bitfield: input",`have.toboollist()` if have.complete(): # Arno: He is seed self.downloader.picker.got_seed() else: # Arno: LIVEWRAP: filter out valid pieces # TODO: may be slow with 32K pieces. validhave = Bitfield(self.downloader.numpieces) for i in self.downloader.picker.get_valid_range_iterator(): if have[i]: validhave[i] = True self.downloader.picker.got_have(i, self.connection) have = validhave # Store filtered bitfield self.have = have #print >>sys.stderr,"Downloader: got_have_bitfield: valid",`have.toboollist()` if self.downloader.endgamemode and not self.downloader.paused: for piece, begin, length in self.downloader.all_requests: if self.have[piece]: self.send_interested() break return self._check_interests()
def aggregate_and_send_haves(self): """ Aggregates the information from the haves bitfields for all the active connections, then calls the proxy class to send the aggregated information as a PROXY_HAVE message """ DEBUG = False if self.proxydownloader: proxyservice_role = self.proxydownloader.dlinstance.get_proxyservice_role( ) if proxyservice_role == PROXYSERVICE_ROLE_PROXY: # The current node is a proxy if DEBUG: print >> sys.stderr, "Downloader: aggregate_and_send_haves" # haves_vector is a matrix, having on each line a Bitfield # len(self.downloads) = the number of connections to swarm peers # +1 = me (the pieces i have locally) haves_vector = [None] * (len(self.downloads) + 1) for i in range(0, len(self.downloads)): haves_vector[i] = self.downloads[i].have haves_vector[len( self.downloads)] = self.storage.get_have_copy() #Calculate the aggregated haves aggregated_haves = Bitfield(self.numpieces) for piece in range(0, self.numpieces): aggregated_value = False # For every column in the haves_vector matrix for d in range(0, len(self.downloads) + 1): # For every active connection aggregated_value = aggregated_value or haves_vector[d][ piece] # Logical OR operation aggregated_haves[piece] = aggregated_value if DEBUG: print >> sys.stderr, "Downloader: aggregate_and_send_haves" #, len(self.downloads), aggregated_haves.toboollist() self.proxydownloader.proxy.send_proxy_have(aggregated_haves)
def setUpPostSession(self): """ override TestAsServer """ TestAsServer.setUpPostSession(self) # Let Tribler start downloading an non-functioning torrent, so # we can talk to a normal download engine. self.tdef = TorrentDef() self.sourcefn = os.path.join(os.getcwd(), "API", "file2.wmv") self.tdef.add_content(self.sourcefn) self.tdef.set_create_merkle_torrent(True) self.tdef.set_tracker("http://127.0.0.1:12/announce") self.tdef.finalize() self.torrentfn = os.path.join(self.session.get_state_dir(), "gen.torrent") self.tdef.save(self.torrentfn) dscfg = self.setUpDownloadConfig() self.session.start_download(self.tdef, dscfg) self.infohash = self.tdef.get_infohash() self.mylistenport = 4810 self.numpieces = (self.tdef.get_length() + self.tdef.get_piece_length() - 1) / self.tdef.get_piece_length() b = Bitfield(self.numpieces) for i in range(self.numpieces): b[i] = True self.assert_(b.complete()) self.seederbitfieldstr = b.tostring() #piece_hashes = ['\x01\x02\x03\x04\x05\x06\x07\x08\x07\x06\x05\x04\x03\x02\x01\x00\x01\x02\x03\x04' ] * npieces # Construct Merkle tree tdef2 = TorrentDef() tdef2.add_content(self.sourcefn) tdef2.set_create_merkle_torrent(False) tdef2.set_tracker("http://127.0.0.1:12/announce") tdef2.set_piece_length(self.tdef.get_piece_length()) tdef2.finalize() metainfo = tdef2.get_metainfo() piecesstr = metainfo['info']['pieces'] print >> sys.stderr, "test: pieces has len", len(piecesstr) piece_hashes = [] for i in range(0, len(piecesstr), 20): hash = piecesstr[i:i + 20] print >> sys.stderr, "test: piece", i / 20, "hash", ` hash ` piece_hashes.append(hash) print >> sys.stderr, "test: Putting", len( piece_hashes), "into MerkleTree, size", self.tdef.get_piece_length( ), tdef2.get_piece_length() self.tree = MerkleTree(self.tdef.get_piece_length(), self.tdef.get_length(), None, piece_hashes) f = open(self.sourcefn, "rb") piece1 = f.read(2**18) piece2 = f.read(2**18) print >> sys.stderr, "read piece1", len(piece1) print >> sys.stderr, "read piece2", len(piece2) f.close() hash1 = sha(piece1).digest() hash2 = sha(piece2).digest() print >> sys.stderr, "hash piece1", ` hash1 ` print >> sys.stderr, "hash piece2", ` hash2 ` f2 = open("piece1.bin", "wb") f2.write(piece2) f2.close()
def _test_proxy(self, genresdict): """ Send messages to the helper instance and test it. Testing ASK_FOR_HELP, STOP_HELPING, REQUEST_PIECES, CANCEL_PIECE and METADATA """ # 1. Establish overlay connection to Tribler ol_connection = OLConnection(self.my_keypair, 'localhost', self.hisport, mylistenport=self.mylistenport2) # 2. Send the ASK_FOR_HELP message (generate_data, sent_good_values) = genresdict[ASK_FOR_HELP] msg = generate_data() ol_connection.send(msg) if sent_good_values: # Read the helper's response resp = ol_connection.recv() # Check the helper's response # 3. At this point, the helper does not have the .torrent file, so it requests it with a METADATA message self.assert_(resp[0] == GET_METADATA) self.check_get_metadata(resp[1:]) print >> sys.stderr, "test: Got GET_METADATA for torrent, good" else: # Read the helper's response resp = ol_connection.recv() # Check the helper's response self.assert_(len(resp) == 0) ol_connection.close() return # 4. Send METADATA (generate_data, sent_good_values) = genresdict[METADATA] msg = generate_data() ol_connection.send(msg) if sent_good_values: # 5. At this point the helper is confirming his availability to help # Read the helper's response resp = ol_connection.recv() # Check the helper's response self.assert_(resp[0] == JOIN_HELPERS) self.check_ask_for_help(resp) print >> sys.stderr, "test: Got JOIN_HELPERS for torrent, good" # 6. At this point, the helper will contact the tracker and then wait for REQUEST_PIECES messages # So we send a request pieces message (generate_data, sent_good_values) = genresdict[REQUEST_PIECES] msg = generate_data() ol_connection.send(msg) # At this point the helper will contact the seeders in the swarm to download the requested piece # There is only one seeder in the swarm, the coordinator's twin # 8. Our tracker says there is another peer (also us) on port 4810 # Now accept a connection on that port and pretend we're a seeder self.myss.settimeout(10.0) conn, addr = self.myss.accept() options = '\x00\x00\x00\x00\x00\x00\x00\x00' s2 = BTConnection('', 0, conn, user_option_pattern=options, user_infohash=self.infohash, myid=self.myid) s2.read_handshake_medium_rare() # Send a bitfield message to the helper (pretending we are a regular seeder) b = Bitfield(self.numpieces) for i in range(self.numpieces): b[i] = True self.assert_(b.complete()) msg = BITFIELD + b.tostring() s2.send(msg) msg = UNCHOKE s2.send(msg) print >> sys.stderr, "test: Got BT connection to us, as fake seeder, good" else: resp = ol_connection.recv() self.assert_(len(resp) == 0) ol_connection.close() return # 7. Accept the data connection the helper wants to establish with us, the coordinator. # The helper will send via this connection the pieces we request it to download. self.myss2.settimeout(10.0) conn, addr = self.myss2.accept() s3 = BTConnection('', 0, conn, user_infohash=self.infohash, myid=self.myid2) s3.read_handshake_medium_rare() msg = UNCHOKE s3.send(msg) print >> sys.stderr, "test: Got data connection to us, as coordinator, good" # 9. At this point the helper should sent a PROXY_HAVE message on the overlay connection # resp = ol_connection.recv() # self.assert_(resp[0] == PROXY_HAVE) # print >>sys.stderr,"test: Got PROXY)HAVE, good" # 10. Await REQUEST on fake seeder try: while True: s2.s.settimeout(10.0) resp = s2.recv() self.assert_(len(resp) > 0) print "test: Fake seeder got message", getMessageName(resp[0]) if resp[0] == REQUEST: self.check_request(resp[1:]) print >> sys.stderr, "test: Fake seeder got REQUEST for reserved piece, good" break except socket.timeout: print >> sys.stderr, "test: Timeout, bad, fake seeder didn't reply with message" self.assert_(False) # 11. Sent the helper a STOP_HELPING message (generate_data, sent_good_values) = genresdict[STOP_HELPING] msg = generate_data() ol_connection.send(msg) # The other side should close the connection, whether the msg was good or bad resp = ol_connection.recv() self.assert_(len(resp) == 0) ol_connection.close()
def got_message(self, connection, message): # connection: Encrypter.Connection; c: Connecter.Connection c = self.connections[connection] t = message[0] # EXTEND handshake will be sent just after BT handshake, # before BITFIELD even st = time.time() if DEBUG_NORMAL_MSGS: print >> sys.stderr, "connecter: Got", getMessageName( t), connection.get_ip() if t == EXTEND: self.got_extend_message(connection, c, message, self.ut_pex_enabled) return if t == BITFIELD and c.got_anything: if DEBUG: print >> sys.stderr, "Close on BITFIELD" connection.close() return c.got_anything = True if (t in [CHOKE, UNCHOKE, INTERESTED, NOT_INTERESTED] and len(message) != 1): if DEBUG: print >> sys.stderr, "Close on bad (UN)CHOKE/(NOT_)INTERESTED", t connection.close() return if t == CHOKE: if DEBUG_NORMAL_MSGS: print >> sys.stderr, "connecter: Got CHOKE from", connection.get_ip( ) c.download.got_choke() elif t == UNCHOKE: if DEBUG_NORMAL_MSGS: print >> sys.stderr, "connecter: Got UNCHOKE from", connection.get_ip( ) c.download.got_unchoke() elif t == INTERESTED: if DEBUG_NORMAL_MSGS: print >> sys.stderr, "connecter: Got INTERESTED from", connection.get_ip( ) if c.upload is not None: c.upload.got_interested() elif t == NOT_INTERESTED: c.upload.got_not_interested() elif t == HAVE: if len(message) != 5: if DEBUG: print >> sys.stderr, "Close on bad HAVE: msg len" connection.close() return i = toint(message[1:]) if i >= self.numpieces: if DEBUG: print >> sys.stderr, "Close on bad HAVE: index out of range" connection.close() return if DEBUG_NORMAL_MSGS: print >> sys.stderr, "connecter: Got HAVE(", i, ") from", connection.get_ip( ) c.download.got_have(i) elif t == BITFIELD: if DEBUG_NORMAL_MSGS: print >> sys.stderr, "connecter: Got BITFIELD from", connection.get_ip( ) try: b = Bitfield(self.numpieces, message[1:]) except ValueError: if DEBUG: print >> sys.stderr, "Close on bad BITFIELD" connection.close() return if c.download is not None: c.download.got_have_bitfield(b) elif t == REQUEST: #print >>sys.stderr, "MOJO message: PoPOPOPO...Poker Face" #print >>sys.stderr,"connecter: Got REQUEST(",toint(message[1:5]),") from",connection.get_ip() if len(message) != 13: if DEBUG: print >> sys.stderr, "Close on bad REQUEST: msg len" connection.close() return i = toint(message[1:5]) if i >= self.numpieces: if DEBUG: print >> sys.stderr, "Close on bad REQUEST: index out of range" connection.close() return if DEBUG_NORMAL_MSGS: print >> sys.stderr, "connecter: Got REQUEST(", i, ") from", connection.get_ip( ) c.got_request(i, toint(message[5:9]), toint(message[9:])) elif t == CANCEL: if len(message) != 13: if DEBUG: print >> sys.stderr, "Close on bad CANCEL: msg len" connection.close() return i = toint(message[1:5]) if i >= self.numpieces: if DEBUG: print >> sys.stderr, "Close on bad CANCEL: index out of range" connection.close() return c.upload.got_cancel(i, toint(message[5:9]), toint(message[9:])) elif t == PIECE: x.update("RCVCOUNT", float(x.data["RCVCOUNT"][0]) + 1) if len(message) <= 9: if DEBUG: print >> sys.stderr, "Close on bad PIECE: msg len" connection.close() return i = toint(message[1:5]) if i >= self.numpieces: if DEBUG: print >> sys.stderr, "Close on bad PIECE: msg len" connection.close() return if DEBUG_NORMAL_MSGS: print >> sys.stderr, "connecter: Got PIECE(", i, ") from", connection.get_ip( ) try: if c.download.got_piece(i, toint(message[5:9]), [], message[9:]): self.got_piece(i) except Exception, e: if DEBUG: print >> sys.stderr, "Close on bad PIECE: exception", str( e) traceback.print_exc() connection.close() return
def _test_2fast(self, genresdict): """ test ASK_FOR_HELP, METADATA, PIECES_RESERVED and STOP_DOWNLOAD_HELP sequence """ # 1. Establish overlay connection to Tribler s = OLConnection(self.my_keypair, 'localhost', self.hisport, mylistenport=self.mylistenport2) (func, good) = genresdict[ASK_FOR_HELP] msg = func() s.send(msg) if good: resp = s.recv() self.assert_(resp[0] == GET_METADATA) self.check_get_metadata(resp[1:]) print >> sys.stderr, "test: Got GET_METADATA for torrent, good" else: resp = s.recv() self.assert_(len(resp) == 0) s.close() return (func, good) = genresdict[METADATA] msg = func() s.send(msg) if good: # 2. Accept the data connection Tribler wants to establish with us, the coordinator self.myss2.settimeout(10.0) conn, addr = self.myss2.accept() s3 = BTConnection('', 0, conn, user_infohash=self.infohash, myid=self.myid2) s3.read_handshake_medium_rare() msg = UNCHOKE s3.send(msg) print >> sys.stderr, "test: Got data connection to us, as coordinator, good" else: resp = s.recv() self.assert_(len(resp) == 0) s.close() return # 3. Our tracker says there is another peer (also us) on port 4810 # Now accept a connection on that port and pretend we're a seeder self.myss.settimeout(10.0) conn, addr = self.myss.accept() options = '\x00\x00\x00\x00\x00\x00\x00\x00' s2 = BTConnection('', 0, conn, user_option_pattern=options, user_infohash=self.infohash, myid=self.myid) s2.read_handshake_medium_rare() numpieces = 10 # must correspond to the torrent in test/extend_hs_dir b = Bitfield(numpieces) for i in range(numpieces): b[i] = True self.assert_(b.complete()) msg = BITFIELD + b.tostring() s2.send(msg) msg = UNCHOKE s2.send(msg) print >> sys.stderr, "test: Got BT connection to us, as fake seeder, good" # 4. Await a RESERVE_PIECES message on the overlay connection resp = s.recv() self.assert_(resp[0] == RESERVE_PIECES) pieces = self.check_reserve_pieces(resp[1:]) print >> sys.stderr, "test: Got RESERVE_PIECES, good" (func, good) = genresdict[PIECES_RESERVED] # 5. Reply with PIECES_RESERVED msg = func(pieces) s.send(msg) if good: # 6. Await REQUEST on fake seeder try: while True: s2.s.settimeout(10.0) resp = s2.recv() self.assert_(len(resp) > 0) print "test: Fake seeder got message", getMessageName( resp[0]) if resp[0] == REQUEST: self.check_request(resp[1:], pieces) print >> sys.stderr, "test: Fake seeder got REQUEST for reserved piece, good" break except socket.timeout: print >> sys.stderr, "test: Timeout, bad, fake seeder didn't reply with message" self.assert_(False) else: resp = s.recv() self.assert_(len(resp) == 0) s.close() return (func, good) = genresdict[STOP_DOWNLOAD_HELP] # 5. Reply with STOP_DOWNLOAD_HELP msg = func() s.send(msg) # the other side should close the connection, whether the msg was good or bad resp = s.recv() self.assert_(len(resp) == 0) s.close()
def _test_2fast(self, genresdict): """ test ASK_FOR_HELP, METADATA, PIECES_RESERVED and STOP_DOWNLOAD_HELP sequence """ # 1. Establish overlay connection to Tribler ol_connection = OLConnection(self.my_keypair, 'localhost', self.hisport, mylistenport=self.mylistenport2) # Send ASK_FOR_HELP (generate_data, sent_good_values) = genresdict[ASK_FOR_HELP] msg = generate_data() ol_connection.send(msg) if sent_good_values: resp = ol_connection.recv() self.assert_(resp[0] == GET_METADATA) self.check_get_metadata(resp[1:]) print >> sys.stderr, "test: Got GET_METADATA for torrent, sent_good_values" else: resp = ol_connection.recv() self.assert_(len(resp) == 0) ol_connection.close() return # Send METADATA (generate_data, sent_good_values) = genresdict[METADATA] msg = generate_data() ol_connection.send(msg) if sent_good_values: # 2. Accept the data connection Tribler wants to establish with us, the coordinator self.myss2.settimeout(10.0) conn, addr = self.myss2.accept() #(self,hostname,port,opensock=None,user_option_pattern=None,user_infohash=None,myid=None,mylistenport=None,myoversion=None): bt_connection_2 = BTConnection('', 0, conn, user_infohash=self.infohash, myid=self.myid2) bt_connection_2.read_handshake_medium_rare() msg = UNCHOKE bt_connection_2.send(msg) print >> sys.stderr, "test: Got data connection to us, as coordinator, sent_good_values" else: resp = ol_connection.recv() self.assert_(len(resp) == 0) ol_connection.close() return # 3. Our tracker says there is another peer (also us) on port 4810 # Now accept a connection on that port and pretend we're a seeder self.myss.settimeout(10.0) conn, addr = self.myss.accept() options = '\x00\x00\x00\x00\x00\x00\x00\x00' bt_connection = BTConnection('', 0, conn, user_option_pattern=options, user_infohash=self.infohash, myid=self.myid) bt_connection.read_handshake_medium_rare() # Get the number of pieces from the .torrent file torrentfile_content = open(self.torrentfile, "rb") metadata_dict = bdecode(torrentfile_content.read()) torrentfile_content.close() if "length" in metadata_dict["info"]: length = metadata_dict["info"]["length"] else: length = 0 for file in metadata_dict["info"]["files"]: length += file["length"] numpieces = length / metadata_dict["info"]["piece length"] bitf = Bitfield(numpieces) for i in range(numpieces): bitf[i] = True self.assert_(bitf.complete()) msg = BITFIELD + bitf.tostring() bt_connection.send(msg) msg = UNCHOKE bt_connection.send(msg) print >> sys.stderr, "test: Got BT connection to us, as fake seeder, sent_good_values" # 4. Await a RESERVE_PIECES message on the overlay connection resp = ol_connection.recv() self.assert_(resp[0] == RESERVE_PIECES) pieces = self.check_reserve_pieces(resp[1:]) print >> sys.stderr, "test: Got RESERVE_PIECES, sent_good_values" # 5. Reply with PIECES_RESERVED (generate_data, sent_good_values) = genresdict[PIECES_RESERVED] msg = generate_data(pieces) ol_connection.send(msg) if sent_good_values: # 6. Await REQUEST on fake seeder while True: resp = bt_connection.recv() self.assert_(len(resp) > 0) print "test: Fake seeder got message", getMessageName(resp[0]) if resp[0] == REQUEST: self.check_request(resp[1:], pieces) print >> sys.stderr, "test: Fake seeder got REQUEST for reserved piece, sent_good_values" break else: resp = ol_connection.recv() self.assert_(len(resp) == 0) ol_connection.close() return # 7. Reply with STOP_DOWNLOAD_HELP (generate_data, sent_good_values) = genresdict[STOP_DOWNLOAD_HELP] msg = generate_data() ol_connection.send(msg) # the other side should close the connection, whether the msg was sent_good_values or bad resp = ol_connection.recv() self.assert_(len(resp) == 0) ol_connection.close()
def got_have_bitfield(self, have): if self.downloader.picker.am_I_complete() and have.complete(): # Arno: If we're both seeds if self.downloader.super_seeding: self.connection.send_bitfield( have.tostring()) # be nice, show you're a seed too # Niels: We're both seeds, but try to get some additional peers from this seed self.connection.try_send_pex() def auto_close(): self.connection.close() self.downloader.add_disconnected_seed( self.connection.get_readable_id()) self.downloader.scheduler(auto_close, REPEX_LISTEN_TIME) return if DEBUGBF: st = time.time() if have.complete(): # Arno: He is seed self.downloader.picker.got_seed() else: # Arno: pass on HAVE knowledge to PiecePicker and if LIVEWRAP: # filter out valid pieces # STBSPEED: if we haven't hooked in yet, don't iterate over whole range # just over the active ranges in the received Bitfield activerangeiterators = [] if self.downloader.picker.videostatus and self.downloader.picker.videostatus.live_streaming and self.downloader.picker.videostatus.get_live_startpos( ) is None: # Not hooked in activeranges = have.get_active_ranges() if len(activeranges) == 0: # Bug, fallback to whole range activerangeiterators = [ self.downloader.picker.get_valid_range_iterator() ] else: # Create iterators for the active ranges for (s, e) in activeranges: activerangeiterators.append(xrange(s, e + 1)) else: # Hooked in, use own valid range as active range # Arno, 2010-04-20: Not correct for VOD with seeking, then we # should store the HAVE info for things before playback too. activerangeiterators = [ self.downloader.picker.get_valid_range_iterator() ] if DEBUGBF: print >> sys.stderr, "Downloader: got_have_field: live: Filtering bitfield", activerangeiterators if not self.downloader.picker.videostatus or self.downloader.picker.videostatus.live_streaming: if DEBUGBF: print >> sys.stderr, "Downloader: got_have_field: live or normal filter" # Transfer HAVE knowledge to PiecePicker and filter pieces if live validhave = Bitfield(self.downloader.numpieces) for iterator in activerangeiterators: for i in iterator: if have[i]: validhave[i] = True self.downloader.picker.got_have(i, self.connection) else: # VOD if DEBUGBF: print >> sys.stderr, "Downloader: got_have_field: VOD filter" validhave = Bitfield(self.downloader.numpieces) (first, last) = self.downloader.picker.videostatus.download_range() for i in xrange(first, last): if have[i]: validhave[i] = True self.downloader.picker.got_have(i, self.connection) # ProxyService_ # # Aggregate the haves bitfields and send them to the doe nodes # ARNOPS: Shouldn't this be done after have = validhave? self.downloader.aggregate_and_send_haves() # # _ProxyService """ # SANITY CHECK checkhave = Bitfield(self.downloader.numpieces) for i in self.downloader.picker.get_valid_range_iterator(): if have[i]: checkhave[i] = True assert validhave.tostring() == checkhave.tostring() """ # Store filtered bitfield instead of received one have = validhave if DEBUGBF: et = time.time() diff = et - st print >> sys.stderr, "Download: got_have_field: took", diff self.have = have #print >>sys.stderr,"Downloader: got_have_bitfield: valid",`have.toboollist()` if self.downloader.endgamemode and not self.downloader.paused: for piece, begin, length in self.downloader.all_requests: if self.have[piece]: self.send_interested() break return self._check_interests()