Beispiel #1
0
 /**
  * Bytes not yet in storage. Does NOT account for skipped files.
  *
  * @return exact value. or -1 if no storage yet. getNeeded() * pieceLength(0) isn't accurate if
  *     last piece is still needed.
  * @since 0.8.9
  */
 public long getRemainingLength() {
   if (meta != null && storage != null) {
     long needed = storage.needed();
     long length0 = meta.getPieceLength(0);
     long remaining = needed * length0;
     // fixup if last piece is needed
     int last = meta.getPieces() - 1;
     if (last != 0 && !storage.getBitField().get(last))
       remaining -= length0 - meta.getPieceLength(last);
     return remaining;
   }
   return -1;
 }
Beispiel #2
0
  void requestMessage(int piece, int begin, int length) {
    if (_log.shouldLog(Log.DEBUG))
      _log.debug(peer + " rcv request(" + piece + ", " + begin + ", " + length + ") ");
    if (metainfo == null) return;
    if (choking) {
      if (_log.shouldLog(Log.INFO)) _log.info("Request received, but choking " + peer);
      return;
    }

    // Sanity check
    if (piece < 0
        || piece >= metainfo.getPieces()
        || begin < 0
        || begin > metainfo.getPieceLength(piece)
        || length <= 0
        || length > MAX_PARTSIZE) {
      // XXX - Protocol error -> disconnect?
      if (_log.shouldLog(Log.WARN))
        _log.warn(
            "Got strange 'request: "
                + piece
                + ", "
                + begin
                + ", "
                + length
                + "' message from "
                + peer);
      return;
    }

    // Limit total pipelined requests to MAX_PIPELINE bytes
    // to conserve memory and prevent DOS
    // Todo: limit number of requests also? (robert 64 x 4KB)
    if (out.queuedBytes() + length > MAX_PIPELINE_BYTES) {
      if (_log.shouldLog(Log.WARN))
        _log.warn("Discarding request over pipeline limit from " + peer);
      return;
    }

    if (_log.shouldLog(Log.DEBUG))
      _log.debug("Queueing (" + piece + ", " + begin + ", " + length + ")" + " to " + peer);

    // don't load the data into mem now, let PeerConnectionOut do it
    out.sendPiece(piece, begin, length, this);
  }
Beispiel #3
0
  /**
   * Adds a new request to the outstanding requests list. Then send interested if we weren't. Then
   * send new requests if not choked. If nothing to request, send not interested if we were.
   *
   * <p>This is called from several places:
   *
   * <pre>
   *   By getOustandingRequest() when the first part of a chunk comes in
   *   By havePiece() when somebody got a new piece completed
   *   By chokeMessage() when we receive an unchoke
   *   By setInteresting() when we are now interested
   *   By PeerCoordinator.updatePiecePriorities()
   * </pre>
   */
  synchronized void addRequest() {
    // no bitfield yet? nothing to request then.
    if (bitfield == null) return;
    if (metainfo == null) return;
    boolean more_pieces = true;
    while (more_pieces) {
      more_pieces = outstandingRequests.size() < MAX_PIPELINE;
      // We want something and we don't have outstanding requests?
      if (more_pieces && lastRequest == null) {
        // we have nothing in the queue right now
        if (!interesting) {
          // If we need something, set interesting but delay pulling
          // a request from the PeerCoordinator until unchoked.
          if (listener.needPiece(this.peer, bitfield)) {
            setInteresting(true);
            if (_log.shouldLog(Log.DEBUG))
              _log.debug(
                  peer
                      + " addRequest() we need something, setting interesting, delaying requestNextPiece()");
          } else {
            if (_log.shouldLog(Log.DEBUG)) _log.debug(peer + " addRequest() needs nothing");
          }
          return;
        }
        if (choked) {
          // If choked, delay pulling
          // a request from the PeerCoordinator until unchoked.
          if (_log.shouldLog(Log.DEBUG))
            _log.debug(peer + " addRequest() we are choked, delaying requestNextPiece()");
          return;
        }
        // huh? rv unused
        more_pieces = requestNextPiece();
      } else if (more_pieces) // We want something
      {
        int pieceLength;
        boolean isLastChunk;
        pieceLength = metainfo.getPieceLength(lastRequest.getPiece());
        isLastChunk = lastRequest.off + lastRequest.len == pieceLength;

        // Last part of a piece?
        if (isLastChunk) more_pieces = requestNextPiece();
        else {
          PartialPiece nextPiece = lastRequest.getPartialPiece();
          int nextBegin = lastRequest.off + PARTSIZE;
          int maxLength = pieceLength - nextBegin;
          int nextLength = maxLength > PARTSIZE ? PARTSIZE : maxLength;
          Request req = new Request(nextPiece, nextBegin, nextLength);
          outstandingRequests.add(req);
          if (!choked) out.sendRequest(req);
          lastRequest = req;
        }
      }
    }

    // failsafe
    // However this is bad as it thrashes the peer when we change our mind
    // Ticket 691 cause here?
    if (interesting && lastRequest == null && outstandingRequests.isEmpty()) setInteresting(false);

    if (_log.shouldLog(Log.DEBUG)) _log.debug(peer + " requests " + outstandingRequests);
  }
Beispiel #4
0
 /**
  * @param p the piece number
  * @return metainfo piece length or 16K if fetching magnet
  * @since 0.8.4
  */
 public int getPieceLength(int p) {
   if (meta != null) return meta.getPieceLength(p);
   return 16 * 1024;
 }