this.interested = false;
break;
case HAVE:
// Record this peer has the given piece
PeerMessage.HaveMessage have = (PeerMessage.HaveMessage)msg;
Piece havePiece = this.torrent.getPiece(have.getPieceIndex());
synchronized (this.availablePieces) {
this.availablePieces.set(havePiece.getIndex());
logger.trace("Peer {} now has {} [{}/{}].",
new Object[] {
this,
havePiece,
this.availablePieces.cardinality(),
this.torrent.getPieceCount()
});
}
this.firePieceAvailabity(havePiece);
break;
case BITFIELD:
// Augment the hasPiece bit field from this BITFIELD message
PeerMessage.BitfieldMessage bitfield =
(PeerMessage.BitfieldMessage)msg;
synchronized (this.availablePieces) {
this.availablePieces.or(bitfield.getBitfield());
logger.trace("Recorded bitfield from {} with {} " +
"pieces(s) [{}/{}].",
new Object[] {
this,
bitfield.getBitfield().cardinality(),
this.availablePieces.cardinality(),
this.torrent.getPieceCount()
});
}
this.fireBitfieldAvailabity();
break;
case REQUEST:
PeerMessage.RequestMessage request =
(PeerMessage.RequestMessage)msg;
Piece rp = this.torrent.getPiece(request.getPiece());
// If we are choking from this peer and it still sends us
// requests, it is a violation of the BitTorrent protocol.
// Similarly, if the peer requests a piece we don't have, it
// is a violation of the BitTorrent protocol. In these
// situation, terminate the connection.
if (this.isChoking() || !rp.isValid()) {
logger.warn("Peer {} violated protocol, " +
"terminating exchange.", this);
this.unbind(true);
break;
}
if (request.getLength() >
PeerMessage.RequestMessage.MAX_REQUEST_SIZE) {
logger.warn("Peer {} requested a block too big, " +
"terminating exchange.", this);
this.unbind(true);
break;
}
// At this point we agree to send the requested piece block to
// the remote peer, so let's queue a message with that block
try {
ByteBuffer block = rp.read(request.getOffset(),
request.getLength());
this.send(PeerMessage.PieceMessage.craft(request.getPiece(),
request.getOffset(), block));
this.upload.add(block.capacity());
if (request.getOffset() + request.getLength() == rp.size()) {
this.firePieceSent(rp);
}
} catch (IOException ioe) {
this.fireIOException(new IOException(
"Error while sending piece block request!", ioe));
}
break;
case PIECE:
// Record the incoming piece block.
// Should we keep track of the requested pieces and act when we
// get a piece we didn't ask for, or should we just stay
// greedy?
PeerMessage.PieceMessage piece = (PeerMessage.PieceMessage)msg;
Piece p = this.torrent.getPiece(piece.getPiece());
// Remove the corresponding request from the request queue to
// make room for next block requests.
this.removeBlockRequest(piece);
this.download.add(piece.getBlock().capacity());
try {
synchronized (p) {
if (p.isValid()) {
this.requestedPiece = null;
this.cancelPendingRequests();
this.firePeerReady();
logger.debug("Discarding block for already completed " + p);
break;
}
p.record(piece.getBlock(), piece.getOffset());
// If the block offset equals the piece size and the block
// length is 0, it means the piece has been entirely
// downloaded. In this case, we have nothing to save, but
// we should validate the piece.
if (piece.getOffset() + piece.getBlock().capacity()
== p.size()) {
p.validate();
this.firePieceCompleted(p);
this.requestedPiece = null;
this.firePeerReady();
} else {
this.requestNextBlocks();