// Commented for the Learning branch
package com.limegroup.bittorrent.messages;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* A BitTorrent program sends a Have message to tell a computer it has a numbered piece.
*
* In BitTorrent, a .torrent file has information about a file BitTorrent programs can download and share.
* The .torrent file tells the shared file's size, how many pieces it's broken into, and the size of a piece.
* Each piece has a number, and the first piece is number 0.
*
* A Have message is 9 bytes long:
*
* LLLLTPPPP
*
* LLLL and NNNN are ints with big endian byte ordering.
* LLLL is the length of the rest of the message, 5.
* T is the type code, 0x04 for a Have message.
* PPPP is the piece number.
*/
public class BTHave extends BTMessage {
/**
* The payload of this Have message.
* An entire Have message looks like "LLLLTNNNN", with length, type, and piece number.
* The payload is just the piece number, "NNNN".
*/
private ByteBuffer _payload = null;
/**
* The file piece number the computer that sends this Have message has.
*
* In BitTorrent, a file is split into pieces.
* Each piece has a number, with the first piece being number 0.
* When a computer gets a piece and checks it's hash, it tells others with a Have message. (do)
*/
private final int _pieceNum;
/**
* Make a new BTHave object to represent a BitTorrent Have message.
*
* @param pieceNum The file piece number to write in the new message
*/
private BTHave(int pieceNum) {
// Call the BTMessage constructor, giving it the type byte 0x04 Have
super(HAVE);
// Save the given piece number
_pieceNum = pieceNum;
}
/**
* Parse the data of a Have message from a remote computer into a BTHave object.
* This is the message parser.
*
* Only BTMessage.parseMessage() calls this method.
*
* A BitTorrent Not Interested message is 9 bytes, like "LLLLTNNNN".
* LLLL is the length, 1, in big endian in 4 bytes.
* T is the type byte, 0x04 for a Have message.
* NNNN is the piece number.
*
* @param payload A ByteBuffer with the data of a Not Interested message a remote computer sent us.
* We've already read the LLLL prefix and the T type byte.
* The 4 bytes of the piece number are still in the buffer.
* This method moves position forward 4 bytes, to length, closing the buffer.
*/
public static BTHave readMessage(ByteBuffer payload) throws BadBTMessageException {
// Make sure there are 4 bytes left in the buffer, this is the NNNN piece number
if (payload.remaining() != 4) throw new BadBTMessageException("unexpected payload in have message: " + new String(payload.array()));
// Read the piece number from the buffer
payload.order(ByteOrder.BIG_ENDIAN);
int pieceNum = payload.getInt(); // Moves position past the NNNN piece number, closing it to length
/*
* Every integer in the BitTorrent peer protocol is unsigned.
* But, the int type in Java is signed.
* If the piece number we read is big enough to flip it to a negative number in Java, we treat it as invalid.
*/
// Make sure the piece number isn't so big that Java treats the int as negative
if (pieceNum < 0) throw new BadBTMessageException("invalid piece number in have message: " + pieceNum);
// Return a new BTHave object with the piece number we read
return new BTHave(pieceNum);
}
/**
* Make a new BTHave message we can send to tell a remote computer a piece number we have.
*
* @param pieceNum The file piece number we have
* @return A new BTHave object that represents a BitTorrent Have message with the given piece number written in it
*/
public static BTHave createMessage(int pieceNum) {
// Not used
ByteBuffer buf = ByteBuffer.allocate(4);
buf.order(ByteOrder.BIG_ENDIAN);
buf.putInt(pieceNum);
buf.clear();
// Return a new BTHave object with the given piece number
return new BTHave(pieceNum);
}
/**
* Get the piece number this Have message contains.
* This is a piece of the file the computer that sends this message has.
* The first piece is numbered 0.
* The size of the pieces are defined in the .torrent file.
*
* @return The piece number
*/
public int getPieceNum() {
// Return the piece number we saved or parsed
return _pieceNum;
}
/**
* Compose the payload of this Have message.
* An entire Have message consists of 9 bytes:
*
* LLLLTNNNN
*
* LLLL is the size of the rest, 5.
* T is 0x04 for a Have message.
* NNNN is the piece number written in 4 bytes in big endian order.
*
* getPayload() just returns NNNN, the part after the length and type.
*
* @return A 4-byte ByteBuffer with position at the start and length at the end
*/
public ByteBuffer getPayload() {
// If we haven't composed the payload for this Have message yet
if (_payload == null) {
// Compose it
_payload = ByteBuffer.allocate(4); // Make a ByteBuffer that holds exactly 4 bytes
_payload.order(ByteOrder.BIG_ENDIAN); // Have it write the numbers we put in it in big endian order
_payload.putInt(_pieceNum); // Write a 4-byte int, the piece number of this BTHave object
_payload = _payload.asReadOnlyBuffer(); // Make a read-only buffer from that, and point _payload at it instead
}
// Move position to the start and length to the end to clip around the data in the ByteBuffer
_payload.clear();
// Return a reference to the ByteBuffer we prepared
return _payload;
}
/**
* Express this BTHave object as text.
* Composes text like "BTHave (258)" if this Have message has a piece number of 258.
*
* @return A String
*/
public String toString() {
// Compose and return text that includes the piece number
return "BTHave (" + _pieceNum + ")";
}
}