Client now asks servers to tracker !

This commit is contained in:
Louis Royer 2020-03-21 15:48:18 +01:00
parent 683529b21c
commit 3f21797b09
11 changed files with 151 additions and 139 deletions

View File

@ -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<HostItem> 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<HostItem> 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 servers response");
logger.writeTCP("Error: Cannot decode servers response", LogLevel.Error);
logger.writeTCP("Cannot decode servers response", LogLevel.Error);
} catch (VersionError e) {
System.err.println("Error: Servers response use bad version of the protocol");
logger.writeTCP("Error: Servers response use bad version of the protocol", LogLevel.Error);
logger.writeTCP("Servers 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 clients request");
logger.writeTCP("Error: Server cannot decode clients request", LogLevel.Error);
logger.writeTCP("Server cannot decode clients 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();
}
}
}

View File

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

View File

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

View File

@ -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

View File

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

View File

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

View File

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

View File

@ -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<HostItem> getServList() {
List<HostItem> serverList = new ArrayList<HostItem>();
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;
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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) {