/** * 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; }
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); }
/** * 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); }
/** * @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; }