Change to ProtocolP2PPacket, should be easier to implement tcp

This commit is contained in:
Louis Royer 2020-02-29 00:19:50 +01:00
parent c17a7e6cd5
commit b6351d30d3
12 changed files with 632 additions and 464 deletions

View File

@ -20,7 +20,7 @@ import java.nio.file.Files;
import java.io.File;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import protocolP2P.ProtocolP2PDatagram;
import protocolP2P.ProtocolP2PPacketUDP;
import protocolP2P.Payload;
import protocolP2P.RequestResponseCode;
import protocolP2P.FileList;
@ -52,9 +52,13 @@ public class ClientManagementUDP implements Runnable {
this.UDPPort = UDPPort;
try {
socket = new DatagramSocket();
socket.connect(InetAddress.getByName(host), UDPPort);
} catch (SocketException e) {
System.err.println("Error: No socket available.");
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 {
final long MAX_PARTIAL_SIZE = 1024;
ProtocolP2PDatagram d = new ProtocolP2PDatagram((Payload) new LoadRequest(filename, 0, MAX_PARTIAL_SIZE));
d.send(socket, host, UDPPort);
ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP((Payload) new LoadRequest(filename, 0, MAX_PARTIAL_SIZE));
d.sendRequest((Object)socket);
boolean fileFullyWritten = false;
long offset = 0;
do {
try {
Payload p = ProtocolP2PDatagram.receive(socket).getPayload();
Payload p = d.receiveResponse().getPayload();
assert p instanceof FilePart : "This payload must be instance of FilePart";
if (!(p instanceof FilePart)) {
throw new InternalError();
@ -148,8 +152,8 @@ public class ClientManagementUDP implements Runnable {
// next partialContentRequest
if (offset != fp.getTotalSize()) {
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.send(socket, host, UDPPort);
d = new ProtocolP2PPacketUDP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
d.sendRequest((Object)socket);
} else {
fileFullyWritten = true;
}
@ -168,8 +172,8 @@ public class ClientManagementUDP implements Runnable {
fileFullyWritten = true;
} else {
// next partialContentRequest
d = new ProtocolP2PDatagram((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
d.send(socket, host, UDPPort);
d = new ProtocolP2PPacketUDP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
d.sendRequest((Object)socket);
}
} else {
@ -199,10 +203,10 @@ public class ClientManagementUDP implements Runnable {
* @throws 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));
d.send(socket, host, UDPPort);
ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.LIST_REQUEST));
d.sendRequest((Object)socket);
try {
Payload p = ProtocolP2PDatagram.receive(socket).getPayload();
Payload p = d.receiveResponse().getPayload();
assert p instanceof FileList : "This payload must be instance of Filelist";
if (!(p instanceof FileList)) {
throw new InternalError();

View File

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

View File

@ -1,5 +1,5 @@
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 {
private static final long serialVersionUID = 12L;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

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

View File

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