void bitfieldMessage(byte[] bitmap) { synchronized (this) { if (_log.shouldLog(Log.DEBUG)) _log.debug(peer + " rcv bitfield"); if (bitfield != null) { // XXX - Be liberal in what you accept? if (_log.shouldLog(Log.WARN)) _log.warn("Got unexpected bitfield message from " + peer); return; } // XXX - Check for weird bitfield and disconnect? // FIXME will have to regenerate the bitfield after we know exactly // how many pieces there are, as we don't know how many spare bits there are. if (metainfo == null) bitfield = new BitField(bitmap, bitmap.length * 8); else bitfield = new BitField(bitmap, metainfo.getPieces()); } if (metainfo == null) return; boolean interest = listener.gotBitField(peer, bitfield); setInteresting(interest); if (bitfield.complete() && !interest) { // They are seeding and we are seeding, // why did they contact us? (robert) // Dump them quick before we send our whole bitmap if (_log.shouldLog(Log.WARN)) _log.warn("Disconnecting seed that connects to seeds: " + peer); peer.disconnect(true); } }
/** * Switch from magnet mode to normal mode. If we already have the metainfo, this does nothing. * * @param meta non-null * @since 0.8.4 */ public void setMetaInfo(MetaInfo meta) { if (metainfo != null) return; BitField oldBF = bitfield; if (oldBF != null) { if (oldBF.size() != meta.getPieces()) // fix bitfield, it was too big by 1-7 bits bitfield = new BitField(oldBF.getFieldBytes(), meta.getPieces()); // else no extra } else { // it will be initialized later // bitfield = new BitField(meta.getPieces()); } metainfo = meta; if (bitfield != null && bitfield.count() > 0) setInteresting(true); }
void haveMessage(int piece) { if (_log.shouldLog(Log.DEBUG)) _log.debug(peer + " rcv have(" + piece + ")"); // FIXME we will lose these until we get the metainfo if (metainfo == null) return; // Sanity check if (piece < 0 || piece >= metainfo.getPieces()) { // XXX disconnect? if (_log.shouldLog(Log.WARN)) _log.warn("Got strange 'have: " + piece + "' message from " + peer); return; } synchronized (this) { // Can happen if the other side never send a bitfield message. if (bitfield == null) bitfield = new BitField(metainfo.getPieces()); bitfield.set(piece); } if (listener.gotHave(peer, piece)) setInteresting(true); }
/** * Sets whether or not we are interested in pieces from this peer. Defaults to false. When * interest is true and this peer unchokes us then we start downloading from it. Has no effect * when not connected. * * @deprecated unused */ public void setInteresting(boolean interest) { PeerState s = state; if (s != null) s.setInteresting(interest); }
/** * 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); }