From 230092ab2ad9bab86fd9002a71e5ba46066bdaf7 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Wed, 25 Mar 2020 14:05:48 +0100 Subject: [PATCH 01/13] Update protocol.md Fix #42 --- doc/protocol.md | 71 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/doc/protocol.md b/doc/protocol.md index 64dae57..3bc45b1 100644 --- a/doc/protocol.md +++ b/doc/protocol.md @@ -2,7 +2,7 @@ All strings in the datagram are utf-8 encoded. -```Datagram format +```text 1 byte: [(byte 0 ): VERSION(0x11, first quartet is major version, second is minor)] 1 byte: [(byte 1 ): REQUEST/RESPONSE CODE] @@ -20,12 +20,15 @@ x bytes: [(bytes 8-?): PAYLOAD] - `DISCOVER` (0x03) - `REGISTER` (0x04) - `UNREGISTER` (0x05) + - `RATIO` (0x06) + - `UPDATE RATIO` (0x07) - RESPONSES (msb is 1): - `LIST` (0x80) - `LOAD` (0x81) - `HASH` (0x82) - `DISCOVER` (0x83) + - `RATIO` (0x86) - `VERSION ERROR` (0xC0) - `PROTOCOL ERROR` (0xC1) - `INTERNAL ERROR` (0xC2) @@ -33,6 +36,8 @@ x bytes: [(bytes 8-?): PAYLOAD] - `NOT FOUND` (0xC4) - `EMPTY FILE` (0xC5) - `NOT A TRACKER` (0xC6) + - `UNKNOWN HOST` (0xC7) + - `DENIED` (0xC8) ### List Payload size for list request is always zero. @@ -52,7 +57,7 @@ Payload size for Not found is zero. #### Load response Payload contains -``` +```text 8 bytes: [(bytes 8-15): OFFSET OF FILE CONTENT IN BYTES] 8 bytes: [(bytes 16-23): TOTAL FILESIZE] 4 bytes: [(bytes 24-27): FILENAME SIZE] (cannot be > to PAYLOAD_SIZE - 20 or be zero) @@ -63,18 +68,21 @@ z bytes: [PARTIAL CONTENT] #### Load request Payload contains -``` +```text 8 bytes: [(bytes 8-15): OFFSET OF FILE CONTENT IN BYTES] 8 bytes: [(bytes 16-23): MAX SIZE OF PARTIAL CONTENT (partial content in response should not excess this size, but this can be less (by example if endoffile is reached or server doesn't have the full block requested) 4 bytes: [(bytes 24-27): FILENAME SIZE] (cannot be > to PAYLOAD_SIZE - 20 or be zero) y bytes: [] +2 bytes: port used to register on tracker +? bytes: hostname used to register on tracker followed by \n ``` +Possible responses: Load Response, or Denied -### Hash +### Hash #### Hash request Get hash of a file. Payload contains -``` +```text 4 bytes: [(bytes 8-11): FILENAME SIZE] y bytes: [] z bytes: [ALGO_NAMES requested separated by \n] (ex.: SHA-256, MD5) @@ -86,7 +94,7 @@ If file does not exists, a NotFound can be responded. Payload contains: -``` +```text 4 bytes: [(bytes 8-11): FILENAME SIZE] y bytes: [] [[ multiple algo hashes bloc]] @@ -94,7 +102,7 @@ y bytes: [] A algo hash bloc contains: -``` +```text 4 bytes [ALGO_NAME size] ? [ALGO_NAME] 4 bytes: [HASH SIZE (bytes)] / or 0 if this hash algorithm is unsupported. @@ -108,7 +116,7 @@ Used by a server to register itself on a tracker. Server may want to do a free `DISCOVER` to check if they have been registered. Payload contains: -``` +```text 2 bytes: [] ``` @@ -118,7 +126,7 @@ No error is raised if the server was not registered. Server may want to do a free `DISCOVER` to check if they have been unregistered. Payload contains: -``` +```text 2 bytes: [] ? bytes: [] ``` @@ -127,14 +135,14 @@ Payload contains: If payload size is null, lists all servers registered. If payload contains a filename, list all servers having this file in their list. -``` +```text ? bytes: [] ? bytes: [] ``` #### Discover response Contains: -``` +```text 4 bytes: [(bytes 8-11): FILENAME SIZE] y bytes: [] ? bytes [multiple server blocks] @@ -142,7 +150,7 @@ y bytes: [] Server block is composed with: -``` +```text 2 bytes: [port] ? bytes: hostname \n @@ -152,6 +160,45 @@ Server block is composed with: This error is raised when receiving a DISCOVER, a REGISTER, or an UNREGISTER request, but this application is not a tracker. +#### Ratio Request +Contains: +```text +2 bytes: port +? bytes: hostname +``` +Possible responses: Ratio Response, or Unknown Host + +#### Ratio Response +Contains: +```text +2 bytes: port +? bytes: hostname followed by \n +8 bytes: total sent bytes +8 bytes: total received bytes +``` + +#### Update Ratio +Contains: +```text +2 bytes: server port +2 bytes: client* port +? bytes: server hostname followed by \n +? bytes: client* hostname +* note: used by client to register on tracker +``` +Possible responses: No response, or Unknown Host (if client is not registered or server is not registered) + +Note: client must have verified hash before sending Update Ratio to tracker for each server which participated. + +#### Unknown Host +Payload size is zero. + +#### Denied +Contains +```text +?bytes: filename +``` + ### Other response code (errors) #### Version error Response when datagram received use wrong version code. From c5e8a7df3979465d7777c010c10764bd3934d964 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Fri, 27 Mar 2020 16:22:42 +0100 Subject: [PATCH 02/13] Changes to LoadRequest --- doc/protocol.md | 2 +- src/clientP2P/ClientDownload.java | 12 ++++---- src/clientP2P/ClientDownloadPart.java | 8 +++-- src/clientP2P/ClientDownloadPartTCP.java | 6 ++-- src/clientP2P/ClientDownloadPartUDP.java | 6 ++-- src/clientP2P/ClientDownloadTCP.java | 10 +++---- src/clientP2P/ClientDownloadUDP.java | 10 +++---- src/clientP2P/ClientManagement.java | 5 +++- src/clientP2P/ClientManagementTCP.java | 7 +++-- src/clientP2P/ClientManagementUDP.java | 7 +++-- src/clientP2P/ClientP2P.java | 4 +-- src/protocolP2P/LoadRequest.java | 38 ++++++++++++++++++++---- src/protocolP2P/RequestResponseCode.java | 7 ++++- 13 files changed, 84 insertions(+), 38 deletions(-) diff --git a/doc/protocol.md b/doc/protocol.md index 3bc45b1..997adb0 100644 --- a/doc/protocol.md +++ b/doc/protocol.md @@ -74,7 +74,7 @@ Payload contains 4 bytes: [(bytes 24-27): FILENAME SIZE] (cannot be > to PAYLOAD_SIZE - 20 or be zero) y bytes: [] 2 bytes: port used to register on tracker -? bytes: hostname used to register on tracker followed by \n +? bytes: hostname used to register on tracker ``` Possible responses: Load Response, or Denied diff --git a/src/clientP2P/ClientDownload.java b/src/clientP2P/ClientDownload.java index ed58c3b..c4405c3 100644 --- a/src/clientP2P/ClientDownload.java +++ b/src/clientP2P/ClientDownload.java @@ -57,6 +57,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { protected String dirStorage; protected boolean success = false; protected Logger logger; + protected HostItem client; /** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage * @param filename name of file to download @@ -64,13 +65,15 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { * @param partsSubdir directory to store .part files * @param dirStorage directory to write assembled file * @param logger Logger + * @param client HostItem of the application */ - public ClientDownload(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger) { + public ClientDownload(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client) { this.partsSubdir = partsSubdir; this.dirStorage = dirStorage; this.filename = filename; this.hostList = hostList; this.logger = logger; + this.client = client; this.stop = false; } @@ -125,16 +128,15 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { } /** Create a clientDownloadPart - * @param filename name of the file to download * @param hostItem Hostitem of the server */ - protected abstract ClientDownloadPart createDownloadPart(String filename, HostItem hostItem); + protected abstract ClientDownloadPart createDownloadPart(HostItem hostItem); /** Starts threads for each server in hostList. */ protected void initThreads() { for(HostItem hostItem: hostList) { - sockList.add(createDownloadPart(filename, hostItem)); + sockList.add(createDownloadPart(hostItem)); } for(ClientDownloadPart c: sockList) { Thread t = new Thread(c); @@ -289,7 +291,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { * @throws InternalError */ protected void setSize() throws InternalError { - ProtocolP2PPacket d = createProtocolP2PPacket(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE)); + ProtocolP2PPacket d = createProtocolP2PPacket(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE, client)); try { d.sendRequest(getHostItemSocket(hostList.get(0))); try { diff --git a/src/clientP2P/ClientDownloadPart.java b/src/clientP2P/ClientDownloadPart.java index e12fce3..cccd3ba 100644 --- a/src/clientP2P/ClientDownloadPart.java +++ b/src/clientP2P/ClientDownloadPart.java @@ -26,6 +26,7 @@ import exception.RemoteException; import tools.Logger; import tools.LogLevel; import tools.ServeErrors; +import tools.HostItem; /** Class to download file parts. * @author Louis Royer @@ -46,18 +47,21 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable protected static final long MAX_PARTIAL_SIZE = 4096; protected ClientDownload manager; protected Logger logger; + protected HostItem client; /** Constructor with filename, socket, and part subdir * @param filename name of file to download * @param socket socket to use * @param partsSubdir directory to store .part files * @param logger Logger + * @param client HostItem of the application */ - public ClientDownloadPart(ClientDownload manager, String filename, String partsSubdir, Logger logger) { + public ClientDownloadPart(ClientDownload manager, String filename, String partsSubdir, Logger logger, HostItem client) { this.manager = manager; this.partsSubdir = partsSubdir; this.filename = filename; this.logger = logger; + this.client = client; stop = false; failed = false; pendingTasks = new ArrayList<>(); @@ -224,7 +228,7 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable } // send request try { - ProtocolP2PPacket d = createProtocolP2PPacket(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE)); + ProtocolP2PPacket d = createProtocolP2PPacket(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE, client)); d.sendRequest(getSocket()); return d; } catch (InternalError e) { diff --git a/src/clientP2P/ClientDownloadPartTCP.java b/src/clientP2P/ClientDownloadPartTCP.java index 7928735..d354ed4 100644 --- a/src/clientP2P/ClientDownloadPartTCP.java +++ b/src/clientP2P/ClientDownloadPartTCP.java @@ -25,6 +25,7 @@ import remoteException.NotFound; import remoteException.NotATracker; import tools.Logger; import tools.LogLevel; +import tools.HostItem; import clientP2P.ClientDownloadPart; /** Class to download file parts on tcp. @@ -42,9 +43,10 @@ public class ClientDownloadPartTCP extends ClientDownloadPart { * @param socket socket to use * @param partsSubdir directory to store .part files * @param logger Logger + * @param client HostItem of the application */ - public ClientDownloadPartTCP(ClientDownload manager, String filename, Socket socket, String partsSubdir, Logger logger) { - super(manager, filename, partsSubdir, logger); + public ClientDownloadPartTCP(ClientDownload manager, String filename, Socket socket, String partsSubdir, Logger logger, HostItem client) { + super(manager, filename, partsSubdir, logger, client); this.socket = socket; } diff --git a/src/clientP2P/ClientDownloadPartUDP.java b/src/clientP2P/ClientDownloadPartUDP.java index 0387c0c..ae0a24c 100644 --- a/src/clientP2P/ClientDownloadPartUDP.java +++ b/src/clientP2P/ClientDownloadPartUDP.java @@ -24,6 +24,7 @@ import java.io.File; import java.io.IOException; import tools.Logger; import tools.LogLevel; +import tools.HostItem; import clientP2P.ClientDownloadPart; /** Class to download file parts on udp. @@ -42,9 +43,10 @@ public class ClientDownloadPartUDP extends ClientDownloadPart { * @param socket socket to use * @param partsSubdir directory to store .part files * @param logger Logger + * @param client HostItem of the application */ - public ClientDownloadPartUDP(ClientDownload manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger) { - super(manager, filename, partsSubdir, logger); + public ClientDownloadPartUDP(ClientDownload manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger, HostItem client) { + super(manager, filename, partsSubdir, logger, client); this.socket = socket; } diff --git a/src/clientP2P/ClientDownloadTCP.java b/src/clientP2P/ClientDownloadTCP.java index 5d32835..0751845 100644 --- a/src/clientP2P/ClientDownloadTCP.java +++ b/src/clientP2P/ClientDownloadTCP.java @@ -50,17 +50,17 @@ public class ClientDownloadTCP extends ClientDownload { * @param partsSubdir directory to store .part files * @param dirStorage directory to write assembled file * @param logger Logger + * @param client HostItem of the application */ - public ClientDownloadTCP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger) { - super(filename, hostList, partsSubdir, dirStorage, logger); + public ClientDownloadTCP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client) { + super(filename, hostList, partsSubdir, dirStorage, logger, client); } /** Create a clientDownloadPart - * @param filename name of the file to download * @param hostItem Hostitem of the server */ - protected ClientDownloadPart createDownloadPart(String filename, HostItem hostItem) { - return (ClientDownloadPart)new ClientDownloadPartTCP((ClientDownload)this, filename, hostItem.getTCPSocket(), partsSubdir, logger); + protected ClientDownloadPart createDownloadPart(HostItem hostItem) { + return (ClientDownloadPart)new ClientDownloadPartTCP((ClientDownload)this, filename, hostItem.getTCPSocket(), partsSubdir, logger, client); } /** Close HostItem socket diff --git a/src/clientP2P/ClientDownloadUDP.java b/src/clientP2P/ClientDownloadUDP.java index 008caaf..5d5dd2a 100644 --- a/src/clientP2P/ClientDownloadUDP.java +++ b/src/clientP2P/ClientDownloadUDP.java @@ -50,17 +50,17 @@ public class ClientDownloadUDP extends ClientDownload { * @param partsSubdir directory to store .part files * @param dirStorage directory to write assembled file * @param logger Logger + * @param client HostItem of the application */ - public ClientDownloadUDP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger) { - super(filename, hostList, partsSubdir, dirStorage, logger); + public ClientDownloadUDP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client) { + super(filename, hostList, partsSubdir, dirStorage, logger, client); } /** Create a clientDownloadPart - * @param filename name of the file to download * @param hostItem Hostitem of the server */ - protected ClientDownloadPart createDownloadPart(String filename, HostItem hostItem) { - return (ClientDownloadPart)new ClientDownloadPartUDP((ClientDownload)this, filename, hostItem.getUDPSocket(), partsSubdir, logger); + protected ClientDownloadPart createDownloadPart(HostItem hostItem) { + return (ClientDownloadPart)new ClientDownloadPartUDP((ClientDownload)this, filename, hostItem.getUDPSocket(), partsSubdir, logger, client); } /** Implementation of writeLog diff --git a/src/clientP2P/ClientManagement.java b/src/clientP2P/ClientManagement.java index cf1dad8..a5a481e 100644 --- a/src/clientP2P/ClientManagement.java +++ b/src/clientP2P/ClientManagement.java @@ -46,6 +46,7 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { protected String partsSubdir; protected List hostList; protected HostItem tracker; + protected HostItem client; protected Logger logger; protected Scanner scanner; protected ClientDownload downLoader; @@ -56,13 +57,15 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { * @param partsSubdir subdirectory to store file parts * @param logger Loggger * @param scanner Scanner used to read input + * @param client HostItem of the application */ - public ClientManagement(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { + public ClientManagement(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner, HostItem client) { this.scanner = scanner; this.baseDirectory = baseDirectory; this.tracker = tracker; this.partsSubdir = partsSubdir; this.logger = logger; + this.client = client; try { initHostList(); } catch (InternalError e) { diff --git a/src/clientP2P/ClientManagementTCP.java b/src/clientP2P/ClientManagementTCP.java index 559fd71..e922157 100644 --- a/src/clientP2P/ClientManagementTCP.java +++ b/src/clientP2P/ClientManagementTCP.java @@ -24,16 +24,17 @@ public class ClientManagementTCP extends ClientManagement { * @param partsSubdir subdirectory to store file parts * @param logger Loggger * @param scanner Scanner used to read input + * @param client HostItem of the application */ - public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { - super(baseDirectory, tracker, partsSubdir, logger, scanner); + public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner, HostItem client) { + super(baseDirectory, tracker, partsSubdir, logger, scanner, client); } /** Initialize downloader * @param filename Name of the file to download */ protected void initDownloader(String filename) { - downLoader = (ClientDownload) new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger); + downLoader = (ClientDownload) new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger, client); } diff --git a/src/clientP2P/ClientManagementUDP.java b/src/clientP2P/ClientManagementUDP.java index 19e7a0b..e34db9c 100644 --- a/src/clientP2P/ClientManagementUDP.java +++ b/src/clientP2P/ClientManagementUDP.java @@ -23,16 +23,17 @@ public class ClientManagementUDP extends ClientManagement { * @param partsSubdir subdirectory to store file parts * @param logger Loggger * @param scanner Scanner used to read input + * @param client HostItem of the application */ - public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { - super(baseDirectory, tracker, partsSubdir, logger, scanner); + public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner, HostItem client) { + super(baseDirectory, tracker, partsSubdir, logger, scanner, client); } /** Initialize downloader * @param filename Name of the file to download */ protected void initDownloader(String filename) { - downLoader = (ClientDownload) new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger); + downLoader = (ClientDownload) new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger, client); } /** Implementation of writeLog diff --git a/src/clientP2P/ClientP2P.java b/src/clientP2P/ClientP2P.java index 5985479..15c8acc 100644 --- a/src/clientP2P/ClientP2P.java +++ b/src/clientP2P/ClientP2P.java @@ -178,7 +178,7 @@ public class ClientP2P { case "upd": // to avoid users typos case "2" : System.out.println("Starting with UDP"); - ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner); + ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner, c.server); tclient = new Thread(cmudp); break; case "TCP": @@ -186,7 +186,7 @@ public class ClientP2P { case "1": default: System.out.println("Starting with TCP"); - ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner); + ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner, c.server); tclient = new Thread(cmtcp); break; } diff --git a/src/protocolP2P/LoadRequest.java b/src/protocolP2P/LoadRequest.java index 86f0b75..b6622a0 100644 --- a/src/protocolP2P/LoadRequest.java +++ b/src/protocolP2P/LoadRequest.java @@ -6,6 +6,7 @@ import localException.ProtocolError; import localException.InternalError; import localException.SizeError; import tools.BytesArrayTools; +import tools.HostItem; /** Representation of payload for load request. * @author Louis Royer @@ -17,18 +18,20 @@ public class LoadRequest extends Payload { private String filename; private long maxSizePartialContent; private long offset; + private HostItem hostItem; static final private int OFFSET_POSITION = PAYLOAD_START_POSITION; static final private int MAX_SIZE_PARTIAL_CONTENT_POSITION = OFFSET_POSITION + 8; static final private int FILENAME_SIZE_POSITION = MAX_SIZE_PARTIAL_CONTENT_POSITION + 8; static final private int FILENAME_POSITION = FILENAME_SIZE_POSITION + 4; - /** Constructor (typically used by the server) with a filename parameter. + /** Constructor (typically used by the client) with a filename parameter. * @param filename name of the file to download. Must not be empty. * @param offset offset of the bloc * @param maxSizePartialContent partial content in response should not excess this size, but this can be less (by example if endoffile is reached or server doesn't have the full block requested) + * @param hostItem hostItem used by the client to register on the tracker * @throws InternalError */ - public LoadRequest(String filename, long offset, long maxSizePartialContent) throws InternalError { + public LoadRequest(String filename, long offset, long maxSizePartialContent, HostItem hostItem) throws InternalError { super(RequestResponseCode.LOAD_REQUEST); /* assert to help debugging */ assert filename.length() != 0 : "Payload size of LoadRequest must not be empty"; @@ -38,9 +41,10 @@ public class LoadRequest extends Payload { this.filename = filename; this.maxSizePartialContent = maxSizePartialContent; this.offset = offset; + this.hostItem = hostItem; } - /** Constructor (typically used by client) with a byte[] parameter containing the Packet received. + /** Constructor (typically used by server) with a byte[] parameter containing the Packet received. * @param packet the full Packet received * @throws SizeError * @throws InternalError @@ -64,6 +68,12 @@ public class LoadRequest extends Payload { /* Read filename */ int size = BytesArrayTools.readInt(packet, FILENAME_SIZE_POSITION); filename = BytesArrayTools.readString(packet, FILENAME_POSITION, size); + + /* Read hostItem */ + int portPosition = FILENAME_POSITION + size; + int hostnameStartPosition = portPosition + 2; + int hostnameSize = getPayloadSize(packet) - hostnameStartPosition; + hostItem = new HostItem(BytesArrayTools.readString(packet, hostnameStartPosition, hostnameSize), BytesArrayTools.readInt16Bits(packet, portPosition)); } /** Returns a byte[] containing Packet with padding. @@ -75,8 +85,9 @@ public class LoadRequest extends Payload { protected byte[] toPacket() throws InternalError { // compute size int filenameSize = filename.length(); - int size = FILENAME_POSITION + filenameSize; - byte[] packet = new byte[size + 1]; // java initialize all to zero + String hostname = hostItem.getHostname(); + int size = 1 + FILENAME_POSITION + filenameSize + 2 + hostname.length(); + byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; // set Payload size @@ -89,7 +100,15 @@ public class LoadRequest extends Payload { BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filenameSize); // Write filename BytesArrayTools.write(packet, filename, FILENAME_POSITION); - return packet; + // Write hostitem + int portPosition = FILENAME_POSITION + filenameSize; + try { + BytesArrayTools.write16Bits(packet, portPosition, hostItem.getPort()); + BytesArrayTools.write(packet, hostname, portPosition + 2); + return packet; + } catch (SizeError e) { + throw new InternalError(); + } } /** filename getter. @@ -112,4 +131,11 @@ public class LoadRequest extends Payload { public long getMaxSizePartialContent() { return maxSizePartialContent; } + + /** hostItem getter. + * @return hostItem + */ + public HostItem getHostItem() { + return hostItem; + } } diff --git a/src/protocolP2P/RequestResponseCode.java b/src/protocolP2P/RequestResponseCode.java index f216d8c..b2994f4 100644 --- a/src/protocolP2P/RequestResponseCode.java +++ b/src/protocolP2P/RequestResponseCode.java @@ -18,17 +18,22 @@ public enum RequestResponseCode { DISCOVER_REQUEST(CodeType.REQUEST_TRACKER, (byte)0x03), REGISTER(CodeType.REQUEST_TRACKER, (byte)0x04), UNREGISTER(CodeType.REQUEST_TRACKER, (byte)0x05), + RATIO_REQUEST(CodeType.REQUEST_TRACKER, (byte)0x06), + UPDATE_RATIO(CodeType.REQUEST_TRACKER, (byte)0x07), LIST_RESPONSE(CodeType.RESPONSE, (byte)0x80), LOAD_RESPONSE(CodeType.RESPONSE, (byte)0x81), HASH_RESPONSE(CodeType.RESPONSE, (byte)0x82), DISCOVER_RESPONSE(CodeType.RESPONSE, (byte)0x83), + RATIO_RESPONSE(CodeType.RESPONSE, (byte)0x86), VERSION_ERROR(CodeType.ERROR, (byte)0xC0), PROTOCOL_ERROR(CodeType.ERROR, (byte)0xC1), INTERNAL_ERROR(CodeType.ERROR, (byte)0xC2), EMPTY_DIRECTORY(CodeType.ERROR, (byte)0xC3), NOT_FOUND(CodeType.ERROR, (byte)0xC4), EMPTY_FILE(CodeType.ERROR, (byte)0xC5), - NOT_A_TRACKER(CodeType.ERROR, (byte)0xC6); + NOT_A_TRACKER(CodeType.ERROR, (byte)0xC6), + UNKNOWN_HOST(CodeType.ERROR, (byte)0xC7), + DENIED(CodeType.ERROR, (byte)0xC8); public final CodeType codeType; public final byte codeValue; From 5fa160d98d7a90963f42b86fdb05274743dbc359 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Fri, 27 Mar 2020 16:59:17 +0100 Subject: [PATCH 03/13] Add classes for ratio --- doc/protocol.md | 5 +- src/protocolP2P/RatioRequest.java | 77 ++++++++++++++++++++ src/protocolP2P/RatioResponse.java | 106 +++++++++++++++++++++++++++ src/protocolP2P/Register.java | 4 +- src/protocolP2P/Unregister.java | 4 +- src/protocolP2P/UpdateRatio.java | 112 +++++++++++++++++++++++++++++ 6 files changed, 302 insertions(+), 6 deletions(-) create mode 100644 src/protocolP2P/RatioRequest.java create mode 100644 src/protocolP2P/RatioResponse.java create mode 100644 src/protocolP2P/UpdateRatio.java diff --git a/doc/protocol.md b/doc/protocol.md index 997adb0..045382c 100644 --- a/doc/protocol.md +++ b/doc/protocol.md @@ -171,15 +171,16 @@ Possible responses: Ratio Response, or Unknown Host #### Ratio Response Contains: ```text -2 bytes: port -? bytes: hostname followed by \n 8 bytes: total sent bytes 8 bytes: total received bytes +2 bytes: port +? bytes: hostname ``` #### Update Ratio Contains: ```text +8 bytes: bytes sent by the server 2 bytes: server port 2 bytes: client* port ? bytes: server hostname followed by \n diff --git a/src/protocolP2P/RatioRequest.java b/src/protocolP2P/RatioRequest.java new file mode 100644 index 0000000..87e76bf --- /dev/null +++ b/src/protocolP2P/RatioRequest.java @@ -0,0 +1,77 @@ +package protocolP2P; +import protocolP2P.Payload; +import tools.HostItem; +import tools.BytesArrayTools; +import localException.SizeError; +import localException.InternalError; +import localException.TransmissionError; +import localException.ProtocolError; + +/** Representation of payload for ratio request. + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public class RatioRequest extends Payload { + private HostItem hostItem; + private static final int HOSTNAME_START_POSITION = PAYLOAD_START_POSITION + 2; + + /** Constructor with hostItem (typically used by client/server) + * @param hostItem Host to get ratio of. + * @throws InternalError + */ + public RatioRequest(HostItem hostItem) throws InternalError { + super(RequestResponseCode.RATIO_REQUEST); + this.hostItem = hostItem; + } + + /** Constructor (typically used by tracker) with a byte[] parameter containing the Packet received. + * @param packet the full Packet received + * @throws SizeError + * @throws InternalError + * @throws ProtocolError + * @throws TransmissionError + */ + protected RatioRequest(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError { + super(packet); + int size = getPayloadSize(packet); + int port = BytesArrayTools.readInt16Bits(packet, PAYLOAD_START_POSITION); + String hostname = BytesArrayTools.readString(packet, HOSTNAME_START_POSITION, size - HOSTNAME_START_POSITION + PAYLOAD_START_POSITION); + hostItem = new HostItem(hostname, port); + } + + /** Returns a byte[] containing Packet with padding. + * This Packet is still incomplete and should not be send directly. + * ProtocolP2PPacket will use this method to generate the complete Packet. + * @return Packet with padding + * @throws InternalError + */ + protected byte[] toPacket() throws InternalError { + String hostname = hostItem.getHostname(); + // compute total size + int size = 1 + HOSTNAME_START_POSITION + hostname.length(); + byte[] packet = new byte[size]; // java initialize all to zero + // set request/response code + packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; + // set Payload size + setPayloadSize(size - PAYLOAD_START_POSITION, packet); + // write port to Packet + try { + BytesArrayTools.write16Bits(packet, PAYLOAD_START_POSITION, hostItem.getPort()); + } catch (SizeError e) { + throw new InternalError(); + } + // write hostname to Packet + BytesArrayTools.write(packet, hostname, HOSTNAME_START_POSITION); + return packet; + } + + /** HostItem getter. + * @return hostItem + */ + public HostItem getHostItem() { + return hostItem; + } + +} diff --git a/src/protocolP2P/RatioResponse.java b/src/protocolP2P/RatioResponse.java new file mode 100644 index 0000000..05e07ca --- /dev/null +++ b/src/protocolP2P/RatioResponse.java @@ -0,0 +1,106 @@ +package protocolP2P; +import protocolP2P.Payload; +import tools.HostItem; +import tools.BytesArrayTools; +import localException.SizeError; +import localException.InternalError; +import localException.TransmissionError; +import localException.ProtocolError; + +/** Representation of payload for ratio response. + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public class RatioResponse extends Payload { + private HostItem hostItem; + private long totalUp; + private long totalDown; + private static final int TOTAL_UP_START_POSITION = PAYLOAD_START_POSITION; + private static final int TOTAL_DOWN_START_POSITION = TOTAL_UP_START_POSITION + 8; + private static final int PORT_START_POSITION = TOTAL_DOWN_START_POSITION + 8; + private static final int HOSTNAME_START_POSITION = PORT_START_POSITION + 2; + + /** Constructor with hostItem (typically used by tracker) + * @param hostItem Host to get ratio of. + * @param totalUp total bytes uploaded + * @param totalDown total bytes downloaded + * @throws InternalError + */ + public RatioResponse(HostItem hostItem, long totalUp, long totalDown) throws InternalError { + super(RequestResponseCode.RATIO_RESPONSE); + this.hostItem = hostItem; + this.totalUp = totalUp; + this.totalDown = totalDown; + } + + /** Constructor (typically used by client/server) with a byte[] parameter containing the Packet received. + * @param packet the full Packet received + * @throws SizeError + * @throws InternalError + * @throws ProtocolError + * @throws TransmissionError + */ + protected RatioResponse(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError { + super(packet); + int size = getPayloadSize(packet); + totalUp = BytesArrayTools.readLong(packet, TOTAL_UP_START_POSITION); + totalDown = BytesArrayTools.readLong(packet, TOTAL_DOWN_START_POSITION); + int port = BytesArrayTools.readInt16Bits(packet, PORT_START_POSITION); + String hostname = BytesArrayTools.readString(packet, HOSTNAME_START_POSITION, size - HOSTNAME_START_POSITION + PAYLOAD_START_POSITION); + hostItem = new HostItem(hostname, port); + } + + /** Returns a byte[] containing Packet with padding. + * This Packet is still incomplete and should not be send directly. + * ProtocolP2PPacket will use this method to generate the complete Packet. + * @return Packet with padding + * @throws InternalError + */ + protected byte[] toPacket() throws InternalError { + String hostname = hostItem.getHostname(); + // compute total size + int size = 1 + HOSTNAME_START_POSITION + hostname.length(); + byte[] packet = new byte[size]; // java initialize all to zero + // set request/response code + packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; + // set Payload size + setPayloadSize(size - PAYLOAD_START_POSITION, packet); + // write totalUp + BytesArrayTools.write(packet, TOTAL_UP_START_POSITION, totalUp); + // write totalDown + BytesArrayTools.write(packet, TOTAL_DOWN_START_POSITION, totalDown); + // write port to Packet + try { + BytesArrayTools.write16Bits(packet, PORT_START_POSITION, hostItem.getPort()); + } catch (SizeError e) { + throw new InternalError(); + } + // write hostname to Packet + BytesArrayTools.write(packet, hostname, HOSTNAME_START_POSITION); + return packet; + } + + /** HostItem getter. + * @return hostItem + */ + public HostItem getHostItem() { + return hostItem; + } + + /** totalUp getter. + * @return totalUp + */ + public long getTotalUp() { + return totalUp; + } + + /** totalDown getter. + * @return totalDown + */ + public long getTotalDown() { + return totalDown; + } + +} diff --git a/src/protocolP2P/Register.java b/src/protocolP2P/Register.java index 790ac2b..4f49022 100644 --- a/src/protocolP2P/Register.java +++ b/src/protocolP2P/Register.java @@ -50,8 +50,8 @@ public class Register extends Payload { protected byte[] toPacket() throws InternalError { String hostname = hostItem.getHostname(); // compute total size - int size = HOSTNAME_START_POSITION + hostname.length(); - byte[] packet = new byte[size + 1]; // java initialize all to zero + int size = 1 + HOSTNAME_START_POSITION + hostname.length(); + byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; // set Payload size diff --git a/src/protocolP2P/Unregister.java b/src/protocolP2P/Unregister.java index 8307a5b..35e34a8 100644 --- a/src/protocolP2P/Unregister.java +++ b/src/protocolP2P/Unregister.java @@ -50,8 +50,8 @@ public class Unregister extends Payload { protected byte[] toPacket() throws InternalError { String hostname = hostItem.getHostname(); // compute total size - int size = HOSTNAME_START_POSITION + hostname.length(); - byte[] packet = new byte[size + 1]; // java initialize all to zero + int size = 1 + HOSTNAME_START_POSITION + hostname.length(); + byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; // set Payload size diff --git a/src/protocolP2P/UpdateRatio.java b/src/protocolP2P/UpdateRatio.java new file mode 100644 index 0000000..b373623 --- /dev/null +++ b/src/protocolP2P/UpdateRatio.java @@ -0,0 +1,112 @@ +package protocolP2P; +import protocolP2P.Payload; +import tools.HostItem; +import tools.BytesArrayTools; +import localException.SizeError; +import localException.InternalError; +import localException.TransmissionError; +import localException.ProtocolError; + +/** Representation of payload for update ratio. + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public class UpdateRatio extends Payload { + private HostItem client; + private HostItem server; + private long dataSize; + private static final int DATA_SIZE_POSITION = PAYLOAD_START_POSITION; + private static final int SERVER_PORT_START_POSITION = DATA_SIZE_POSITION + 8; + private static final int CLIENT_PORT_START_POSITION = SERVER_PORT_START_POSITION + 2; + private static final int HOSTNAMES_START_POSITION = CLIENT_PORT_START_POSITION + 2; + + /** Constructor with hostItem (typically used by client) + * @param client HostItem of the client application. + * @param server HostItem of the server application. + * @param dataSize size of data sent. + * @throws InternalError + */ + public UpdateRatio(HostItem client, HostItem server, long dataSize) throws InternalError { + super(RequestResponseCode.UPDATE_RATIO); + this.client = client; + this.server = server; + this.dataSize = dataSize; + } + + /** Constructor (typically used by tracker) with a byte[] parameter containing the Packet received. + * @param packet the full Packet received + * @throws SizeError + * @throws InternalError + * @throws ProtocolError + * @throws TransmissionError + */ + protected UpdateRatio(byte[] packet) throws SizeError, ProtocolError, InternalError, TransmissionError { + super(packet); + int size = getPayloadSize(packet); + dataSize = BytesArrayTools.readLong(packet, DATA_SIZE_POSITION); + int portServer = BytesArrayTools.readInt16Bits(packet, SERVER_PORT_START_POSITION); + int portClient = BytesArrayTools.readInt16Bits(packet, CLIENT_PORT_START_POSITION); + String[] hostnames = BytesArrayTools.readStringArray(packet, HOSTNAMES_START_POSITION, size - HOSTNAMES_START_POSITION + PAYLOAD_START_POSITION, "\n"); + server = new HostItem(hostnames[0], portServer); + client = new HostItem(hostnames[1], portClient); + } + + /** Returns a byte[] containing Packet with padding. + * This Packet is still incomplete and should not be send directly. + * ProtocolP2PPacket will use this method to generate the complete Packet. + * @return Packet with padding + * @throws InternalError + */ + protected byte[] toPacket() throws InternalError { + String[] hostnames = { server.getHostname(), client.getHostname()}; + // compute total size + int size = 1 + HOSTNAMES_START_POSITION + BytesArrayTools.computeStringArraySize(hostnames, "\n"); + byte[] packet = new byte[size]; // java initialize all to zero + // set request/response code + packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; + // set Payload size + setPayloadSize(size - PAYLOAD_START_POSITION, packet); + // write dataSize + BytesArrayTools.write(packet, DATA_SIZE_POSITION, dataSize); + // write server port to Packet + try { + BytesArrayTools.write16Bits(packet, SERVER_PORT_START_POSITION, server.getPort()); + } catch (SizeError e) { + throw new InternalError(); + } + // write client port to Packet + try { + BytesArrayTools.write16Bits(packet, CLIENT_PORT_START_POSITION, client.getPort()); + } catch (SizeError e) { + throw new InternalError(); + } + // write hostnames to Packet + BytesArrayTools.write(packet, hostnames, HOSTNAMES_START_POSITION, "\n"); + return packet; + } + + /** Client getter. + * @return client + */ + public HostItem getClient() { + return client; + } + + /** Server getter + * @return server + */ + public HostItem getServer() { + return server; + } + + /** dataSize getter. + * @return dataSize + */ + public long getDataSize() { + return dataSize; + } + + +} From d6fbfa66835e055bde7b97e30e028961c1e83511 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Fri, 27 Mar 2020 17:10:09 +0100 Subject: [PATCH 04/13] Update Payload and protocolP2P packet to allow ratio --- src/protocolP2P/Payload.java | 12 ++++++++++++ src/protocolP2P/ProtocolP2PPacketTCP.java | 13 +++++++++++++ src/protocolP2P/ProtocolP2PPacketUDP.java | 13 +++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/protocolP2P/Payload.java b/src/protocolP2P/Payload.java index 990df6b..5f2a3a2 100644 --- a/src/protocolP2P/Payload.java +++ b/src/protocolP2P/Payload.java @@ -9,6 +9,9 @@ import protocolP2P.DiscoverRequest; import protocolP2P.DiscoverResponse; import protocolP2P.Register; import protocolP2P.Unregister; +import protocolP2P.RatioRequest; +import protocolP2P.RatioResponse; +import protocolP2P.UpdateRatio; import localException.ProtocolError; import localException.InternalError; import localException.TransmissionError; @@ -40,6 +43,9 @@ public class Payload { assert requestResponseCode != RequestResponseCode.DISCOVER_RESPONSE || (this instanceof DiscoverResponse) : "DISCOVER_RESPONSE must use DiscoverResponse class"; assert requestResponseCode != RequestResponseCode.REGISTER || (this instanceof Register) : "REGISTER must use Register class"; assert requestResponseCode != RequestResponseCode.UNREGISTER || (this instanceof Unregister) : "UNREGISTER must use Unregister class"; + assert requestResponseCode != RequestResponseCode.RATIO_REQUEST || (this instanceof RatioRequest) : "RATIO_REQUEST must use RatioRequest class"; + assert requestResponseCode != RequestResponseCode.RATIO_RESPONSE || (this instanceof RatioResponse) : "RATIO_RESPONSE must use RatioResponse class"; + assert requestResponseCode != RequestResponseCode.UPDATE_RATIO || (this instanceof UpdateRatio) : "UPDATE_RATIO must use UpdateRatio class"; this.requestResponseCode = requestResponseCode; checkRequestResponseCode(); // this can throw InternalError } @@ -67,6 +73,9 @@ public class Payload { assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.DISCOVER_RESPONSE || (this instanceof DiscoverResponse) : "DISCOVER_RESPONSE must use DiscoverResponse class"; assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.REGISTER || (this instanceof Register) : "REGISTER must use Register class"; assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.UNREGISTER || (this instanceof Unregister) : "UNREGISTER must use Unregister class"; + assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.RATIO_REQUEST || (this instanceof RatioRequest) : "RATIO_REQUEST must use RatioRequest class"; + assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.RATIO_RESPONSE || (this instanceof RatioResponse) : "RATIO_RESPONSE must use RatioResponse class"; + assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.UPDATE_RATIO || (this instanceof UpdateRatio) : "UPDATE_RATIO must use UpdateRatio class"; requestResponseCode = RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]); checkRequestResponseCode(); // this can throw InternalError } @@ -85,6 +94,9 @@ public class Payload { || (requestResponseCode == RequestResponseCode.DISCOVER_RESPONSE && !(this instanceof DiscoverResponse)) || (requestResponseCode == RequestResponseCode.REGISTER && !(this instanceof Register)) || (requestResponseCode == RequestResponseCode.UNREGISTER && !(this instanceof Unregister)) + || (requestResponseCode == RequestResponseCode.RATIO_REQUEST && !(this instanceof RatioRequest)) + || (requestResponseCode == RequestResponseCode.RATIO_RESPONSE && !(this instanceof RatioResponse)) + || (requestResponseCode == RequestResponseCode.UPDATE_RATIO && !(this instanceof UpdateRatio)) ) { throw new InternalError(); } diff --git a/src/protocolP2P/ProtocolP2PPacketTCP.java b/src/protocolP2P/ProtocolP2PPacketTCP.java index 708ee38..4eb2bfd 100644 --- a/src/protocolP2P/ProtocolP2PPacketTCP.java +++ b/src/protocolP2P/ProtocolP2PPacketTCP.java @@ -18,6 +18,9 @@ import protocolP2P.RequestResponseCode; import protocolP2P.LoadRequest; import protocolP2P.FileList; import protocolP2P.FilePart; +import protocolP2P.RatioRequest; +import protocolP2P.RatioResponse; +import protocolP2P.UpdateRatio; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; @@ -141,6 +144,7 @@ public class ProtocolP2PPacketTCP < T extends Payload > extends ProtocolP2PPacke case HASH_RESPONSE: case DISCOVER_RESPONSE: case NOT_A_TRACKER: + case RATIO_RESPONSE: // we were expecting a request, but we are receiving a response throw new ProtocolError(); default : @@ -319,6 +323,15 @@ public class ProtocolP2PPacketTCP < T extends Payload > extends ProtocolP2PPacke case DISCOVER_RESPONSE: payload = (Payload) new DiscoverResponse(packet); break; + case RATIO_REQUEST: + payload = (Payload) new RatioRequest(packet); + break; + case RATIO_RESPONSE: + payload = (Payload) new RatioResponse(packet); + break; + case UPDATE_RATIO: + payload = (Payload) new UpdateRatio(packet); + break; default: payload = new Payload(packet); // this can throw TransmissionError break; diff --git a/src/protocolP2P/ProtocolP2PPacketUDP.java b/src/protocolP2P/ProtocolP2PPacketUDP.java index a54733b..e7fbbc5 100644 --- a/src/protocolP2P/ProtocolP2PPacketUDP.java +++ b/src/protocolP2P/ProtocolP2PPacketUDP.java @@ -19,6 +19,9 @@ import protocolP2P.RequestResponseCode; import protocolP2P.LoadRequest; import protocolP2P.FileList; import protocolP2P.FilePart; +import protocolP2P.RatioRequest; +import protocolP2P.RatioResponse; +import protocolP2P.UpdateRatio; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress; @@ -134,6 +137,7 @@ public class ProtocolP2PPacketUDP < T extends Payload> extends ProtocolP2PPacket case HASH_RESPONSE: case DISCOVER_RESPONSE: case NOT_A_TRACKER: + case RATIO_RESPONSE: // we were expecting a request, but we are receiving a response throw new ProtocolError(); default : @@ -304,6 +308,15 @@ public class ProtocolP2PPacketUDP < T extends Payload> extends ProtocolP2PPacket case DISCOVER_RESPONSE: payload = (Payload) new DiscoverResponse(packet); break; + case RATIO_REQUEST: + payload = (Payload) new RatioRequest(packet); + break; + case RATIO_RESPONSE: + payload = (Payload) new RatioResponse(packet); + break; + case UPDATE_RATIO: + payload = (Payload) new UpdateRatio(packet); + break; default: payload = new Payload(packet); // this can throw TransmissionError break; From d9c4c8ba40b478fc85e6e27b9caa5d7f9aa109ba Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Fri, 27 Mar 2020 17:40:58 +0100 Subject: [PATCH 05/13] Fix off by 1 lengths; fix debug color --- src/protocolP2P/DiscoverRequest.java | 4 ++-- src/protocolP2P/DiscoverResponse.java | 4 ++-- src/protocolP2P/FilePart.java | 2 +- src/protocolP2P/HashRequest.java | 2 +- src/protocolP2P/HashResponse.java | 2 +- src/tools/Logger.java | 3 ++- src/tracker/TrackerManagementTCP.java | 4 ++-- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/protocolP2P/DiscoverRequest.java b/src/protocolP2P/DiscoverRequest.java index 7ef1751..3852b4e 100644 --- a/src/protocolP2P/DiscoverRequest.java +++ b/src/protocolP2P/DiscoverRequest.java @@ -50,8 +50,8 @@ public class DiscoverRequest extends Payload { */ protected byte[] toPacket() throws InternalError { // compute total size - int size = PAYLOAD_START_POSITION + filename.length(); - byte[] packet = new byte[size + 1]; // java initialize all to zero + int size = 1 + PAYLOAD_START_POSITION + filename.length(); + byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; // set Payload size diff --git a/src/protocolP2P/DiscoverResponse.java b/src/protocolP2P/DiscoverResponse.java index 4c73e36..b499f65 100644 --- a/src/protocolP2P/DiscoverResponse.java +++ b/src/protocolP2P/DiscoverResponse.java @@ -74,8 +74,8 @@ public class DiscoverResponse extends Payload { hostListSize += (2 + hostItem.getHostname().length() + 1); } // compute total size - int size = FILENAME_POSITION + filename.length() + hostListSize; - byte[] packet = new byte[size + 1]; // java initialize all to zero + int size = 1 + FILENAME_POSITION + filename.length() + hostListSize; + byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; // set Payload size diff --git a/src/protocolP2P/FilePart.java b/src/protocolP2P/FilePart.java index d168a05..a410f51 100644 --- a/src/protocolP2P/FilePart.java +++ b/src/protocolP2P/FilePart.java @@ -77,7 +77,7 @@ public class FilePart extends Payload { protected byte[] toPacket() throws InternalError { // compute total size int size = FILENAME_POSITION + filename.length() + partialContent.length; - byte[] packet = new byte[size + 1]; // java initialize all to zero + byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; // set Payload size diff --git a/src/protocolP2P/HashRequest.java b/src/protocolP2P/HashRequest.java index 1eec671..cad74f7 100644 --- a/src/protocolP2P/HashRequest.java +++ b/src/protocolP2P/HashRequest.java @@ -90,7 +90,7 @@ public class HashRequest extends Payload { i++; } int size = FILENAME_POSITION + filenameSize + BytesArrayTools.computeStringArraySize(algoListStr, "\n"); - byte[] packet = new byte[size + 1]; // java initialize all to zero + byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; // set Payload size diff --git a/src/protocolP2P/HashResponse.java b/src/protocolP2P/HashResponse.java index 743b13e..041c8a3 100644 --- a/src/protocolP2P/HashResponse.java +++ b/src/protocolP2P/HashResponse.java @@ -98,7 +98,7 @@ public class HashResponse extends Payload { for (byte[] s : hashes.values()) { size += 4 + s.length; } - byte[] packet = new byte[size + 1]; // java initialize all to zero + byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; diff --git a/src/tools/Logger.java b/src/tools/Logger.java index ce0f82e..b08f15a 100644 --- a/src/tools/Logger.java +++ b/src/tools/Logger.java @@ -34,7 +34,7 @@ public class Logger { * @param text Text to log */ public void write(String text, LogLevel logLevel) { - String colorize = "\u001B[0"; + String colorize = "\u001B[0m"; String msg = "[" + new Timestamp(System.currentTimeMillis()) + "] " + text + "\n"; String level = null; switch (logLevel) { @@ -55,6 +55,7 @@ public class Logger { break; case Debug: level = "[Debug]"; + colorize = "\u001B[36m"; // CYAN break; default: System.err.println("Error: incorrect logLevel"); diff --git a/src/tracker/TrackerManagementTCP.java b/src/tracker/TrackerManagementTCP.java index 603bab5..0f8abec 100644 --- a/src/tracker/TrackerManagementTCP.java +++ b/src/tracker/TrackerManagementTCP.java @@ -86,11 +86,11 @@ public class TrackerManagementTCP extends TrackerManagement { public void run() { boolean end = false; - writeLog("[ " + addr + "] New connection", LogLevel.Action); + writeLog("[" + addr + "] New connection", LogLevel.Action); do { end = handleClientRequest(); } while(!end); - writeLog("[ " + addr + "] End of connection", LogLevel.Action); + writeLog("[" + addr + "] End of connection", LogLevel.Action); } /** Respond to next request incomming on socket s. From 77655cb828b85ce034375d268d8449e0c625c3b2 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Fri, 27 Mar 2020 18:00:06 +0100 Subject: [PATCH 06/13] Add DENIED protocol element --- doc/protocol.md | 5 +- src/protocolP2P/Denied.java | 86 +++++++++++++++++++++++ src/protocolP2P/Payload.java | 4 ++ src/protocolP2P/ProtocolP2PPacketTCP.java | 5 ++ src/protocolP2P/ProtocolP2PPacketUDP.java | 5 ++ src/protocolP2P/RequestResponseCode.java | 4 +- src/remoteException/UnknownHost.java | 7 ++ 7 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 src/protocolP2P/Denied.java create mode 100644 src/remoteException/UnknownHost.java diff --git a/doc/protocol.md b/doc/protocol.md index 045382c..c5e5460 100644 --- a/doc/protocol.md +++ b/doc/protocol.md @@ -29,6 +29,7 @@ x bytes: [(bytes 8-?): PAYLOAD] - `HASH` (0x82) - `DISCOVER` (0x83) - `RATIO` (0x86) + - `DENIED` (0x87) - `VERSION ERROR` (0xC0) - `PROTOCOL ERROR` (0xC1) - `INTERNAL ERROR` (0xC2) @@ -37,7 +38,6 @@ x bytes: [(bytes 8-?): PAYLOAD] - `EMPTY FILE` (0xC5) - `NOT A TRACKER` (0xC6) - `UNKNOWN HOST` (0xC7) - - `DENIED` (0xC8) ### List Payload size for list request is always zero. @@ -197,7 +197,8 @@ Payload size is zero. #### Denied Contains ```text -?bytes: filename +8 bytes: offset of content asked +? bytes: filename ``` ### Other response code (errors) diff --git a/src/protocolP2P/Denied.java b/src/protocolP2P/Denied.java new file mode 100644 index 0000000..7b20eec --- /dev/null +++ b/src/protocolP2P/Denied.java @@ -0,0 +1,86 @@ +package protocolP2P; +import protocolP2P.Payload; +import protocolP2P.RequestResponseCode; +import localException.ProtocolError; +import localException.InternalError; +import localException.SizeError; +import localException.TransmissionError; +import tools.BytesArrayTools; + +/** Representation of payload for denied response. + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public class Denied extends Payload { + private String filename; + private long offset; + static final private int OFFSET_POSITION = PAYLOAD_START_POSITION; + static final private int FILENAME_POSITION = OFFSET_POSITION + 8; + + /** Constructor (typically used by server) with informations about file part to send as parameters. + * @param filename name of the file to send + * @param offset where in the file begins the part we are sending + * @throws InternalError + */ + public Denied(String filename, long offset) throws InternalError { + super(RequestResponseCode.DENIED); + /* asserts to help debugging */ + assert offset >= 0 : "offset cannot be negative"; + assert filename != null : "filename is required"; + if (offset < 0 || filename == null) { + throw new InternalError(); + } + this.filename = filename; + this.offset = offset; + } + + /** Constructor (typically used by client) with Packet received as parameter. + * @param packet the full Packet received + * @throws SizeError + * @throws InternalError + * @throws TransmissionError + */ + protected Denied(byte[] packet) throws TransmissionError, SizeError, ProtocolError, InternalError { + super(packet); + int filenameSize = getPayloadSize(packet) - FILENAME_POSITION + PAYLOAD_START_POSITION; + offset = BytesArrayTools.readLong(packet, OFFSET_POSITION); + filename = BytesArrayTools.readString(packet, FILENAME_POSITION, filenameSize); + } + + /** Returns a byte[] containing Packet with padding. + * This Packet is still incomplete and should not be send directly. + * ProtocolP2PPacket will use this method to generate the complete Packet. + * @return Packet with padding + * @throws InternalError + */ + protected byte[] toPacket() throws InternalError { + // compute total size + int size = FILENAME_POSITION + filename.length(); + byte[] packet = new byte[size]; // java initialize all to zero + // set request/response code + packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; + // set Payload size + setPayloadSize(size - PAYLOAD_START_POSITION, packet); + // write offset to Packet + BytesArrayTools.write(packet, OFFSET_POSITION, offset); + // write filename to Packet + BytesArrayTools.write(packet, filename, FILENAME_POSITION); + return packet; + } + + /** filename getter. + * @return String + */ + public String getFilename() { + return filename; + } + + /** offset getter. + * @return offset + */ + public long getOffset() { + return offset; + } +} diff --git a/src/protocolP2P/Payload.java b/src/protocolP2P/Payload.java index 5f2a3a2..e41f94c 100644 --- a/src/protocolP2P/Payload.java +++ b/src/protocolP2P/Payload.java @@ -12,6 +12,7 @@ import protocolP2P.Unregister; import protocolP2P.RatioRequest; import protocolP2P.RatioResponse; import protocolP2P.UpdateRatio; +import protocolP2P.Denied; import localException.ProtocolError; import localException.InternalError; import localException.TransmissionError; @@ -46,6 +47,7 @@ public class Payload { assert requestResponseCode != RequestResponseCode.RATIO_REQUEST || (this instanceof RatioRequest) : "RATIO_REQUEST must use RatioRequest class"; assert requestResponseCode != RequestResponseCode.RATIO_RESPONSE || (this instanceof RatioResponse) : "RATIO_RESPONSE must use RatioResponse class"; assert requestResponseCode != RequestResponseCode.UPDATE_RATIO || (this instanceof UpdateRatio) : "UPDATE_RATIO must use UpdateRatio class"; + assert requestResponseCode != RequestResponseCode.DENIED || (this instanceof Denied) : "DENIED must use Denied class"; this.requestResponseCode = requestResponseCode; checkRequestResponseCode(); // this can throw InternalError } @@ -76,6 +78,7 @@ public class Payload { assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.RATIO_REQUEST || (this instanceof RatioRequest) : "RATIO_REQUEST must use RatioRequest class"; assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.RATIO_RESPONSE || (this instanceof RatioResponse) : "RATIO_RESPONSE must use RatioResponse class"; assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.UPDATE_RATIO || (this instanceof UpdateRatio) : "UPDATE_RATIO must use UpdateRatio class"; + assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.DENIED || (this instanceof Denied) : "DENIED must use Denied class"; requestResponseCode = RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]); checkRequestResponseCode(); // this can throw InternalError } @@ -97,6 +100,7 @@ public class Payload { || (requestResponseCode == RequestResponseCode.RATIO_REQUEST && !(this instanceof RatioRequest)) || (requestResponseCode == RequestResponseCode.RATIO_RESPONSE && !(this instanceof RatioResponse)) || (requestResponseCode == RequestResponseCode.UPDATE_RATIO && !(this instanceof UpdateRatio)) + || (requestResponseCode == RequestResponseCode.DENIED && !(this instanceof Denied)) ) { throw new InternalError(); } diff --git a/src/protocolP2P/ProtocolP2PPacketTCP.java b/src/protocolP2P/ProtocolP2PPacketTCP.java index 4eb2bfd..0c348e5 100644 --- a/src/protocolP2P/ProtocolP2PPacketTCP.java +++ b/src/protocolP2P/ProtocolP2PPacketTCP.java @@ -21,6 +21,7 @@ import protocolP2P.FilePart; import protocolP2P.RatioRequest; import protocolP2P.RatioResponse; import protocolP2P.UpdateRatio; +import protocolP2P.Denied; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; @@ -145,6 +146,7 @@ public class ProtocolP2PPacketTCP < T extends Payload > extends ProtocolP2PPacke case DISCOVER_RESPONSE: case NOT_A_TRACKER: case RATIO_RESPONSE: + case DENIED: // we were expecting a request, but we are receiving a response throw new ProtocolError(); default : @@ -332,6 +334,9 @@ public class ProtocolP2PPacketTCP < T extends Payload > extends ProtocolP2PPacke case UPDATE_RATIO: payload = (Payload) new UpdateRatio(packet); break; + case DENIED: + payload = (Payload) new Denied(packet); + break; default: payload = new Payload(packet); // this can throw TransmissionError break; diff --git a/src/protocolP2P/ProtocolP2PPacketUDP.java b/src/protocolP2P/ProtocolP2PPacketUDP.java index e7fbbc5..894be60 100644 --- a/src/protocolP2P/ProtocolP2PPacketUDP.java +++ b/src/protocolP2P/ProtocolP2PPacketUDP.java @@ -22,6 +22,7 @@ import protocolP2P.FilePart; import protocolP2P.RatioRequest; import protocolP2P.RatioResponse; import protocolP2P.UpdateRatio; +import protocolP2P.Denied; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress; @@ -138,6 +139,7 @@ public class ProtocolP2PPacketUDP < T extends Payload> extends ProtocolP2PPacket case DISCOVER_RESPONSE: case NOT_A_TRACKER: case RATIO_RESPONSE: + case DENIED: // we were expecting a request, but we are receiving a response throw new ProtocolError(); default : @@ -317,6 +319,9 @@ public class ProtocolP2PPacketUDP < T extends Payload> extends ProtocolP2PPacket case UPDATE_RATIO: payload = (Payload) new UpdateRatio(packet); break; + case DENIED: + payload = (Payload) new Denied(packet); + break; default: payload = new Payload(packet); // this can throw TransmissionError break; diff --git a/src/protocolP2P/RequestResponseCode.java b/src/protocolP2P/RequestResponseCode.java index b2994f4..1941870 100644 --- a/src/protocolP2P/RequestResponseCode.java +++ b/src/protocolP2P/RequestResponseCode.java @@ -25,6 +25,7 @@ public enum RequestResponseCode { HASH_RESPONSE(CodeType.RESPONSE, (byte)0x82), DISCOVER_RESPONSE(CodeType.RESPONSE, (byte)0x83), RATIO_RESPONSE(CodeType.RESPONSE, (byte)0x86), + DENIED(CodeType.RESPONSE, (byte)0x87), VERSION_ERROR(CodeType.ERROR, (byte)0xC0), PROTOCOL_ERROR(CodeType.ERROR, (byte)0xC1), INTERNAL_ERROR(CodeType.ERROR, (byte)0xC2), @@ -32,8 +33,7 @@ public enum RequestResponseCode { NOT_FOUND(CodeType.ERROR, (byte)0xC4), EMPTY_FILE(CodeType.ERROR, (byte)0xC5), NOT_A_TRACKER(CodeType.ERROR, (byte)0xC6), - UNKNOWN_HOST(CodeType.ERROR, (byte)0xC7), - DENIED(CodeType.ERROR, (byte)0xC8); + UNKNOWN_HOST(CodeType.ERROR, (byte)0xC7); public final CodeType codeType; public final byte codeValue; diff --git a/src/remoteException/UnknownHost.java b/src/remoteException/UnknownHost.java new file mode 100644 index 0000000..0c2ccad --- /dev/null +++ b/src/remoteException/UnknownHost.java @@ -0,0 +1,7 @@ +package remoteException; + +import exception.RemoteException; + +public class UnknownHost extends RemoteException { + private static final long serialVersionUID = 12L; +} From c81f5d2e5a7adda5e9fa68ff3ec716c360d4f7ac Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Fri, 27 Mar 2020 18:41:27 +0100 Subject: [PATCH 07/13] Fix #41 --- doc/protocol.md | 20 +++++- src/clientP2P/ClientDownload.java | 34 +++------ src/protocolP2P/DiscoverRequest.java | 2 +- src/protocolP2P/DiscoverResponse.java | 2 +- src/protocolP2P/FilePart.java | 29 +------- src/protocolP2P/LoadRequest.java | 2 +- src/protocolP2P/Payload.java | 8 +++ src/protocolP2P/ProtocolP2PPacketTCP.java | 9 +++ src/protocolP2P/ProtocolP2PPacketUDP.java | 9 +++ src/protocolP2P/RatioRequest.java | 2 +- src/protocolP2P/RatioResponse.java | 2 +- src/protocolP2P/Register.java | 2 +- src/protocolP2P/RequestResponseCode.java | 2 + src/protocolP2P/SizeRequest.java | 70 ++++++++++++++++++ src/protocolP2P/SizeResponse.java | 86 +++++++++++++++++++++++ src/protocolP2P/Unregister.java | 2 +- src/protocolP2P/UpdateRatio.java | 2 +- src/serverP2P/ServerManagement.java | 45 +++++++++++- 18 files changed, 267 insertions(+), 61 deletions(-) create mode 100644 src/protocolP2P/SizeRequest.java create mode 100644 src/protocolP2P/SizeResponse.java diff --git a/doc/protocol.md b/doc/protocol.md index c5e5460..f8d5b94 100644 --- a/doc/protocol.md +++ b/doc/protocol.md @@ -22,6 +22,7 @@ x bytes: [(bytes 8-?): PAYLOAD] - `UNREGISTER` (0x05) - `RATIO` (0x06) - `UPDATE RATIO` (0x07) + - `SIZE` (0x08) - RESPONSES (msb is 1): - `LIST` (0x80) @@ -30,6 +31,7 @@ x bytes: [(bytes 8-?): PAYLOAD] - `DISCOVER` (0x83) - `RATIO` (0x86) - `DENIED` (0x87) + - `SIZE` (0x88) - `VERSION ERROR` (0xC0) - `PROTOCOL ERROR` (0xC1) - `INTERNAL ERROR` (0xC2) @@ -59,7 +61,6 @@ Payload contains ```text 8 bytes: [(bytes 8-15): OFFSET OF FILE CONTENT IN BYTES] -8 bytes: [(bytes 16-23): TOTAL FILESIZE] 4 bytes: [(bytes 24-27): FILENAME SIZE] (cannot be > to PAYLOAD_SIZE - 20 or be zero) y bytes: [] z bytes: [PARTIAL CONTENT] @@ -78,6 +79,23 @@ y bytes: [] ``` Possible responses: Load Response, or Denied +### Size +#### Size request +Payload contains + +```text +? bytes: filename +``` +Possible responses: Size response, EmptyFile or NotFound + +#### Size response +Payload contains + +```text +8 bytes: file size +? bytes: filename +``` + ### Hash #### Hash request Get hash of a file. Payload contains diff --git a/src/clientP2P/ClientDownload.java b/src/clientP2P/ClientDownload.java index c4405c3..99aabbd 100644 --- a/src/clientP2P/ClientDownload.java +++ b/src/clientP2P/ClientDownload.java @@ -29,7 +29,8 @@ import protocolP2P.HashResponse; import protocolP2P.HashRequest; import protocolP2P.Payload; import protocolP2P.FilePart; -import protocolP2P.LoadRequest; +import protocolP2P.SizeRequest; +import protocolP2P.SizeResponse; import protocolP2P.ProtocolP2PPacket; import clientP2P.ClientDownloadPart; import tools.HostItem; @@ -291,39 +292,22 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { * @throws InternalError */ protected void setSize() throws InternalError { - ProtocolP2PPacket d = createProtocolP2PPacket(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE, client)); + ProtocolP2PPacket d = createProtocolP2PPacket(new SizeRequest(filename)); try { d.sendRequest(getHostItemSocket(hostList.get(0))); try { Payload p = d.receiveResponse().getPayload(); - assert p instanceof FilePart : "This payload must be instance of FilePart"; - if (!(p instanceof FilePart)) { - System.err.println("Error: cannot get size."); + assert p instanceof SizeResponse : "This payload must be instance of SizeResponse"; + if (!(p instanceof SizeResponse)) { writeLog("cannot get size.", LogLevel.Error); throw new InternalError(); } else { - FilePart fp = (FilePart)p; + SizeResponse fp = (SizeResponse)p; if (!fp.getFilename().equals(filename)) { - System.err.println("Error: wrong file received: `" + fp.getFilename() + "`"); - writeLog("wrong file received: `" + fp.getFilename() + "`", LogLevel.Error); + writeLog("wrong file size received: `" + fp.getFilename() + "`", LogLevel.Error); throw new ProtocolError(); } - if (fp.getOffset() == 0) { - try { - Files.write(new File(partsSubdir + filename + "_0.part").toPath(), fp.getPartialContent()); - } catch (IOException e) { - System.err.println("Error: cannot write file (" + partsSubdir + filename + "_0.part)"); - writeLog("cannot write file (" + partsSubdir + filename + "_0.part)", LogLevel.Error); - } - size = fp.getTotalSize(); - if (fp.getPartialContent().length == size) { - stop = true; - } - } else { - System.err.println("Error: wrong file part received."); - writeLog("wrong file part received.", LogLevel.Error); - throw new InternalError(); - } + size = fp.getTotalSize(); } } catch (EmptyDirectory e) { System.err.println("Error: empty directory."); @@ -395,7 +379,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { // Add tasks if (!stop) { - for(long i=MAX_PARTIAL_SIZE; i= 0 : "totalSize cannot be negative"; assert partialContent.length != 0 : "partialContent.length cannot be zero, see RRCode.EMPTY_FILE"; - assert totalSize >= partialContent.length : "totalSize must be greater than partialContent.length"; assert offset >= 0 : "offset cannot be negative"; assert filename != null : "filename is required"; - if (totalSize < 0 || partialContent.length == 0 || totalSize < partialContent.length - || offset < 0 || filename == null) { + if (partialContent.length == 0 || offset < 0 || filename == null) { throw new InternalError(); } this.filename = filename; - this.totalSize = totalSize; this.offset = offset; this.partialContent = partialContent; } @@ -63,7 +57,6 @@ public class FilePart extends Payload { throw new InternalError(); } 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 } @@ -84,8 +77,6 @@ public class FilePart extends Payload { setPayloadSize(size - PAYLOAD_START_POSITION, packet); // write offset to Packet BytesArrayTools.write(packet, OFFSET_POSITION, offset); - // write totalSize to Packet - BytesArrayTools.write(packet, TOTAL_FILESIZE_POSITION, totalSize); // write filename’s size to Packet BytesArrayTools.write(packet, FILENAME_SIZE_POSITION, filename.length()); // write filename to Packet @@ -102,13 +93,6 @@ public class FilePart extends Payload { private void setOffset(byte[] packet) throws SizeError { offset = BytesArrayTools.readLong(packet, OFFSET_POSITION); } - /** Write from Packet into totalSize. - * @param packet received Packet - * @throws SizeError - */ - private void setTotalSize(byte[] packet) throws SizeError { - totalSize = BytesArrayTools.readLong(packet, TOTAL_FILESIZE_POSITION); - } /** Read filename’s size from Packet. * @param packet received Packet @@ -171,11 +155,4 @@ public class FilePart extends Payload { public long getOffset() { return offset; } - - /** totalSize getter. - * @return totalSize - */ - public long getTotalSize() { - return totalSize; - } } diff --git a/src/protocolP2P/LoadRequest.java b/src/protocolP2P/LoadRequest.java index b6622a0..a662f62 100644 --- a/src/protocolP2P/LoadRequest.java +++ b/src/protocolP2P/LoadRequest.java @@ -86,7 +86,7 @@ public class LoadRequest extends Payload { // compute size int filenameSize = filename.length(); String hostname = hostItem.getHostname(); - int size = 1 + FILENAME_POSITION + filenameSize + 2 + hostname.length(); + int size = FILENAME_POSITION + filenameSize + 2 + hostname.length(); byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; diff --git a/src/protocolP2P/Payload.java b/src/protocolP2P/Payload.java index e41f94c..6fca87d 100644 --- a/src/protocolP2P/Payload.java +++ b/src/protocolP2P/Payload.java @@ -13,6 +13,8 @@ import protocolP2P.RatioRequest; import protocolP2P.RatioResponse; import protocolP2P.UpdateRatio; import protocolP2P.Denied; +import protocolP2P.SizeRequest; +import protocolP2P.SizeResponse; import localException.ProtocolError; import localException.InternalError; import localException.TransmissionError; @@ -48,6 +50,8 @@ public class Payload { assert requestResponseCode != RequestResponseCode.RATIO_RESPONSE || (this instanceof RatioResponse) : "RATIO_RESPONSE must use RatioResponse class"; assert requestResponseCode != RequestResponseCode.UPDATE_RATIO || (this instanceof UpdateRatio) : "UPDATE_RATIO must use UpdateRatio class"; assert requestResponseCode != RequestResponseCode.DENIED || (this instanceof Denied) : "DENIED must use Denied class"; + assert requestResponseCode != RequestResponseCode.SIZE_REQUEST || (this instanceof SizeRequest) : "SIZE_REQUEST must use SizeRequest class"; + assert requestResponseCode != RequestResponseCode.SIZE_RESPONSE || (this instanceof SizeResponse) : "SIZE_RESPONSE must use SizeResponse class"; this.requestResponseCode = requestResponseCode; checkRequestResponseCode(); // this can throw InternalError } @@ -79,6 +83,8 @@ public class Payload { assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.RATIO_RESPONSE || (this instanceof RatioResponse) : "RATIO_RESPONSE must use RatioResponse class"; assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.UPDATE_RATIO || (this instanceof UpdateRatio) : "UPDATE_RATIO must use UpdateRatio class"; assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.DENIED || (this instanceof Denied) : "DENIED must use Denied class"; + assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.SIZE_REQUEST || (this instanceof SizeRequest) : "SIZE_REQUEST must use SizeRequest class"; + assert RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]) != RequestResponseCode.SIZE_RESPONSE || (this instanceof SizeResponse) : "SIZE_RESPONSE must use SizeResponse class"; requestResponseCode = RequestResponseCode.fromCode(packet[RequestResponseCode.RRCODE_POSITION]); checkRequestResponseCode(); // this can throw InternalError } @@ -101,6 +107,8 @@ public class Payload { || (requestResponseCode == RequestResponseCode.RATIO_RESPONSE && !(this instanceof RatioResponse)) || (requestResponseCode == RequestResponseCode.UPDATE_RATIO && !(this instanceof UpdateRatio)) || (requestResponseCode == RequestResponseCode.DENIED && !(this instanceof Denied)) + || (requestResponseCode == RequestResponseCode.SIZE_REQUEST && !(this instanceof SizeRequest)) + || (requestResponseCode == RequestResponseCode.SIZE_RESPONSE && !(this instanceof SizeResponse)) ) { throw new InternalError(); } diff --git a/src/protocolP2P/ProtocolP2PPacketTCP.java b/src/protocolP2P/ProtocolP2PPacketTCP.java index 0c348e5..52da813 100644 --- a/src/protocolP2P/ProtocolP2PPacketTCP.java +++ b/src/protocolP2P/ProtocolP2PPacketTCP.java @@ -22,6 +22,8 @@ import protocolP2P.RatioRequest; import protocolP2P.RatioResponse; import protocolP2P.UpdateRatio; import protocolP2P.Denied; +import protocolP2P.SizeRequest; +import protocolP2P.SizeResponse; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; @@ -147,6 +149,7 @@ public class ProtocolP2PPacketTCP < T extends Payload > extends ProtocolP2PPacke case NOT_A_TRACKER: case RATIO_RESPONSE: case DENIED: + case SIZE_RESPONSE: // we were expecting a request, but we are receiving a response throw new ProtocolError(); default : @@ -337,6 +340,12 @@ public class ProtocolP2PPacketTCP < T extends Payload > extends ProtocolP2PPacke case DENIED: payload = (Payload) new Denied(packet); break; + case SIZE_REQUEST: + payload = (Payload) new SizeRequest(packet); + break; + case SIZE_RESPONSE: + payload = (Payload) new SizeResponse(packet); + break; default: payload = new Payload(packet); // this can throw TransmissionError break; diff --git a/src/protocolP2P/ProtocolP2PPacketUDP.java b/src/protocolP2P/ProtocolP2PPacketUDP.java index 894be60..5073d0e 100644 --- a/src/protocolP2P/ProtocolP2PPacketUDP.java +++ b/src/protocolP2P/ProtocolP2PPacketUDP.java @@ -23,6 +23,8 @@ import protocolP2P.RatioRequest; import protocolP2P.RatioResponse; import protocolP2P.UpdateRatio; import protocolP2P.Denied; +import protocolP2P.SizeRequest; +import protocolP2P.SizeResponse; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketAddress; @@ -140,6 +142,7 @@ public class ProtocolP2PPacketUDP < T extends Payload> extends ProtocolP2PPacket case NOT_A_TRACKER: case RATIO_RESPONSE: case DENIED: + case SIZE_RESPONSE: // we were expecting a request, but we are receiving a response throw new ProtocolError(); default : @@ -322,6 +325,12 @@ public class ProtocolP2PPacketUDP < T extends Payload> extends ProtocolP2PPacket case DENIED: payload = (Payload) new Denied(packet); break; + case SIZE_REQUEST: + payload = (Payload) new SizeRequest(packet); + break; + case SIZE_RESPONSE: + payload = (Payload) new SizeResponse(packet); + break; default: payload = new Payload(packet); // this can throw TransmissionError break; diff --git a/src/protocolP2P/RatioRequest.java b/src/protocolP2P/RatioRequest.java index 87e76bf..ace53c7 100644 --- a/src/protocolP2P/RatioRequest.java +++ b/src/protocolP2P/RatioRequest.java @@ -50,7 +50,7 @@ public class RatioRequest extends Payload { protected byte[] toPacket() throws InternalError { String hostname = hostItem.getHostname(); // compute total size - int size = 1 + HOSTNAME_START_POSITION + hostname.length(); + int size = HOSTNAME_START_POSITION + hostname.length(); byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; diff --git a/src/protocolP2P/RatioResponse.java b/src/protocolP2P/RatioResponse.java index 05e07ca..b59d7f6 100644 --- a/src/protocolP2P/RatioResponse.java +++ b/src/protocolP2P/RatioResponse.java @@ -61,7 +61,7 @@ public class RatioResponse extends Payload { protected byte[] toPacket() throws InternalError { String hostname = hostItem.getHostname(); // compute total size - int size = 1 + HOSTNAME_START_POSITION + hostname.length(); + int size = HOSTNAME_START_POSITION + hostname.length(); byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; diff --git a/src/protocolP2P/Register.java b/src/protocolP2P/Register.java index 4f49022..3de3328 100644 --- a/src/protocolP2P/Register.java +++ b/src/protocolP2P/Register.java @@ -50,7 +50,7 @@ public class Register extends Payload { protected byte[] toPacket() throws InternalError { String hostname = hostItem.getHostname(); // compute total size - int size = 1 + HOSTNAME_START_POSITION + hostname.length(); + int size = HOSTNAME_START_POSITION + hostname.length(); byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; diff --git a/src/protocolP2P/RequestResponseCode.java b/src/protocolP2P/RequestResponseCode.java index 1941870..7a51a7d 100644 --- a/src/protocolP2P/RequestResponseCode.java +++ b/src/protocolP2P/RequestResponseCode.java @@ -20,12 +20,14 @@ public enum RequestResponseCode { UNREGISTER(CodeType.REQUEST_TRACKER, (byte)0x05), RATIO_REQUEST(CodeType.REQUEST_TRACKER, (byte)0x06), UPDATE_RATIO(CodeType.REQUEST_TRACKER, (byte)0x07), + SIZE_REQUEST(CodeType.REQUEST, (byte)0x08), LIST_RESPONSE(CodeType.RESPONSE, (byte)0x80), LOAD_RESPONSE(CodeType.RESPONSE, (byte)0x81), HASH_RESPONSE(CodeType.RESPONSE, (byte)0x82), DISCOVER_RESPONSE(CodeType.RESPONSE, (byte)0x83), RATIO_RESPONSE(CodeType.RESPONSE, (byte)0x86), DENIED(CodeType.RESPONSE, (byte)0x87), + SIZE_RESPONSE(CodeType.RESPONSE, (byte)0x88), VERSION_ERROR(CodeType.ERROR, (byte)0xC0), PROTOCOL_ERROR(CodeType.ERROR, (byte)0xC1), INTERNAL_ERROR(CodeType.ERROR, (byte)0xC2), diff --git a/src/protocolP2P/SizeRequest.java b/src/protocolP2P/SizeRequest.java new file mode 100644 index 0000000..0e23b5c --- /dev/null +++ b/src/protocolP2P/SizeRequest.java @@ -0,0 +1,70 @@ +package protocolP2P; +import protocolP2P.Payload; +import protocolP2P.RequestResponseCode; +import localException.TransmissionError; +import localException.ProtocolError; +import localException.InternalError; +import localException.SizeError; +import tools.BytesArrayTools; +import tools.HostItem; + +/** Representation of payload for load request. + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public class SizeRequest extends Payload { + private String filename; + /** Constructor (typically used by the client) with a filename parameter. + * @param filename name of the file to download. Must not be empty. + */ + public SizeRequest(String filename) throws InternalError { + super(RequestResponseCode.SIZE_REQUEST); + /* assert to help debugging */ + assert filename.length() != 0 : "Payload size of LoadRequest must not be empty"; + if (filename.length() == 0) { + throw new InternalError(); + } + this.filename = filename; + } + + /** Constructor (typically used by server) with a byte[] parameter containing the Packet received. + * @param packet the full Packet received + * @throws SizeError + * @throws InternalError + * @throws ProtocolError + * @throws TransmissionError + */ + protected SizeRequest(byte[] packet) throws TransmissionError, SizeError, ProtocolError, InternalError { + super(packet); + /* Read filename */ + int size = getPayloadSize(packet); + filename = BytesArrayTools.readString(packet, PAYLOAD_START_POSITION, size); + } + + /** Returns a byte[] containing Packet with padding. + * This Packet is still incomplete and should not be send directly. + * ProtocolP2PPacket will use this method to generate the complete Packet. + * @return Packet with padding + * @throws InternalError + */ + protected byte[] toPacket() throws InternalError { + int size = PAYLOAD_START_POSITION + filename.length(); + byte[] packet = new byte[size]; // java initialize all to zero + // set request/response code + packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; + // set Payload size + setPayloadSize(size - PAYLOAD_START_POSITION, packet); + // Write filename + BytesArrayTools.write(packet, filename, PAYLOAD_START_POSITION); + return packet; + } + + /** filename getter. + * @return filename + */ + public String getFilename() { + return filename; + } +} diff --git a/src/protocolP2P/SizeResponse.java b/src/protocolP2P/SizeResponse.java new file mode 100644 index 0000000..f02b01b --- /dev/null +++ b/src/protocolP2P/SizeResponse.java @@ -0,0 +1,86 @@ +package protocolP2P; +import protocolP2P.Payload; +import protocolP2P.RequestResponseCode; +import localException.ProtocolError; +import localException.InternalError; +import localException.SizeError; +import localException.TransmissionError; +import tools.BytesArrayTools; + +/** Representation of payload for size response. + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public class SizeResponse extends Payload { + private String filename; + private long totalSize; + static final private int TOTAL_SIZE_POSITION = PAYLOAD_START_POSITION; + static final private int FILENAME_POSITION = TOTAL_SIZE_POSITION + 8; + + /** Constructor (typically used by server) with informations about file part to send as parameters. + * @param filename name of the file + * @param totalSize size of the file + * @throws InternalError + */ + public SizeResponse(String filename, long totalSize) throws InternalError { + super(RequestResponseCode.SIZE_RESPONSE); + /* asserts to help debugging */ + assert totalSize >= 0 : "offset cannot be negative"; + assert filename != null : "filename is required"; + if (filename == null || totalSize < 0) { + throw new InternalError(); + } + this.filename = filename; + this.totalSize = totalSize; + } + + /** Constructor (typically used by client) with Packet received as parameter. + * @param packet the full Packet received + * @throws SizeError + * @throws InternalError + * @throws TransmissionError + */ + protected SizeResponse(byte[] packet) throws TransmissionError, SizeError, ProtocolError, InternalError { + super(packet); + int filenameSize = getPayloadSize(packet) - FILENAME_POSITION + PAYLOAD_START_POSITION; + totalSize = BytesArrayTools.readLong(packet, TOTAL_SIZE_POSITION); + filename = BytesArrayTools.readString(packet, FILENAME_POSITION, filenameSize); + } + + /** Returns a byte[] containing Packet with padding. + * This Packet is still incomplete and should not be send directly. + * ProtocolP2PPacket will use this method to generate the complete Packet. + * @return Packet with padding + * @throws InternalError + */ + protected byte[] toPacket() throws InternalError { + // compute total size + int size = FILENAME_POSITION + filename.length(); + byte[] packet = new byte[size]; // java initialize all to zero + // set request/response code + packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; + // set Payload size + setPayloadSize(size - PAYLOAD_START_POSITION, packet); + // write totalSize to Packet + BytesArrayTools.write(packet, TOTAL_SIZE_POSITION, totalSize); + // write filename to Packet + BytesArrayTools.write(packet, filename, FILENAME_POSITION); + return packet; + } + + /** filename getter. + * @return String + */ + public String getFilename() { + return filename; + } + + /** totalSize getter. + * @return totalSize + */ + public long getTotalSize() { + return totalSize; + } +} diff --git a/src/protocolP2P/Unregister.java b/src/protocolP2P/Unregister.java index 35e34a8..88294f9 100644 --- a/src/protocolP2P/Unregister.java +++ b/src/protocolP2P/Unregister.java @@ -50,7 +50,7 @@ public class Unregister extends Payload { protected byte[] toPacket() throws InternalError { String hostname = hostItem.getHostname(); // compute total size - int size = 1 + HOSTNAME_START_POSITION + hostname.length(); + int size = HOSTNAME_START_POSITION + hostname.length(); byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; diff --git a/src/protocolP2P/UpdateRatio.java b/src/protocolP2P/UpdateRatio.java index b373623..334cda0 100644 --- a/src/protocolP2P/UpdateRatio.java +++ b/src/protocolP2P/UpdateRatio.java @@ -62,7 +62,7 @@ public class UpdateRatio extends Payload { protected byte[] toPacket() throws InternalError { String[] hostnames = { server.getHostname(), client.getHostname()}; // compute total size - int size = 1 + HOSTNAMES_START_POSITION + BytesArrayTools.computeStringArraySize(hostnames, "\n"); + int size = HOSTNAMES_START_POSITION + BytesArrayTools.computeStringArraySize(hostnames, "\n"); byte[] packet = new byte[size]; // java initialize all to zero // set request/response code packet[RequestResponseCode.RRCODE_POSITION] = requestResponseCode.codeValue; diff --git a/src/serverP2P/ServerManagement.java b/src/serverP2P/ServerManagement.java index de4fdd2..e9f8fcc 100644 --- a/src/serverP2P/ServerManagement.java +++ b/src/serverP2P/ServerManagement.java @@ -14,8 +14,11 @@ import protocolP2P.HashRequest; import protocolP2P.HashResponse; import protocolP2P.HashAlgorithm; import protocolP2P.Unregister; +import protocolP2P.SizeRequest; +import protocolP2P.SizeResponse; import java.nio.file.Paths; import java.nio.file.Files; +import java.io.File; import java.util.Arrays; import java.util.Map; import java.util.HashMap; @@ -153,7 +156,7 @@ public abstract class ServerManagement extends ServeErrors implements Runnable { if (load.length == 0) { sendEmptyFile(pd); } else { - pd.sendResponse(createProtocolP2PPacket((Payload)(new FilePart(filename, fullLoad.length, offset, load)))); + pd.sendResponse(createProtocolP2PPacket((Payload)(new FilePart(filename, offset, load)))); } } catch (Exception e2) { writeLog(e2, LogLevel.Error); @@ -177,6 +180,42 @@ public abstract class ServerManagement extends ServeErrors implements Runnable { } } + /** Send response to size request + * @param pd Request received + */ + protected < T extends ProtocolP2PPacket > void sendSizeResponse(T pd) { + Payload p = pd.getPayload(); + assert p instanceof SizeRequest : "payload must be an instance of SizeRequest"; + if (!(p instanceof SizeRequest)) { + sendInternalError(pd); + } else { + String filename = ((SizeRequest)p).getFilename(); + try { + long size = (new File(baseDirectory + filename)).length(); + String[] fileList = fileListWatcher.getFileList(); + if (Arrays.binarySearch(fileList, filename) >= 0) { + try { + if (size == 0) { + sendEmptyFile(pd); + } else { + pd.sendResponse(createProtocolP2PPacket((new SizeResponse(filename, size)))); + } + } catch (Exception e2) { + writeLog(e2, LogLevel.Error); + } + } else { + throw new IOException(); // to send a NOT_FOUND in the catch block + } + } catch (IOException e) { + try { + sendNotFound(pd); + } catch (Exception e2) { + writeLog(e2, LogLevel.Debug); + } + } + } + } + /** Getter for tracker socket */ @@ -205,6 +244,10 @@ public abstract class ServerManagement extends ServeErrors implements Runnable { writeLog("Received LOAD_REQUEST from host " + pd.getHostItem(), LogLevel.Action); sendLoadResponse(pd); break; + case SIZE_REQUEST: + writeLog("Received SIZE_REQUEST from host " + pd.getHostItem(), LogLevel.Action); + sendSizeResponse(pd); + break; case LIST_REQUEST: writeLog("Received LIST_REQUEST from host " + pd.getHostItem(), LogLevel.Action); sendListResponse(pd); From 97d173e8eb7375c090186b72540984466f60be67 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Fri, 27 Mar 2020 19:09:20 +0100 Subject: [PATCH 08/13] Add RATIO REQUEST/RESPONSES handling in tracker To do: UPDATE RATIO --- src/tracker/TrackerManagement.java | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/tracker/TrackerManagement.java b/src/tracker/TrackerManagement.java index 37c3cbc..b4a51fc 100644 --- a/src/tracker/TrackerManagement.java +++ b/src/tracker/TrackerManagement.java @@ -15,6 +15,8 @@ import protocolP2P.FileList; import protocolP2P.Unregister; import protocolP2P.Register; import protocolP2P.RequestResponseCode; +import protocolP2P.RatioRequest; +import protocolP2P.RatioResponse; import localException.InternalError; import remoteException.EmptyDirectory; import exception.LocalException; @@ -30,6 +32,8 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable protected HostItem tracker; protected Logger logger; protected List hostList = new ArrayList<>(); + protected Map ratioUp = new HashMap<>(); + protected Map ratioDown = new HashMap<>(); protected Map> fileList = new HashMap<>(); protected volatile boolean stop; @@ -62,6 +66,32 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable } } + + /** Handle Ratio request + * @param pd Received request + * @throws InternalError + */ + protected < T extends ProtocolP2PPacket > void handleRatio(T pd) throws InternalError { + Payload p = pd.getPayload(); + assert p instanceof RatioRequest : "payload must be an instance of RatioRequest"; + if (!(p instanceof RatioRequest)) { + sendInternalError(pd); + } else { + HostItem host = ((RatioRequest)p).getHostItem(); + try { + if (!hostList.contains(host)) { + pd.sendResponse(createProtocolP2PPacket(new Payload(RequestResponseCode.UNKNOWN_HOST))); + } else { + pd.sendResponse(createProtocolP2PPacket(new RatioResponse(host, + ratioUp.get(host).longValue(), + ratioDown.get(host).longValue()))); + } + } catch (Exception e) { + writeLog(e, LogLevel.Error); + } + } + } + /** Handle List Responses * @param pd Received response * @throws InternalError @@ -108,6 +138,10 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable fileList.remove(f); } } + + /* Note: we do not remove host from ratioUp and ratioDown since Unregistering is only here to indicate + * the host is temporary not serving any files (ie. is down). + */ } /** Getter for HostItem socket @@ -135,6 +169,14 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable if (!hostList.contains(host)) { hostList.add(host); } + + // initialize ratios if this is a new host + if (!ratioUp.containsKey(host)) { + ratioUp.put(host, Long.valueOf(0)); + } + if (!ratioDown.containsKey(host)) { + ratioDown.put(host, Long.valueOf(0)); + } // send a list request try { ProtocolP2PPacket pLReq = createProtocolP2PPacket(new Payload(RequestResponseCode.LIST_REQUEST)); @@ -186,6 +228,10 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable writeLog("Received DISCOVER REQUEST from host " + pd.getHostItem(), LogLevel.Action); handleDiscover(pd); break; + case RATIO_REQUEST: + writeLog("Received RATIO REQUEST from host " + pd.getHostItem(), LogLevel.Action); + handleRatio(pd); + break; default: writeLog("Received grabbage from host " + pd.getHostItem(), LogLevel.Action); sendInternalError(pd); From f7b1216b259a204bbe3f5d4d61e2841eb11f402c Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Fri, 27 Mar 2020 19:37:31 +0100 Subject: [PATCH 09/13] Fix #33 partially --- src/serverP2P/FileWatcher.java | 11 ++++++++++- src/serverP2P/ServerManagement.java | 6 ++++++ src/serverP2P/ServerManagementTCP.java | 17 +++++++++++++---- src/serverP2P/ServerManagementUDP.java | 11 ++++++++--- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/serverP2P/FileWatcher.java b/src/serverP2P/FileWatcher.java index d6bf632..ce428ac 100644 --- a/src/serverP2P/FileWatcher.java +++ b/src/serverP2P/FileWatcher.java @@ -30,6 +30,7 @@ public abstract class FileWatcher implements Runnable { protected HostItem tracker; protected String baseDirectory; protected Map sha512 = new HashMap<>(); + protected Thread thread; /** Constructor @@ -83,7 +84,7 @@ public abstract class FileWatcher implements Runnable { try { Thread.sleep(time); } catch(InterruptedException e) { - writeLog("File list watcher interrupted", LogLevel.Error); + writeLog("File list watcher interrupted", LogLevel.Info); setStop(); } } @@ -123,6 +124,7 @@ public abstract class FileWatcher implements Runnable { */ public void setStop() { stop = true; + thread.interrupt(); } /** Init sha512 map. @@ -153,4 +155,11 @@ public abstract class FileWatcher implements Runnable { */ protected abstract void writeLog(Exception e, LogLevel logLevel); + /** Set thread + * @param thread Thread + */ + public void setThread(Thread thread) { + this.thread = thread; + } + } diff --git a/src/serverP2P/ServerManagement.java b/src/serverP2P/ServerManagement.java index e9f8fcc..702b550 100644 --- a/src/serverP2P/ServerManagement.java +++ b/src/serverP2P/ServerManagement.java @@ -57,8 +57,14 @@ public abstract class ServerManagement extends ServeErrors implements Runnable { /** Stop the thread */ public void setStop() { stop = true; + fileListWatcher.setStop(); + sendUnregisterRequest(); + closeSocket(); } + /** Closes socket */ + protected abstract void closeSocket(); + /** Trigger a manual check of the file list */ public void updateFileList() { diff --git a/src/serverP2P/ServerManagementTCP.java b/src/serverP2P/ServerManagementTCP.java index fad6ddf..01be104 100644 --- a/src/serverP2P/ServerManagementTCP.java +++ b/src/serverP2P/ServerManagementTCP.java @@ -79,18 +79,18 @@ public class ServerManagementTCP extends ServerManagement { public void run() { writeLog("Server sucessfully started", LogLevel.Info); fileListWatcher = (FileWatcher)new FileWatcherTCP(logger, 10000, server, tracker, baseDirectory); // checking every 10 seconds - (new Thread(fileListWatcher)).start(); + Thread flwt = new Thread(fileListWatcher); + flwt.start(); + fileListWatcher.setThread(flwt); while(!stop) { try { Socket s = socket.accept(); ClientHandler c = new ClientHandler(s); (new Thread(c)).start(); } catch (IOException e) { - writeLog("Error while accepting new connection", LogLevel.Warning); + writeLog("Socket has been closed", LogLevel.Info); } } - fileListWatcher.setStop(); - sendUnregisterRequest(); } /** Private runnable class allowing to serve one client. @@ -162,4 +162,13 @@ public class ServerManagementTCP extends ServerManagement { protected Object getTrackerSocket() { return (Object)tracker.getTCPSocket(); } + + /** Closes socket */ + protected void closeSocket() { + try { + socket.close(); + } catch (IOException e) { + writeLog("Could not close socket", LogLevel.Error); + } + } } diff --git a/src/serverP2P/ServerManagementUDP.java b/src/serverP2P/ServerManagementUDP.java index 7ea6b39..52aa88e 100644 --- a/src/serverP2P/ServerManagementUDP.java +++ b/src/serverP2P/ServerManagementUDP.java @@ -74,7 +74,9 @@ public class ServerManagementUDP extends ServerManagement { public void run() { logger.writeUDP("Server sucessfully started", LogLevel.Info); fileListWatcher = (FileWatcher)new FileWatcherUDP(logger, 10000, server, tracker, baseDirectory); // checking every 10 seconds - (new Thread(fileListWatcher)).start(); + Thread flwt = new Thread(fileListWatcher); + flwt.start(); + fileListWatcher.setThread(flwt); while(!stop) { try { ProtocolP2PPacketUDP pd = new ProtocolP2PPacketUDP<>((Object)socket); @@ -83,8 +85,6 @@ public class ServerManagementUDP extends ServerManagement { } catch (LocalException e) { } } - fileListWatcher.setStop(); - sendUnregisterRequest(); } @@ -116,4 +116,9 @@ public class ServerManagementUDP extends ServerManagement { protected Object getTrackerSocket() { return (Object)tracker.getUDPSocket(); } + + /** Closes socket */ + protected void closeSocket() { + socket.close(); + } } From a5b1abc9a8cc668cdaeeea4efefa5db6b4fba4f7 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Sat, 28 Mar 2020 11:34:28 +0100 Subject: [PATCH 10/13] Add attribute null check --- src/serverP2P/FileWatcher.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/serverP2P/FileWatcher.java b/src/serverP2P/FileWatcher.java index ce428ac..39877d2 100644 --- a/src/serverP2P/FileWatcher.java +++ b/src/serverP2P/FileWatcher.java @@ -124,7 +124,9 @@ public abstract class FileWatcher implements Runnable { */ public void setStop() { stop = true; - thread.interrupt(); + if (thread != null) { + thread.interrupt(); + } } /** Init sha512 map. From c60fdedf80c1ea963a53c9fcf4d587cd083e43a0 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Sat, 28 Mar 2020 15:46:05 +0100 Subject: [PATCH 11/13] Update tracker: 100% --- src/tools/ServeErrors.java | 11 +++++++++ src/tracker/TrackerManagement.java | 37 +++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/tools/ServeErrors.java b/src/tools/ServeErrors.java index ff083f9..4392aa6 100644 --- a/src/tools/ServeErrors.java +++ b/src/tools/ServeErrors.java @@ -79,4 +79,15 @@ public abstract class ServeErrors { } } + /** Send an unknown host message. + * @param pd Request received + */ + protected < T extends ProtocolP2PPacket > void sendUnknownHost(T pd) { + try { + pd.sendResponse(createProtocolP2PPacket(new Payload(RequestResponseCode.UNKNOWN_HOST))); + } catch (Exception e) { + writeLog(e, LogLevel.Error); + } + } + } diff --git a/src/tracker/TrackerManagement.java b/src/tracker/TrackerManagement.java index b4a51fc..617f101 100644 --- a/src/tracker/TrackerManagement.java +++ b/src/tracker/TrackerManagement.java @@ -17,6 +17,7 @@ import protocolP2P.Register; import protocolP2P.RequestResponseCode; import protocolP2P.RatioRequest; import protocolP2P.RatioResponse; +import protocolP2P.UpdateRatio; import localException.InternalError; import remoteException.EmptyDirectory; import exception.LocalException; @@ -154,6 +155,29 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable */ protected abstract void closeHostItemSocket(HostItem hostItem); + /** Handle Update Ratio + * @param pd Received request + * @throws InternalError + */ + protected < T extends ProtocolP2PPacket > void handleUpdateRatio(T pd) throws InternalError { + Payload p = pd.getPayload(); + assert p instanceof UpdateRatio : "payload must be an instance of UpdateRatio"; + if (!(p instanceof UpdateRatio)) { + throw new InternalError(); + } + + UpdateRatio updateRatio = (UpdateRatio) p; + HostItem updateRatioServer = updateRatio.getServer(); + HostItem updateRatioClient = updateRatio.getClient(); + long ratioSize = updateRatio.getDataSize(); + if (!ratioDown.containsKey(updateRatioClient) || ! ratioUp.containsKey(updateRatioServer)) { + sendUnknownHost(pd); + } else { + ratioDown.put(updateRatioClient, Long.valueOf(ratioDown.get(updateRatioClient).longValue() + ratioSize)); + ratioUp.put(updateRatioServer, Long.valueOf(ratioUp.get(updateRatioServer).longValue() + ratioSize)); + } + } + /** Handle Registering * @param pd Received request * @throws InternalError @@ -171,12 +195,9 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable } // initialize ratios if this is a new host - if (!ratioUp.containsKey(host)) { - ratioUp.put(host, Long.valueOf(0)); - } - if (!ratioDown.containsKey(host)) { - ratioDown.put(host, Long.valueOf(0)); - } + ratioUp.putIfAbsent(host, Long.valueOf(0)); + ratioDown.putIfAbsent(host, Long.valueOf(0)); + // send a list request try { ProtocolP2PPacket pLReq = createProtocolP2PPacket(new Payload(RequestResponseCode.LIST_REQUEST)); @@ -232,6 +253,10 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable writeLog("Received RATIO REQUEST from host " + pd.getHostItem(), LogLevel.Action); handleRatio(pd); break; + case UPDATE_RATIO: + writeLog("Received UPDATE RATIO from host " + pd.getHostItem(), LogLevel.Action); + handleUpdateRatio(pd); + break; default: writeLog("Received grabbage from host " + pd.getHostItem(), LogLevel.Action); sendInternalError(pd); From f33b91dccdf5b7f6602dc471334f83955c750dd8 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Sat, 28 Mar 2020 16:31:24 +0100 Subject: [PATCH 12/13] Ratio implementation for client --- src/clientP2P/ClientDownload.java | 31 ++++++++++++++++++++++-- src/clientP2P/ClientDownloadPart.java | 26 ++++++++++++++++++-- src/clientP2P/ClientDownloadPartTCP.java | 5 ++-- src/clientP2P/ClientDownloadPartUDP.java | 5 ++-- src/clientP2P/ClientDownloadTCP.java | 7 +++--- src/clientP2P/ClientDownloadUDP.java | 7 +++--- src/clientP2P/ClientManagement.java | 2 ++ src/clientP2P/ClientManagementTCP.java | 2 +- src/clientP2P/ClientManagementUDP.java | 2 +- src/tracker/TrackerManagement.java | 1 + 10 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/clientP2P/ClientDownload.java b/src/clientP2P/ClientDownload.java index 99aabbd..0a3b18d 100644 --- a/src/clientP2P/ClientDownload.java +++ b/src/clientP2P/ClientDownload.java @@ -1,5 +1,7 @@ package clientP2P; +import java.util.Map; +import java.util.HashMap; import java.util.List; import java.util.ArrayList; import java.util.Arrays; @@ -24,6 +26,7 @@ import remoteException.ProtocolRemoteError; import remoteException.NotFound; import remoteException.InternalRemoteError; import remoteException.NotATracker; +import remoteException.UnknownHost; import protocolP2P.HashAlgorithm; import protocolP2P.HashResponse; import protocolP2P.HashRequest; @@ -32,6 +35,7 @@ import protocolP2P.FilePart; import protocolP2P.SizeRequest; import protocolP2P.SizeResponse; import protocolP2P.ProtocolP2PPacket; +import protocolP2P.UpdateRatio; import clientP2P.ClientDownloadPart; import tools.HostItem; import tools.Logger; @@ -49,6 +53,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { protected String filename; protected byte[] hash512; protected List sockList = new ArrayList(); + protected Map ratioUpdater = new HashMap<>(); protected List offsetsToAsk = new ArrayList(); protected List offsetsPending = new ArrayList(); protected boolean stop; @@ -59,6 +64,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { protected boolean success = false; protected Logger logger; protected HostItem client; + protected HostItem tracker; /** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage * @param filename name of file to download @@ -67,14 +73,16 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { * @param dirStorage directory to write assembled file * @param logger Logger * @param client HostItem of the application + * @param tracker HostItem of the tracker */ - public ClientDownload(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client) { + public ClientDownload(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client, HostItem tracker) { this.partsSubdir = partsSubdir; this.dirStorage = dirStorage; this.filename = filename; this.hostList = hostList; this.logger = logger; this.client = client; + this.tracker = tracker; this.stop = false; } @@ -165,6 +173,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { } catch (InterruptedException e) { throw new InternalError(); } + ratioUpdater.put(c.getServer(), c.getReceivedBytesCount()); } writeLog("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending", LogLevel.Info); if (offsetsToAsk.isEmpty() && offsetsPending.isEmpty()) { @@ -180,6 +189,25 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { } } + /** Send Ratio update to the tracker + */ + public void sendRatioUpdate() { + for(HostItem server: ratioUpdater.keySet()) { + Long r = ratioUpdater.get(server); + if (r != null) { + long rl = r.longValue(); + if (rl != 0) { + try { + ProtocolP2PPacket d = createProtocolP2PPacket(new UpdateRatio(client, server, rl)); + d.sendRequest(getHostItemSocket(tracker)); + } catch (Exception e) { + writeLog(e, LogLevel.Error); + } + } + } + } + } + /** Get hashsum from server. * @param hostItem server to ask hash * @return hash512sum @@ -350,7 +378,6 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { while(!stop) { assignTasks(); checkTasksStatus(); - } } writeLog("Reassembling file parts.", LogLevel.Info); diff --git a/src/clientP2P/ClientDownloadPart.java b/src/clientP2P/ClientDownloadPart.java index cccd3ba..c66fbfe 100644 --- a/src/clientP2P/ClientDownloadPart.java +++ b/src/clientP2P/ClientDownloadPart.java @@ -35,6 +35,7 @@ import tools.HostItem; * @version 1.0 */ public abstract class ClientDownloadPart extends ServeErrors implements Runnable { + protected long receivedBytesCount; protected List toDoTasks; protected List pendingTasks; protected List tasksDone; @@ -48,6 +49,7 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable protected ClientDownload manager; protected Logger logger; protected HostItem client; + private HostItem server; /** Constructor with filename, socket, and part subdir * @param filename name of file to download @@ -55,13 +57,15 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable * @param partsSubdir directory to store .part files * @param logger Logger * @param client HostItem of the application + * @param server HostItem of the server application */ - public ClientDownloadPart(ClientDownload manager, String filename, String partsSubdir, Logger logger, HostItem client) { + public ClientDownloadPart(ClientDownload manager, String filename, String partsSubdir, Logger logger, HostItem client, HostItem server) { this.manager = manager; this.partsSubdir = partsSubdir; this.filename = filename; this.logger = logger; this.client = client; + this.server = server; stop = false; failed = false; pendingTasks = new ArrayList<>(); @@ -69,6 +73,22 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable tasksDone = new ArrayList<>(); noTask = true; tasksListsLock = false; + receivedBytesCount = 0; + } + + + /** receivedBytesCount getter + * @return receivedBytesCount + */ + public Long getReceivedBytesCount() { + return Long.valueOf(receivedBytesCount); + } + + /** Server getter + * @return server + */ + public HostItem getServer() { + return server; } /** True if thread has failed to get a file. @@ -271,8 +291,10 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable } Long offset = Long.valueOf(fp.getOffset()); if (pendingTasks.contains(offset)) { + byte[] partialContent = fp.getPartialContent(); try { - Files.write(new File(partsSubdir + filename + "_" + offset + ".part").toPath(), fp.getPartialContent()); + Files.write(new File(partsSubdir + filename + "_" + offset + ".part").toPath(), partialContent); + receivedBytesCount += partialContent.length; } catch (IOException e) { writeLog("cannot write file (" + partsSubdir + filename + "_" + offset + ".part)", LogLevel.Error); } diff --git a/src/clientP2P/ClientDownloadPartTCP.java b/src/clientP2P/ClientDownloadPartTCP.java index d354ed4..f7dde9d 100644 --- a/src/clientP2P/ClientDownloadPartTCP.java +++ b/src/clientP2P/ClientDownloadPartTCP.java @@ -44,9 +44,10 @@ public class ClientDownloadPartTCP extends ClientDownloadPart { * @param partsSubdir directory to store .part files * @param logger Logger * @param client HostItem of the application + * @param server HostItem of the server application */ - public ClientDownloadPartTCP(ClientDownload manager, String filename, Socket socket, String partsSubdir, Logger logger, HostItem client) { - super(manager, filename, partsSubdir, logger, client); + public ClientDownloadPartTCP(ClientDownload manager, String filename, Socket socket, String partsSubdir, Logger logger, HostItem client, HostItem server) { + super(manager, filename, partsSubdir, logger, client, server); this.socket = socket; } diff --git a/src/clientP2P/ClientDownloadPartUDP.java b/src/clientP2P/ClientDownloadPartUDP.java index ae0a24c..3ab0a80 100644 --- a/src/clientP2P/ClientDownloadPartUDP.java +++ b/src/clientP2P/ClientDownloadPartUDP.java @@ -44,9 +44,10 @@ public class ClientDownloadPartUDP extends ClientDownloadPart { * @param partsSubdir directory to store .part files * @param logger Logger * @param client HostItem of the application + * @param server HostItem of the server application */ - public ClientDownloadPartUDP(ClientDownload manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger, HostItem client) { - super(manager, filename, partsSubdir, logger, client); + public ClientDownloadPartUDP(ClientDownload manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger, HostItem client, HostItem server) { + super(manager, filename, partsSubdir, logger, client, server); this.socket = socket; } diff --git a/src/clientP2P/ClientDownloadTCP.java b/src/clientP2P/ClientDownloadTCP.java index 0751845..9be9afe 100644 --- a/src/clientP2P/ClientDownloadTCP.java +++ b/src/clientP2P/ClientDownloadTCP.java @@ -51,16 +51,17 @@ public class ClientDownloadTCP extends ClientDownload { * @param dirStorage directory to write assembled file * @param logger Logger * @param client HostItem of the application + * @param tracker HostItem of the tracker */ - public ClientDownloadTCP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client) { - super(filename, hostList, partsSubdir, dirStorage, logger, client); + public ClientDownloadTCP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client, HostItem tracker) { + super(filename, hostList, partsSubdir, dirStorage, logger, client, tracker); } /** Create a clientDownloadPart * @param hostItem Hostitem of the server */ protected ClientDownloadPart createDownloadPart(HostItem hostItem) { - return (ClientDownloadPart)new ClientDownloadPartTCP((ClientDownload)this, filename, hostItem.getTCPSocket(), partsSubdir, logger, client); + return (ClientDownloadPart)new ClientDownloadPartTCP((ClientDownload)this, filename, hostItem.getTCPSocket(), partsSubdir, logger, client, hostItem); } /** Close HostItem socket diff --git a/src/clientP2P/ClientDownloadUDP.java b/src/clientP2P/ClientDownloadUDP.java index 5d5dd2a..ce37434 100644 --- a/src/clientP2P/ClientDownloadUDP.java +++ b/src/clientP2P/ClientDownloadUDP.java @@ -51,16 +51,17 @@ public class ClientDownloadUDP extends ClientDownload { * @param dirStorage directory to write assembled file * @param logger Logger * @param client HostItem of the application + * @param tracker HostItem of the tracker */ - public ClientDownloadUDP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client) { - super(filename, hostList, partsSubdir, dirStorage, logger, client); + public ClientDownloadUDP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger, HostItem client, HostItem tracker) { + super(filename, hostList, partsSubdir, dirStorage, logger, client, tracker); } /** Create a clientDownloadPart * @param hostItem Hostitem of the server */ protected ClientDownloadPart createDownloadPart(HostItem hostItem) { - return (ClientDownloadPart)new ClientDownloadPartUDP((ClientDownload)this, filename, hostItem.getUDPSocket(), partsSubdir, logger, client); + return (ClientDownloadPart)new ClientDownloadPartUDP((ClientDownload)this, filename, hostItem.getUDPSocket(), partsSubdir, logger, client, tracker); } /** Implementation of writeLog diff --git a/src/clientP2P/ClientManagement.java b/src/clientP2P/ClientManagement.java index a5a481e..2750c4f 100644 --- a/src/clientP2P/ClientManagement.java +++ b/src/clientP2P/ClientManagement.java @@ -210,6 +210,8 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { line += "\n"; writeLog(line, LogLevel.Info); throw new InternalError(); + } else { + downLoader.sendRatioUpdate(); } } else { throw new InternalError(); diff --git a/src/clientP2P/ClientManagementTCP.java b/src/clientP2P/ClientManagementTCP.java index e922157..90f4c71 100644 --- a/src/clientP2P/ClientManagementTCP.java +++ b/src/clientP2P/ClientManagementTCP.java @@ -34,7 +34,7 @@ public class ClientManagementTCP extends ClientManagement { * @param filename Name of the file to download */ protected void initDownloader(String filename) { - downLoader = (ClientDownload) new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger, client); + downLoader = (ClientDownload) new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger, client, tracker); } diff --git a/src/clientP2P/ClientManagementUDP.java b/src/clientP2P/ClientManagementUDP.java index e34db9c..224a466 100644 --- a/src/clientP2P/ClientManagementUDP.java +++ b/src/clientP2P/ClientManagementUDP.java @@ -33,7 +33,7 @@ public class ClientManagementUDP extends ClientManagement { * @param filename Name of the file to download */ protected void initDownloader(String filename) { - downLoader = (ClientDownload) new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger, client); + downLoader = (ClientDownload) new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger, client, tracker); } /** Implementation of writeLog diff --git a/src/tracker/TrackerManagement.java b/src/tracker/TrackerManagement.java index 617f101..ab87305 100644 --- a/src/tracker/TrackerManagement.java +++ b/src/tracker/TrackerManagement.java @@ -170,6 +170,7 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable HostItem updateRatioServer = updateRatio.getServer(); HostItem updateRatioClient = updateRatio.getClient(); long ratioSize = updateRatio.getDataSize(); + writeLog("Ratio += " + ratioSize + ", client: " + updateRatioClient + " / server: " + updateRatioServer, LogLevel.Debug); if (!ratioDown.containsKey(updateRatioClient) || ! ratioUp.containsKey(updateRatioServer)) { sendUnknownHost(pd); } else { From e02386453bb93f32b8af769467f0dea4ed4d7279 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Sat, 28 Mar 2020 19:43:33 +0100 Subject: [PATCH 13/13] Update server to punish clients --- src/clientP2P/ClientDownload.java | 22 +-- src/clientP2P/ClientDownloadPart.java | 20 ++- src/clientP2P/ClientManagement.java | 5 + src/protocolP2P/DiscoverResponse.java | 2 +- src/protocolP2P/LoadRequest.java | 2 +- src/protocolP2P/ProtocolP2PPacket.java | 4 +- src/protocolP2P/ProtocolP2PPacketTCP.java | 6 +- src/protocolP2P/ProtocolP2PPacketUDP.java | 6 +- src/serverP2P/RatioWatcher.java | 177 ++++++++++++++++++++++ src/serverP2P/RatioWatcherTCP.java | 66 ++++++++ src/serverP2P/RatioWatcherUDP.java | 64 ++++++++ src/serverP2P/ServerManagement.java | 61 ++++++-- src/serverP2P/ServerManagementTCP.java | 4 + src/serverP2P/ServerManagementUDP.java | 4 + src/tools/HostItem.java | 2 +- src/tracker/TrackerManagement.java | 6 + 16 files changed, 413 insertions(+), 38 deletions(-) create mode 100644 src/serverP2P/RatioWatcher.java create mode 100644 src/serverP2P/RatioWatcherTCP.java create mode 100644 src/serverP2P/RatioWatcherUDP.java diff --git a/src/clientP2P/ClientDownload.java b/src/clientP2P/ClientDownload.java index 0a3b18d..f1b44f9 100644 --- a/src/clientP2P/ClientDownload.java +++ b/src/clientP2P/ClientDownload.java @@ -126,8 +126,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { try { sockList.get(rand.nextInt(sockList.size())).assignTask(offset); offsetsPending.add(offset); - System.err.println("Assigned task "+ offset); - writeLog("Assigned task "+ offset, LogLevel.Info); + writeLog("Assigned task: #"+ offset, LogLevel.Info); } catch(InterruptedException e) { writeLog(e, LogLevel.Error); throw new InternalError(); @@ -232,7 +231,6 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { writeLog(e, LogLevel.Error); hash = new byte[0]; } catch (NotFound e) { - writeLog(e, LogLevel.Error); hash = new byte[0]; } catch (LocalException e) { writeLog(e, LogLevel.Error); @@ -258,6 +256,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { */ protected void purgeList() throws InternalError { List blackList = new ArrayList(); + writeLog("Potential peers (before purge): " + hostList.size(), LogLevel.Debug); boolean first = false; byte[] hashsum; for(HostItem host: hostList) { @@ -276,6 +275,7 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { for(HostItem host: blackList) { hostList.remove(host); } + writeLog("Peers (after purge): " + hostList.size(), LogLevel.Debug); writeLog("Host list purge: done", LogLevel.Info); } @@ -368,17 +368,11 @@ public abstract class ClientDownload extends ServeErrors implements Runnable { public void run() { try { init(); - if (stop) { - writeLog("File is smaller than part max size.", LogLevel.Info); - closeHostItemSocket(hostList.get(0)); - } else { - writeLog("File is bigger than part max size.", LogLevel.Info); - purgeList(); - initThreads(); - while(!stop) { - assignTasks(); - checkTasksStatus(); - } + purgeList(); + initThreads(); + while(!stop) { + assignTasks(); + checkTasksStatus(); } writeLog("Reassembling file parts.", LogLevel.Info); reassembleFile(); diff --git a/src/clientP2P/ClientDownloadPart.java b/src/clientP2P/ClientDownloadPart.java index c66fbfe..e9cd602 100644 --- a/src/clientP2P/ClientDownloadPart.java +++ b/src/clientP2P/ClientDownloadPart.java @@ -8,6 +8,7 @@ import protocolP2P.ProtocolP2PPacket; import protocolP2P.Payload; import protocolP2P.LoadRequest; import protocolP2P.FilePart; +import protocolP2P.Denied; import localException.InternalError; import localException.ProtocolError; import localException.TransmissionError; @@ -203,7 +204,6 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable if (p == null) { stop = true; } - failed = downloadPart(p); if (failed) { System.err.println("Error: DownloadPart failed."); @@ -224,7 +224,7 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable * @return ProtocolP2PPacketTCP used to send request */ protected ProtocolP2PPacket reqPart(Long offset) { - writeLog("New request: " + offset, LogLevel.Info); + writeLog("New request: #" + offset, LogLevel.Info); // maintain tracking of tasks if (toDoTasks.contains(offset)) { try { @@ -279,6 +279,22 @@ public abstract class ClientDownloadPart extends ServeErrors implements Runnable } try { Payload p = d.receiveResponse().getPayload(); + if (p instanceof Denied) { + Denied denied = (Denied)p; + if (!denied.getFilename().equals(filename)) { + writeLog("wrong file deny response received: `" + denied.getFilename() + "`", LogLevel.Error); + return true; + } + Long offset = Long.valueOf(denied.getOffset()); + if (pendingTasks.contains(offset)) { + pendingTasks.remove(offset); + toDoTasks.add(offset); + return false; + } else { + writeLog("wrong file offset deny received: " + offset, LogLevel.Error); + return true; + } + } assert p instanceof FilePart : "This payload must be instance of FilePart"; if (!(p instanceof FilePart)) { writeLog("cannot get size.", LogLevel.Error); diff --git a/src/clientP2P/ClientManagement.java b/src/clientP2P/ClientManagement.java index 2750c4f..97f07d2 100644 --- a/src/clientP2P/ClientManagement.java +++ b/src/clientP2P/ClientManagement.java @@ -26,6 +26,7 @@ import remoteException.NotFound; import remoteException.ProtocolRemoteError; import remoteException.VersionRemoteError; import remoteException.NotATracker; +import remoteException.UnknownHost; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -165,6 +166,9 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { } catch (NotATracker e) { writeLog(e, LogLevel.Error); throw new ProtocolError(); + } catch (UnknownHost e) { + writeLog(e, LogLevel.Error); + throw new ProtocolError(); } } @@ -212,6 +216,7 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { throw new InternalError(); } else { downLoader.sendRatioUpdate(); + writeLog("Ratio updates sent.", LogLevel.Info); } } else { throw new InternalError(); diff --git a/src/protocolP2P/DiscoverResponse.java b/src/protocolP2P/DiscoverResponse.java index 97a9cd4..6fa7bb5 100644 --- a/src/protocolP2P/DiscoverResponse.java +++ b/src/protocolP2P/DiscoverResponse.java @@ -56,7 +56,7 @@ public class DiscoverResponse extends Payload { int port = BytesArrayTools.readInt16Bits(packet, i); i += 2; String hostname = BytesArrayTools.readString(packet, i, "\n"); - i += hostname.length(); + i += hostname.length() + 1; // 1 for the "\n" hostList.add(new HostItem(hostname, port)); } } diff --git a/src/protocolP2P/LoadRequest.java b/src/protocolP2P/LoadRequest.java index a662f62..2834f9b 100644 --- a/src/protocolP2P/LoadRequest.java +++ b/src/protocolP2P/LoadRequest.java @@ -72,7 +72,7 @@ public class LoadRequest extends Payload { /* Read hostItem */ int portPosition = FILENAME_POSITION + size; int hostnameStartPosition = portPosition + 2; - int hostnameSize = getPayloadSize(packet) - hostnameStartPosition; + int hostnameSize = getPayloadSize(packet) - hostnameStartPosition + PAYLOAD_START_POSITION; hostItem = new HostItem(BytesArrayTools.readString(packet, hostnameStartPosition, hostnameSize), BytesArrayTools.readInt16Bits(packet, portPosition)); } diff --git a/src/protocolP2P/ProtocolP2PPacket.java b/src/protocolP2P/ProtocolP2PPacket.java index db9c4b4..dd1cb79 100644 --- a/src/protocolP2P/ProtocolP2PPacket.java +++ b/src/protocolP2P/ProtocolP2PPacket.java @@ -12,6 +12,7 @@ import remoteException.ProtocolRemoteError; import remoteException.VersionRemoteError; import remoteException.EmptyFile; import remoteException.NotATracker; +import remoteException.UnknownHost; import java.io.IOException; import tools.HostItem; @@ -72,8 +73,9 @@ public abstract class ProtocolP2PPacket < T extends Payload>{ * @throws SizeError * @throws IOException * @throws SocketClosed + * @throws UnknownHost */ - public abstract ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, NotATracker, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException, SocketClosed; + public abstract ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, NotATracker, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException, SocketClosed, UnknownHost; /** Receive a request, subclasses must overwrite this constructor. * @param socket socket used to get the request diff --git a/src/protocolP2P/ProtocolP2PPacketTCP.java b/src/protocolP2P/ProtocolP2PPacketTCP.java index 52da813..69c8e6e 100644 --- a/src/protocolP2P/ProtocolP2PPacketTCP.java +++ b/src/protocolP2P/ProtocolP2PPacketTCP.java @@ -12,6 +12,7 @@ import remoteException.NotFound; import remoteException.ProtocolRemoteError; import remoteException.VersionRemoteError; import remoteException.EmptyFile; +import remoteException.UnknownHost; import tools.HostItem; import protocolP2P.Payload; import protocolP2P.RequestResponseCode; @@ -212,8 +213,9 @@ public class ProtocolP2PPacketTCP < T extends Payload > extends ProtocolP2PPacke * @throws SizeError * @throws IOException * @throws SocketClosed + * @throws UnknownHost */ - public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, NotATracker, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException, SocketClosed { + public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, NotATracker, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException, SocketClosed, UnknownHost { assert requestSocket != null : "Cannot receive response because request packet not sent."; if (requestSocket == null) { throw new InternalError(); @@ -253,6 +255,8 @@ public class ProtocolP2PPacketTCP < T extends Payload > extends ProtocolP2PPacke throw new EmptyFile(); case NOT_A_TRACKER: throw new NotATracker(); + case UNKNOWN_HOST: + throw new UnknownHost(); default : return (ProtocolP2PPacket)p; } diff --git a/src/protocolP2P/ProtocolP2PPacketUDP.java b/src/protocolP2P/ProtocolP2PPacketUDP.java index 5073d0e..0b639fe 100644 --- a/src/protocolP2P/ProtocolP2PPacketUDP.java +++ b/src/protocolP2P/ProtocolP2PPacketUDP.java @@ -12,6 +12,7 @@ import remoteException.NotFound; import remoteException.ProtocolRemoteError; import remoteException.VersionRemoteError; import remoteException.EmptyFile; +import remoteException.UnknownHost; import tools.BytesArrayTools; import tools.HostItem; import protocolP2P.Payload; @@ -207,8 +208,9 @@ public class ProtocolP2PPacketUDP < T extends Payload> extends ProtocolP2PPacket * @throws InternalError * @throws SizeError * @throws IOException + * @throws UnknownHost */ - public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, NotATracker, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException { + public ProtocolP2PPacket receiveResponse() throws EmptyFile, NotFound, NotATracker, EmptyDirectory, InternalRemoteError, VersionRemoteError, ProtocolRemoteError, TransmissionError, ProtocolError, VersionError, InternalError, SizeError, IOException, UnknownHost { assert requestSocket != null : "Cannot receive response because request packet not sent."; if (requestSocket == null) { throw new InternalError(); @@ -237,6 +239,8 @@ public class ProtocolP2PPacketUDP < T extends Payload> extends ProtocolP2PPacket throw new EmptyFile(); case NOT_A_TRACKER: throw new NotATracker(); + case UNKNOWN_HOST: + throw new UnknownHost(); default : return (ProtocolP2PPacket)p; } diff --git a/src/serverP2P/RatioWatcher.java b/src/serverP2P/RatioWatcher.java new file mode 100644 index 0000000..884c818 --- /dev/null +++ b/src/serverP2P/RatioWatcher.java @@ -0,0 +1,177 @@ +package serverP2P; +import tools.Logger; +import tools.LogLevel; +import tools.HostItem; +import java.util.Map; +import java.util.HashMap; +import java.io.IOException; +import exception.RemoteException; +import exception.LocalException; +import protocolP2P.RatioRequest; +import protocolP2P.RatioResponse; +import protocolP2P.Payload; +import protocolP2P.ProtocolP2PPacket; +import remoteException.UnknownHost; +import remoteException.NotATracker; +import localException.InternalError; + +/** Class allowing to keep the tracker informed about ratios + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public abstract class RatioWatcher implements Runnable { + final static double punishmentFactor = 1.2; + protected Logger logger; + protected volatile boolean stop; + protected long time; + protected boolean force; + protected HostItem tracker; + protected Thread thread; + protected Map cachePunishmentProbability = new HashMap<>(); + protected boolean lock; + + + /** Constructor + * @param logger Logger + * @param millis Time interval before recheck + * @param tracker HostItem for the tracker + */ + public RatioWatcher(Logger logger, long millis, HostItem tracker) { + assert logger != null : "Logger is null"; + assert tracker != null : "Tracker is null"; + this.logger = logger; + time = millis; + this.tracker = tracker; + lock = false; + } + + + /** Runnable implementation */ + public void run() { + writeLog("Ratio watcher started : delay " + time + " milliseconds.", LogLevel.Info); + while(!stop) { + try { + clean(); + Thread.sleep(time); + } catch(InterruptedException e) { + writeLog("Ratio watcher interrupted", LogLevel.Info); + setStop(); + } + } + } + + /** Invalidate the cache by cleaning all hashmaps + * @throws InterruptedException + */ + protected synchronized void clean() throws InterruptedException{ + while(lock) { + this.wait(); + } + lock = true; + cachePunishmentProbability.clear(); + lock = false; + this.notifyAll(); + } + + + /** Get Up-ratio for an applications + * @param application HostItem of the application + * @return Punishment Probability + * @throws UnknownHost + */ + protected synchronized double getPunishmentProbability(HostItem application) throws InternalError, UnknownHost { + try { + while(lock) { + this.wait(); + } + lock = true; + if (!cachePunishmentProbability.containsKey(application)) { + // update if not in cache + try { + ProtocolP2PPacket p = createProtocolP2PPacket(new RatioRequest(application)); + p.sendRequest(getTrackerSocket()); + Payload resp = p.receiveResponse().getPayload(); + if (!(resp instanceof RatioResponse)) { + throw new InternalError(); + } + RatioResponse rresp = (RatioResponse)resp; + if (!rresp.getHostItem().equals(application)) { + writeLog("Ratio response host is not the expected one. Expected : " + + application + ". Received : " + rresp.getHostItem(), LogLevel.Debug); + throw new InternalError(); + } + long up = rresp.getTotalUp(); + long down = rresp.getTotalDown(); + assert punishmentFactor > 1 : "The punishment factor must be greater than 1"; + if (down == 0 || (punishmentFactor * up) >= down) { + cachePunishmentProbability.put(application, Double.valueOf(0)); + } else { + cachePunishmentProbability.put(application, Double.valueOf((down - up)/(down * punishmentFactor))); + } + } catch (UnknownHost e) { + throw e; + } catch (IOException e) { + throw new InternalError(); + } catch (LocalException e) { + writeLog(e, LogLevel.Error); + throw new InternalError(); + } catch (RemoteException e) { + writeLog(e, LogLevel.Error); + throw new InternalError(); + } + } + double ret = cachePunishmentProbability.get(application); + lock = false; + this.notifyAll(); + return ret; + } catch (InterruptedException e) { + throw new InternalError(); + } + } + + /** Ask the thread to stop + */ + public void setStop() { + stop = true; + if (thread != null) { + thread.interrupt(); + } + } + + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging + */ + protected abstract void writeLog(String text, LogLevel logLevel); + + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging + */ + protected abstract void writeLog(Exception e, LogLevel logLevel); + + /** Set thread + * @param thread Thread + */ + public void setThread(Thread thread) { + this.thread = thread; + } + + /** Create packets + * @param payload Payload + */ + protected abstract < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload); + + /** Tracker socket getter + * @return tracker socket + */ + protected abstract Object getTrackerSocket(); + + /** Closes tracker socket + */ + protected abstract void closeTrackerSocket(); + + +} diff --git a/src/serverP2P/RatioWatcherTCP.java b/src/serverP2P/RatioWatcherTCP.java new file mode 100644 index 0000000..5184ce4 --- /dev/null +++ b/src/serverP2P/RatioWatcherTCP.java @@ -0,0 +1,66 @@ +package serverP2P; +import tools.Logger; +import tools.LogLevel; +import protocolP2P.ProtocolP2PPacket; +import protocolP2P.ProtocolP2PPacketTCP; +import protocolP2P.Payload; +import tools.HostItem; +import serverP2P.RatioWatcher; + +/** Class allowing to keep the tracker informed about file list (TCP impl.) + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public class RatioWatcherTCP extends RatioWatcher { + + /** Constructor + * @param logger Logger + * @param millis Time interval before recheck + * @param tracker HostItem for the tracker + */ + public RatioWatcherTCP(Logger logger, long millis, HostItem tracker) { + super(logger, millis, tracker); + assert logger != null : "Logger is null"; + assert tracker != null : "Tracker is null"; + } + + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging + */ + protected void writeLog(String text, LogLevel logLevel) { + logger.writeTCP(text, logLevel); + } + + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging + */ + protected void writeLog(Exception e, LogLevel logLevel) { + logger.writeTCP(e, logLevel); + } + + /** Create packets + * @param payload Payload + */ + protected < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload) { + return (ProtocolP2PPacket)new ProtocolP2PPacketTCP(payload); + } + + /** Tracker socket getter + * @return tracker socket + */ + protected Object getTrackerSocket() { + return tracker.getTCPSocket(); + } + + /** Closes tracker socket + */ + protected void closeTrackerSocket() { + tracker.closeTCPSocket(); + } + + +} diff --git a/src/serverP2P/RatioWatcherUDP.java b/src/serverP2P/RatioWatcherUDP.java new file mode 100644 index 0000000..dca0789 --- /dev/null +++ b/src/serverP2P/RatioWatcherUDP.java @@ -0,0 +1,64 @@ +package serverP2P; +import tools.Logger; +import tools.LogLevel; +import protocolP2P.ProtocolP2PPacket; +import protocolP2P.ProtocolP2PPacketUDP; +import protocolP2P.Payload; +import tools.HostItem; +import serverP2P.RatioWatcher; + +/** Class allowing to keep the tracker informed about file list (UDP impl.) + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public class RatioWatcherUDP extends RatioWatcher { + + /** Constructor + * @param logger Logger + * @param millis Time interval before recheck + * @param tracker HostItem for the tracker + */ + public RatioWatcherUDP(Logger logger, long millis, HostItem tracker) { + super(logger, millis, tracker); + assert logger != null : "Logger is null"; + assert tracker != null : "Tracker is null"; + } + + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging + */ + protected void writeLog(String text, LogLevel logLevel) { + logger.writeUDP(text, logLevel); + } + + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging + */ + protected void writeLog(Exception e, LogLevel logLevel) { + logger.writeUDP(e, logLevel); + } + + /** Create packets + * @param payload Payload + */ + protected < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload) { + return (ProtocolP2PPacket)new ProtocolP2PPacketUDP(payload); + } + + /** Tracker socket getter + * @return tracker socket + */ + protected Object getTrackerSocket() { + return tracker.getUDPSocket(); + } + + /** Closes tracker socket + */ + protected void closeTrackerSocket() { + tracker.closeUDPSocket(); + } +} diff --git a/src/serverP2P/ServerManagement.java b/src/serverP2P/ServerManagement.java index 702b550..af7ed6f 100644 --- a/src/serverP2P/ServerManagement.java +++ b/src/serverP2P/ServerManagement.java @@ -1,5 +1,6 @@ package serverP2P; import serverP2P.FileWatcher; +import serverP2P.RatioWatcher; import tools.Logger; import tools.LogLevel; import tools.HostItem; @@ -16,14 +17,18 @@ import protocolP2P.HashAlgorithm; import protocolP2P.Unregister; import protocolP2P.SizeRequest; import protocolP2P.SizeResponse; +import protocolP2P.Denied; import java.nio.file.Paths; import java.nio.file.Files; import java.io.File; import java.util.Arrays; import java.util.Map; import java.util.HashMap; +import java.util.Random; import java.io.IOException; import exception.LocalException; +import localException.InternalError; +import remoteException.UnknownHost; /** Implementation of P2P-JAVA-PROJECT VERSION 1.0 protocol. * @author Louis Royer @@ -39,6 +44,8 @@ public abstract class ServerManagement extends ServeErrors implements Runnable { protected String baseDirectory; protected HostItem server; protected HostItem tracker; + protected Random punisher = new Random(); + protected RatioWatcher ratioWatcher; /** Constructor */ public ServerManagement(String baseDirectory, HostItem server, HostItem tracker, Logger logger) { @@ -58,6 +65,7 @@ public abstract class ServerManagement extends ServeErrors implements Runnable { public void setStop() { stop = true; fileListWatcher.setStop(); + ratioWatcher.setStop(); sendUnregisterRequest(); closeSocket(); } @@ -145,27 +153,48 @@ public abstract class ServerManagement extends ServeErrors implements Runnable { long offset = ((LoadRequest)p).getOffset(); long maxSizePartialContent = ((LoadRequest)p).getMaxSizePartialContent(); try { - byte[] fullLoad = Files.readAllBytes(Paths.get(baseDirectory + filename)); - long sizeToSend = 0; - if (fullLoad.length - offset < maxSizePartialContent) { - writeLog("Sending last partialContent", LogLevel.Debug); - sizeToSend = fullLoad.length - offset; - } else { - sizeToSend = maxSizePartialContent; - } - writeLog("maxSizePartialContent: " + maxSizePartialContent, LogLevel.Debug); - writeLog("Sending " + filename + " from " + offset + " to " + (offset + sizeToSend), LogLevel.Debug); - byte[] load = Arrays.copyOfRange(fullLoad, (int)offset, (int)(offset + sizeToSend)); String[] fileList = fileListWatcher.getFileList(); if (Arrays.binarySearch(fileList, filename) >= 0) { try { - if (load.length == 0) { - sendEmptyFile(pd); + double proba = ratioWatcher.getPunishmentProbability(((LoadRequest)p).getHostItem()); + if (punisher.nextDouble() <= proba) { + writeLog("Sending punishment", LogLevel.Debug); + pd.sendResponse(createProtocolP2PPacket(new Denied(filename, offset))); } else { - pd.sendResponse(createProtocolP2PPacket((Payload)(new FilePart(filename, offset, load)))); + byte[] fullLoad = Files.readAllBytes(Paths.get(baseDirectory + filename)); + long sizeToSend = 0; + if (fullLoad.length - offset < maxSizePartialContent) { + writeLog("Sending last partialContent", LogLevel.Debug); + sizeToSend = fullLoad.length - offset; + } else { + sizeToSend = maxSizePartialContent; + } + writeLog("maxSizePartialContent: " + maxSizePartialContent, LogLevel.Debug); + writeLog("Sending " + filename + " from " + offset + " to " + (offset + sizeToSend), LogLevel.Debug); + byte[] load = Arrays.copyOfRange(fullLoad, (int)offset, (int)(offset + sizeToSend)); + try { + if (load.length == 0) { + sendEmptyFile(pd); + } else { + pd.sendResponse(createProtocolP2PPacket((Payload)(new FilePart(filename, offset, load)))); + } + } catch (Exception e2) { + writeLog(e2, LogLevel.Error); + } } - } catch (Exception e2) { - writeLog(e2, LogLevel.Error); + } catch (InternalError e) { + writeLog("InternalError", LogLevel.Debug); + writeLog(e, LogLevel.Debug); + sendInternalError(pd); + return; + } catch (UnknownHost e) { + writeLog("Unknown host: " + ((LoadRequest)p).getHostItem(), LogLevel.Debug); + writeLog(e, LogLevel.Debug); + sendInternalError(pd); + return; + } catch(LocalException e) { + sendInternalError(pd); + return; } } else { writeLog("File requested not found: `" + filename + "` " + Arrays.binarySearch(fileList, filename), LogLevel.Debug); diff --git a/src/serverP2P/ServerManagementTCP.java b/src/serverP2P/ServerManagementTCP.java index 01be104..da84132 100644 --- a/src/serverP2P/ServerManagementTCP.java +++ b/src/serverP2P/ServerManagementTCP.java @@ -82,6 +82,10 @@ public class ServerManagementTCP extends ServerManagement { Thread flwt = new Thread(fileListWatcher); flwt.start(); fileListWatcher.setThread(flwt); + ratioWatcher = (RatioWatcher)new RatioWatcherTCP(logger, 10000, tracker); + Thread rwt = new Thread(ratioWatcher); + rwt.start(); + ratioWatcher.setThread(rwt); while(!stop) { try { Socket s = socket.accept(); diff --git a/src/serverP2P/ServerManagementUDP.java b/src/serverP2P/ServerManagementUDP.java index 52aa88e..7e541a9 100644 --- a/src/serverP2P/ServerManagementUDP.java +++ b/src/serverP2P/ServerManagementUDP.java @@ -77,6 +77,10 @@ public class ServerManagementUDP extends ServerManagement { Thread flwt = new Thread(fileListWatcher); flwt.start(); fileListWatcher.setThread(flwt); + ratioWatcher = (RatioWatcher)new RatioWatcherUDP(logger, 10000, tracker); + Thread rwt = new Thread(ratioWatcher); + rwt.start(); + ratioWatcher.setThread(rwt); while(!stop) { try { ProtocolP2PPacketUDP pd = new ProtocolP2PPacketUDP<>((Object)socket); diff --git a/src/tools/HostItem.java b/src/tools/HostItem.java index 95960af..3467a73 100644 --- a/src/tools/HostItem.java +++ b/src/tools/HostItem.java @@ -128,7 +128,7 @@ public class HostItem { boolean result = false; if (other instanceof HostItem) { HostItem that = (HostItem) other; - result = this.getHostname() == that.getHostname() && this.getPort() == that.getPort(); + result = this.getHostname().equals(that.getHostname()) && this.getPort() == that.getPort(); } return result; } diff --git a/src/tracker/TrackerManagement.java b/src/tracker/TrackerManagement.java index ab87305..4d1a37a 100644 --- a/src/tracker/TrackerManagement.java +++ b/src/tracker/TrackerManagement.java @@ -79,8 +79,14 @@ public abstract class TrackerManagement extends ServeErrors implements Runnable sendInternalError(pd); } else { HostItem host = ((RatioRequest)p).getHostItem(); + writeLog("Ratio request for host " + host, LogLevel.Debug); try { if (!hostList.contains(host)) { + String l = ""; + for (HostItem h: hostList) { + l += h + " "; + } + writeLog(host + " is not in hostlist [ " + l + "]", LogLevel.Debug); pd.sendResponse(createProtocolP2PPacket(new Payload(RequestResponseCode.UNKNOWN_HOST))); } else { pd.sendResponse(createProtocolP2PPacket(new RatioResponse(host,