--- BitTorrent/Rerequester.py 29 Sep 2004 22:18:49 -0000 1.1.1.7.2.2 +++ BitTorrent/Rerequester.py 3 Nov 2004 14:02:48 -0000 1.1.1.7.2.5 @@ -10,33 +10,56 @@ from random import randrange from binascii import b2a_hex +reuse_ports=True +if reuse_ports : + import random + puerto_a_reutilizar=random.randint(16384,32768) + class Rerequester: def __init__(self, url, interval, sched, howmany, minpeers, connect, externalsched, amount_left, up, down, port, ip, myid, infohash, timeout, errorfunc, maxpeers, doneflag, upratefunc, downratefunc, ever_got_incoming,announce_list=None): - self.url = ('%s?info_hash=%s&peer_id=%s&port=%s&key=%s' % - (url, quote(infohash), quote(myid), str(port), - b2a_hex(''.join([chr(randrange(256)) for i in xrange(4)])))) - if ip != '': - self.url += '&ip=' + quote(ip) - - if announce_list : - if url not in announce_list : - announce_list.append(url) - self.announce_list=[] # Mutable - for i in announce_list : - url= ('%s?info_hash=%s&peer_id=%s&port=%s&key=%s' % - (i, quote(infohash), quote(myid), str(port), - b2a_hex(''.join([chr(randrange(256)) for i in xrange(4)])))) - if ip != '' : - url += '&ip=' + quote(ip) - self.announce_list.append(url) + + if not announce_list : + announce_list=[[url]] + + class _announce_list(object) : + def __init__(self,announce_list) : import random random.seed() - random.shuffle(self.announce_list) - else : - self.announce_list=None + self.last_hit=None + self._announce_list=[] # Mutable + self._announce_list_index={} # Mutable + for n,l in enumerate(announce_list) : + for i in l : + url= ('%s?info_hash=%s&peer_id=%s&port=%s&key=%s' % + (i, quote(infohash), quote(myid), str(port), + b2a_hex(''.join([chr(randrange(256)) for i in xrange(4)])))) + if ip != '' : + url += '&ip=' + quote(ip) + + v=[n,0,url] # MUTABLE + self._announce_list_index[url]=v + self._announce_list.append(v) + def get_list(self) : + import random + import copy + a=copy.copy(self._announce_list) # Shallow Copy + for i in a : + i[1]=random.random() + v=self._announce_list_index.get(self.last_hit) + self.last_hit=None + if v : + v[1]=0 + a.sort() + return [i[2] for i in a] + + def hit(self,url) : + self.last_hit=url + + + self.announce_list=_announce_list(announce_list) self.interval = interval self.last = None @@ -75,8 +98,8 @@ def announce(self, event = None): self.last_time = time() - s = ('%s&uploaded=%s&downloaded=%s&left=%s' % - (self.url, str(self.up()), str(self.down()), + s = ('&uploaded=%s&downloaded=%s&left=%s' % + (str(self.up()), str(self.down()), str(self.amount_left()))) if self.last is not None: s += '&last=' + quote(str(self.last)) @@ -88,40 +111,78 @@ s += '&compact=1' if event != None: s += '&event=' + ['started', 'completed', 'stopped'][event] - set = SetOnce().set - def checkfail(self = self, set = set): - if set(): - if self.last_failed and self.upratefunc() < 100 and self.downratefunc() < 100: - self.errorfunc('Problem connecting to tracker - timeout exceeded') - self.last_failed = True - if self.announce_list : - self.url=self.announce_list.pop(0) - self.announce_list.append(self.url) - - self.sched(checkfail, self.timeout) - Thread(target = self.rerequest, args = [s, set]).start() - def rerequest(self, url, set): - try: - h = urlopen(url) + Thread(target = self.rerequest, args = [s]).start() + + def rerequest(self, url): + import httplib + import urllib2 + import socket + + class http_handler_timeout1(httplib.HTTPConnection) : + # Copia casi literal de la rutina original, an~adiendo "timeout" + def connect(self,timeout=self.timeout): + """Connect to the host and port specified in __init__.""" + msg = "getaddrinfo returns an empty list" + for res in socket.getaddrinfo(self.host, self.port, 0, + socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + try: + self.sock = socket.socket(af, socktype, proto) + self.sock.settimeout(timeout) # LA NOVEDAD + + if reuse_ports : + for i in xrange(puerto_a_reutilizar,puerto_a_reutilizar+1000) : + try : + self.sock.bind(("",i)) + except : + import time + import random + time.sleep(random.random()) + else : + break + + if self.debuglevel > 0: + print "connect: (%s, %s)" % (self.host, self.port) + self.sock.connect(sa) + except socket.error, msg: + if self.debuglevel > 0: + print 'connect fail:', (self.host, self.port) + if self.sock: + self.sock.close() + self.sock = None + continue + break + if not self.sock: + raise socket.error, msg + + class http_handler_timeout2(httplib.HTTP) : + _connection_class=http_handler_timeout1 + + class http_handler_timeout3(urllib2.HTTPHandler) : + def http_open(self, req): + return self.do_open(http_handler_timeout2, req) + + http_handler_timeout=urllib2.build_opener(http_handler_timeout3) + + for url2 in self.announce_list.get_list() : + try : + h = http_handler_timeout.open(url2+url) r = h.read() h.close() - if set(): - def add(self = self, r = r): - self.last_failed = False - self.postrequest(r) - self.externalsched(add, 0) - except (IOError, error), e: - if set(): - def fail(self = self, r = 'Problem connecting to tracker - ' + str(e)): - if self.last_failed: - self.errorfunc(r) - self.last_failed = True - if self.announce_list : - self.url=self.announce_list.pop(0) - self.announce_list.append(self.url) + def add(self = self, r = r): + self.last_failed = False + self.postrequest(r) + self.externalsched(add, 0) + self.announce_list.hit(url2) + return + except (IOError, error), e: + def fail(self = self, r = 'Problem connecting to tracker - ' + str(e)): + if self.last_failed: + self.errorfunc(r) + self.last_failed = True - self.externalsched(fail, 0) + self.externalsched(fail, 0) def postrequest(self, data): try: @@ -160,17 +221,3 @@ if data != '': self.errorfunc('bad data from tracker - ' + str(e)) -class SetOnce: - def __init__(self): - self.lock = Lock() - self.first = True - - def set(self): - try: - self.lock.acquire() - r = self.first - self.first = False - return r - finally: - self.lock.release() - --- BitTorrent/download.py 29 Sep 2004 21:54:19 -0000 1.1.1.13.2.2 +++ BitTorrent/download.py 13 Oct 2004 19:48:08 -0000 1.1.1.13.2.3 @@ -272,17 +272,6 @@ config['keepalive_interval'], infohash, config['max_initiate']) announce_list=response.get('announce-list') - def plano(a) : - import types - r=[] - for i in a : - if type(i) in types.StringTypes : - r.append(i) - else : - r.extend(plano(i)) - return r - if announce_list : - announce_list=plano(announce_list) rerequest = Rerequester(response['announce'], config['rerequest_interval'], rawserver.add_task, connecter.how_many_connections,