示例#1
0
    async def handle_request(self, request: BlobRequest):
        addr = self.transport.get_extra_info('peername')
        peer_address, peer_port = addr

        responses = []
        address_request = request.get_address_request()
        if address_request:
            responses.append(
                BlobPaymentAddressResponse(
                    lbrycrd_address=self.lbrycrd_address))
        availability_request = request.get_availability_request()
        if availability_request:
            responses.append(
                BlobAvailabilityResponse(available_blobs=list(
                    set(
                        filter(
                            lambda blob_hash: blob_hash in self.blob_manager.
                            completed_blob_hashes,
                            availability_request.requested_blobs)))))
        price_request = request.get_price_request()
        if price_request:
            responses.append(
                BlobPriceResponse(blob_data_payment_rate='RATE_ACCEPTED'))
        download_request = request.get_blob_request()

        if download_request:
            blob = self.blob_manager.get_blob(download_request.requested_blob)
            if blob.get_is_verified():
                incoming_blob = {
                    'blob_hash': blob.blob_hash,
                    'length': blob.length
                }
                responses.append(
                    BlobDownloadResponse(incoming_blob=incoming_blob))
                self.send_response(responses)
                bh = blob.blob_hash[:8]
                log.debug("send %s to %s:%i", bh, peer_address, peer_port)
                self.started_transfer.set()
                try:
                    sent = await asyncio.wait_for(blob.sendfile(self),
                                                  self.transfer_timeout,
                                                  loop=self.loop)
                    self.blob_manager.connection_manager.sent_data(
                        self.peer_address_and_port, sent)
                    log.info("sent %s (%i bytes) to %s:%i", bh, sent,
                             peer_address, peer_port)
                except (ConnectionResetError, BrokenPipeError, RuntimeError,
                        OSError, asyncio.TimeoutError) as err:
                    if isinstance(err, asyncio.TimeoutError):
                        log.debug("timed out sending blob %s to %s", bh,
                                  peer_address)
                    else:
                        log.debug("stopped sending %s to %s:%i", bh,
                                  peer_address, peer_port)
                    self.close()
                finally:
                    self.transfer_finished.set()
        if responses:
            self.send_response(responses)
示例#2
0
文件: server.py 项目: zhyniq/lbry-sdk
 def data_received(self, data):
     request = None
     if len(self.buf) + len(data or b'') >= MAX_REQUEST_SIZE:
         log.warning("request from %s is too large",
                     self.peer_address_and_port)
         self.close()
         return
     if data:
         self.blob_manager.connection_manager.received_data(
             self.peer_address_and_port, len(data))
         _, separator, remainder = data.rpartition(b'}')
         if not separator:
             self.buf += data
             return
         try:
             request = BlobRequest.deserialize(self.buf + data)
             self.buf = remainder
         except JSONDecodeError:
             log.error(
                 "request from %s is not valid json (%i bytes): %s",
                 self.peer_address_and_port, len(self.buf + data),
                 '' if not data else binascii.hexlify(self.buf +
                                                      data).decode())
             self.close()
             return
     if not request.requests:
         log.error(
             "failed to decode request from %s (%i bytes): %s",
             self.peer_address_and_port, len(self.buf + data),
             '' if not data else binascii.hexlify(self.buf + data).decode())
         self.close()
         return
     self.loop.create_task(self.handle_request(request))
示例#3
0
 def data_received(self, data):
     request = None
     if data:
         self.blob_manager.connection_manager.received_data(
             self.peer_address_and_port, len(data))
         message, separator, remainder = data.rpartition(b'}')
         if not separator:
             self.buf += data
             return
         try:
             request = BlobRequest.deserialize(self.buf + data)
             self.buf = remainder
         except JSONDecodeError:
             addr = self.transport.get_extra_info('peername')
             peer_address, peer_port = addr
             log.error(
                 "failed to decode blob request from %s:%i (%i bytes): %s",
                 peer_address, peer_port, len(data),
                 '' if not data else binascii.hexlify(data).decode())
     if not request:
         addr = self.transport.get_extra_info('peername')
         peer_address, peer_port = addr
         log.warning("failed to decode blob request from %s:%i",
                     peer_address, peer_port)
         self.transport.close()
         return
     self.loop.create_task(self.handle_request(request))
示例#4
0
    async def handle_request(self, request: BlobRequest):
        addr = self.transport.get_extra_info('peername')
        peer_address, peer_port = addr

        responses = []
        address_request = request.get_address_request()
        if address_request:
            responses.append(
                BlobPaymentAddressResponse(
                    lbrycrd_address=self.lbrycrd_address))
        availability_request = request.get_availability_request()
        if availability_request:
            responses.append(
                BlobAvailabilityResponse(available_blobs=list(
                    set((filter(
                        lambda blob_hash: blob_hash in self.blob_manager.
                        completed_blob_hashes,
                        availability_request.requested_blobs))))))
        price_request = request.get_price_request()
        if price_request:
            responses.append(
                BlobPriceResponse(blob_data_payment_rate='RATE_ACCEPTED'))
        download_request = request.get_blob_request()

        if download_request:
            blob = self.blob_manager.get_blob(download_request.requested_blob)
            if blob.get_is_verified():
                incoming_blob = {
                    'blob_hash': blob.blob_hash,
                    'length': blob.length
                }
                responses.append(
                    BlobDownloadResponse(incoming_blob=incoming_blob))
                self.send_response(responses)
                log.debug("send %s to %s:%i", blob.blob_hash[:8], peer_address,
                          peer_port)
                try:
                    sent = await blob.sendfile(self)
                except (ConnectionResetError, BrokenPipeError, RuntimeError,
                        OSError):
                    if self.transport:
                        self.transport.close()
                    return
                log.info("sent %s (%i bytes) to %s:%i", blob.blob_hash[:8],
                         sent, peer_address, peer_port)
        if responses:
            self.send_response(responses)
示例#5
0
 async def test_server_chunked_request(self):
     blob_hash = "7f5ab2def99f0ddd008da71db3a3772135f4002b19b7605840ed1034c8955431bd7079549e65e6b2a3b9c17c773073ed"
     server_protocol = BlobServerProtocol(self.loop, self.server_blob_manager, self.server.lbrycrd_address)
     transport = asyncio.Transport(extra={'peername': ('ip', 90)})
     received_data = BytesIO()
     transport.write = received_data.write
     server_protocol.connection_made(transport)
     blob_request = BlobRequest.make_request_for_blob_hash(blob_hash).serialize()
     for byte in blob_request:
         server_protocol.data_received(bytes([byte]))
     await asyncio.sleep(0.1)  # yield execution
     self.assertGreater(len(received_data.getvalue()), 0)
示例#6
0
async def check_p2p(ip, port):
    writer = None
    try:
        reader, writer = await asyncio.open_connection(ip, port)
        writer.write(
            BlobRequest.make_request_for_blob_hash('0' * 96).serialize())
        return BlobResponse.deserialize(
            await
            reader.readuntil(b'}')).get_address_response().lbrycrd_address
    except OSError:
        return None
    finally:
        if writer:
            writer.close()
            await writer.wait_closed()
示例#7
0
    async def _download_blob(self) -> typing.Tuple[int, typing.Optional[asyncio.Transport]]:
        """
        :return: download success (bool), keep connection (bool)
        """
        request = BlobRequest.make_request_for_blob_hash(self.blob.blob_hash)
        blob_hash = self.blob.blob_hash
        if not self.peer_address:
            addr_info = self.transport.get_extra_info('peername')
            self.peer_address, self.peer_port = addr_info
        try:
            msg = request.serialize()
            log.debug("send request to %s:%i -> %s", self.peer_address, self.peer_port, msg.decode())
            self.transport.write(msg)
            if self.connection_manager:
                self.connection_manager.sent_data(f"{self.peer_address}:{self.peer_port}", len(msg))
            response: BlobResponse = await asyncio.wait_for(self._response_fut, self.peer_timeout, loop=self.loop)
            availability_response = response.get_availability_response()
            price_response = response.get_price_response()
            blob_response = response.get_blob_response()
            if self.closed.is_set():
                msg = f"cancelled blob request for {blob_hash} immediately after we got a response"
                log.warning(msg)
                raise asyncio.CancelledError(msg)
            if (not blob_response or blob_response.error) and\
                    (not availability_response or not availability_response.available_blobs):
                log.warning("%s not in availability response from %s:%i", self.blob.blob_hash, self.peer_address,
                            self.peer_port)
                log.warning(response.to_dict())
                return self._blob_bytes_received, self.close()
            elif availability_response and availability_response.available_blobs and \
                    availability_response.available_blobs != [self.blob.blob_hash]:
                log.warning("blob availability response doesn't match our request from %s:%i",
                            self.peer_address, self.peer_port)
                return self._blob_bytes_received, self.close()
            elif not availability_response:
                log.warning("response from %s:%i did not include an availability response (we requested %s)",
                            self.peer_address, self.peer_port, blob_hash)
                return self._blob_bytes_received, self.close()

            if not price_response or price_response.blob_data_payment_rate != 'RATE_ACCEPTED':
                log.warning("data rate rejected by %s:%i", self.peer_address, self.peer_port)
                return self._blob_bytes_received, self.close()
            if not blob_response or blob_response.error:
                log.warning("blob cant be downloaded from %s:%i", self.peer_address, self.peer_port)
                return self._blob_bytes_received, self.close()
            if not blob_response.error and blob_response.blob_hash != self.blob.blob_hash:
                log.warning("incoming blob hash mismatch from %s:%i", self.peer_address, self.peer_port)
                return self._blob_bytes_received, self.close()
            if self.blob.length is not None and self.blob.length != blob_response.length:
                log.warning("incoming blob unexpected length from %s:%i", self.peer_address, self.peer_port)
                return self._blob_bytes_received, self.close()
            msg = f"downloading {self.blob.blob_hash[:8]} from {self.peer_address}:{self.peer_port}," \
                f" timeout in {self.peer_timeout}"
            log.debug(msg)
            msg = f"downloaded {self.blob.blob_hash[:8]} from {self.peer_address}:{self.peer_port}"
            await asyncio.wait_for(self.writer.finished, self.peer_timeout, loop=self.loop)
            log.info(msg)
            # await self.blob.finished_writing.wait()  not necessary, but a dangerous change. TODO: is it needed?
            return self._blob_bytes_received, self.transport
        except asyncio.TimeoutError:
            return self._blob_bytes_received, self.close()
        except (InvalidBlobHashError, InvalidDataError):
            log.warning("invalid blob from %s:%i", self.peer_address, self.peer_port)
            return self._blob_bytes_received, self.close()