Esempio n. 1
0
    def _handle_info_response(self, response_dict, peer, request):
        if not request.response_identifier in response_dict:
            return InvalidResponseError("response identifier not in response")
        response = response_dict[request.response_identifier]
        if 'error' in response:
            if response['error'] == 'RATE_UNSET':
                return 0
            else:
                return InvalidResponseError(
                    "Got an unknown error from the peer: %s" %
                    (response['error'], ))
        if not 'blob_lengths' in response:
            return InvalidResponseError(
                "Missing the required field 'blob_lengths'")
        raw_blob_lengths = response['blob_lengths']
        log.info("Handling %s blob lengths from %s",
                 str(len(raw_blob_lengths)), str(peer))
        log.debug("blobs: %s", str(raw_blob_lengths))
        infos = []
        unique_hashes = set()
        for blob_hash, length in raw_blob_lengths:
            if blob_hash in self._valuable_hashes:
                peer_score, reference, peer = self._valuable_hashes[blob_hash]
                del self._valuable_hashes[blob_hash]
                infos.append(
                    ValuableBlobInfo(blob_hash, length, reference, peer,
                                     peer_score))
                unique_hashes.add(blob_hash)
            elif blob_hash in request.request_dict['blob_length'][
                    'blob_hashes']:
                unique_hashes.add(blob_hash)
        d = self.info_manager.save_blob_infos(infos)
        d.addCallback(
            lambda _: self.download_manager.add_blobs_to_download(infos))

        def pay_or_penalize_peer():
            if len(unique_hashes):
                self._update_local_score(peer, len(unique_hashes))
                peer.update_stats('downloaded_valuable_blob_infos',
                                  len(unique_hashes))
                peer.update_score(len(unique_hashes))
            else:
                self._update_local_score(peer, -.0001)
            return len(unique_hashes)

        d.addCallback(lambda _: pay_or_penalize_peer())

        return d
Esempio n. 2
0
def _handle_incoming_blob(response_dict, peer, request):
    if request.response_identifier not in response_dict:
        return InvalidResponseError("response identifier not in response")
    if not isinstance(response_dict[request.response_identifier], dict):
        return InvalidResponseError(
            "response not a dict. got %s" %
            type(response_dict[request.response_identifier]))
    response = response_dict[request.response_identifier]
    if 'error' in response:
        # This means we're not getting our blob for some reason
        if response['error'] == "RATE_UNSET":
            # Stop the download with an error that won't penalize the peer
            request.cancel(PriceDisagreementError())
        else:
            # The peer has done something bad so we should get out of here
            return InvalidResponseError(
                "Got an unknown error from the peer: %s" %
                (response['error'], ))
    else:
        if 'blob_hash' not in response:
            return InvalidResponseError(
                "Missing the required field 'blob_hash'")
        if not response['blob_hash'] == request.request_dict['requested_blob']:
            return InvalidResponseError(
                "Incoming blob does not match expected. Incoming: %s. Expected: %s"
                % (response['blob_hash'],
                   request.request_dict['requested_blob']))
        if 'length' not in response:
            return InvalidResponseError("Missing the required field 'length'")
        if not request.blob.set_length(response['length']):
            return InvalidResponseError("Could not set the length of the blob")
    return True
Esempio n. 3
0
 def _handle_price_response(self, response_dict, peer, request, protocol):
     if not request.response_identifier in response_dict:
         return InvalidResponseError("response identifier not in response")
     assert protocol in self._protocol_prices
     response = response_dict[request.response_identifier]
     if response == "RATE_ACCEPTED":
         return True
     else:
         del self._protocol_prices[protocol]
         self._price_disagreements.append(peer)
     return True
Esempio n. 4
0
    def _handle_valuable_blob_response(self, response_dict, peer, request):
        if not request.response_identifier in response_dict:
            return InvalidResponseError("response identifier not in response")
        response = response_dict[request.response_identifier]
        if 'error' in response:
            if response['error'] == "RATE_UNSET":
                return 0
            else:
                return InvalidResponseError(
                    "Got an unknown error from the peer: %s" %
                    (response['error'], ))
        if not 'valuable_blob_hashes' in response:
            return InvalidResponseError(
                "Missing the required field 'valuable_blob_hashes'")
        hashes = response['valuable_blob_hashes']
        log.info("Handling %s valuable blob hashes from %s", str(len(hashes)),
                 str(peer))
        expire_time = datetime.datetime.now() + datetime.timedelta(minutes=10)
        reference = None
        unique_hashes = set()
        if 'reference' in response:
            reference = response['reference']
        for blob_hash, peer_score in hashes:
            if reference is None:
                reference = blob_hash
            self._last_blob_hashes_from_peers[peer] = (blob_hash, expire_time)
            if not (blob_hash in self._valuable_hashes
                    or blob_hash in self._blob_infos):
                self._valuable_hashes[blob_hash] = (peer_score, reference,
                                                    peer)
            unique_hashes.add(blob_hash)

        if len(unique_hashes):
            self._update_local_score(peer, len(unique_hashes))
            peer.update_stats('downloaded_valuable_blob_hashes',
                              len(unique_hashes))
            peer.update_score(len(unique_hashes))
        else:
            self._update_local_score(peer, -.0001)
        return len(unique_hashes)
Esempio n. 5
0
 def _handle_availability(self, response_dict, request):
     assert request.response_identifier == 'available_blobs'
     if 'available_blobs' not in response_dict:
         raise InvalidResponseError("response identifier not in response")
     log.debug("Received a response to the availability request")
     # save available blobs
     blob_hashes = response_dict['available_blobs']
     for blob_hash in blob_hashes:
         if blob_hash in request.request_dict['requested_blobs']:
             self.process_available_blob_hash(blob_hash, request)
     # everything left in the request is missing
     for blob_hash in request.request_dict['requested_blobs']:
         self.unavailable_blobs.append(blob_hash)
     return True
Esempio n. 6
0
 def _handle_availability(self, response_dict, peer, request):
     if not request.response_identifier in response_dict:
         raise InvalidResponseError("response identifier not in response")
     log.debug("Received a response to the availability request")
     blob_hashes = response_dict[request.response_identifier]
     for blob_hash in blob_hashes:
         if blob_hash in request.request_dict['requested_blobs']:
             log.debug(
                 "The server has indicated it has the following blob available: %s",
                 blob_hash)
             self._available_blobs[peer].append(blob_hash)
             if blob_hash in self._unavailable_blobs[peer]:
                 self._unavailable_blobs[peer].remove(blob_hash)
             request.request_dict['requested_blobs'].remove(blob_hash)
     for blob_hash in request.request_dict['requested_blobs']:
         self._unavailable_blobs[peer].append(blob_hash)
     return True
Esempio n. 7
0
 def _handle_availability(self, response_dict, request):
     assert request.response_identifier == 'available_blobs'
     if 'available_blobs' not in response_dict:
         raise InvalidResponseError("response identifier not in response")
     log.debug("Received a response to the availability request")
     # save available blobs
     blob_hashes = response_dict['available_blobs']
     if not blob_hashes:
         # should not send any more requests as it doesn't have any blob we need
         self.update_local_score(-10.0)
         return True
     for blob_hash in blob_hashes:
         if blob_hash in request.request_dict['requested_blobs']:
             self.process_available_blob_hash(blob_hash, request)
     # everything left in the request is missing
     for blob_hash in request.request_dict['requested_blobs']:
         self.unavailable_blobs.append(blob_hash)
     return True
Esempio n. 8
0
 def _handle_price_response(self, response_dict, request):
     assert request.response_identifier == 'blob_data_payment_rate'
     if 'blob_data_payment_rate' not in response_dict:
         return InvalidResponseError("response identifier not in response")
     offer_value = self.protocol_offers.pop(self.protocol)
     offer = Offer(offer_value)
     offer.handle(response_dict['blob_data_payment_rate'])
     self.payment_rate_manager.record_offer_reply(self.peer, offer)
     if offer.is_accepted:
         log.info("Offered rate %f/mb accepted by %s", offer.rate, self.peer.host)
         self.protocol_prices[self.protocol] = offer.rate
         return True
     elif offer.is_too_low:
         log.debug("Offered rate %f/mb rejected by %s", offer.rate, self.peer.host)
         return not self.payment_rate_manager.price_limit_reached(self.peer)
     else:
         log.warning("Price disagreement")
         self.requestor._price_disagreements.append(self.peer)
         return False
Esempio n. 9
0
    def _handle_price_response(self, response_dict, request):
        assert request.response_identifier == 'blob_data_payment_rate'
        if 'blob_data_payment_rate' not in response_dict:
            return InvalidResponseError("response identifier not in response")
        assert self.protocol in self.protocol_prices
        rate = self.protocol_prices[self.protocol]
        offer = Offer(rate)
        offer.handle(response_dict['blob_data_payment_rate'])
        self.payment_rate_manager.record_offer_reply(self.peer.host, offer)

        if offer.is_accepted:
            log.debug("Offered rate %f/mb accepted by %s", rate,
                      str(self.peer.host))
            return True
        elif offer.is_too_low:
            log.debug("Offered rate %f/mb rejected by %s", rate,
                      str(self.peer.host))
            del self.protocol_prices[self.protocol]
            return True
        else:
            log.warning("Price disagreement")
            del self.protocol_prices[self.protocol]
            self.requestor._price_disagreements.append(self.peer)
            return False
Esempio n. 10
0
    def _handle_discover_response(self, response_dict, peer, request):
        if not request.response_identifier in response_dict:
            return InvalidResponseError("response identifier not in response")
        response = response_dict[request.response_identifier]
        blob_infos = []
        if 'error' in response:
            if response['error'] == 'RATE_UNSET':
                return defer.succeed(0)
            else:
                return InvalidResponseError(
                    "Got an unknown error from the peer: %s" %
                    (response['error'], ))
        if not 'blob_infos' in response:
            return InvalidResponseError(
                "Missing the required field 'blob_infos'")
        raw_blob_infos = response['blob_infos']
        log.info("Handling %s further blobs from %s", str(len(raw_blob_infos)),
                 str(peer))
        log.debug("blobs: %s", str(raw_blob_infos))
        for raw_blob_info in raw_blob_infos:
            length = raw_blob_info['length']
            if length != 0:
                blob_hash = raw_blob_info['blob_hash']
            else:
                blob_hash = None
            num = raw_blob_info['blob_num']
            revision = raw_blob_info['revision']
            iv = raw_blob_info['iv']
            signature = raw_blob_info['signature']
            blob_info = LiveBlobInfo(blob_hash, num, length, iv, revision,
                                     signature)
            log.debug("Learned about a potential blob: %s", str(blob_hash))
            if self._verify_blob(blob_info):
                if blob_hash is None:
                    log.info("Setting _final_blob_num to %s", str(num - 1))
                    self._final_blob_num = num - 1
                else:
                    blob_infos.append(blob_info)
            else:
                raise ValueError("Peer sent an invalid blob info")
        d = self.stream_info_manager.add_blobs_to_stream(
            self.stream_hash, blob_infos)

        def add_blobs_to_download_manager():
            blob_nums = [b.blob_num for b in blob_infos]
            log.info(
                "Adding the following blob nums to the download manager: %s",
                str(blob_nums))
            self.download_manager.add_blobs_to_download(blob_infos)

        d.addCallback(lambda _: add_blobs_to_download_manager())

        def pay_or_penalize_peer():
            if len(blob_infos):
                self._update_local_score(peer, len(blob_infos))
                peer.update_stats('downloaded_crypt_blob_infos',
                                  len(blob_infos))
                peer.update_score(len(blob_infos))
            else:
                self._update_local_score(peer, -.0001)
            return len(blob_infos)

        d.addCallback(lambda _: pay_or_penalize_peer())

        return d