package protocolP2P; import protocolP2P.Payload; import protocolP2P.RequestResponseCode; import localException.TransmissionError; import localException.ProtocolError; import localException.InternalError; import localException.SizeError; import tools.BytesArrayTools; import tools.HostItem; /** Representation of payload for load request. * @author Louis Royer * @author Flavien Haas * @author JS Auge * @version 1.0 */ public class LoadRequest extends Payload { private String filename; private long maxSizePartialContent; private long offset; private HostItem hostItem; static final private int OFFSET_POSITION = PAYLOAD_START_POSITION; static final private int MAX_SIZE_PARTIAL_CONTENT_POSITION = OFFSET_POSITION + 8; static final private int FILENAME_SIZE_POSITION = MAX_SIZE_PARTIAL_CONTENT_POSITION + 8; static final private int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4; /** Constructor (typically used by the client) with a filename parameter. * @param filename name of the file to download. Must not be empty. * @param offset offset of the bloc * @param maxSizePartialContent partial content in response should not excess this size, but this can be less (by example if endoffile is reached or server doesn't have the full block requested) * @param hostItem hostItem used by the client to register on the tracker * @throws InternalError */ public LoadRequest(String filename, long offset, long maxSizePartialContent, HostItem hostItem) throws InternalError { super(RequestResponseCode.LOAD_REQUEST); /* assert to help debugging */ assert filename.length() != 0 : "Payload size of LoadRequest must not be empty"; if (filename.length() == 0) { throw new InternalError(); } this.filename = filename; this.maxSizePartialContent = maxSizePartialContent; this.offset = offset; this.hostItem = hostItem; } /** Constructor (typically used by server) with a byte[] parameter containing the Packet received. * @param packet the full Packet received * @throws SizeError * @throws InternalError * @throws ProtocolError * @throws TransmissionError */ protected LoadRequest(byte[] packet) throws TransmissionError, SizeError, ProtocolError, InternalError { super(packet); /* assert to help debugging */ assert requestResponseCode == RequestResponseCode.LOAD_REQUEST : "LoadRequest subclass is incompatible with this Packet, request/response code must be checked before using this constructor"; /* InternalErrorException */ if (requestResponseCode!= RequestResponseCode.LOAD_REQUEST) { throw new InternalError(); } /* Read offset */ offset = BytesArrayTools.readLong(packet, OFFSET_POSITION); /* Read maxSizePartialContent */ maxSizePartialContent = BytesArrayTools.readLong(packet, MAX_SIZE_PARTIAL_CONTENT_POSITION); /* Read filename */ int size = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION); filename = BytesArrayTools.readString(packet, FILENAME_POSITION, size); /* Read hostItem */ int portPosition = FILENAME_POSITION + size; int hostnameStartPosition = portPosition + 2; int hostnameSize = getPayloadSize(packet) - hostnameStartPosition; hostItem = new HostItem(BytesArrayTools.readString(packet, hostnameStartPosition, hostnameSize), BytesArrayTools.readInt16Bits(packet, portPosition)); } /** Returns a byte[] containing Packet with padding. * This Packet is still incomplete and should not be send directly. * ProtocolP2PPacket will use this method to generate the complete Packet. * @return Packet with padding * @throws InternalError */ protected byte[] toPacket() throws InternalError { // compute size int filenameSize = filename.length(); String hostname = hostItem.getHostname(); int size = 1 + FILENAME_POSITION + filenameSize + 2 + hostname.length(); byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; // set Payload size setPayloadSize(size - OFFSET_POSITION, packet); // Write offset BytesArrayTools.write(packet, OFFSET_POSITION, offset); // Write maxSizePartialContent BytesArrayTools.write(packet, MAX_SIZE_PARTIAL_CONTENT_POSITION, maxSizePartialContent); // Write filenameSize BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filenameSize); // Write filename BytesArrayTools.write(packet, filename, FILENAME_POSITION); // Write hostitem int portPosition = FILENAME_POSITION + filenameSize; try { BytesArrayTools.write16Bits(packet, portPosition, hostItem.getPort()); BytesArrayTools.write(packet, hostname, portPosition + 2); return packet; } catch (SizeError e) { throw new InternalError(); } } /** filename getter. * @return filename */ public String getFilename() { return filename; } /** offset getter. * @return offset */ public long getOffset() { return offset; } /** maxSizePartialContent getter. * @return maxSizePartialContent */ public long getMaxSizePartialContent() { return maxSizePartialContent; } /** hostItem getter. * @return hostItem */ public HostItem getHostItem() { return hostItem; } }