Change to ProtocolP2PPacket, should be easier to implement tcp

pull/20/head
Louis Royer 4 years ago
parent c17a7e6cd5
commit b6351d30d3

@ -20,7 +20,7 @@ import java.nio.file.Files;
import java.io.File; import java.io.File;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import protocolP2P.ProtocolP2PDatagram; import protocolP2P.ProtocolP2PPacketUDP;
import protocolP2P.Payload; import protocolP2P.Payload;
import protocolP2P.RequestResponseCode; import protocolP2P.RequestResponseCode;
import protocolP2P.FileList; import protocolP2P.FileList;
@ -52,9 +52,13 @@ public class ClientManagementUDP implements Runnable {
this.UDPPort = UDPPort; this.UDPPort = UDPPort;
try { try {
socket = new DatagramSocket(); socket = new DatagramSocket();
socket.connect(InetAddress.getByName(host), UDPPort);
} catch (SocketException e) { } catch (SocketException e) {
System.err.println("Error: No socket available."); System.err.println("Error: No socket available.");
System.exit(-1); System.exit(-1);
} catch (UnknownHostException e) {
System.err.println("Error: Unknown host.");
System.exit(-1);
} }
} }
@ -118,13 +122,13 @@ public class ClientManagementUDP implements Runnable {
*/ */
private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
final long MAX_PARTIAL_SIZE = 1024; final long MAX_PARTIAL_SIZE = 1024;
ProtocolP2PDatagram d = new ProtocolP2PDatagram((Payload) new LoadRequest(filename, 0, MAX_PARTIAL_SIZE)); ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP((Payload) new LoadRequest(filename, 0, MAX_PARTIAL_SIZE));
d.send(socket, host, UDPPort); d.sendRequest((Object)socket);
boolean fileFullyWritten = false; boolean fileFullyWritten = false;
long offset = 0; long offset = 0;
do { do {
try { try {
Payload p = ProtocolP2PDatagram.receive(socket).getPayload(); Payload p = d.receiveResponse().getPayload();
assert p instanceof FilePart : "This payload must be instance of FilePart"; assert p instanceof FilePart : "This payload must be instance of FilePart";
if (!(p instanceof FilePart)) { if (!(p instanceof FilePart)) {
throw new InternalError(); throw new InternalError();
@ -148,8 +152,8 @@ public class ClientManagementUDP implements Runnable {
// next partialContentRequest // next partialContentRequest
if (offset != fp.getTotalSize()) { if (offset != fp.getTotalSize()) {
System.err.println("Sending following request with offset: " + offset + " maxpartialsize: " + MAX_PARTIAL_SIZE); System.err.println("Sending following request with offset: " + offset + " maxpartialsize: " + MAX_PARTIAL_SIZE);
d = new ProtocolP2PDatagram((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE)); d = new ProtocolP2PPacketUDP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
d.send(socket, host, UDPPort); d.sendRequest((Object)socket);
} else { } else {
fileFullyWritten = true; fileFullyWritten = true;
} }
@ -168,8 +172,8 @@ public class ClientManagementUDP implements Runnable {
fileFullyWritten = true; fileFullyWritten = true;
} else { } else {
// next partialContentRequest // next partialContentRequest
d = new ProtocolP2PDatagram((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE)); d = new ProtocolP2PPacketUDP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
d.send(socket, host, UDPPort); d.sendRequest((Object)socket);
} }
} else { } else {
@ -199,10 +203,10 @@ public class ClientManagementUDP implements Runnable {
* @throws VersionRemoteError * @throws VersionRemoteError
*/ */
private String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { private String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
ProtocolP2PDatagram d = new ProtocolP2PDatagram(new Payload(RequestResponseCode.LIST_REQUEST)); ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.LIST_REQUEST));
d.send(socket, host, UDPPort); d.sendRequest((Object)socket);
try { try {
Payload p = ProtocolP2PDatagram.receive(socket).getPayload(); Payload p = d.receiveResponse().getPayload();
assert p instanceof FileList : "This payload must be instance of Filelist"; assert p instanceof FileList : "This payload must be instance of Filelist";
if (!(p instanceof FileList)) { if (!(p instanceof FileList)) {
throw new InternalError(); throw new InternalError();

@ -1,6 +1,6 @@
package clientP2P; package clientP2P;
import clientP2P.ClientManagementUDP; import clientP2P.ClientManagementUDP;
import clientP2P.ClientManagementTCP; //import clientP2P.ClientManagementTCP;
import tools.Directories; import tools.Directories;
import java.util.Scanner; import java.util.Scanner;
@ -21,20 +21,24 @@ public class ClientP2P {
System.out.println("Which transport protocol do you want to use? [TCP/udp]"); System.out.println("Which transport protocol do you want to use? [TCP/udp]");
Scanner sc = new Scanner(System.in); Scanner sc = new Scanner(System.in);
String transportchoosen = sc.nextLine(); String transportchoosen = sc.nextLine();
Thread t;
switch(transportchoosen){ switch(transportchoosen){
case "UDP": case "UDP":
case "udp": case "udp":
case "2" : case "2" :
ClientManagementUDP cm = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.host, c.port); ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.host, c.port);
t = new Thread(cmudp);
break; break;
case "TCP": case "TCP":
case "tcp": case "tcp":
case "1": case "1":
default: default:
ClientManagementTCP cm = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.host, c.port); //ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.host, c.port);
break; //t = new Thread(cmtcp);
//break;
throw new java.lang.UnsupportedOperationException();
} }
Thread t = new Thread(cm);
t.setName("client P2P-JAVA-PROJECT"); t.setName("client P2P-JAVA-PROJECT");
t.start(); t.start();
} }

@ -1,5 +1,5 @@
package exception; package exception;
/** Used on reception side when size as set in datagram is too big, and we cant store this in a int/long as usual. */ /** Used on reception side when size as set in Packet is too big, and we cant store this in a int/long as usual. */
public class SizeError extends Exception { public class SizeError extends Exception {
private static final long serialVersionUID = 12L; private static final long serialVersionUID = 12L;
} }

@ -32,54 +32,54 @@ public class FileList extends Payload {
this.fileList = fileList; this.fileList = fileList;
} }
/** Constructor (typically used by client) with a byte[] parameter containing the datagram received. /** Constructor (typically used by client) with a byte[] parameter containing the Packet received.
* @param datagram the full datagram received * @param packet the full packet received
* @throws SizeError * @throws SizeError
* @throws InternalError * @throws InternalError
* @throws ProtocolError * @throws ProtocolError
* @throws TransmissionError * @throws TransmissionError
*/ */
protected FileList(byte[] datagram) throws TransmissionError, SizeError, ProtocolError, InternalError { protected FileList(byte[] packet) throws TransmissionError, SizeError, ProtocolError, InternalError {
super(datagram); super(packet);
/* assert to help debugging */ /* assert to help debugging */
assert requestResponseCode == RequestResponseCode.LIST_RESPONSE : "FileList subclass is incompatible with this datagram, request/response code must be checked before using this constructor"; assert requestResponseCode == RequestResponseCode.LIST_RESPONSE : "FileList subclass is incompatible with this Packet, request/response code must be checked before using this constructor";
/* InternalErrorException */ /* InternalErrorException */
if (requestResponseCode!= RequestResponseCode.LIST_RESPONSE) { if (requestResponseCode!= RequestResponseCode.LIST_RESPONSE) {
throw new InternalError(); throw new InternalError();
} }
int size = getPayloadSize(datagram); int size = getPayloadSize(packet);
try { try {
fileList = (new String(datagram, 8, size, "UTF-8")).split("\n"); fileList = (new String(packet, PAYLOAD_START_POSITION, size, "UTF-8")).split("\n");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new InternalError(); throw new InternalError();
} }
} }
/** Returns a byte[] containing datagram with padding. /** Returns a byte[] containing Packet with padding.
* This datagram is still incomplete and should not be send directly. * This Packet is still incomplete and should not be send directly.
* ProtocolP2PDatagram will use this method to generate the complete datagram. * ProtocolP2PPacket will use this method to generate the complete Packet.
* @return datagram with padding * @return Packet with padding
* @throws InternalError * @throws InternalError
*/ */
protected byte[] toDatagram() throws InternalError { protected byte[] toPacket() throws InternalError {
// compute size // compute size
int size = 8; int size = PAYLOAD_START_POSITION;
for (String s : fileList) { for (String s : fileList) {
size += s.length(); size += s.length();
size += 1; size += 1; // size for '\n'
} }
size -=1; size -=1; // remove trailing '\n'
byte[] datagram = new byte[size]; // java initialize all to zero byte[] packet = new byte[size]; // java initialize all to zero
// set request/response code // set request/response code
datagram[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
// bits 16-31 are reserved for future use // set payload size
setPayloadSize(size - 8, datagram); setPayloadSize(size - PAYLOAD_START_POSITION, packet);
// Write fileList // Write fileList
int bCount = 8; int bCount = PAYLOAD_START_POSITION;
for(String s : fileList) { for(String s : fileList) {
if (bCount != 8) { // not on first iteration if (bCount != PAYLOAD_START_POSITION) { // not on first iteration
try { try {
datagram[bCount] = "\n".getBytes("UTF-8")[0]; // separator packet[bCount] = "\n".getBytes("UTF-8")[0]; // separator
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new InternalError(); throw new InternalError();
} }
@ -89,7 +89,7 @@ public class FileList extends Payload {
try { try {
byte[] sb = s.getBytes("UTF-8"); byte[] sb = s.getBytes("UTF-8");
for(byte b : sb) { for(byte b : sb) {
datagram[bCount] = b; packet[bCount] = b;
bCount += 1; bCount += 1;
} }
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
@ -97,7 +97,7 @@ public class FileList extends Payload {
} }
} }
return datagram; return packet;
} }
/** fileList getter. /** fileList getter.

@ -20,7 +20,7 @@ public class FilePart extends Payload {
private long totalSize; private long totalSize;
private long offset; private long offset;
private byte[] partialContent; private byte[] partialContent;
static final private int OFFSET_POSITION = 8; static final private int OFFSET_POSITION = PAYLOAD_START_POSITION;
static final private int TOTAL_FILESIZE_POSITION = OFFSET_POSITION + 8; static final private int TOTAL_FILESIZE_POSITION = OFFSET_POSITION + 8;
static final private int FILENAME_SIZE_POSITION = TOTAL_FILESIZE_POSITION + 8; static final private int FILENAME_SIZE_POSITION = TOTAL_FILESIZE_POSITION + 8;
static final private int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4; static final private int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4;
@ -50,123 +50,123 @@ public class FilePart extends Payload {
this.partialContent = partialContent; this.partialContent = partialContent;
} }
/** Constructor (typically used by client) with datagram received as parameter. /** Constructor (typically used by client) with Packet received as parameter.
* @param datagram the full datagram received * @param packet the full Packet received
* @throws SizeError * @throws SizeError
* @throws InternalError * @throws InternalError
* @throws TransmissionError * @throws TransmissionError
*/ */
protected FilePart(byte[] datagram) throws TransmissionError, SizeError, ProtocolError, InternalError { protected FilePart(byte[] packet) throws TransmissionError, SizeError, ProtocolError, InternalError {
super(datagram); super(packet);
/* assert to help debugging */ /* assert to help debugging */
assert requestResponseCode == RequestResponseCode.LOAD_RESPONSE : "FilePart subclass is incompatible with this datagram, request/response code must be checked before using this constructor"; assert requestResponseCode == RequestResponseCode.LOAD_RESPONSE : "FilePart subclass is incompatible with this Packet, request/response code must be checked before using this constructor";
/* InternalErrorException */ /* InternalErrorException */
if (requestResponseCode != RequestResponseCode.LOAD_RESPONSE) { if (requestResponseCode != RequestResponseCode.LOAD_RESPONSE) {
throw new InternalError(); throw new InternalError();
} }
setOffset(datagram); // this can throw SizeError setOffset(packet); // this can throw SizeError
setTotalSize(datagram); // this can throw SizeError setTotalSize(packet); // this can throw SizeError
setFilename(datagram); // this can throw ProtocolError, SizeError setFilename(packet); // this can throw ProtocolError, SizeError
setPartialContent(datagram); // this can throw SizeError setPartialContent(packet); // this can throw SizeError
} }
/** Returns a byte[] containing datagram with padding. /** Returns a byte[] containing Packet with padding.
* This datagram is still incomplete and should not be send directly. * This Packet is still incomplete and should not be send directly.
* ProtocolP2PDatagram will use this method to generate the complete datagram. * ProtocolP2PPacket will use this method to generate the complete Packet.
* @return datagram with padding * @return Packet with padding
* @throws InternalError * @throws InternalError
*/ */
protected byte[] toDatagram() throws InternalError { protected byte[] toPacket() throws InternalError {
// compute total size // compute total size
int size = FILENAME_POSITION + filename.length() + partialContent.length; int size = FILENAME_POSITION + filename.length() + partialContent.length;
byte[] datagram = new byte[size + 1]; // java initialize all to zero byte[] packet = new byte[size + 1]; // java initialize all to zero
// set request/response code // set request/response code
datagram[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
// bits 16-31 are reserved for future use // set Payload size
setPayloadSize(size - OFFSET_POSITION, datagram); setPayloadSize(size - OFFSET_POSITION, packet);
// write offset to datagram // write offset to Packet
BytesArrayTools.write(datagram, OFFSET_POSITION, (long)offset); BytesArrayTools.write(packet, OFFSET_POSITION, offset);
// write totalSize to datagram // write totalSize to Packet
BytesArrayTools.write(datagram, TOTAL_FILESIZE_POSITION, (long)totalSize); BytesArrayTools.write(packet, TOTAL_FILESIZE_POSITION, totalSize);
// write filenames size to datagram // write filenames size to Packet
BytesArrayTools.write(datagram, FILENAME_SIZE_POSITION, (int)filename.length()); BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filename.length());
try { try {
// write filename to datagram // write filename to Packet
int i = FILENAME_POSITION; int i = FILENAME_POSITION;
for (byte b : filename.getBytes("UTF-8")) { for (byte b : filename.getBytes("UTF-8")) {
datagram[i] = b; packet[i] = b;
i += 1; i += 1;
} }
// write partialContent to datagram // write partialContent to Packet
for (byte b: partialContent) { for (byte b: partialContent) {
datagram[i] = b; packet[i] = b;
i += 1; i += 1;
} }
return datagram; return packet;
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new InternalError(); throw new InternalError();
} }
} }
/** Write from datagram into offset. /** Write from Packet into offset.
* @param datagram received datagram * @param packet received Packet
* @throws SizeError * @throws SizeError
*/ */
private void setOffset(byte[] datagram) throws SizeError { private void setOffset(byte[] packet) throws SizeError {
offset = BytesArrayTools.readLong(datagram, OFFSET_POSITION); offset = BytesArrayTools.readLong(packet, OFFSET_POSITION);
} }
/** Write from datagram into totalSize. /** Write from Packet into totalSize.
* @param datagram received datagram * @param packet received Packet
* @throws SizeError * @throws SizeError
*/ */
private void setTotalSize(byte[] datagram) throws SizeError { private void setTotalSize(byte[] packet) throws SizeError {
totalSize = BytesArrayTools.readLong(datagram, TOTAL_FILESIZE_POSITION); totalSize = BytesArrayTools.readLong(packet, TOTAL_FILESIZE_POSITION);
} }
/** Read filenames size from datagram. /** Read filenames size from Packet.
* @param datagram received datagram * @param packet received Packet
* @throws ProtocolError * @throws ProtocolError
* @throws SizeError * @throws SizeError
* @return filenames size * @return filenames size
*/ */
private int getFilenameSize(byte[] datagram) throws SizeError, ProtocolError { private int getFilenameSize(byte[] packet) throws SizeError, ProtocolError {
int size = BytesArrayTools.readInt(datagram, FILENAME_SIZE_POSITION); // this can throw SizeError int size = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION); // this can throw SizeError
// filename size cannot be zero // filename size cannot be zero
if (size == 0) { if (size == 0) {
throw new ProtocolError(); throw new ProtocolError();
} }
// cannot excess datagram size // cannot excess packet size
if ((FILENAME_POSITION + size) > (getPayloadSize(datagram) + OFFSET_POSITION)) { if ((FILENAME_POSITION + size) > (getPayloadSize(packet) + OFFSET_POSITION)) {
throw new ProtocolError(); throw new ProtocolError();
} }
return size; return size;
} }
/** Write from datagram into filename. /** Write from Packet into filename.
* @param datagram received datagram * @param packet received Packet
* @throws ProtocolError * @throws ProtocolError
* @throws SizeError * @throws SizeError
* @throws InternalError * @throws InternalError
*/ */
private void setFilename(byte[] datagram) throws ProtocolError, SizeError, InternalError { private void setFilename(byte[] packet) throws ProtocolError, SizeError, InternalError {
int filenameSize = getFilenameSize(datagram); // this can throw ProtocolError or SizeError int filenameSize = getFilenameSize(packet); // this can throw ProtocolError or SizeError
try { try {
filename = new String(datagram, FILENAME_POSITION, filenameSize, "UTF-8"); filename = new String(packet, FILENAME_POSITION, filenameSize, "UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new InternalError(); throw new InternalError();
} }
} }
/** Write from datagram into partialContent. /** Write from Packet into partialContent.
* @param datagram received datagram * @param packet received Packet
* @throws SizeError * @throws SizeError
* @throws ProtocolError * @throws ProtocolError
*/ */
private void setPartialContent(byte[] datagram) throws ProtocolError, SizeError { private void setPartialContent(byte[] packet) throws ProtocolError, SizeError {
int start = FILENAME_POSITION + getFilenameSize(datagram); // this can throw SizeError or ProtocolError int start = FILENAME_POSITION + getFilenameSize(packet); // this can throw SizeError or ProtocolError
int end = OFFSET_POSITION + getPayloadSize(datagram); // this can throw SizeError int end = OFFSET_POSITION + getPayloadSize(packet); // this can throw SizeError
try { try {
partialContent = Arrays.copyOfRange(datagram, start, end); partialContent = Arrays.copyOfRange(packet, start, end);
} catch (ArrayIndexOutOfBoundsException e) { } catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolError(); throw new ProtocolError();
} }

@ -18,7 +18,7 @@ public class LoadRequest extends Payload {
private String filename; private String filename;
private long maxSizePartialContent; private long maxSizePartialContent;
private long offset; private long offset;
static final private int OFFSET_POSITION = 8; 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 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_SIZE_POSITION = MAX_SIZE_PARTIAL_CONTENT_POSITION + 8;
static final private int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4; static final private int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4;
@ -41,74 +41,75 @@ public class LoadRequest extends Payload {
this.offset = offset; this.offset = offset;
} }
/** Constructor (typically used by client) with a byte[] parameter containing the datagram received. /** Constructor (typically used by client) with a byte[] parameter containing the Packet received.
* @param datagram the full datagram received * @param packet the full Packet received
* @throws SizeError * @throws SizeError
* @throws InternalError * @throws InternalError
* @throws ProtocolError * @throws ProtocolError
* @throws TransmissionError * @throws TransmissionError
*/ */
protected LoadRequest(byte[] datagram) throws TransmissionError, SizeError, ProtocolError, InternalError { protected LoadRequest(byte[] packet) throws TransmissionError, SizeError, ProtocolError, InternalError {
super(datagram); super(packet);
/* assert to help debugging */ /* assert to help debugging */
assert requestResponseCode == RequestResponseCode.LOAD_REQUEST : "LoadRequest subclass is incompatible with this datagram, request/response code must be checked before using this constructor"; assert requestResponseCode == RequestResponseCode.LOAD_REQUEST : "LoadRequest subclass is incompatible with this Packet, request/response code must be checked before using this constructor";
/* InternalErrorException */ /* InternalErrorException */
if (requestResponseCode!= RequestResponseCode.LOAD_REQUEST) { if (requestResponseCode!= RequestResponseCode.LOAD_REQUEST) {
throw new InternalError(); throw new InternalError();
} }
/* Read offset */ /* Read offset */
offset = BytesArrayTools.readLong(datagram, OFFSET_POSITION); offset = BytesArrayTools.readLong(packet, OFFSET_POSITION);
/* Read maxSizePartialContent */ /* Read maxSizePartialContent */
maxSizePartialContent = BytesArrayTools.readLong(datagram, MAX_SIZE_PARTIAL_CONTENT_POSITION); maxSizePartialContent = BytesArrayTools.readLong(packet, MAX_SIZE_PARTIAL_CONTENT_POSITION);
/* Read filename */ /* Read filename */
int size = BytesArrayTools.readInt(datagram, FILENAME_SIZE_POSITION); int size = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION);
try { try {
filename = new String(datagram, FILENAME_POSITION, size, "UTF-8"); filename = new String(packet, FILENAME_POSITION, size, "UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new InternalError(); throw new InternalError();
} }
} }
/** Returns a byte[] containing datagram with padding. /** Returns a byte[] containing Packet with padding.
* This datagram is still incomplete and should not be send directly. * This Packet is still incomplete and should not be send directly.
* ProtocolP2PDatagram will use this method to generate the complete datagram. * ProtocolP2PPacket will use this method to generate the complete Packet.
* @return datagram with padding * @return Packet with padding
* @throws InternalError * @throws InternalError
*/ */
protected byte[] toDatagram() throws InternalError { protected byte[] toPacket() throws InternalError {
// compute size // compute size
int filenameSize = filename.length(); int filenameSize = filename.length();
int size = FILENAME_POSITION + filenameSize; int size = FILENAME_POSITION + filenameSize;
byte[] datagram = new byte[size + 1]; // java initialize all to zero byte[] packet = new byte[size + 1]; // java initialize all to zero
// set request/response code // set request/response code
datagram[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
// bits 16-31 are reserved for future use
// 8 bytes for headers // set Payload size
setPayloadSize(size - OFFSET_POSITION, datagram); setPayloadSize(size - OFFSET_POSITION, packet);
// Write offset // Write offset
BytesArrayTools.write(datagram, OFFSET_POSITION, (long)offset); BytesArrayTools.write(packet, OFFSET_POSITION, (long)offset);
// Write maxSizePartialContent // Write maxSizePartialContent
BytesArrayTools.write(datagram, MAX_SIZE_PARTIAL_CONTENT_POSITION, (long)maxSizePartialContent); BytesArrayTools.write(packet, MAX_SIZE_PARTIAL_CONTENT_POSITION, (long)maxSizePartialContent);
// Write filenameSize // Write filenameSize
BytesArrayTools.write(datagram, FILENAME_SIZE_POSITION, (int)filenameSize); BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, (int)filenameSize);
// Write filename // Write filename
int bCount = FILENAME_POSITION; int bCount = FILENAME_POSITION;
try { try {
byte[] sb = filename.getBytes("UTF-8"); byte[] sb = filename.getBytes("UTF-8");
for(byte b : sb) { for(byte b : sb) {
datagram[bCount] = b; packet[bCount] = b;
bCount += 1; bCount += 1;
} }
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new InternalError(); throw new InternalError();
} }
return datagram; return packet;
} }
/** filename getter. /** filename getter.

@ -32,24 +32,24 @@ public class Payload {
checkRequestResponseCode(); // this can throw InternalError checkRequestResponseCode(); // this can throw InternalError
} }
/** Constructor used to create a Payload (when no more specific subclasses exists) using datagram as parameter. /** Constructor used to create a Payload (when no more specific subclasses exists) using packet as parameter.
* If payload size is not empty, using subclass is required. * If payload size is not empty, using subclass is required.
* @param datagram the full datagram received * @param packet the full packet received
* @throws ProtocolError * @throws ProtocolError
* @throws InternalError * @throws InternalError
* @throws TransmissionError * @throws TransmissionError
* @throws SizeError * @throws SizeError
*/ */
protected Payload(byte[] datagram) throws SizeError, ProtocolError, InternalError, TransmissionError { protected Payload(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError {
/* asserts to help debugging */ /* asserts to help debugging */
assert getPayloadSize(datagram) + 8 <= datagram.length : "Payload is truncated"; assert getPayloadSize(packet) + 8 <= packet.length : "Payload is truncated";
if (datagram.length < getPayloadSize(datagram) + 8) { if (packet.length < getPayloadSize(packet) + 8) {
throw new TransmissionError(); throw new TransmissionError();
} }
assert RequestResponseCode.fromCode(datagram[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LIST_RESPONSE || (this instanceof FileList) : "LIST_RESPONSE must use FilePart class"; assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LIST_RESPONSE || (this instanceof FileList) : "LIST_RESPONSE must use FilePart class";
assert RequestResponseCode.fromCode(datagram[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LOAD_RESPONSE || (this instanceof FilePart) : "LOAD_RESPONSE must use FileList class"; assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LOAD_RESPONSE || (this instanceof FilePart) : "LOAD_RESPONSE must use FileList class";
assert RequestResponseCode.fromCode(datagram[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LOAD_REQUEST || (this instanceof LoadRequest) : "LOAD_REQUEST must use LoadRequest class"; assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.LOAD_REQUEST || (this instanceof LoadRequest) : "LOAD_REQUEST must use LoadRequest class";
requestResponseCode = RequestResponseCode.fromCode(datagram[RequestResponseCode.RRCODE_POSITION]); requestResponseCode = RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]);
checkRequestResponseCode(); // this can throw InternalError checkRequestResponseCode(); // this can throw InternalError
} }
@ -65,29 +65,29 @@ public class Payload {
} }
} }
/** Returns a byte[] containing datagram with padding. /** Returns a byte[] containing Packet with padding.
* This datagram is still incomplete and should not be send directly. * This Packet is still incomplete and should not be send directly.
* ProtocolP2PDatagram will use this method to generate the complete datagram. * ProtocolP2PPacket will use this method to generate the complete Packet.
* @return datagram with padding * @return Packet with padding
* @throws InternalError * @throws InternalError
*/ */
protected byte[] toDatagram() throws InternalError { protected byte[] toPacket() throws InternalError {
// InternalError is impossible in this method on Payload class but still on subclasses // InternalError is impossible in this method on Payload class but still on subclasses
byte [] datagram = new byte[8]; // java initialize all to zero byte [] packet = new byte[8]; // java initialize all to zero
// size is zero (and this is the default) // size is zero (and this is the default)
// set request/response code // set request/response code
datagram[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue;
// bits 16-31 are reserved for future use // bits 16-31 are reserved for future use
// payload size is 0 (this is what java have initialized datagram) // payload size is 0 (this is what java have initialized Packet)
return datagram; return packet;
} }
/** Set payloads size in a datagram. /** Set payloads size in a Packet.
* @param size integer representing payload size * @param size integer representing payload size
* @param datagram datagram to be completed * @param packet Packet to be completed
* @throws InternalError * @throws InternalError
*/ */
protected static void setPayloadSize(int size, byte[] datagram) throws InternalError { protected static void setPayloadSize(int size, byte[] packet) throws InternalError {
/* assert to help debugging */ /* assert to help debugging */
assert size >= 0: "Payload size cannot be negative"; assert size >= 0: "Payload size cannot be negative";
if (size < 0) { if (size < 0) {
@ -95,16 +95,16 @@ public class Payload {
// because this is only for reception side // because this is only for reception side
throw new InternalError(); throw new InternalError();
} }
BytesArrayTools.write(datagram, PAYLOAD_SIZE_POSITION, size); BytesArrayTools.write(packet, PAYLOAD_SIZE_POSITION, size);
} }
/** Get payloads size from a datagram. /** Get payloads size from a Packet.
* @param datagram the full datagram received * @param packet the full Packet received
* @return integer representing payload size * @return integer representing payload size
* @throws SizeError * @throws SizeError
*/ */
protected static int getPayloadSize(byte[] datagram) throws SizeError { protected static int getPayloadSize(byte[] packet) throws SizeError {
return BytesArrayTools.readInt(datagram, PAYLOAD_SIZE_POSITION); return BytesArrayTools.readInt(packet, PAYLOAD_SIZE_POSITION);
} }
/** RRCode getter. /** RRCode getter.

@ -1,298 +0,0 @@
package protocolP2P;
import exception.InternalError;
import exception.ProtocolError;
import exception.SizeError;
import exception.TransmissionError;
import exception.VersionError;
import remoteException.EmptyDirectory;
import remoteException.InternalRemoteError;
import remoteException.NotFound;
import remoteException.ProtocolRemoteError;
import remoteException.VersionRemoteError;
import remoteException.EmptyFile;
import tools.BytesArrayTools;
import protocolP2P.Payload;
import protocolP2P.RequestResponseCode;
import protocolP2P.LoadRequest;
import protocolP2P.FileList;
import protocolP2P.FilePart;
import java.util.ArrayList;
import java.lang.Byte;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.io.IOException;
import java.net.UnknownHostException;
/** Representation of datagram.
* @author Louis Royer
* @author Flavien Haas
* @author JS Auge
* @version 1.0
*/
public class ProtocolP2PDatagram {
private final static byte PROTOCOL_VERSION = 0x12;
private final static int VERSION_POSITON = 0;
private byte version;
private Payload payload;
private InetAddress hostR;
private int portR;
private final static int CHECKSUM_POSITION = 2;
/** Constructor with payload parameter (typically used when sending datagram).
* @param payload the payload associated with the datagram to send
*/
public ProtocolP2PDatagram(Payload payload) {
version = PROTOCOL_VERSION;
this.payload = payload;
}
/** Send datagram on socket (from client)
* @param socket DatagramSocket used to send datagram.
* @param host host to send datagram (null if this is a response)
* @param port port to send datagram (null if this is a response)
* @throws InternalError
* @throws UnknownHostException
* @throws IOException
*/
public void send(DatagramSocket socket, String host, int port) throws InternalError, UnknownHostException, IOException {
InetAddress dst = InetAddress.getByName(host);
byte[] datagram = toDatagram();
// generate DatagramPacket
DatagramPacket datagramPacket = new DatagramPacket(datagram, datagram.length, dst, port);
// send it
socket.send(datagramPacket);
}
/** Send datagram on socket (from server, as a response)
* @param socket DatagramSocket used to send datagram.
* @param received datagram to respond (aka request)
* @throws InternalError
* @throws IOException
*/
public void send(DatagramSocket socket, ProtocolP2PDatagram received) throws InternalError, IOException {
assert received.getPortR() != 0 && received.getHostR() != null : "This method should be used only as response to a request";
if (received.getPortR() == 0 || received.getHostR() == null) {
throw new InternalError();
}
byte[] datagram = toDatagram();
// generate DatagramPacket
DatagramPacket datagramPacket = new DatagramPacket(datagram, datagram.length, received.getHostR(), received.getPortR());
socket.send(datagramPacket);
}
/** Send a response.
* @param socket DatagramSocket used to send response
* @param host host to send response
* @param port port to send response
* @throws InternalError
* @throws IOException
*/
protected void sendResponse(DatagramSocket socket, InetAddress host, int port) throws InternalError, IOException {
assert port != 0 && host != null : "This method should be used only as response to a request";
if (port == 0 || host == null) {
throw new InternalError();
}
byte[] datagram = toDatagram();
DatagramPacket datagramPacket = new DatagramPacket(datagram, datagram.length, host, port);
socket.send(datagramPacket);
}
/** Receive datagram on socket
* @param socket DatagramSocket used to receive datagram
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
* @throws ProtocolRemoteError
* @throws VersionRemoteError
* @throws InternalRemoteError
* @throws EmptyDirectory
* @throws NotFound
* @throws IOException
* @throws EmptyFile
*/
public static ProtocolP2PDatagram receive(DatagramSocket socket) throws EmptyFile, NotFound, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {
// reception
byte[] datagram = new byte[4096*2];
DatagramPacket reception = new DatagramPacket(datagram, datagram.length);
socket.receive(reception);
// contruction
try {
ProtocolP2PDatagram p = new ProtocolP2PDatagram(datagram);
p.setHostR(reception.getAddress());
p.setPortR(reception.getPort());
Payload payload = p.getPayload();
switch (payload.getRequestResponseCode()) {
case PROTOCOL_ERROR :
throw new ProtocolRemoteError();
case VERSION_ERROR :
throw new VersionRemoteError();
case INTERNAL_ERROR :
throw new InternalRemoteError();
case EMPTY_DIRECTORY :
throw new EmptyDirectory();
case NOT_FOUND :
throw new NotFound();
case EMPTY_FILE:
throw new EmptyFile();
default :
return p;
}
} catch (TransmissionError e) {
(new ProtocolP2PDatagram(new Payload(RequestResponseCode.INTERNAL_ERROR))).sendResponse(socket, reception.getAddress(), reception.getPort());
throw e;
} catch (ProtocolError e) {
(new ProtocolP2PDatagram(new Payload(RequestResponseCode.PROTOCOL_ERROR))).sendResponse(socket, reception.getAddress(), reception.getPort());
throw e;
} catch (VersionError e) {
(new ProtocolP2PDatagram(new Payload(RequestResponseCode.VERSION_ERROR))).sendResponse(socket, reception.getAddress(), reception.getPort());
throw e;
} catch (InternalError e) {
(new ProtocolP2PDatagram(new Payload(RequestResponseCode.INTERNAL_ERROR))).sendResponse(socket, reception.getAddress(), reception.getPort());
throw e;
} catch (SizeError e) {
(new ProtocolP2PDatagram(new Payload(RequestResponseCode.INTERNAL_ERROR))).sendResponse(socket, reception.getAddress(), reception.getPort());
throw e;
}
}
/** Private constructor with datagram as byte[] parameter (typically used when receiving datagram).
* @param datagram the full datagram received
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
*/
private ProtocolP2PDatagram(byte[] datagram) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError {
// unwrap version
version = datagram[VERSION_POSITON];
checkProtocolVersion(); // this can throw VersionError
checkCheckSum(datagram);
RequestResponseCode r = RequestResponseCode.fromCode(datagram[RequestResponseCode.RRCODE_POSITION]); // this can throw ProtocolError
switch (r) {
case LIST_RESPONSE:
payload = (Payload) new FileList(datagram);
break;
case LOAD_RESPONSE:
payload = (Payload) new FilePart(datagram);
break;
case LOAD_REQUEST:
payload = (Payload) new LoadRequest(datagram);
break;
default:
payload = new Payload(datagram); // this can throw TransmissionError
break;
}
}
/** Returns a byte[] containing full datagram (typically used when sending datagram).
* This datagram is still complete and ready to be send.
* @return the full datagram to send
* @throws InternalError
*/
protected byte[] toDatagram() throws InternalError {
byte[] datagram = payload.toDatagram();
datagram[VERSION_POSITON] = version;
setCheckSum(datagram);
return datagram;
}
/** Returns Payload associated with the datagram.
* @return payload associated with the datagram
*/
public Payload getPayload() {
return payload;
}
/** Used to check protocol version when a datagram is constructed from bytes[].
* @throws VersionError
*/
private void checkProtocolVersion() throws VersionError {
if (PROTOCOL_VERSION != version) {
throw new VersionError();
}
}
/** portR getter.
* @return portR
*/
protected int getPortR() {
return portR;
}
/** portR setter.
* @param portR portR
*/
protected void setPortR(int portR) {
this.portR = portR;
}
/** hostR getter.
* @return hostR
*/
protected InetAddress getHostR() {
return hostR;
}
/** hostH setter.
* @param hostR hostR
*/
protected void setHostR(InetAddress hostR) {
this.hostR = hostR;
}
/** Used to compute Checksum of a specific datagram
* @param datagram full datagram
* @return checksum
* @throws SizeError
*/
private int computeCheckSum(byte [] datagram) throws SizeError {
/*
* The checksum field is the 16 bit ones complement of the ones complement sum of all 16-bit words
* in the header and text. If a segment contains an odd number of header and text octets to be checksummed,
* the last octet is padded on the right with zeros to form a 16-bit word for checksum purposes.
* The pad is not transmitted as part of the segment. While computing the checksum, the checksum field
* itself is replaced with zeros.
*/
int checksum = 0;
for (int i=CHECKSUM_POSITION+2; i<CHECKSUM_POSITION+2+4+Payload.getPayloadSize(datagram); ++i) {
checksum += BytesArrayTools.readInt16Bits(datagram,i);
checksum &= 0xffff;
}
return checksum ^ 0xffff;
}
/** Used to set checksum into datagram
* @param datagram full datagram
* @throws InternalError
*/
private void setCheckSum(byte [] datagram) throws InternalError {
try {
int checksum = computeCheckSum(datagram);
BytesArrayTools.write16Bits(datagram,CHECKSUM_POSITION,checksum);
} catch (SizeError e) {
throw new InternalError();
}
}
/** Used to check if the checksum is correct
* @param datagram full datagram
* @throws TransmissionError
*/
private void checkCheckSum(byte [] datagram) throws TransmissionError {
try {
int checksum = BytesArrayTools.readInt16Bits(datagram,CHECKSUM_POSITION);
int computedCheckSum = computeCheckSum(datagram);
if (computedCheckSum != checksum){
throw new TransmissionError();
}
} catch(SizeError e) {
throw new TransmissionError();
}
}
}

@ -0,0 +1,102 @@
package protocolP2P;
import exception.InternalError;
import exception.ProtocolError;
import exception.SizeError;
import exception.TransmissionError;
import exception.VersionError;
import remoteException.EmptyDirectory;
import remoteException.InternalRemoteError;
import remoteException.NotFound;
import remoteException.ProtocolRemoteError;
import remoteException.VersionRemoteError;
import remoteException.EmptyFile;
import java.net.InetAddress;
import java.io.IOException;
/** Representation of packet.
* @author Louis Royer
* @author Flavien Haas
* @author JS Auge
* @version 1.0
*/
public abstract class ProtocolP2PPacket {
private final static byte PROTOCOL_VERSION = 0x12;
protected final static int VERSION_POSITION = 0;
protected byte version;
protected Payload payload;
/** Constructor with payload parameter (typically used when sending Packet).
* @param payload the payload associated with the Packet to send
*/
public ProtocolP2PPacket(Payload payload) {
version = PROTOCOL_VERSION;
this.payload = payload;
}
/** Send a request
* @param socket Socket used to send packet.
* @throws InternalError
* @throws IOException
*/
public abstract void sendRequest(Object socket) throws InternalError, IOException;
/** Send a response
* @param response Response to send.
* @throws InternalError
* @throws IOException
*/
public abstract void sendResponse(ProtocolP2PPacket response) throws InternalError, IOException;
/** Receive a response
* @throws EmptyFile
* @throws NotFound
* @throws EmptyDirectory
* @throws InternalRemoteError
* @throws VersionRemoteError
* @throws ProtocolRemoteError
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
* @throws IOException
*/
public abstract ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException;
/** Receive a request, subclasses must overwrite this constructor.
* @param serverSocket socket used to get the request
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
* @throws IOException
*/
protected ProtocolP2PPacket(Object serverSocket) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {}
/** Construct a packet from byte[], subclasses must overwrite this constructor.
* @param packet Packet received
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
*/
protected ProtocolP2PPacket(byte[] packet) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError {}
/** Returns Payload associated with the Packet.
* @return payload associated with the Packet.
*/
public Payload getPayload() {
return payload;
}
/** Used to check protocol version when a Packet is constructed from bytes[].
* @throws VersionError
*/
protected void checkProtocolVersion() throws VersionError {
if (PROTOCOL_VERSION != version) {
throw new VersionError();
}
}
}

@ -0,0 +1,359 @@
package protocolP2P;
import exception.InternalError;
import exception.ProtocolError;
import exception.SizeError;
import exception.TransmissionError;
import exception.VersionError;
import remoteException.EmptyDirectory;
import remoteException.InternalRemoteError;
import remoteException.NotFound;
import remoteException.ProtocolRemoteError;
import remoteException.VersionRemoteError;
import remoteException.EmptyFile;
import tools.BytesArrayTools;
import protocolP2P.Payload;
import protocolP2P.RequestResponseCode;
import protocolP2P.LoadRequest;
import protocolP2P.FileList;
import protocolP2P.FilePart;
import java.util.ArrayList;
import java.lang.Byte;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.io.IOException;
/** Representation of packet.
* @author Louis Royer
* @author Flavien Haas
* @author JS Auge
* @version 1.0
*/
public class ProtocolP2PPacketUDP extends ProtocolP2PPacket {
private final static int CHECKSUM_POSITION = 2;
private SocketAddress responseSocketAddress; // socket address used when receptionning request and to sending response
private DatagramSocket responseSocket; // socket used to recept request and send response
private DatagramSocket requestSocket; // socket used to send request and to reception response
/** Constructor with payload parameter (typically used when sending packet).
* @param payload the payload associated with the packet to send
*/
public ProtocolP2PPacketUDP(Payload payload) {
super(payload);
}
/** Send a Packet. Socket must be set and connected.
* @param socket DatagramSocket used to send Packet.
* @throws InternalError
* @throws IOException
*/
protected void send(DatagramSocket socket) throws InternalError, IOException {
send(socket, null);
}
/** Send a Packet. Socket must be set and connected, or an addr can be given.
* @param socket DatagramSocket used to send Packet.
* @param addr SocketAddress used to send Packet.
* @throws InternalError
* @throws IOException
*/
protected void send(DatagramSocket socket, SocketAddress addr) throws InternalError, IOException {
assert socket != null : "Trying to send a Packet but no socket defined";
assert socket.isConnected() || addr != null : "Trying to send a Packet but socket not connected, and no socketAddress given";
if (socket == null || ((!socket.isConnected()) && (addr == null))) {
throw new InternalError();
}
// generate DatagramPacket
byte[] packet = toPacket();
DatagramPacket datagramPacket = new DatagramPacket(packet, packet.length);
if (addr != null) {
datagramPacket.setSocketAddress(addr);
}
// send it
socket.send(datagramPacket);
}
/** Send a Request throught socket. Socket must be connected (typically used from client).
* @param socket DatagramSocket. Must be connected.
* @throws InternalError
* @throws IOException
*/
public void sendRequest(Object socket) throws InternalError, IOException {
assert socket instanceof DatagramSocket: "Wrong socket type";
if (socket instanceof DatagramSocket) {
requestSocket = (DatagramSocket)socket;
send(requestSocket);
} else {
throw new InternalError();
}
}
/** Receive Request (typically used from server).
* @param serverSocket socket used to receive request
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
* @throws IOException
* @return ProtocolP2PPacket received.
*/
public ProtocolP2PPacketUDP(Object serverSocket) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {
super(serverSocket);
assert serverSocket instanceof DatagramSocket : "Wrong socket type";
if (!(serverSocket instanceof DatagramSocket)) {
throw new InternalError();
}
DatagramSocket ss = (DatagramSocket)serverSocket;
byte[] packet = new byte[1024];
DatagramPacket reception = new DatagramPacket(packet, packet.length);
ss.receive(reception);
responseSocketAddress = reception.getSocketAddress();
// contruction
boolean protocolError = false;
try {
constructPacket(packet, ss);
Payload payload = getPayload();
switch (payload.getRequestResponseCode()) {
case PROTOCOL_ERROR :
// we do not want to create an infinite loop of protocolError message exchange.
protocolError = true;
break;
case VERSION_ERROR :
case INTERNAL_ERROR :
case EMPTY_DIRECTORY :
case NOT_FOUND :
case EMPTY_FILE:
case LOAD_RESPONSE:
case LIST_RESPONSE:
// we were expecting a request, but we are receiving a response
throw new ProtocolError();
default :
break;
}
} catch (TransmissionError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(ss, responseSocketAddress);
throw e;
} catch (ProtocolError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.PROTOCOL_ERROR))).send(ss, responseSocketAddress);
throw e;
} catch (VersionError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.VERSION_ERROR))).send(ss, responseSocketAddress);
throw e;
} catch (InternalError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(ss, responseSocketAddress);
throw e;
} catch (SizeError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(ss, responseSocketAddress);
throw e;
}
if (protocolError) {
throw new ProtocolError();
}
}
/** Send a Response to a Request (typically used from server).
* @param response Packet to send as a response.
* @throws InternalError
* @throws IOException
*/
public void sendResponse(ProtocolP2PPacket response) throws InternalError, IOException {
assert response instanceof ProtocolP2PPacketUDP: "Wrong Packet type";
if (response instanceof ProtocolP2PPacketUDP) {
ProtocolP2PPacketUDP r = (ProtocolP2PPacketUDP) response;
assert responseSocket != null : "Cannot send response to a packet not received";
if (responseSocket == null) {
throw new InternalError();
}
assert responseSocketAddress != null : "Cannot send response because address of client has not been saved";
if (responseSocketAddress == null) {
throw new InternalError();
}
r.send(responseSocket, responseSocketAddress);
} else {
throw new InternalError();
}
}
/** Receive response (typically used by client).
* @return ProtocolP2PPacket received
* @throws EmptyFile
* @throws NotFound
* @throws EmptyDirectory
* @throws InternalRemoteError
* @throws VersionRemoteError
* @throws ProtocolRemoteError
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
* @throws IOException
*/
public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException {
assert requestSocket != null : "Cannot receive response because request packet not sent.";
if (requestSocket == null) {
throw new InternalError();
}
// reception
byte[] packet = new byte[8192];
DatagramPacket reception = new DatagramPacket(packet, packet.length);
requestSocket.receive(reception);
// contruction
try {
ProtocolP2PPacketUDP p = new ProtocolP2PPacketUDP(packet);
Payload payload = p.getPayload();
switch (payload.getRequestResponseCode()) {
case PROTOCOL_ERROR :
throw new ProtocolRemoteError();
case VERSION_ERROR :
throw new VersionRemoteError();
case INTERNAL_ERROR :
throw new InternalRemoteError();
case EMPTY_DIRECTORY :
throw new EmptyDirectory();
case NOT_FOUND :
throw new NotFound();
case EMPTY_FILE:
throw new EmptyFile();
default :
return (ProtocolP2PPacket)p;
}
} catch (TransmissionError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(requestSocket);
throw e;
} catch (ProtocolError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.PROTOCOL_ERROR))).send(requestSocket);
throw e;
} catch (VersionError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.VERSION_ERROR))).send(requestSocket);
throw e;
} catch (InternalError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(requestSocket);
throw e;
} catch (SizeError e) {
(new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(requestSocket);
throw e;
}
}
/** Private constructor with packet as byte[] parameter (typically used when receiving Packet response).
* @param packet the full Packet received
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
*/
private ProtocolP2PPacketUDP(byte[] packet) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError {
super(packet);
constructPacket(packet);
}
/** Private constructor helper with packet as byte[] parameter (typically used when receiving Packet response/request).
* @param packet the full Packet received
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
*/
private void constructPacket(byte[] packet) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError {
// unwrap version
version = packet[VERSION_POSITION];
checkProtocolVersion(); // this can throw VersionError
checkCheckSum(packet);
RequestResponseCode r = RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]); // this can throw ProtocolError
switch (r) {
case LIST_RESPONSE:
payload = (Payload) new FileList(packet);
break;
case LOAD_RESPONSE:
payload = (Payload) new FilePart(packet);
break;
case LOAD_REQUEST:
payload = (Payload) new LoadRequest(packet);
break;
default:
payload = new Payload(packet); // this can throw TransmissionError
break;
}
}
/** Private constructor helper with packet as byte[] parameter and (typically used when receiving Packet request).
* @param packet the full Packet received
* @param responseSocket socket address used to reception this request (use this one to respond)
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws InternalError
* @throws SizeError
*/
private void constructPacket(byte[] packet, DatagramSocket responseSocket) throws TransmissionError, ProtocolError, VersionError, InternalError, SizeError {
constructPacket(packet);
this.responseSocket = responseSocket;
}
/** Returns a byte[] containing full packet (typically used when sending packet).
* This packet is complete and ready to be send.
* @return the full packet to send
* @throws InternalError
*/
protected byte[] toPacket() throws InternalError {
byte[] packet = payload.toPacket();
packet[VERSION_POSITION] = version;
setCheckSum(packet);
return packet;
}
/** Compute checksum associated to packet.
* @param packet the full packet received
* @throws SizeError
*/
private int computeCheckSum(byte [] packet) throws SizeError {
/*
* The checksum field is the 16 bit ones complement of the ones complement sum of all 16-bit words
* in the header and text. If a segment contains an odd number of header and text octets to be checksummed,
* the last octet is padded on the right with zeros to form a 16-bit word for checksum purposes.
* The pad is not transmitted as part of the segment. While computing the checksum, the checksum field
* itself is replaced with zeros.
*/
int checksum = 0;
for (int i=CHECKSUM_POSITION+2; i<CHECKSUM_POSITION+2+4+Payload.getPayloadSize(packet); ++i) {
checksum += BytesArrayTools.readInt16Bits(packet, i);
checksum &= 0xffff;
}
return checksum ^ 0xffff;
}
/** Used to set checksum into packet
* @param packet full packet
* @throws InternalError
*/
private void setCheckSum(byte [] packet) throws InternalError {
try {
int checksum = computeCheckSum(packet);
BytesArrayTools.write16Bits(packet, CHECKSUM_POSITION, checksum);
} catch (SizeError e) {
throw new InternalError();
}
}
/** Used to check if the checksum is correct
* @param packet full packet
* @throws TransmissionError
*/
private void checkCheckSum(byte [] packet) throws TransmissionError {
try {
int checksum = BytesArrayTools.readInt16Bits(packet, CHECKSUM_POSITION);
int computedCheckSum = computeCheckSum(packet);
if (computedCheckSum != checksum){
throw new TransmissionError();
}
} catch(SizeError e) {
throw new TransmissionError();
}
}
}

@ -39,7 +39,7 @@ public enum RequestResponseCode {
/** Private constructor /** Private constructor
* @param codeType type of code (request or response) * @param codeType type of code (request or response)
* @param codeValue value of the element in datagram * @param codeValue value of the element in Packet
* @return enum element * @return enum element
*/ */
private RequestResponseCode(CodeType codeType, byte codeValue) { private RequestResponseCode(CodeType codeType, byte codeValue) {
@ -47,8 +47,8 @@ public enum RequestResponseCode {
this.codeValue = codeValue; this.codeValue = codeValue;
} }
/** Gives enum from datagram code. /** Gives enum from Packet code.
* @param code value of the element in datagram * @param code value of the element in packet
* @return enum element * @return enum element
*/ */
protected static RequestResponseCode fromCode(byte code) throws ProtocolError { protected static RequestResponseCode fromCode(byte code) throws ProtocolError {

@ -3,10 +3,12 @@ import java.util.Vector;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.DatagramSocket; import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException; import java.net.SocketException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.nio.file.Files; import java.nio.file.Files;
import protocolP2P.ProtocolP2PDatagram; import protocolP2P.ProtocolP2PPacketUDP;
import protocolP2P.ProtocolP2PPacket;
import protocolP2P.RequestResponseCode; import protocolP2P.RequestResponseCode;
import protocolP2P.Payload; import protocolP2P.Payload;
import protocolP2P.LoadRequest; import protocolP2P.LoadRequest;
@ -60,7 +62,7 @@ public class ServerManagementUDP implements Runnable {
public void run() { public void run() {
while(true) { while(true) {
try { try {
ProtocolP2PDatagram pd = ProtocolP2PDatagram.receive(socket); ProtocolP2PPacketUDP pd = new ProtocolP2PPacketUDP((Object)socket);
Payload p = pd.getPayload(); Payload p = pd.getPayload();
switch (p.getRequestResponseCode()) { switch (p.getRequestResponseCode()) {
case LOAD_REQUEST: case LOAD_REQUEST:
@ -87,9 +89,9 @@ public class ServerManagementUDP implements Runnable {
if (Arrays.binarySearch(fileList, filename) >= 0) { if (Arrays.binarySearch(fileList, filename) >= 0) {
try { try {
if (load.length == 0) { if (load.length == 0) {
(new ProtocolP2PDatagram(new Payload(RequestResponseCode.EMPTY_FILE))).send(socket, pd); pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.EMPTY_FILE)));
} else { } else {
(new ProtocolP2PDatagram((Payload)(new FilePart(filename, fullLoad.length, offset, load)))).send(socket, pd); pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)(new FilePart(filename, fullLoad.length, offset, load))));
} }
} catch (Exception e2) { } catch (Exception e2) {
System.err.println(e2); System.err.println(e2);
@ -105,7 +107,7 @@ public class ServerManagementUDP implements Runnable {
} }
} catch (IOException e) { } catch (IOException e) {
try { try {
(new ProtocolP2PDatagram(new Payload(RequestResponseCode.NOT_FOUND))).send(socket, pd); pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.NOT_FOUND)));
} catch (Exception e2) { } catch (Exception e2) {
System.err.println(e2); System.err.println(e2);
} }
@ -117,10 +119,10 @@ public class ServerManagementUDP implements Runnable {
try { try {
if (fileList.length == 0) { if (fileList.length == 0) {
System.err.println("Sending EMPTY_DIRECTORY"); System.err.println("Sending EMPTY_DIRECTORY");
(new ProtocolP2PDatagram(new Payload(RequestResponseCode.EMPTY_DIRECTORY))).send(socket, pd); pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.EMPTY_DIRECTORY)));
} else { } else {
System.out.println("Sending LIST_RESPONSE"); System.out.println("Sending LIST_RESPONSE");
(new ProtocolP2PDatagram((Payload)(new FileList(fileList)))).send(socket, pd); pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)(new FileList(fileList))));
} }
} catch (Exception e2) { } catch (Exception e2) {
System.err.println(e2); System.err.println(e2);
@ -129,18 +131,12 @@ public class ServerManagementUDP implements Runnable {
default: default:
sendInternalError(pd); sendInternalError(pd);
} }
} catch (NotFound e) {
} catch (EmptyDirectory e) {
} catch (InternalRemoteError e) {
} catch (VersionRemoteError e) {
} catch (ProtocolRemoteError e) {
} catch (IOException e) { } catch (IOException e) {
} catch (TransmissionError e) { } catch (TransmissionError e) {
} catch (ProtocolError e) { } catch (ProtocolError e) {
} catch (VersionError e) { } catch (VersionError e) {
} catch (InternalError e) { } catch (InternalError e) {
} catch (SizeError e) { } catch (SizeError e) {
} catch (EmptyFile e) {
} }
} }
} }
@ -165,11 +161,11 @@ public class ServerManagementUDP implements Runnable {
/** Send an internal error message. /** Send an internal error message.
* @param pd ProtocolP2PDatagram to respond * @param pd ProtocolP2PPacketUDP to respond
*/ */
private void sendInternalError(ProtocolP2PDatagram pd) { private void sendInternalError(ProtocolP2PPacketUDP pd) {
try { try {
(new ProtocolP2PDatagram(new Payload(RequestResponseCode.INTERNAL_ERROR))).send(socket, pd); pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.INTERNAL_ERROR)));
} catch (Exception e) { } catch (Exception e) {
System.err.println(e); System.err.println(e);
} }

Loading…
Cancel
Save