diff --git a/src/clientP2P/ClientManagementTCP.java b/src/clientP2P/ClientManagementTCP.java index 28fe131..b52899c 100644 --- a/src/clientP2P/ClientManagementTCP.java +++ b/src/clientP2P/ClientManagementTCP.java @@ -31,6 +31,8 @@ import clientP2P.ClientDownloadTCP; import tools.HostItem; import tools.Logger; import tools.LogLevel; +import protocolP2P.DiscoverRequest; +import protocolP2P.DiscoverResponse; /** Implementation of P2P-JAVA-PROJECT CLIENT * @author Louis Royer @@ -42,26 +44,36 @@ public class ClientManagementTCP implements Runnable { private String baseDirectory; private String partsSubdir; private List hostList; + private HostItem tracker; private Logger logger; + private Scanner scanner; - /** Constructor for TCP implementation, with baseDirectory and TCPPort parameters. + /** Constructor for TCP implementation, with baseDirectory, tracker, partsSubdir, logger, and scanner parameters. * @param baseDirectory the root directory where files are stored - * @param host hostname of the server - * @param TCPPort the server will listen on this port + * @param tracker Tracker hostItem + * @param partsSubdir subdirectory to store file parts + * @param logger Loggger + * @param scanner Scanner used to read input */ - public ClientManagementTCP(String baseDirectory, List hostList, String partsSubdir, Logger logger) { + public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { + this.scanner = scanner; this.baseDirectory = baseDirectory; - this.hostList = hostList; + this.tracker = tracker; this.partsSubdir = partsSubdir; this.logger = logger; + try { + initHostList(); + } catch (InternalError e) { + System.exit(-1); + } catch (ProtocolError e) { + System.exit(-2); + } } /** Implementation of Runnable */ public void run() { try { - System.out.println("Enter all servers: type \"stop\" when finished"); - Scanner scanner = new Scanner(System.in); String[] list = listDirectory(); System.out.println("Files present on the server:"); for(String listItem: list) { @@ -69,49 +81,35 @@ public class ClientManagementTCP implements Runnable { } System.out.println("Name of the file to download:"); String f = scanner.nextLine(); - scanner.close(); download(f); System.out.println("File " + f + " sucessfully downloaded"); logger.writeTCP("File " + f + " sucessfully downloaded", LogLevel.Info); } catch (EmptyDirectory e) { - System.err.println("Error: Server has no file in directory"); - logger.writeTCP("Error: Server has no file in directory", LogLevel.Error); + logger.writeTCP("Server has no file in directory", LogLevel.Error); } catch (InternalError e) { - System.err.println("Error: Client internal error"); - logger.writeTCP("Error: Client internal error", LogLevel.Error); + logger.writeTCP("Client internal error", LogLevel.Error); } catch (UnknownHostException e) { - System.err.println("Error: Server host is unknown"); - logger.writeTCP("Error: Server host is unknown", LogLevel.Error); + logger.writeTCP("Server host is unknown", LogLevel.Error); } catch (IOException e) { - System.err.println("Error: Request cannot be send or response cannot be received"); - logger.writeTCP("Error: Request cannot be send or response cannot be received", LogLevel.Error); + logger.writeTCP("Request cannot be send or response cannot be received", LogLevel.Error); } catch (TransmissionError e) { - System.err.println("Error: Message received is too big"); - logger.writeTCP("Error: Message received is too big", LogLevel.Error); + logger.writeTCP("Message received is too big", LogLevel.Error); } catch (ProtocolError e) { - System.err.println("Error: Cannot decode server’s response"); - logger.writeTCP("Error: Cannot decode server’s response", LogLevel.Error); + logger.writeTCP("Cannot decode server’s response", LogLevel.Error); } catch (VersionError e) { - System.err.println("Error: Server’s response use bad version of the protocol"); - logger.writeTCP("Error: Server’s response use bad version of the protocol", LogLevel.Error); + logger.writeTCP("Server’s response use bad version of the protocol", LogLevel.Error); } catch (SizeError e) { - System.err.println("Error: Cannot handle this packets because of internal representation limitations of numbers on the client"); - logger.writeTCP("Error: Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error); + logger.writeTCP("Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error); } catch (InternalRemoteError e) { - System.err.println("Error: Server internal error"); - logger.writeTCP("Error: Server internal error", LogLevel.Error); + logger.writeTCP("Server internal error", LogLevel.Error); } catch (ProtocolRemoteError e) { - System.err.println("Error: Server cannot decode client’s request"); - logger.writeTCP("Error: Server cannot decode client’s request", LogLevel.Error); + logger.writeTCP("Server cannot decode client’s request", LogLevel.Error); } catch (VersionRemoteError e) { - System.err.println("Error: Server cannot decode this version of the protocol"); - logger.writeTCP("Error: Server cannot decode this version of the protocol", LogLevel.Error); + logger.writeTCP("Server cannot decode this version of the protocol", LogLevel.Error); } catch (NotFound e) { - System.err.println("Error: Server has not this file in directory"); - logger.writeTCP("Error: Server has not this file in directory", LogLevel.Error); + logger.writeTCP("Server has not this file in directory", LogLevel.Error); } catch (EmptyFile e) { - System.err.println("Error: File is empty"); - logger.writeTCP("Error: File is empty", LogLevel.Error); + logger.writeTCP("File is empty", LogLevel.Error); } } @@ -139,21 +137,18 @@ public class ClientManagementTCP implements Runnable { if (downLoader.getSuccess()) { byte[] hash512 = downLoader.getHashSum512(); if (!Arrays.equals(hash512, computeHashsum(filename, HashAlgorithm.SHA512))) { - System.err.println("Error: Hashsum does not match"); - logger.writeTCP("Error: Hashsum does not match", LogLevel.Error); - System.err.println("Computed checksum:"); + logger.writeTCP("Hashsum does not match", LogLevel.Error); + String line = "Computed checksum:\n"; byte[] c = computeHashsum(filename, HashAlgorithm.SHA512); for (byte b: c) { - System.err.print(String.format("%02X", b)); - logger.writeTCP("Computed checksum:" + String.format("%02X", b), LogLevel.Info); + line += String.format("%02X", b); } - System.err.println(""); - System.err.println("Received checksum:"); + line += "\nReceived checksum:\n"; for (byte b: hash512) { - System.err.print(String.format("%02X", b)); - logger.writeTCP("Received checksum:" + String.format("%02X", b), LogLevel.Info); + line += String.format("%02X", b); } - System.err.println(""); + line += "\n"; + logger.writeTCP(line, LogLevel.Info); throw new InternalError(); } } else { @@ -196,7 +191,6 @@ public class ClientManagementTCP implements Runnable { logger.writeTCP(e, LogLevel.Error); throw new ProtocolError(); } catch (SocketClosed e){ - System.err.println("listDirectory : SocketClosed"); logger.writeTCP("listDirectory : SocketClosed", LogLevel.Error); throw new ProtocolError(); } catch (NotATracker e) { @@ -214,12 +208,37 @@ public class ClientManagementTCP implements Runnable { MessageDigest md = MessageDigest.getInstance(HashAlgorithm.SHA512.getName()); return md.digest(Files.readAllBytes(Paths.get(baseDirectory + filename))); } catch (NoSuchAlgorithmException e) { - System.out.println("Error: " + h.getName() + " not supported"); - logger.writeTCP("Error: " + h.getName() + " not supported", LogLevel.Error); + logger.writeTCP(h.getName() + " not supported", LogLevel.Error); } catch (IOException e) { - System.out.println("Error: cannot read " + filename); - logger.writeTCP("Error: cannot read " + filename, LogLevel.Error); + logger.writeTCP("cannot read " + filename, LogLevel.Error); } return new byte[0]; } + + /** Initialize hostList from tracker + * @throws ProtocolError + * @throws InternalError + */ + private void initHostList() throws ProtocolError, InternalError { + ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP((Payload) new DiscoverRequest(null)); + try { + d.sendRequest((Object)tracker.getTCPSocket()); + Payload p = d.receiveResponse().getPayload(); + assert p instanceof DiscoverResponse : "This payload must be instance of Filelist"; + if (!(p instanceof DiscoverResponse)) { + throw new InternalError(); + } else { + hostList = ((DiscoverResponse)p).getHostList(); + } + } catch (SocketClosed e){ + logger.writeTCP("listDirectory : SocketClosed", LogLevel.Error); + throw new ProtocolError(); + } catch (NotATracker e) { + logger.writeTCP(e, LogLevel.Error); + throw new ProtocolError(); + } catch (Exception e) { + logger.writeTCP(e, LogLevel.Error); + throw new ProtocolError(); + } + } } diff --git a/src/clientP2P/ClientManagementUDP.java b/src/clientP2P/ClientManagementUDP.java index aa1da60..b298fc7 100644 --- a/src/clientP2P/ClientManagementUDP.java +++ b/src/clientP2P/ClientManagementUDP.java @@ -26,6 +26,8 @@ import protocolP2P.Payload; import protocolP2P.RequestResponseCode; import protocolP2P.FileList; import protocolP2P.HashAlgorithm; +import protocolP2P.DiscoverRequest; +import protocolP2P.DiscoverResponse; import tools.HostItem; import tools.Logger; import tools.LogLevel; @@ -41,26 +43,36 @@ public class ClientManagementUDP implements Runnable { private String baseDirectory; private String partsSubdir; private List hostList; + private HostItem tracker; private Logger logger; + private Scanner scanner; - /** Constructor for UDP implementation, with baseDirectory and UDPPort parameters. + /** Constructor for UDP implementation, with baseDirectory, tracker, partsSubdir, logger and scanner parameters. * @param baseDirectory the root directory where files are stored - * @param host hostname of the server - * @param UDPPort the server will listen on this port + * @param tracker tracker HostItem + * @param partsSubdir subdirectory to store file parts + * @param logger Loggger + * @param scanner Scanner used to read input */ - public ClientManagementUDP(String baseDirectory, List hostList, String partsSubdir, Logger logger) { + public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { + this.scanner = scanner; this.baseDirectory = baseDirectory; - this.hostList = hostList; + this.tracker = tracker; this.partsSubdir = partsSubdir; this.logger = logger; + try { + initHostList(); + } catch (InternalError e) { + System.exit(-1); + } catch (ProtocolError e) { + System.exit(-2); + } } /** Implementation of Runnable */ public void run() { try { - System.out.println("Enter all servers: type \"stop\" when finished"); - Scanner scanner = new Scanner(System.in); String[] list = listDirectory(); System.out.println("Files present on the server:"); for(String listItem: list) { @@ -68,7 +80,6 @@ public class ClientManagementUDP implements Runnable { } System.out.println("Name of the file to download:"); String f = scanner.nextLine(); - scanner.close(); download(f); System.out.println("File " + f + " sucessfully downloaded"); logger.writeUDP("File " + f + " sucessfully downloaded", LogLevel.Info); @@ -217,4 +228,28 @@ public class ClientManagementUDP implements Runnable { } return new byte[0]; } + + /** Initialize hostList from tracker + * @throws ProtocolError + * @throws InternalError + */ + private void initHostList() throws ProtocolError, InternalError { + ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP((Payload) new DiscoverRequest(null)); + try { + d.sendRequest((Object)tracker.getUDPSocket()); + Payload p = d.receiveResponse().getPayload(); + assert p instanceof DiscoverResponse : "This payload must be instance of Filelist"; + if (!(p instanceof DiscoverResponse)) { + throw new InternalError(); + } else { + hostList = ((DiscoverResponse)p).getHostList(); + } + } catch (NotATracker e) { + logger.writeUDP(e, LogLevel.Error); + throw new ProtocolError(); + } catch (Exception e) { + logger.writeUDP(e, LogLevel.Error); + throw new ProtocolError(); + } + } } diff --git a/src/clientP2P/ClientP2P.java b/src/clientP2P/ClientP2P.java index a1700b9..1d1b224 100644 --- a/src/clientP2P/ClientP2P.java +++ b/src/clientP2P/ClientP2P.java @@ -10,7 +10,6 @@ import tools.Logger; import tools.LogLevel; import tools.Directories; import tools.HostItem; -import tools.HostList; /** Client + Server implementation. * @author Louis Royer @@ -27,9 +26,9 @@ public class ClientP2P { private String host; private int port; private Directories directories; - private List hostList; private static final int defaultPort = 20000; private HostItem tracker; + private Scanner scanner; /** Initialize loggers if directories and logger are null, @@ -47,6 +46,7 @@ public class ClientP2P { * @param portStr String containing port for server listenning. */ public ClientP2P(String portStr) { + scanner = new Scanner(System.in); tracker = new HostItem("localhost", 30000); // TODO : make it configurable try{ port = Integer.valueOf(Integer.parseInt(portStr)); @@ -62,7 +62,7 @@ public class ClientP2P { directories.createSubdir(parts); host = "localhost"; System.out.println("Server will listen on port " + port + " and serve files from " + directories.getDataHomeDirectory() + subdir); - directories.askOpenDataHomeDirectory(subdir); + directories.askOpenDataHomeDirectory(subdir, scanner); System.out.println("Please enter list of servers to use; first one will be used to ask list of files"); } @@ -102,11 +102,9 @@ public class ClientP2P { } // initialize Host lists - c.hostList = HostList.getServList(); System.out.println("Client : Which transport protocol do you want to use? [TCP/udp]"); - Scanner sc = new Scanner(System.in); - String transportchoosen = sc.nextLine(); - sc.close(); + c.scanner.hasNextLine(); + String transportchoosen = c.scanner.nextLine(); Thread t; switch(transportchoosen){ case "UDP": @@ -114,7 +112,7 @@ public class ClientP2P { case "upd": // alias typo case "2" : System.out.println("Starting with UDP"); - ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.hostList, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient); + ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient, c.scanner); t = new Thread(cmudp); break; case "TCP": @@ -122,12 +120,16 @@ public class ClientP2P { case "1": default: System.out.println("Starting with TCP"); - ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.hostList, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient); + ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient, c.scanner); t = new Thread(cmtcp); break; } t.setName("client P2P-JAVA-PROJECT"); t.start(); + try { + t.join(); + } catch (InterruptedException e) {} + c.scanner.close(); } } } diff --git a/src/serverP2P/ServerP2P.java b/src/serverP2P/ServerP2P.java index 1b57958..df0a3f1 100644 --- a/src/serverP2P/ServerP2P.java +++ b/src/serverP2P/ServerP2P.java @@ -4,6 +4,7 @@ import serverP2P.ServerManagementTCP; import tools.Directories; import tools.Logger; import tools.HostItem; +import java.util.Scanner; /** Server only implementation * First argument of main method is port listened by the server, and is mandatory. @@ -29,7 +30,9 @@ public class ServerP2P { directories.createSubdir(subdir); logger = new Logger(directories.getDataHomeDirectory() + "server.log"); System.out.println("Server will listen on port " + port + " and serve files from " + directories.getDataHomeDirectory() + subdir); - directories.askOpenDataHomeDirectory(subdir); + Scanner scanner = new Scanner(System.in); + directories.askOpenDataHomeDirectory(subdir, scanner); + scanner.close(); } /** Main program entry point diff --git a/src/tools/BytesArrayTools.java b/src/tools/BytesArrayTools.java index f1cbe85..554bc3a 100644 --- a/src/tools/BytesArrayTools.java +++ b/src/tools/BytesArrayTools.java @@ -231,11 +231,13 @@ public class BytesArrayTools { try { int i = start; while(true) { + int j = i; for(byte b: endStr.getBytes()) { - if (b != array[i]) { + if (b != array[j]) { failed = true; break; } + j++; } if (failed) { i++; @@ -244,7 +246,7 @@ public class BytesArrayTools { break; } } - return readString(array, start, i -1 - start); + return readString(array, start, i - start); } catch(IndexOutOfBoundsException e) { throw new InternalError(); } diff --git a/src/tools/Directories.java b/src/tools/Directories.java index 8c9a86e..0ee49c6 100644 --- a/src/tools/Directories.java +++ b/src/tools/Directories.java @@ -70,6 +70,7 @@ public class Directories { } /** Opens dataHomeDirectory if supported. + * @param subdir Subdir to open (optional) */ private void openDataHomeDirectory(String subdir) { String d = dataHomeDirectory; @@ -93,13 +94,13 @@ public class Directories { } /** Asks the user to choose opening dataHomeDirectory or not. + * @param subdir subdirectory to open (optional) + * @param scanner Scanner to use for reading input */ - public void askOpenDataHomeDirectory(String subdir) { + public void askOpenDataHomeDirectory(String subdir, Scanner scanner) { if (os.equals("Linux") || os.equals("Mac") || os.equals("Mac OS X")) { System.out.println("Do you want to open this directory? (y/N)"); - Scanner scanner = new Scanner(System.in); String resp = scanner.nextLine(); - scanner.close(); if (resp.equals("y") || resp.equals("Y")) { System.out.println("Openning"); openDataHomeDirectory(subdir); diff --git a/src/tools/HostItem.java b/src/tools/HostItem.java index 80b4f13..231e6b7 100644 --- a/src/tools/HostItem.java +++ b/src/tools/HostItem.java @@ -36,13 +36,13 @@ public class HostItem { try { tcpSocket = new Socket(InetAddress.getByName(hostname), port); } catch (SocketException e) { - System.err.println("Error: No TCP socket available."); + System.err.println("getTCPSocket error: No TCP socket available."); System.exit(-1); } catch (UnknownHostException e) { - System.err.println("Error: Unknown host."); + System.err.println("getTCPSocket error: Unknown host (" + this + ")."); System.exit(-1); } catch (IOException e) { - System.err.println("Error: Cannot create TCP socket"); + System.err.println("getTCPSocket error: Cannot create TCP socket (" + this + ")."); System.exit(-1); } } @@ -71,10 +71,10 @@ public class HostItem { udpSocket = new DatagramSocket(); udpSocket.connect(InetAddress.getByName(hostname), port); } catch (SocketException e) { - System.err.println("Error: No UDP socket available."); + System.err.println("getUDPSocket error: No UDP socket available." ); System.exit(-1); } catch (UnknownHostException e) { - System.err.println("Error: Unknown host."); + System.err.println("getUDPSocket error: Unknown host (" + this + ")."); System.exit(-1); } } @@ -135,7 +135,7 @@ public class HostItem { try { inetAddress = InetAddress.getByName(getHostname()); } catch (UnknownHostException e) { - System.err.println("Error: Unknown host."); + System.err.println("getInetAddress error: Unknown host (" + this + ")."); System.exit(-1); } } diff --git a/src/tools/HostList.java b/src/tools/HostList.java deleted file mode 100644 index eae5e4e..0000000 --- a/src/tools/HostList.java +++ /dev/null @@ -1,56 +0,0 @@ -package tools; - -import java.util.Scanner; -import java.util.ArrayList; -import java.util.List; -import java.util.InputMismatchException; -import tools.HostItem; - -/** Helper to get the server list from the user -* @author Louis Royer -* @author Flavien Haas -* @author JS Auge -* @version 1.0 -*/ -public class HostList { - /** - * Let the user enter all server and puts it in a list - * @return list of servers - */ - public static List getServList() { - List serverList = new ArrayList(); - Scanner scanner = new Scanner(System.in); - String servName; - int port = 0; - do { - System.out.println("Enter hostname of next server: (or \"stop\" when finished, default: localhost)."); - servName = scanner.nextLine(); - if (servName.equals("")) { - servName = "localhost"; - } - if (!servName.equals("stop")) { - boolean err = false; - do { - System.out.println("Enter port for this server"); - try { - port = scanner.nextInt(); - scanner.nextLine(); - if (port > 65535 || port <= 0) { - err = true; - System.out.println("Port number must be in 1-65535 range. Try again."); - } else { - err = false; - } - } catch (InputMismatchException e) { - System.out.println("Invalid number. Try again."); - err = true; - } - } while (err); - serverList.add(new HostItem(servName, port)); - } - - } while (!servName.equals("stop")); - scanner.close(); - return serverList; - } -} diff --git a/src/tracker/Tracker.java b/src/tracker/Tracker.java index bb82422..8607610 100644 --- a/src/tracker/Tracker.java +++ b/src/tracker/Tracker.java @@ -3,6 +3,7 @@ import tracker.TrackerManagementTCP; import tracker.TrackerManagementUDP; import tools.Directories; import tools.Logger; +import java.util.Scanner; /** Tracker implementation * First argument of main method is port listened by the tracker, and is mandatory. @@ -24,7 +25,9 @@ public class Tracker { directories = new Directories("P2P_JAVA_PROJECT_TRACKER_" + port); logger = new Logger(directories.getDataHomeDirectory() + "tracker.log"); System.out.println("Tracker will listen on port " + port + " and write logs into " + directories.getDataHomeDirectory()); - directories.askOpenDataHomeDirectory(null); + Scanner scanner = new Scanner(System.in); + directories.askOpenDataHomeDirectory(null, scanner); + scanner.close(); } /** Main program entry point diff --git a/src/tracker/TrackerManagementTCP.java b/src/tracker/TrackerManagementTCP.java index 5f75aa2..c26c9c9 100644 --- a/src/tracker/TrackerManagementTCP.java +++ b/src/tracker/TrackerManagementTCP.java @@ -20,8 +20,8 @@ import java.util.HashMap; import protocolP2P.DiscoverRequest; import protocolP2P.DiscoverResponse; import protocolP2P.FileList; -import protocolP2P.HashRequest; import localException.InternalError; +import remoteException.EmptyDirectory; import java.net.UnknownHostException; import java.net.InetAddress; import localException.SocketClosed; @@ -204,6 +204,10 @@ public class TrackerManagementTCP implements Runnable { handleListResponse((ProtocolP2PPacketTCP)pLReq.receiveResponse(), host); logger.writeTCP("Received LIST RESPONSE from host " + pd.getHostItem(), LogLevel.Action); host.closeTCPSocket(); + } catch (EmptyDirectory e) { + logger.writeTCP("Empty Directory", LogLevel.Debug); + hostList.remove(host); + logger.writeTCP("Received EMPTY DIRECTORY from host " + pd.getHostItem() + ". Aborting.", LogLevel.Action); } catch (Exception e) { // remove from list because list request could not be send hostList.remove(host); @@ -245,7 +249,7 @@ public class TrackerManagementTCP implements Runnable { if (!(p instanceof DiscoverRequest)) { sendInternalError(pd); } else { - String filename = ((HashRequest)p).getFilename(); + String filename = ((DiscoverRequest)p).getFilename(); try { pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new DiscoverResponse(filename, fileList.getOrDefault(filename, hostList)))); } catch (Exception e) { diff --git a/src/tracker/TrackerManagementUDP.java b/src/tracker/TrackerManagementUDP.java index 3a3cbc2..4d31c2f 100644 --- a/src/tracker/TrackerManagementUDP.java +++ b/src/tracker/TrackerManagementUDP.java @@ -19,7 +19,6 @@ import java.util.HashMap; import protocolP2P.DiscoverRequest; import protocolP2P.DiscoverResponse; import protocolP2P.FileList; -import protocolP2P.HashRequest; import localException.InternalError; import remoteException.EmptyDirectory; import java.net.InetAddress; @@ -201,7 +200,7 @@ public class TrackerManagementUDP implements Runnable { if (!(p instanceof DiscoverRequest)) { sendInternalError(pd); } else { - String filename = ((HashRequest)p).getFilename(); + String filename = ((DiscoverRequest)p).getFilename(); try { pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new DiscoverResponse(filename, fileList.getOrDefault(filename, hostList)))); } catch (Exception e) {