Example #1
0
 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)
Example #2
0
 def pickle(self):
     if self.have.complete:
         return {'pieces': 1}
     pieces = Bitfield(len(self.hashes))
     places = []
     partials = []
     for p in xrange(len(self.hashes)):
         if self.blocked[p] or p not in self.places:
             continue
         h = self.have[p]
         pieces[p] = h
         pp = self.dirty.get(p)
         if not h and not pp:  # no data
             places.extend([self.places[p], self.places[p]])
         elif self.places[p] != p:
             places.extend([p, self.places[p]])
         if h or not pp:
             continue
         pp.sort()
         r = []
         while len(pp) > 1:
             if pp[0][0] + pp[0][1] == pp[1][0]:
                 pp[0] = list(pp[0])
                 pp[0][1] += pp[1][1]
                 del pp[1]
             else:
                 r.extend(pp[0])
                 del pp[0]
         r.extend(pp[0])
         partials.extend([p, r])
     return {'pieces': str(pieces), 'places': places, 'partials': partials}
Example #3
0
    def print_message(self, message):
        t = message[0]
        output = ''
        if t == CHOKE:
            output += 'CHOKE'
        elif t == UNCHOKE:
            output += 'UNCHOKE'
        elif t == INTERESTED:
            output += 'INTERESTED'
        elif t == NOT_INTERESTED:
            output += 'NOT_INTERESTED'
        elif t == HAVE:
            i = toint(message[1:])
            output += 'HAVE:{0}'.format(i)
        elif t == BITFIELD:
            try:
                b = Bitfield(self.numpieces, message[1:])
                output += 'BITFIELD:{0}'.format(' '.join([ str(ord(ch)) for ch in b.tostring()]))
            except ValueError:
                output += 'BITFIELD:ValueError'
                return output
        elif t == REQUEST:
            index = toint(message[1:5])
            begin = toint(message[5:9]) 
            length = toint(message[9:])
            output += 'REQUEST:i:{0} b:{1} l:{2}'.format(index, begin, length)
        elif t == CANCEL:
            index = toint(message[1:5])
            begin = toint(message[5:9]) 
            length = toint(message[9:])
            output += 'CANCEL:i:{0} b:{1} l:{2}'.format(index, begin, length)
        elif t == PIECE:
            index = toint(message[1:5])
            begin = toint(message[5:9])
            length = len(message) - 8
            output += 'PIECE:i:{0} b:{1} l:{2}'.format(index, begin, length)
        else:
            output += 'Wrong Message'

        return output
Example #4
0
 def test_bitfield(self):
     """Unit test Bitfield"""
     self.assertRaises(ValueError, Bitfield, 7, b'ab')
     self.assertRaises(ValueError, Bitfield, 7, b'ab')
     self.assertRaises(ValueError, Bitfield, 9, b'abc')
     self.assertRaises(ValueError, Bitfield, 0, b'a')
     self.assertRaises(ValueError, Bitfield, 1, b'')
     self.assertRaises(ValueError, Bitfield, 7, b'')
     self.assertRaises(ValueError, Bitfield, 8, b'')
     self.assertRaises(ValueError, Bitfield, 9, b'a')
     self.assertRaises(ValueError, Bitfield, 7, b'\x01')
     self.assertRaises(ValueError, Bitfield, 9, b'\x00\x40')
     self.assertEqual(bytes(Bitfield(0, b'')), b'')
     self.assertEqual(bytes(Bitfield(1, b'\x80')), b'\x80')
     self.assertEqual(bytes(Bitfield(7, b'\x02')), b'\x02')
     self.assertEqual(bytes(Bitfield(8, b'\xFF')), b'\xFF')
     self.assertEqual(bytes(Bitfield(9, b'\x00\x80')), b'\x00\x80')
     testx = Bitfield(1)
     self.assertEqual(testx.numfalse, 1)
     testx[0] = 1
     self.assertEqual(testx.numfalse, 0)
     testx[0] = 1
     self.assertEqual(testx.numfalse, 0)
     self.assertEqual(bytes(testx), b'\x80')
     testx = Bitfield(7)
     self.assertEqual(len(testx), 7)
     testx[6] = 1
     self.assertEqual(testx.numfalse, 6)
     self.assertEqual(bytes(testx), b'\x02')
     testx = Bitfield(8)
     testx[7] = 1
     self.assertEqual(bytes(testx), b'\x01')
     testx = Bitfield(9)
     testx[8] = 1
     self.assertEqual(testx.numfalse, 8)
     self.assertEqual(bytes(testx), b'\x00\x80')
     testx = Bitfield(8, b'\xc4')
     self.assertEqual(len(testx), 8)
     self.assertEqual(testx.numfalse, 5)
     self.assertEqual(bytes(testx), b'\xc4')
Example #5
0
 def get_have_list_cloaked(self):
     if self.have_cloaked_data is None:
         newhave = Bitfield(copyfrom=self.have)
         unhaves = []
         # between 2-4 unless torrent is small
         n = min(random.randrange(2, 5), len(self.hashes))
         while len(unhaves) < n:
             # all in first 4 bytes
             unhave = random.randrange(min(32, len(self.hashes)))
             if not unhave in unhaves:
                 unhaves.append(unhave)
                 newhave[unhave] = False
         self.have_cloaked_data = (str(newhave), unhaves)
     return self.have_cloaked_data
Example #6
0
 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.example_interest = None
     self.backlog = 2
     self.ip = connection.get_ip()
     self.guard = BadDataGuard(self)
Example #7
0
class SingleDownload:
    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)

    def _backlog(self, just_unchoked):
        self.backlog = min(
            2 + int(4 * self.measure.get_rate() / self.downloader.chunksize),
            (2 * just_unchoked) + self.downloader.queue_limit())
        if self.backlog > 50:
            self.backlog = max(50, self.backlog * 0.075)
        return self.backlog

    def disconnected(self):
        self.downloader.lost_peer(self)
        if self.have.complete():
            self.downloader.picker.lost_seed(self.connection.isVODPeer())
        else:
            for i in xrange(len(self.have)):
                if self.have[i]:
                    self.downloader.picker.lost_have(i)
        if self.have.complete() and self.downloader.storage.is_endgame():
            self.downloader.add_disconnected_seed(
                self.connection.get_readable_id())
        self._letgo()
        self.guard.download = None

    def _letgo(self):
        if self.downloader.queued_out.has_key(self):
            del self.downloader.queued_out[self]
        if not self.active_requests:
            return
        if self.downloader.endgamemode:
            self.active_requests = []
            return
        lost = {}
        for index, begin, length in self.active_requests:
            self.downloader.storage.request_lost(index, begin, length)
            lost[index] = 1
        lost = lost.keys()
        self.active_requests = []
        if self.downloader.paused:
            return
        ds = [d for d in self.downloader.downloads if not d.choked]
        shuffle(ds)
        for d in ds:
            d._request_more()
        for d in self.downloader.downloads:
            if d.choked and not d.interested:
                for l in lost:
                    if d.have[l] and self.downloader.storage.do_I_have_requests(
                            l):
                        d.send_interested()
                        break

    def got_choke(self):
        if not self.choked:
            self.choked = True
            self._letgo()

    def got_unchoke(self):
        if self.choked:
            self.choked = False
            if self.interested:
                self._request_more(new_unchoke=True)
            self.last2 = clock()

    def is_choked(self):
        return self.choked

    def is_interested(self):
        return self.interested

    def send_interested(self):
        if not self.interested:
            self.interested = True
            self.connection.send_interested()
            if not self.choked:
                self.last2 = clock()

    def send_not_interested(self):
        if self.interested:
            self.interested = False
            self.connection.send_not_interested()

    def got_piece(self, index, begin, piece):
        length = len(piece)
        try:
            self.active_requests.remove((index, begin, length))
        except ValueError:
            self.downloader.discarded += length
            return False
        if self.downloader.endgamemode:
            self.downloader.all_requests.remove((index, begin, length))
        self.last = clock()
        self.last2 = clock()
        self.measure.update_rate(length)
        self.downloader.measurefunc(length)
        if not self.downloader.storage.piece_came_in(index, begin, piece,
                                                     self.guard):
            self.downloader.piece_flunked(index)
            return False
        if self.downloader.storage.do_I_have(index):
            self.downloader.picker.complete(index)
        if self.downloader.endgamemode:
            for d in self.downloader.downloads:
                if d is not self:
                    if d.interested:
                        if d.choked:
                            assert not d.active_requests
                            d.fix_download_endgame()
                        else:
                            try:
                                d.active_requests.remove(
                                    (index, begin, length))
                            except ValueError:
                                continue
                            d.connection.send_cancel(index, begin, length)
                            d.fix_download_endgame()
                    else:
                        assert not d.active_requests
        self._request_more()
        self.downloader.check_complete(index)
        return self.downloader.storage.do_I_have(index)

    def _request_more(self, new_unchoke=False):
        assert not self.choked
        if self.downloader.endgamemode:
            self.fix_download_endgame(new_unchoke)
            return
        if self.downloader.paused:
            return
        if len(self.active_requests) >= self._backlog(new_unchoke):
            if not (self.active_requests or self.backlog):
                self.downloader.queued_out[self] = 1
            return
        lost_interests = []
        while len(self.active_requests) < self.backlog:
            interest = self.downloader.picker.next(
                self.have,
                self.downloader.storage.do_I_have_requests,
                complete_first=self.downloader.too_many_partials(),
                rate=self.measure.get_rate())
            if interest is None:
                break
            self.example_interest = interest
            self.send_interested()
            loop = True
            while len(self.active_requests) < self.backlog and loop:
                begin, length = self.downloader.storage.new_request(interest)
                self.downloader.picker.requested(interest)
                self.active_requests.append((interest, begin, length))
                self.connection.send_request(interest, begin, length)
                self.downloader.chunk_requested(length)
                if not self.downloader.storage.do_I_have_requests(interest):
                    loop = False
                    lost_interests.append(interest)
        if not self.active_requests:
            self.send_not_interested()
        if lost_interests:
            for d in self.downloader.downloads:
                if d.active_requests or not d.interested:
                    continue
                if d.example_interest is not None and self.downloader.storage.do_I_have_requests(
                        d.example_interest):
                    continue
                for lost in lost_interests:
                    if d.have[lost]:
                        break
                else:
                    continue
                interest = self.downloader.picker.next(
                    d.have,
                    self.downloader.storage.do_I_have_requests,
                    complete_first=self.downloader.too_many_partials(),
                    rate=d.measure.get_rate())
                if interest is None:
                    d.send_not_interested()
                else:
                    d.example_interest = interest
        if self.downloader.storage.is_endgame():
            self.downloader.start_endgame()

    def fix_download_endgame(self, new_unchoke=False):
        if self.downloader.paused:
            return
        if len(self.active_requests) >= self._backlog(new_unchoke):
            if not (self.active_requests or self.backlog) and not self.choked:
                self.downloader.queued_out[self] = 1
            return
        want = [
            a for a in self.downloader.all_requests
            if self.have[a[0]] and a not in self.active_requests
        ]
        if not (self.active_requests or want):
            self.send_not_interested()
            return
        if want:
            self.send_interested()
        if self.choked:
            return
        shuffle(want)
        del want[self.backlog - len(self.active_requests):]
        self.active_requests.extend(want)
        for piece, begin, length in want:
            self.connection.send_request(piece, begin, length)
            self.downloader.chunk_requested(length)

    def got_have(self, index):
        if index == self.downloader.numpieces - 1:
            self.downloader.totalmeasure.update_rate(
                self.downloader.storage.total_length -
                (self.downloader.numpieces - 1) *
                self.downloader.storage.piece_length)
            self.peermeasure.update_rate(self.downloader.storage.total_length -
                                         (self.downloader.numpieces - 1) *
                                         self.downloader.storage.piece_length)
        else:
            self.downloader.totalmeasure.update_rate(
                self.downloader.storage.piece_length)
            self.peermeasure.update_rate(self.downloader.storage.piece_length)
        if not self.have[index]:
            self.have[index] = True
            self.downloader.picker.got_have(index)
            if self.have.complete():
                self.downloader.picker.became_seed(self.connection.isVODPeer())
                if self.downloader.storage.am_I_complete():
                    self.downloader.add_disconnected_seed(
                        self.connection.get_readable_id())
                    self.connection.close()
            elif self.downloader.endgamemode:
                self.fix_download_endgame()
            elif (not self.downloader.paused
                  and not self.downloader.picker.is_blocked(index)
                  and self.downloader.storage.do_I_have_requests(index)):
                if not self.choked:
                    self._request_more()
                else:
                    self.send_interested()
        return self.have.complete()

    def _check_interests(self):
        if self.interested or self.downloader.paused:
            return
        for i in xrange(len(self.have)):
            if (self.have[i] and not self.downloader.picker.is_blocked(i)
                    and (self.downloader.endgamemode
                         or self.downloader.storage.do_I_have_requests(i))):
                self.send_interested()
                return

    def got_have_bitfield(self, have):
        if self.downloader.storage.am_I_complete() and have.complete():
            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 False
        self.have = have
        if have.complete():

            self.downloader.picker.got_seed(self.connection.isVODPeer())
        else:
            for i in xrange(len(have)):
                if have[i]:
                    self.downloader.picker.got_have(i)
        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
        else:
            self._check_interests()
        return have.complete()

    def get_rate(self):
        return self.measure.get_rate()

    def is_snubbed(self):
        if (self.interested and not self.choked
                and clock() - self.last2 > self.downloader.snub_time):
            for index, begin, length in self.active_requests:
                self.connection.send_cancel(index, begin, length)
            self.got_choke()  # treat it just like a choke
        return clock() - self.last > self.downloader.snub_time
Example #8
0
class SingleDownload:
    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)

    def _backlog(self, just_unchoked):
        self.backlog = min(
            2+int(4*self.measure.get_rate()/self.downloader.chunksize),
            (2*just_unchoked)+self.downloader.queue_limit() )
        if self.backlog > 50:
            self.backlog = max(50, self.backlog * 0.075)
        return self.backlog
    
    def disconnected(self):
        self.downloader.lost_peer(self)
        if self.have.complete():
            self.downloader.picker.lost_seed()
        else:
            for i in xrange(len(self.have)):
                if self.have[i]:
                    self.downloader.picker.lost_have(i)
        if self.have.complete() and self.downloader.storage.is_endgame():
            self.downloader.add_disconnected_seed(self.connection.get_readable_id())
        self._letgo()
        self.guard.download = None

    def _letgo(self):
        if self.downloader.queued_out.has_key(self):
            del self.downloader.queued_out[self]
        if not self.active_requests:
            return
        if self.downloader.endgamemode:
            self.active_requests = []
            return
        lost = {}
        for index, begin, length in self.active_requests:
            self.downloader.storage.request_lost(index, begin, length)
            lost[index] = 1
        lost = lost.keys()
        self.active_requests = []
        if self.downloader.paused:
            return
        ds = [d for d in self.downloader.downloads if not d.choked]
        shuffle(ds)
        for d in ds:
            d._request_more()
        for d in self.downloader.downloads:
            if d.choked and not d.interested:
                for l in lost:
                    if d.have[l] and self.downloader.storage.do_I_have_requests(l):
                        d.send_interested()
                        break

    def got_choke(self):
        if not self.choked:
            self.choked = True
            self._letgo()

    def got_unchoke(self):
        if self.choked:
            self.choked = False
            if self.interested:
                self._request_more(new_unchoke = True)
            self.last2 = clock()

    def is_choked(self):
        return self.choked

    def is_interested(self):
        return self.interested

    def send_interested(self):
        if not self.interested:
            self.interested = True
            self.connection.send_interested()
            if not self.choked:
                self.last2 = clock()

    def send_not_interested(self):
        if self.interested:
            self.interested = False
            self.connection.send_not_interested()

    def got_piece(self, index, begin, piece):
        length = len(piece)
        try:
            self.active_requests.remove((index, begin, length))
        except ValueError:
            self.downloader.discarded += length
            return False
        if self.downloader.endgamemode:
            self.downloader.all_requests.remove((index, begin, length))
        self.last = clock()
        self.last2 = clock()
        self.measure.update_rate(length)
        self.downloader.measurefunc(length)
        if not self.downloader.storage.piece_came_in(index, begin, piece, self.guard):
            self.downloader.piece_flunked(index)
            return False
        if self.downloader.storage.do_I_have(index):
            self.downloader.picker.complete(index)
        if self.downloader.endgamemode:
            for d in self.downloader.downloads:
                if d is not self:
                  if d.interested:
                    if d.choked:
                        assert not d.active_requests
                        d.fix_download_endgame()
                    else:
                        try:
                            d.active_requests.remove((index, begin, length))
                        except ValueError:
                            continue
                        d.connection.send_cancel(index, begin, length)
                        d.fix_download_endgame()
                  else:
                      assert not d.active_requests
        self._request_more()
        self.downloader.check_complete(index)
        return self.downloader.storage.do_I_have(index)

    def _request_more(self, new_unchoke = False):
        assert not self.choked
        if self.downloader.endgamemode:
            self.fix_download_endgame(new_unchoke)
            return
        if self.downloader.paused:
            return
        if len(self.active_requests) >= self._backlog(new_unchoke):
            if not (self.active_requests or self.backlog):
                self.downloader.queued_out[self] = 1
            return
        lost_interests = []
        while len(self.active_requests) < self.backlog:
            interest = self.downloader.picker.next(self.have,
                               self.downloader.storage.do_I_have_requests,
                               self.downloader.too_many_partials())
            if interest is None:
                break
            self.example_interest = interest
            self.send_interested()
            loop = True
            while len(self.active_requests) < self.backlog and loop:
                begin, length = self.downloader.storage.new_request(interest)
                self.downloader.picker.requested(interest)
                self.active_requests.append((interest, begin, length))
                self.connection.send_request(interest, begin, length)
                self.downloader.chunk_requested(length)
                if not self.downloader.storage.do_I_have_requests(interest):
                    loop = False
                    lost_interests.append(interest)
        if not self.active_requests:
            self.send_not_interested()
        if lost_interests:
            for d in self.downloader.downloads:
                if d.active_requests or not d.interested:
                    continue
                if d.example_interest is not None and self.downloader.storage.do_I_have_requests(d.example_interest):
                    continue
                for lost in lost_interests:
                    if d.have[lost]:
                        break
                else:
                    continue
                interest = self.downloader.picker.next(d.have,
                                   self.downloader.storage.do_I_have_requests,
                                   self.downloader.too_many_partials())
                if interest is None:
                    d.send_not_interested()
                else:
                    d.example_interest = interest
        if self.downloader.storage.is_endgame():
            self.downloader.start_endgame()


    def fix_download_endgame(self, new_unchoke = False):
        if self.downloader.paused:
            return
        if len(self.active_requests) >= self._backlog(new_unchoke):
            if not (self.active_requests or self.backlog) and not self.choked:
                self.downloader.queued_out[self] = 1
            return
        want = [a for a in self.downloader.all_requests if self.have[a[0]] and a not in self.active_requests]
        if not (self.active_requests or want):
            self.send_not_interested()
            return
        if want:
            self.send_interested()
        if self.choked:
            return
        shuffle(want)
        print self.backlog, len(self.active_requests)
        #del want[len(self.active_requests):]
        self.active_requests.extend(want)
        for piece, begin, length in want:
            self.connection.send_request(piece, begin, length)
            self.downloader.chunk_requested(length)

    def got_have(self, index):
        if index == self.downloader.numpieces-1:
            self.downloader.totalmeasure.update_rate(self.downloader.storage.total_length-(self.downloader.numpieces-1)*self.downloader.storage.piece_length)
            self.peermeasure.update_rate(self.downloader.storage.total_length-(self.downloader.numpieces-1)*self.downloader.storage.piece_length)
        else:
            self.downloader.totalmeasure.update_rate(self.downloader.storage.piece_length)
            self.peermeasure.update_rate(self.downloader.storage.piece_length)
        if not self.have[index]:
            self.have[index] = True
            self.downloader.picker.got_have(index)
            if self.have.complete():
                self.downloader.picker.became_seed()
                if self.downloader.storage.am_I_complete():
                    self.downloader.add_disconnected_seed(self.connection.get_readable_id())
                    self.connection.close()
            elif self.downloader.endgamemode:
                self.fix_download_endgame()
            elif ( not self.downloader.paused
                   and not self.downloader.picker.is_blocked(index)
                   and self.downloader.storage.do_I_have_requests(index) ):
                if not self.choked:
                    self._request_more()
                else:
                    self.send_interested()
        return self.have.complete()

    def _check_interests(self):
        if self.interested or self.downloader.paused:
            return
        for i in xrange(len(self.have)):
            if ( self.have[i] and not self.downloader.picker.is_blocked(i)
                 and ( self.downloader.endgamemode
                       or self.downloader.storage.do_I_have_requests(i) ) ):
                self.send_interested()
                return

    def got_have_bitfield(self, have):
        if self.downloader.storage.am_I_complete() and have.complete():
            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 False
        self.have = have
        if have.complete():
            self.downloader.picker.got_seed()
        else:
            for i in xrange(len(have)):
                if have[i]:
                    self.downloader.picker.got_have(i)
        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
        else:
            self._check_interests()
        return have.complete()

    def get_rate(self):
        return self.measure.get_rate()

    def is_snubbed(self):
        if ( self.interested and not self.choked
             and clock() - self.last2 > self.downloader.snub_time ):
            for index, begin, length in self.active_requests:
                self.connection.send_cancel(index, begin, length)
            self.got_choke()    # treat it just like a choke
        return clock() - self.last > self.downloader.snub_time
Example #9
0
    def unpickle(self, data, valid_places):
        got = set()
        places = {}
        dirty = {}
        download_history = {}
        stat_active = set()
        stat_numfound = self.stat_numfound
        amount_obtained = self.amount_obtained
        amount_inactive = self.amount_inactive
        amount_left = self.amount_left
        inactive_requests = [x for x in self.inactive_requests]
        restored_partials = []

        try:
            if data['pieces'] == 1:  # a seed
                assert not data.get('places', None)
                assert not data.get('partials', None)
                have = Bitfield(len(self.hashes), val=True)
                assert have.complete
                _places = []
                _partials = []
            else:
                have = Bitfield(len(self.hashes), data['pieces'])
                _places = data['places']
                assert len(_places) % 2 == 0
                _places = [
                    _places[x:x + 2] for x in xrange(0, len(_places), 2)
                ]
                _partials = data['partials']
                assert len(_partials) % 2 == 0
                _partials = [
                    _partials[x:x + 2] for x in xrange(0, len(_partials), 2)
                ]

            for index, place in _places:
                if place not in valid_places:
                    continue
                assert index not in got
                assert place not in got
                places[index] = place
                got.add(index)
                got.add(place)

            for index in xrange(len(self.hashes)):
                if have[index]:
                    if index not in places:
                        if index not in valid_places:
                            have[index] = False
                            continue
                        assert index not in got
                        places[index] = index
                        got.add(index)
                    length = self._piecelen(index)
                    amount_obtained += length
                    stat_numfound += 1
                    amount_inactive -= length
                    amount_left -= length
                    inactive_requests[index] = None

            for index, plist in _partials:
                assert index not in dirty
                assert not have[index]
                if index not in places:
                    if index not in valid_places:
                        continue
                    assert index not in got
                    places[index] = index
                    got.add(index)
                assert len(plist) % 2 == 0
                plist = [plist[x:x + 2] for x in xrange(0, len(plist), 2)]
                dirty[index] = plist
                stat_active.add(index)
                download_history[index] = {}
                # invert given partials
                length = self._piecelen(index)
                l = []
                if plist[0][0] > 0:
                    l.append((0, plist[0][0]))

                for pieceA, pieceB in zip(plist[:-1], plist[1:]):
                    end = pieceA[0] + pieceA[1]
                    assert not end > pieceB[0]
                    l.append((end, pieceB[0] - end))
                end = pieceB[0] + pieceB[1]
                assert not end > length

                if end < length:
                    l.append((end, length - end))
                # split them to request_size
                ll = []
                amount_obtained += length
                amount_inactive -= length
                for nb, nl in l:
                    while nl > 0:
                        r = min(nl, self.request_size)
                        ll.append((nb, r))
                        amount_inactive += r
                        amount_obtained -= r
                        nb += self.request_size
                        nl -= self.request_size
                inactive_requests[index] = ll
                restored_partials.append(index)

            assert amount_obtained + amount_inactive == self.amount_desired
        except Exception:
            #            print_exc()
            return []  # invalid data, discard everything

        self.have = have
        self.places = places
        self.dirty = dirty
        self.download_history = download_history
        self.stat_active = stat_active
        self.stat_numfound = stat_numfound
        self.amount_obtained = amount_obtained
        self.amount_inactive = amount_inactive
        self.amount_left = amount_left
        self.inactive_requests = inactive_requests

        return restored_partials
Example #10
0
    def __init__(self,
                 storage,
                 request_size,
                 hashes,
                 piece_size,
                 finished,
                 failed,
                 statusfunc=dummy_status,
                 flag=fakeflag(),
                 check_hashes=True,
                 data_flunked=lambda x: None,
                 backfunc=None,
                 config={},
                 unpauseflag=fakeflag(True)):
        self.storage = storage
        self.request_size = long(request_size)
        self.hashes = hashes
        self.piece_size = long(piece_size)
        self.piece_length = long(piece_size)
        self.finished = finished
        self.failed = failed
        self.statusfunc = statusfunc
        self.flag = flag
        self.check_hashes = check_hashes
        self.data_flunked = data_flunked
        self.backfunc = backfunc
        self.config = config
        self.unpauseflag = unpauseflag

        self.alloc_type = config.get('alloc_type', 'normal')
        self.double_check = config.get('double_check', 0)
        self.triple_check = config.get('triple_check', 0)
        if self.triple_check:
            self.double_check = True
        self.bgalloc_enabled = False
        self.bgalloc_active = False
        self.total_length = storage.get_total_length()
        self.amount_left = self.total_length
        if self.total_length <= self.piece_size * (len(hashes) - 1):
            raise ValueError('bad data in responsefile - total too small')
        if self.total_length > self.piece_size * len(hashes):
            raise ValueError('bad data in responsefile - total too big')
        self.numactive = [0] * len(hashes)
        self.inactive_requests = [1] * len(hashes)
        self.amount_inactive = self.total_length
        self.amount_obtained = 0
        self.amount_desired = self.total_length
        self.have = Bitfield(len(hashes))
        self.have_cloaked_data = None
        self.blocked = [False] * len(hashes)
        self.blocked_holes = []
        self.blocked_movein = OrderedSet()
        self.blocked_moveout = OrderedSet()
        self.waschecked = [False] * len(hashes)
        self.places = {}
        self.holes = []
        self.stat_active = set()
        self.stat_new = set()
        self.dirty = {}
        self.stat_numflunked = 0
        self.stat_numdownloaded = 0
        self.stat_numfound = 0
        self.download_history = {}
        self.failed_pieces = {}
        self.out_of_place = 0
        self.write_buf_max = config['write_buffer_size'] * 1048576L
        self.write_buf_size = 0L
        self.write_buf = {}  # structure:  piece: [(start, data), ...]
        self.write_buf_list = []

        self.initialize_tasks = [[
            'checking existing data', 0, self.init_hashcheck,
            self.hashcheckfunc
        ], ['moving data', 1, self.init_movedata, self.movedatafunc
            ], ['allocating disk space', 1, self.init_alloc, self.allocfunc]]

        self.backfunc(self._bgalloc, 0.1)
        self.backfunc(self._bgsync, max(self.config['auto_flush'] * 60, 60))
Example #11
0
 def got_message(self, connection, message):
     c = self.connections[connection]
     t = message[0]
     if t == BITFIELD and c.got_anything:
         connection.close()
         return
     c.got_anything = True
     if (t in [CHOKE, UNCHOKE, INTERESTED, NOT_INTERESTED]
             and len(message) != 1):
         connection.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:
             connection.close()
             return
         i = toint(message[1:])
         if i >= self.numpieces:
             connection.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:
             connection.close()
             return
         if c.download.got_have_bitfield(b):
             c.upload.got_not_interested()
     elif t == REQUEST:
         if len(message) != 13:
             connection.close()
             return
         i = toint(message[1:5])
         if i >= self.numpieces:
             connection.close()
             return
         c.got_request(i, toint(message[5:9]), toint(message[9:]))
     elif t == CANCEL:
         if len(message) != 13:
             connection.close()
             return
         i = toint(message[1:5])
         if i >= self.numpieces:
             connection.close()
             return
         c.upload.got_cancel(i, toint(message[5:9]), toint(message[9:]))
     elif t == PIECE:
         if len(message) <= 9:
             connection.close()
             return
         i = toint(message[1:5])
         if i >= self.numpieces:
             connection.close()
             return
         if c.download.got_piece(i, toint(message[5:9]), message[9:]):
             self.got_piece(i)
     else:
         connection.close()
Example #12
0
 def got_message(self, connection, message):
     c = self.connections[connection]
     t = message[:1]
     if DEBUG2:
         print(c.ccount, 'message received', ord(t))
     if t == BITFIELD and c.got_anything:
         if DEBUG2:
             print(c.ccount, 'misplaced bitfield')
         connection.close()
         return
     c.got_anything = True
     if (t in [CHOKE, UNCHOKE, INTERESTED, NOT_INTERESTED]
             and len(message) != 1):
         if DEBUG2:
             print(c.ccount, 'bad message length')
         connection.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:
             if DEBUG2:
                 print(c.ccount, 'bad message length')
             connection.close()
             return
         i = int.from_bytes(message[1:], 'big')
         if i >= self.numpieces:
             if DEBUG2:
                 print(c.ccount, 'bad piece number')
             connection.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:
             if DEBUG2:
                 print(c.ccount, 'bad bitfield')
             connection.close()
             return
         if c.download.got_have_bitfield(b):
             c.upload.got_not_interested()
     elif t == REQUEST:
         if len(message) != 13:
             if DEBUG2:
                 print(c.ccount, 'bad message length')
             connection.close()
             return
         piece_num = int.from_bytes(message[1:5], 'big')
         if piece_num >= self.numpieces:
             if DEBUG2:
                 print(c.ccount, 'bad piece number')
             connection.close()
             return
         c.got_request(piece_num, int.from_bytes(message[5:9], 'big'),
                       int.from_bytes(message[9:], 'big'))
     elif t == CANCEL:
         if len(message) != 13:
             if DEBUG2:
                 print(c.ccount, 'bad message length')
             connection.close()
             return
         i = int.from_bytes(message[1:5], 'big')
         if i >= self.numpieces:
             if DEBUG2:
                 print(c.ccount, 'bad piece number')
             connection.close()
             return
         c.upload.got_cancel(i, int.from_bytes(message[5:9], 'big'),
                             int.from_bytes(message[9:], 'big'))
     elif t == PIECE:
         if len(message) <= 9:
             if DEBUG2:
                 print(c.ccount, 'bad message length')
             connection.close()
             return
         i = int.from_bytes(message[1:5], 'big')
         if i >= self.numpieces:
             if DEBUG2:
                 print(c.ccount, 'bad piece number')
             connection.close()
             return
         if c.download.got_piece(i, int.from_bytes(message[5:9], 'big'),
                                 message[9:]):
             self.got_piece(i)
     else:
         connection.close()