def __init__(self, downloader, connection): self.downloader = downloader self.connection = connection self.choked = True self.interested = False self.active_requests = [] self.measure = Measure(downloader.config['max_rate_period']) self.peermeasure = Measure(max(downloader.storage.piece_size / 10000, 20)) self.have = Bitfield(downloader.numpieces) self.last = 0 self.example_interest = None self.backlog = 2 self.guard = BadDataGuard(self)
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.backlog = 8 self.ip = connection.get_ip() self.guard = BadDataGuard(self)
def got_message(self, protocol, message): c = self.connections[protocol] t = message[0] log_msg('%s message received %s' % (c.ccount, ord(t)), 4, "btprotocol") if t == BITFIELD and c.got_anything: log_msg('%s misplaced bitfield' % (c.ccount), 0, "btprotocol") protocol.close() return c.got_anything = True if (t in [CHOKE, UNCHOKE, INTERESTED, NOT_INTERESTED] and len(message) != 1): log_msg('%s bad message length' % (c.ccount), 0, "btprotocol") protocol.close() return if t == CHOKE: c.download.got_choke() elif t == UNCHOKE: c.download.got_unchoke() elif t == INTERESTED: if not c.download.have.complete(): c.upload.got_interested() elif t == NOT_INTERESTED: c.upload.got_not_interested() elif t == HAVE: if len(message) != 5: log_msg('%s bad message length (HAVE)' % (c.ccount), 0, "btprotocol") protocol.close() return i = toint(message[1:]) if i >= self.numpieces: log_msg('%s bad piece number (HAVE)' % (c.ccount), 0, "btprotocol") protocol.close() return if c.download.got_have(i): c.upload.got_not_interested() elif t == BITFIELD: try: b = Bitfield(self.numpieces, message[1:]) except ValueError: log_msg('%s bad bitfield' % (c.ccount), 0, "btprotocol") protocol.close() return if c.download.got_have_bitfield(b): c.upload.got_not_interested() elif t == REQUEST: if len(message) != 13: log_msg('%s bad message length (REQUEST)' % (c.ccount), 0, "btprotocol") protocol.close() return i = toint(message[1:5]) if i >= self.numpieces: log_msg('%s bad piece number (REQUEST)' % (c.ccount), 0, "btprotocol") protocol.close() return c.got_request(i, toint(message[5:9]), toint(message[9:])) elif t == CANCEL: if len(message) != 13: log_msg('%s bad message length (CANCEL)' % (c.ccount), 0, "btprotocol") protocol.close() return i = toint(message[1:5]) if i >= self.numpieces: log_msg('%s bad piece number (CANCEL)' % (c.ccount), 0, "btprotocol") protocol.close() return c.upload.got_cancel(i, toint(message[5:9]), toint(message[9:])) elif t == PIECE: if len(message) <= 9: log_msg('%s bad message length (PIECE)' % (c.ccount), 0, "btprotocol") protocol.close() return i = toint(message[1:5]) if i >= self.numpieces: log_msg('%s bad piece number (PIECE)' % (c.ccount), 0, "btprotocol") protocol.close() return if c.download.got_piece(i, toint(message[5:9]), message[9:]): c.lastActive = time.time() self.got_piece(i) else: protocol.close()
def __init__(self, storage, config, hashes, piece_size, finished, statusfunc, flag, data_flunked, infohash, errorfunc, resumefile): self.numpieces = len(hashes) self.storage = storage self.config = config check_hashes = config['check_hashes'] self.hashes = hashes self.piece_size = piece_size self.data_flunked = data_flunked self.errorfunc = errorfunc self.total_length = storage.get_total_length() self.amount_left = self.total_length self.partial_mark = "BitTorrent - this part has not been "+\ "downloaded yet."+infohash+\ tobinary(config['download_slice_size']) if self.total_length <= piece_size * (self.numpieces - 1): raise BTFailure, _("bad data in responsefile - total too small") if self.total_length > piece_size * self.numpieces: raise BTFailure, _("bad data in responsefile - total too big") self.finished = finished self.numactive = array('H', [0] * self.numpieces) self.inactive_requests = [1] * self.numpieces self.amount_inactive = self.total_length self.endgame = False self.have = Bitfield(self.numpieces) self.waschecked = Bitfield(self.numpieces) if self.numpieces < 32768: typecode = 'h' else: typecode = 'l' self.places = array(typecode, [NO_PLACE] * self.numpieces) if not check_hashes: self.rplaces = array(typecode, range(self.numpieces)) fastresume = True else: self.rplaces = self._load_fastresume(resumefile, typecode) if self.rplaces is not None: fastresume = True else: self.rplaces = array(typecode, [UNALLOCATED] * self.numpieces) fastresume = False self.holepos = 0 self.stat_numfound = 0 self.stat_numflunked = 0 self.stat_numdownloaded = 0 self.stat_active = {} self.stat_new = {} self.stat_dirty = {} self.download_history = {} self.failed_pieces = {} if self.numpieces == 0: return targets = {} total = 0 if not fastresume: for i in xrange(self.numpieces): if self._waspre(i): self.rplaces[i] = ALLOCATED total += 1 else: targets[hashes[i]] = i if total and check_hashes: statusfunc(_("checking existing file"), 0) def markgot(piece, pos): if self.have[piece]: if piece != pos: return self.rplaces[self.places[pos]] = ALLOCATED self.places[pos] = self.rplaces[pos] = pos return self.places[piece] = pos self.rplaces[pos] = piece self.have[piece] = True self.amount_left -= self._piecelen(piece) self.amount_inactive -= self._piecelen(piece) self.inactive_requests[piece] = None if not fastresume: self.waschecked[piece] = True self.stat_numfound += 1 lastlen = self._piecelen(self.numpieces - 1) partials = {} for i in xrange(self.numpieces): if not self._waspre(i): if self.rplaces[i] != UNALLOCATED: raise BTFailure(_("--check_hashes 0 or fastresume info " "doesn't match file state (missing data)")) continue elif fastresume: t = self.rplaces[i] if t >= 0: markgot(t, i) continue if t == UNALLOCATED: raise BTFailure(_("Bad fastresume info (files contain more " "data)")) if t == ALLOCATED: continue if t!= FASTRESUME_PARTIAL: raise BTFailure(_("Bad fastresume info (illegal value)")) data = self.storage.read(self.piece_size * i, self._piecelen(i)) self._check_partial(i, partials, data) self.rplaces[i] = ALLOCATED else: data = self.storage.read(piece_size * i, self._piecelen(i)) sh = sha(buffer(data, 0, lastlen)) sp = sh.digest() sh.update(buffer(data, lastlen)) s = sh.digest() if s == hashes[i]: markgot(i, i) elif s in targets and self._piecelen(i) == self._piecelen(targets[s]): markgot(targets[s], i) elif not self.have[self.numpieces - 1] and sp == hashes[-1] and (i == self.numpieces - 1 or not self._waspre(self.numpieces - 1)): markgot(self.numpieces - 1, i) else: self._check_partial(i, partials, data) statusfunc(fractionDone = 1 - self.amount_left / self.total_length) if flag.isSet(): return self.amount_left_with_partials = self.amount_left for piece in partials: if self.places[piece] < 0: pos = partials[piece][0] self.places[piece] = pos self.rplaces[pos] = piece self._make_partial(piece, partials[piece][1]) for i in xrange(self.numpieces): if self.rplaces[i] != UNALLOCATED: self.storage.allocated(piece_size * i, self._piecelen(i)) if self.have[i]: self.storage.downloaded(piece_size * i, self._piecelen(i))
def _got_message(self, message): t = message[0] if t == BITFIELD and self.got_anything: self.close() return self.got_anything = True if (t in [CHOKE, UNCHOKE, INTERESTED, NOT_INTERESTED] and len(message) != 1): self.close() return if t == CHOKE: self.download.got_choke() elif t == UNCHOKE: self.download.got_unchoke() elif t == INTERESTED: self.upload.got_interested() elif t == NOT_INTERESTED: self.upload.got_not_interested() elif t == HAVE: if len(message) != 5: self.close() return i = unpack("!xi", message)[0] if i >= self.encoder.numpieces: self.close() return self.download.got_have(i) elif t == BITFIELD: try: b = Bitfield(self.encoder.numpieces, message[1:]) except ValueError: self.close() return self.download.got_have_bitfield(b) elif t == REQUEST: if len(message) != 13: self.close() return i, a, b = unpack("!xiii", message) if i >= self.encoder.numpieces: self.close() return self.upload.got_request(i, a, b) elif t == CANCEL: if len(message) != 13: self.close() return i, a, b = unpack("!xiii", message) if i >= self.encoder.numpieces: self.close() return self.upload.got_cancel(i, a, b) elif t == PIECE: if len(message) <= 9: self.close() return n = len(message) - 9 i, a, b = unpack("!xii%ss" % n, message) if i >= self.encoder.numpieces: self.close() return if self.download.got_piece(i, a, b): for co in self.encoder.complete_connections: co.send_have(i) elif t == PORT: if len(message) != 3: self.close() return self.dht_port = unpack('!H', message[1:3])[0] self.encoder.got_port(self) else: self.close()
def _got_message(self, message): t = message[0] if t == BITFIELD and self.got_anything: self.close() return self.got_anything = True if (t in [CHOKE, UNCHOKE, INTERESTED, NOT_INTERESTED] and len(message) != 1): self.close() return if t == CHOKE: self.download.got_choke() elif t == UNCHOKE: self.download.got_unchoke() elif t == INTERESTED: self.upload.got_interested() elif t == NOT_INTERESTED: self.upload.got_not_interested() elif t == HAVE: if len(message) != 5: self.close() return i = toint(message[1:]) if i >= self.encoder.numpieces: self.close() return self.download.got_have(i) elif t == BITFIELD: try: b = Bitfield(self.encoder.numpieces, message[1:]) except ValueError: self.close() return self.download.got_have_bitfield(b) elif t == REQUEST: if len(message) != 13: self.close() return i = toint(message[1:5]) if i >= self.encoder.numpieces: self.close() return self.upload.got_request(i, toint(message[5:9]), toint(message[9:])) elif t == CANCEL: if len(message) != 13: self.close() return i = toint(message[1:5]) if i >= self.encoder.numpieces: self.close() return self.upload.got_cancel(i, toint(message[5:9]), toint(message[9:])) elif t == PIECE: if len(message) <= 9: self.close() return i = toint(message[1:5]) if i >= self.encoder.numpieces: self.close() return if self.download.got_piece(i, toint(message[5:9]), message[9:]): for co in self.encoder.complete_connections: co.send_have(i) else: self.close()