From 1355ef14b18b0ca48b4461f91e22332a1fdbf150 Mon Sep 17 00:00:00 2001 From: Louis Date: Sun, 22 Mar 2020 16:55:05 +0100 Subject: [PATCH] Fix #40 --- src/clientP2P/ClientDownload.java | 409 ++++++++++++++++++++++ src/clientP2P/ClientDownloadPart.java | 310 +++++++++++++++++ src/clientP2P/ClientDownloadPartTCP.java | 331 ++---------------- src/clientP2P/ClientDownloadPartUDP.java | 316 ++--------------- src/clientP2P/ClientDownloadTCP.java | 410 ++--------------------- src/clientP2P/ClientDownloadUDP.java | 401 ++-------------------- src/clientP2P/ClientManagement.java | 262 +++++++++++++++ src/clientP2P/ClientManagementTCP.java | 242 ++----------- src/clientP2P/ClientManagementUDP.java | 255 +++----------- src/serverP2P/ServerManagementTCP.java | 12 +- src/tracker/TrackerManagement.java | 7 + src/tracker/TrackerManagementTCP.java | 16 +- 12 files changed, 1199 insertions(+), 1772 deletions(-) create mode 100644 src/clientP2P/ClientDownload.java create mode 100644 src/clientP2P/ClientDownloadPart.java create mode 100644 src/clientP2P/ClientManagement.java diff --git a/src/clientP2P/ClientDownload.java b/src/clientP2P/ClientDownload.java new file mode 100644 index 0000000..ed58c3b --- /dev/null +++ b/src/clientP2P/ClientDownload.java @@ -0,0 +1,409 @@ +package clientP2P; + +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Random; +import java.io.IOException; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.nio.file.StandardCopyOption; +import exception.LocalException; +import exception.RemoteException; +import localException.SocketClosed; +import localException.ProtocolError; +import localException.InternalError; +import localException.TransmissionError; +import localException.SizeError; +import localException.VersionError; +import remoteException.EmptyDirectory; +import remoteException.EmptyFile; +import remoteException.VersionRemoteError; +import remoteException.ProtocolRemoteError; +import remoteException.NotFound; +import remoteException.InternalRemoteError; +import remoteException.NotATracker; +import protocolP2P.HashAlgorithm; +import protocolP2P.HashResponse; +import protocolP2P.HashRequest; +import protocolP2P.Payload; +import protocolP2P.FilePart; +import protocolP2P.LoadRequest; +import protocolP2P.ProtocolP2PPacket; +import clientP2P.ClientDownloadPart; +import tools.HostItem; +import tools.Logger; +import tools.LogLevel; +import tools.ServeErrors; + +/** Class to download file +* @author Louis Royer +* @author Flavien Haas +* @author JS Auge +* @version 1.0 +*/ +public abstract class ClientDownload extends ServeErrors implements Runnable { + protected List hostList; + protected String filename; + protected byte[] hash512; + protected List sockList = new ArrayList(); + protected List offsetsToAsk = new ArrayList(); + protected List offsetsPending = new ArrayList(); + protected boolean stop; + protected long size; + protected static final long MAX_PARTIAL_SIZE = 4096; + protected String partsSubdir; + protected String dirStorage; + protected boolean success = false; + protected Logger logger; + + /** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage + * @param filename name of file to download + * @param hostList list of servers + * @param partsSubdir directory to store .part files + * @param dirStorage directory to write assembled file + * @param logger Logger + */ + public ClientDownload(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger) { + this.partsSubdir = partsSubdir; + this.dirStorage = dirStorage; + this.filename = filename; + this.hostList = hostList; + this.logger = logger; + this.stop = false; + } + + /** Success getter. + * @return true when file have successfully been reassembled. + */ + public boolean getSuccess() { + return success; + } + + /** Getter for hash512sum + * @return hash512sum + */ + public byte[] getHashSum512() { + return hash512; + } + + /** Stop threads */ + protected void stopTasks() { + for(ClientDownloadPart c : sockList) { + try { + c.setStop(); + } catch (InterruptedException e) { + writeLog(e, LogLevel.Error); + } + } + } + + /** Asks thread to stop + */ + public void setStop() { + stop = true; + } + + /** Assign tasks randomly to threads. + * @throws InternalError + */ + protected void assignTasks() throws InternalError { + Random rand = new Random(); + for(long offset : offsetsToAsk) { + try { + sockList.get(rand.nextInt(sockList.size())).assignTask(offset); + offsetsPending.add(offset); + System.err.println("Assigned task "+ offset); + writeLog("Assigned task "+ offset, LogLevel.Info); + } catch(InterruptedException e) { + writeLog(e, LogLevel.Error); + throw new InternalError(); + } + } + offsetsToAsk.removeAll(offsetsPending); + } + + /** 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); + + /** Starts threads for each server in hostList. + */ + protected void initThreads() { + for(HostItem hostItem: hostList) { + sockList.add(createDownloadPart(filename, hostItem)); + } + for(ClientDownloadPart c: sockList) { + Thread t = new Thread(c); + t.start(); + } + writeLog("Threads initialized", LogLevel.Info); + } + + /** Remove tasks from failed threads. Update done status. + * @throws InternalError + */ + protected void checkTasksStatus() throws InternalError { + try { + synchronized(this) { + this.wait(); + List sockListCpy = new ArrayList<>(sockList); + for(ClientDownloadPart c: sockListCpy) { + if (c.hasFailed() == true) { + sockList.remove(c); + offsetsPending.removeAll(c.getFailed()); + offsetsToAsk.addAll(c.getFailed()); + } + try { + offsetsPending.removeAll(c.getDone()); + } catch (InterruptedException e) { + throw new InternalError(); + } + } + writeLog("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending", LogLevel.Info); + if (offsetsToAsk.isEmpty() && offsetsPending.isEmpty()) { + stop = true; + } + if (sockList.size() == 0) { + logger.writeUDP("No thread working", LogLevel.Error); + throw new InternalError(); + } + } + } catch (InterruptedException e) { + throw new InternalError(); + } + } + + /** Get hashsum from server. + * @param hostItem server to ask hash + * @return hash512sum + * @throws InternalError + */ + protected byte[] getHashSum512(HostItem hostItem) throws InternalError { + byte[] hash; + HashAlgorithm[] hashesAlgo = new HashAlgorithm[1]; + hashesAlgo[0] = HashAlgorithm.SHA512; + ProtocolP2PPacket d = createProtocolP2PPacket(new HashRequest(filename, hashesAlgo)); + try { + d.sendRequest(getHostItemSocket(hostItem)); + try { + Payload pHash = d.receiveResponse().getPayload(); + assert pHash instanceof HashResponse : "This payload must be instance of HashResponse"; + if (!(pHash instanceof HashResponse)) { + throw new InternalError(); + } else { + hash = ((HashResponse)pHash).getHash(HashAlgorithm.SHA512); + } + } catch (EmptyDirectory e) { + 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); + throw new InternalError(); + } catch (RemoteException e) { + writeLog(e, LogLevel.Error); + throw new InternalError(); + } + return hash; + } catch (IOException e) { + writeLog(e, LogLevel.Error); + throw new InternalError(); + } catch (SocketClosed e){ + System.err.println("getHashSum512 : SocketClosed"); + writeLog("getHashSum512 : SocketClosed", LogLevel.Error); + throw new InternalError(); + } + } + + /** Removes servers not owning the correct file to download from list. + * This is done by comparing hash512sum. + * @throws InternalError + */ + protected void purgeList() throws InternalError { + List blackList = new ArrayList(); + boolean first = false; + byte[] hashsum; + for(HostItem host: hostList) { + // already have hashsum from 1st server + if (!first) { + first = true; + continue; + } + // ask hashsum + hashsum = getHashSum512(host); + if (!Arrays.equals(hash512, hashsum)) { + blackList.add(host); + } + } + // purge list + for(HostItem host: blackList) { + hostList.remove(host); + } + writeLog("Host list purge: done", LogLevel.Info); + } + + + /** Reassemble file from file parts. + * Set success to true if file is reassembled successfully. + */ + protected void reassembleFile() { + boolean firstPart = true; + boolean abort = false; + long nextOffset = 0; + do { + if (firstPart) { + writeLog("Reassembling: First part", LogLevel.Info); + try { + // create file + Files.copy(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath(), new File(dirStorage + filename).toPath(), StandardCopyOption.REPLACE_EXISTING); + nextOffset = (new File(dirStorage + filename)).length(); + firstPart = false; + } catch (IOException e) { + writeLog("Reassembling: aborting on first part", LogLevel.Warning); + abort = true; + } + } else if (nextOffset >= size) { + success = true; + writeLog("Reassembling: success", LogLevel.Info); + } else { + // append to file + try { + Files.write(new File(dirStorage + filename).toPath(), Files.readAllBytes(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath()), StandardOpenOption.APPEND); + nextOffset = (new File(dirStorage + filename)).length(); + } catch (IOException e) { + abort = true; + writeLog("Aborting: bad number " + nextOffset, LogLevel.Error); + } + } + } while((!success) && (!abort)); + } + + + /** Set size of file to download. Also download first file part. + * @throws InternalError + */ + protected void setSize() throws InternalError { + ProtocolP2PPacket d = createProtocolP2PPacket(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE)); + 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."); + writeLog("cannot get size.", LogLevel.Error); + throw new InternalError(); + } else { + FilePart fp = (FilePart)p; + if (!fp.getFilename().equals(filename)) { + System.err.println("Error: wrong file received: `" + fp.getFilename() + "`"); + writeLog("wrong file 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(); + } + } + } catch (EmptyDirectory e) { + System.err.println("Error: empty directory."); + writeLog("empty directory.", LogLevel.Error); + throw new InternalError(); + } catch (LocalException e) { + writeLog(e, LogLevel.Error); + throw new InternalError(); + } catch (RemoteException e) { + writeLog(e, LogLevel.Error); + throw new InternalError(); + } + } catch (IOException e) { + writeLog(e, LogLevel.Error); + throw new InternalError(); + } catch (SocketClosed e){ + System.err.println("setSize : SocketClosed"); + writeLog("setSize : SocketClosed", LogLevel.Error); + } + } + + /** Close HostItem socket + * @param hostItem HostItem + */ + protected abstract void closeHostItemSocket(HostItem hostItem); + + + /** Runnable implementation + */ + 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(); + + } + } + writeLog("Reassembling file parts.", LogLevel.Info); + reassembleFile(); + } catch(InternalError e) { + writeLog("Error while downloading file. Aborting.", LogLevel.Error); + } finally { + stopTasks(); + } + } + + /** Initialize infos about file to download (size, hash512sum, partslist to dl). + * Also download first partfile (to get size). + * @throws InternalError + */ + protected void init() throws InternalError { + // get size + setSize(); + + // get hashsum from 1st server in list + hash512 = getHashSum512(hostList.get(0)); + if (hash512.length == 0) { + writeLog("no hash512sum support.", LogLevel.Error); + throw new InternalError(); + } + + // Add tasks + if (!stop) { + for(long i=MAX_PARTIAL_SIZE; i toDoTasks; + protected List pendingTasks; + protected List tasksDone; + protected volatile boolean tasksListsLock; + protected volatile boolean stop; + protected volatile boolean failed; + protected String filename; + protected volatile boolean noTask; + protected String partsSubdir; + protected static final long MAX_PARTIAL_SIZE = 4096; + protected ClientDownload manager; + protected Logger logger; + + /** 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 + */ + public ClientDownloadPart(ClientDownload manager, String filename, String partsSubdir, Logger logger) { + this.manager = manager; + this.partsSubdir = partsSubdir; + this.filename = filename; + this.logger = logger; + stop = false; + failed = false; + pendingTasks = new ArrayList<>(); + toDoTasks = new ArrayList<>(); + tasksDone = new ArrayList<>(); + noTask = true; + tasksListsLock = false; + } + + /** True if thread has failed to get a file. + * @return true if thread has failed to get a file + */ + public boolean hasFailed() { + return failed; + } + + /** Asks to stop thread. + * @throws InterruptedException + */ + public synchronized void setStop() throws InterruptedException { + stop = true; + this.notifyAll(); + } + + /** Runnable implementation */ + public void run() { + while(!stop) { + try { + doTasks(); + synchronized(manager) { + manager.notify(); + } + } catch(InterruptedException e) { + try { + setStop(); + synchronized(manager) { + manager.notify(); + } + } catch (InterruptedException e2) { + } + } + } + writeLog("Closing socket", LogLevel.Info); + try{ + closeSocket(); + } catch(IOException e){ + writeLog("can't close socket", LogLevel.Error); + } + } + + /** Close the socket + */ + protected abstract void closeSocket() throws IOException; + + /** Get list of offsets that have not be downloaded if failed, else + * empty list. + * @return list of offsets + */ + public List getFailed() { + List ret = new ArrayList<>(); + if (failed) { + ret.addAll(pendingTasks); + ret.addAll(toDoTasks); + } + return ret; + } + + /** Get list of downloaded file parts offset, then clear this list. + * @return list of offsets + * @throws InterruptedException + */ + public List getDone() throws InterruptedException { + if (tasksDone.size() == 0) { + return new ArrayList<>(); + } else { + synchronized (this) { + while(tasksListsLock) { + this.wait(); + } + tasksListsLock = true; + List ret = new ArrayList<>(tasksDone); + tasksDone.clear(); + tasksListsLock = false; + this.notifyAll(); + return ret; + } + } + } + + /** Adds offset of files parts to download. + * @param task offset to download + * @throws InterruptedException + */ + public synchronized void assignTask(Long task) throws InterruptedException { + synchronized(this) { + while(tasksListsLock) { + this.wait(); + } + tasksListsLock = true; + toDoTasks.add(task); + noTask = false; + tasksListsLock = false; + this.notifyAll(); + } + } + + + /** Send one request and wait for one response. Blocks when no task. + * @throws InterruptedException + */ + public synchronized void doTasks() throws InterruptedException { + while(noTask && !stop) { + this.wait(); + } + if (!stop) { + try { + Long offset = toDoTasks.get(0); + ProtocolP2PPacket p = reqPart(offset); + if (p == null) { + stop = true; + } + + failed = downloadPart(p); + if (failed) { + System.err.println("Error: DownloadPart failed."); + writeLog("DownloadPart failed.", LogLevel.Error); + stop = true; + } else if (toDoTasks.isEmpty()) { + noTask = true; + } + } catch (IndexOutOfBoundsException e) { + writeLog(e, LogLevel.Error); + noTask = true; + } + } + } + + /** Send a request for a specific offset. + * @param offset Offset of the file part to download + * @return ProtocolP2PPacketTCP used to send request + */ + protected ProtocolP2PPacket reqPart(Long offset) { + writeLog("New request: " + offset, LogLevel.Info); + // maintain tracking of tasks + if (toDoTasks.contains(offset)) { + try { + synchronized (this) { + while(tasksListsLock) { + this.wait(); + } + tasksListsLock = true; + toDoTasks.remove(offset); + pendingTasks.add(offset); + tasksListsLock = false; + this.notifyAll(); + } + } catch(InterruptedException e) { + writeLog("reqPart interruptedException", LogLevel.Error); + return null; + } + } else { + writeLog("reqPart (offset " + offset + " not in toDoTasks)", LogLevel.Error); + return null; + } + // send request + try { + ProtocolP2PPacket d = createProtocolP2PPacket(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE)); + d.sendRequest(getSocket()); + return d; + } catch (InternalError e) { + writeLog("reqPart internalError", LogLevel.Error); + return null; + } catch (IOException e) { + writeLog("reqPart ioexception", LogLevel.Error); + writeLog(e, LogLevel.Error); + return null; + } catch (SocketClosed e){ + writeLog("reqPart SocketClosed", LogLevel.Error); + return null; + } + } + + /** Get the socket */ + protected abstract Object getSocket(); + + + /** Download file part associated to the request send (d). + * @param d request packet + * @return true on failure, else false + */ + public < T extends ProtocolP2PPacket > boolean downloadPart(T d) { + if (d == null) { + writeLog("downloadPart -> d is null.", LogLevel.Error); + return true; + } + try { + Payload p = d.receiveResponse().getPayload(); + assert p instanceof FilePart : "This payload must be instance of FilePart"; + if (!(p instanceof FilePart)) { + writeLog("cannot get size.", LogLevel.Error); + return true; + } else { + FilePart fp = (FilePart)p; + if (!fp.getFilename().equals(filename)) { + writeLog("wrong file received: `" + fp.getFilename() + "`", LogLevel.Error); + return true; + } + Long offset = Long.valueOf(fp.getOffset()); + if (pendingTasks.contains(offset)) { + try { + Files.write(new File(partsSubdir + filename + "_" + offset + ".part").toPath(), fp.getPartialContent()); + } catch (IOException e) { + writeLog("cannot write file (" + partsSubdir + filename + "_" + offset + ".part)", LogLevel.Error); + } + } else { + writeLog("wrong file part received.", LogLevel.Error); + return true; + } + try { + synchronized(this) { + while(tasksListsLock) { + this.wait(); + } + tasksListsLock = true; + pendingTasks.remove(offset); + tasksDone.add(offset); + tasksListsLock = false; + this.notifyAll(); + } + } catch(InterruptedException e) { + writeLog("DownloadPart Interrupted exception", LogLevel.Error); + return true; + } + } + } catch (LocalException e) { + writeLog(e, LogLevel.Error); + return true; + } catch (RemoteException e) { + writeLog(e, LogLevel.Error); + return true; + } catch (IOException e) { + System.err.println("Error: downloadPart ioexception"); + writeLog("downloadPart ioexception", LogLevel.Error); + return true; + } + return false; + } + + +} diff --git a/src/clientP2P/ClientDownloadPartTCP.java b/src/clientP2P/ClientDownloadPartTCP.java index b2872e9..7928735 100644 --- a/src/clientP2P/ClientDownloadPartTCP.java +++ b/src/clientP2P/ClientDownloadPartTCP.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import protocolP2P.ProtocolP2PPacketTCP; +import protocolP2P.ProtocolP2PPacket; import protocolP2P.Payload; import protocolP2P.LoadRequest; import protocolP2P.FilePart; @@ -24,6 +25,7 @@ import remoteException.NotFound; import remoteException.NotATracker; import tools.Logger; import tools.LogLevel; +import clientP2P.ClientDownloadPart; /** Class to download file parts on tcp. * @author Louis Royer @@ -31,332 +33,55 @@ import tools.LogLevel; * @author JS Auge * @version 1.0 */ -public class ClientDownloadPartTCP implements Runnable { +public class ClientDownloadPartTCP extends ClientDownloadPart { - private List toDoTasks; - private List pendingTasks; - private List tasksDone; - private volatile boolean tasksListsLock; - private volatile boolean stop; - private volatile boolean failed; - private String filename; private Socket socket; - private volatile boolean noTask; - private String partsSubdir; - private static final long MAX_PARTIAL_SIZE = 4096; - private ClientDownloadTCP manager; - private Logger logger; /** 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 */ - public ClientDownloadPartTCP(ClientDownloadTCP manager, String filename, Socket socket, String partsSubdir, Logger logger) { - this.manager = manager; - this.partsSubdir = partsSubdir; - this.filename = filename; + public ClientDownloadPartTCP(ClientDownload manager, String filename, Socket socket, String partsSubdir, Logger logger) { + super(manager, filename, partsSubdir, logger); this.socket = socket; - this.logger = logger; - stop = false; - failed = false; - pendingTasks = new ArrayList<>(); - toDoTasks = new ArrayList<>(); - tasksDone = new ArrayList<>(); - noTask = true; - tasksListsLock = false; } - /** True if thread has failed to get a file. - * @return true if thread has failed to get a file - */ - public boolean hasFailed() { - return failed; - } - - /** Asks to stop thread. - * @throws InterruptedException - */ - public synchronized void setStop() throws InterruptedException { - stop = true; - this.notifyAll(); - } - - /** Runnable implementation */ - public void run() { - while(!stop) { - try { - doTasks(); - synchronized(manager) { - manager.notify(); - } - } catch(InterruptedException e) { - try { - setStop(); - synchronized(manager) { - manager.notify(); - } - } catch (InterruptedException e2) { - } - } - } - System.err.println("Closing socket"); - logger.writeTCP("Closing socket", LogLevel.Info); - try{ - socket.close(); - } catch(IOException e){ - System.err.println("can't close socket"); - logger.writeTCP("can't close socket", LogLevel.Error); - } - } - /** Get list of offsets that have not be downloaded if failed, else - * empty list. - * @return list of offsets - */ - public List getFailed() { - List ret = new ArrayList<>(); - if (failed) { - ret.addAll(pendingTasks); - ret.addAll(toDoTasks); - } - return ret; + + /** Get the socket */ + protected Object getSocket() { + return (Object) socket; } - - /** Get list of downloaded file parts offset, then clear this list. - * @return list of offsets - * @throws InterruptedException + + /** Close the socket */ - public List getDone() throws InterruptedException { - if (tasksDone.size() == 0) { - return new ArrayList<>(); - } else { - synchronized (this) { - while(tasksListsLock) { - this.wait(); - } - tasksListsLock = true; - List ret = new ArrayList<>(tasksDone); - tasksDone.clear(); - tasksListsLock = false; - this.notifyAll(); - return ret; - } - } + protected void closeSocket() throws IOException { + socket.close(); } - /** Adds offset of files parts to download. - * @param task offset to download - * @throws InterruptedException + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging */ - public synchronized void assignTask(Long task) throws InterruptedException { - synchronized(this) { - while(tasksListsLock) { - this.wait(); - } - tasksListsLock = true; - toDoTasks.add(task); - noTask = false; - tasksListsLock = false; - this.notifyAll(); - } + protected void writeLog(String text, LogLevel logLevel) { + logger.writeTCP(text, logLevel); } - /** Send one request and wait for one response. Blocks when no task. - * @throws InterruptedException + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging */ - public synchronized void doTasks() throws InterruptedException { - while(noTask && !stop) { - this.wait(); - } - if (!stop) { - try { - Long offset = toDoTasks.get(0); - ProtocolP2PPacketTCP p = reqPart(offset); - if (p == null) { - stop = true; - } - - failed = downloadPart(p); - if (failed) { - System.err.println("Error: DownloadPart failed."); - logger.writeTCP("DownloadPart failed.", LogLevel.Error); - stop = true; - } else if (toDoTasks.isEmpty()) { - noTask = true; - } - } catch (IndexOutOfBoundsException e) { - logger.writeTCP(e, LogLevel.Error); - noTask = true; - } - - } + protected void writeLog(Exception e, LogLevel logLevel) { + logger.writeTCP(e, logLevel); } - /** Send a request for a specific offset. - * @param offset Offset of the file part to download - * @return ProtocolP2PPacketTCP used to send request - */ - private ProtocolP2PPacketTCP reqPart(Long offset) { - System.err.println("New request: " + offset); - logger.writeTCP("New request: " + offset, LogLevel.Info); - // maintain tracking of tasks - if (toDoTasks.contains(offset)) { - try { - synchronized (this) { - while(tasksListsLock) { - this.wait(); - } - tasksListsLock = true; - toDoTasks.remove(offset); - pendingTasks.add(offset); - tasksListsLock = false; - this.notifyAll(); - } - } catch(InterruptedException e) { - System.err.println("Error: reqPart interruptedException"); - logger.writeTCP("reqPart interruptedException", LogLevel.Error); - return null; - } - } else { - System.err.println("Error: reqPart (offset " + offset + " not in toDoTasks)"); - logger.writeTCP("reqPart (offset " + offset + " not in toDoTasks)", LogLevel.Error); - return null; - } - // send request - try { - ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP<>(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE)); - d.sendRequest((Object)socket); - return d; - } catch (InternalError e) { - System.err.println("Error: reqPart internalError"); - logger.writeTCP("reqPart internalError", LogLevel.Error); - return null; - } catch (IOException e) { - e.printStackTrace(); - System.err.println("Error: reqPart ioexception"); - logger.writeTCP("reqPart ioexception", LogLevel.Error); - return null; - } catch (SocketClosed e){ - System.err.println("Error: reqPart SocketClosed"); - logger.writeTCP("reqPart SocketClosed", LogLevel.Error); - return null; - } - } - /** Download file part associated to the request send (d). - * @param d request packet - * @return true on failure, else false + /** Create packets + * @param payload Payload */ - public boolean downloadPart(ProtocolP2PPacketTCP d) { - if (d == null) { - System.err.println("Error: downloadPart -> d is null."); - logger.writeTCP("downloadPart -> d is null.", LogLevel.Error); - return true; - } - 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."); - logger.writeTCP("cannot get size.", LogLevel.Error); - return true; - } else { - FilePart fp = (FilePart)p; - if (!fp.getFilename().equals(filename)) { - System.err.println("Error: wrong file received: `" + fp.getFilename() + "`"); - logger.writeTCP("wrong file received: `" + fp.getFilename() + "`", LogLevel.Error); - return true; - } - Long offset = Long.valueOf(fp.getOffset()); - if (pendingTasks.contains(offset)) { - try { - Files.write(new File(partsSubdir + filename + "_" + offset + ".part").toPath(), fp.getPartialContent()); - } catch (IOException e) { - System.err.println("Error: cannot write file (" + partsSubdir + filename + "_" + offset + ".part)"); - logger.writeTCP("cannot write file (" + partsSubdir + filename + "_" + offset + ".part)", LogLevel.Error); - } - } else { - System.err.println("Error: wrong file part received."); - logger.writeTCP("wrong file part received.", LogLevel.Error); - return true; - } - try { - synchronized(this) { - while(tasksListsLock) { - this.wait(); - } - tasksListsLock = true; - pendingTasks.remove(offset); - tasksDone.add(offset); - tasksListsLock = false; - this.notifyAll(); - } - } catch(InterruptedException e) { - System.err.println("Error: DownloadPart Interrupted exception"); - logger.writeTCP("DownloadPart Interrupted exception", LogLevel.Error); - return true; - } - } - } catch (EmptyDirectory e) { - System.err.println("Error: empty directory."); - logger.writeTCP("empty directory.", LogLevel.Error); - return true; - } catch (EmptyFile e) { - System.err.println("Error: downloadPart emptyFile"); - logger.writeTCP("downloadPart emptyFile", LogLevel.Error); - // TODO: use more specific errors - return true; - } catch (ProtocolError e) { - System.err.println("Error: downloadPart protocolError"); - logger.writeTCP("downloadPart protocolError", LogLevel.Error); - return true; - } catch (InternalRemoteError e) { - System.err.println("Error: downloadPart internalRemoteError"); - logger.writeTCP("downloadPart internalRemoteError", LogLevel.Error); - return true; - } catch (VersionRemoteError e) { - System.err.println("Error: downloadPart versionRemoteError"); - logger.writeTCP("downloadPart versionRemoteError", LogLevel.Error); - return true; - } catch (ProtocolRemoteError e) { - System.err.println("Error: downloadPart protocolRemoteError"); - logger.writeTCP("downloadPart protocolRemoteError", LogLevel.Error); - return true; - } catch (TransmissionError e) { - System.err.println("Error: downloadPart transmissionError"); - logger.writeTCP("downloadPart transmissionError", LogLevel.Error); - return true; - } catch (VersionError e) { - System.err.println("Error: downloadPart versionError"); - logger.writeTCP("downloadPart versionError", LogLevel.Error); - return true; - } catch (SizeError e) { - System.err.println("Error: downloadPart sizeError"); - logger.writeTCP("downloadPart sizeError", LogLevel.Error); - return true; - } catch (NotFound e) { - System.err.println("Error: downloadPart notFound"); - logger.writeTCP("downloadPart notFound", LogLevel.Error); - return true; - } catch (IOException e) { - System.err.println("Error: downloadPart ioexception"); - logger.writeTCP("downloadPart ioexception", LogLevel.Error); - return true; - } catch (InternalError e) { - System.err.println("Error: downloadPart internalError"); - logger.writeTCP("downloadPart internalError", LogLevel.Error); - return true; - } catch (SocketClosed e){ - System.err.println("Error: downloadPart SocketClosed"); - logger.writeTCP("downloadPart SocketClosed", LogLevel.Error); - return true; - } catch (NotATracker e) { - System.err.println("Error: downloadPart notATracker"); - logger.writeTCP("downloadPart notATracker", LogLevel.Error); - return true; - } - return false; + protected < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload) { + return (ProtocolP2PPacket)new ProtocolP2PPacketTCP(payload); } - } diff --git a/src/clientP2P/ClientDownloadPartUDP.java b/src/clientP2P/ClientDownloadPartUDP.java index 2a2e4a7..0387c0c 100644 --- a/src/clientP2P/ClientDownloadPartUDP.java +++ b/src/clientP2P/ClientDownloadPartUDP.java @@ -3,6 +3,7 @@ import java.util.List; import java.util.ArrayList; import java.net.DatagramSocket; import protocolP2P.ProtocolP2PPacketUDP; +import protocolP2P.ProtocolP2PPacket; import protocolP2P.Payload; import protocolP2P.LoadRequest; import protocolP2P.FilePart; @@ -23,6 +24,7 @@ import java.io.File; import java.io.IOException; import tools.Logger; import tools.LogLevel; +import clientP2P.ClientDownloadPart; /** Class to download file parts on udp. * @author Louis Royer @@ -30,318 +32,54 @@ import tools.LogLevel; * @author JS Auge * @version 1.0 */ -public class ClientDownloadPartUDP implements Runnable { +public class ClientDownloadPartUDP extends ClientDownloadPart { - private List toDoTasks; - private List pendingTasks; - private List tasksDone; - private volatile boolean tasksListsLock; - private volatile boolean stop; - private volatile boolean failed; - private String filename; private DatagramSocket socket; - private volatile boolean noTask; - private String partsSubdir; - private static final long MAX_PARTIAL_SIZE = 4096; - private ClientDownloadUDP manager; - private Logger logger; + /** 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 */ - public ClientDownloadPartUDP(ClientDownloadUDP manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger) { - this.manager = manager; - this.partsSubdir = partsSubdir; - this.filename = filename; + public ClientDownloadPartUDP(ClientDownload manager, String filename, DatagramSocket socket, String partsSubdir, Logger logger) { + super(manager, filename, partsSubdir, logger); this.socket = socket; - this.logger = logger; - stop = false; - failed = false; - pendingTasks = new ArrayList<>(); - toDoTasks = new ArrayList<>(); - tasksDone = new ArrayList<>(); - noTask = true; - tasksListsLock = false; } - /** True if thread has failed to get a file. - * @return true if thread has failed to get a file - */ - public boolean hasFailed() { - return failed; + /** Get the socket */ + protected Object getSocket() { + return (Object) socket; } - - /** Asks to stop thread. - * @throws InterruptedException + + /** Close the socket */ - public synchronized void setStop() throws InterruptedException { - stop = true; - this.notifyAll(); - } - - /** Runnable implementation */ - public void run() { - while(!stop) { - try { - doTasks(); - synchronized(manager) { - manager.notify(); - } - } catch(InterruptedException e) { - try { - setStop(); - synchronized(manager) { - manager.notify(); - } - } catch (InterruptedException e2) { - } - } - } - System.err.println("Closing socket"); - logger.writeUDP("Closing socket", LogLevel.Info); + protected void closeSocket() throws IOException { socket.close(); } - /** Get list of offsets that have not be downloaded if failed, else - * empty list. - * @return list of offsets - */ - public List getFailed() { - List ret = new ArrayList<>(); - if (failed) { - ret.addAll(pendingTasks); - ret.addAll(toDoTasks); - } - return ret; - } - - /** Get list of downloaded file parts offset, then clear this list. - * @return list of offsets - * @throws InterruptedException - */ - public List getDone() throws InterruptedException { - if (tasksDone.size() == 0) { - return new ArrayList<>(); - } else { - synchronized (this) { - while(tasksListsLock) { - this.wait(); - } - tasksListsLock = true; - List ret = new ArrayList<>(tasksDone); - tasksDone.clear(); - tasksListsLock = false; - this.notifyAll(); - return ret; - } - } - } - - /** Adds offset of files parts to download. - * @param task offset to download - * @throws InterruptedException - */ - public synchronized void assignTask(Long task) throws InterruptedException { - synchronized(this) { - while(tasksListsLock) { - this.wait(); - } - tasksListsLock = true; - toDoTasks.add(task); - noTask = false; - tasksListsLock = false; - this.notifyAll(); - } - } - /** Send one request and wait for one response. Blocks when no task. - * @throws InterruptedException + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging */ - public synchronized void doTasks() throws InterruptedException { - while(noTask && !stop) { - this.wait(); - } - if (!stop) { - try { - Long offset = toDoTasks.get(0); - ProtocolP2PPacketUDP p = reqPart(offset); - if (p == null) { - stop = true; - } - - failed = downloadPart(p); - if (failed) { - System.err.println("Error: DownloadPart failed."); - stop = true; - } else if (toDoTasks.isEmpty()) { - noTask = true; - } - } catch (IndexOutOfBoundsException e) { - logger.writeUDP(e, LogLevel.Error); - noTask = true; - } - - } + protected void writeLog(String text, LogLevel logLevel) { + logger.writeUDP(text, logLevel); } - /** Send a request for a specific offset. - * @param offset Offset of the file part to download - * @return ProtocolP2PPacketTCP used to send request + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging */ - private ProtocolP2PPacketUDP reqPart(Long offset) { - System.err.println("New request: "+ offset); - logger.writeUDP("New request: "+ offset, LogLevel.Info); - // maintain tracking of tasks - if (toDoTasks.contains(offset)) { - try { - synchronized (this) { - while(tasksListsLock) { - this.wait(); - } - tasksListsLock = true; - toDoTasks.remove(offset); - pendingTasks.add(offset); - tasksListsLock = false; - this.notifyAll(); - } - } catch(InterruptedException e) { - System.err.println("Error: reqPart interruptedException"); - logger.writeUDP("reqPart interruptedException", LogLevel.Error); - return null; - } - } else { - System.err.println("Error: reqPart (offset " + offset + " not in toDoTasks)"); - logger.writeUDP("reqPart (offset " + offset + " not in toDoTasks)", LogLevel.Error); - return null; - } - // send request - try { - ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP<>(new LoadRequest(filename, offset.longValue(), MAX_PARTIAL_SIZE)); - d.sendRequest((Object)socket); - return d; - } catch (InternalError e) { - System.err.println("Error: reqPart internalError"); - logger.writeUDP("reqPart internalError", LogLevel.Error); - return null; - } catch (IOException e) { - e.printStackTrace(); - System.err.println("Error: reqPart ioexception"); - logger.writeUDP("reqPart ioexception", LogLevel.Error); - return null; - } + protected void writeLog(Exception e, LogLevel logLevel) { + logger.writeUDP(e, logLevel); } - /** Download file part associated to the request send (d). - * @param d request packet - * @return true on failure, else false + /** Create packets + * @param payload Payload */ - public boolean downloadPart(ProtocolP2PPacketUDP d) { - if (d == null) { - System.err.println("Error: downloadPart -> d is null."); - logger.writeUDP("downloadPart -> d is null.", LogLevel.Error); - return true; - } - 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."); - logger.writeUDP("cannot get size.", LogLevel.Error); - return true; - } else { - FilePart fp = (FilePart)p; - if (!fp.getFilename().equals(filename)) { - System.err.println("Error: wrong file received: `" + fp.getFilename() + "`"); - logger.writeUDP("wrong file received: `" + fp.getFilename() + "`", LogLevel.Error); - return true; - } - Long offset = Long.valueOf(fp.getOffset()); - if (pendingTasks.contains(offset)) { - try { - Files.write(new File(partsSubdir + filename + "_" + offset + ".part").toPath(), fp.getPartialContent()); - } catch (IOException e) { - System.err.println("Error: cannot write file (" + partsSubdir + filename + "_" + offset + ".part)"); - logger.writeUDP("cannot write file (" + partsSubdir + filename + "_" + offset + ".part)", LogLevel.Error); - } - } else { - System.err.println("Error: wrong file part received."); - logger.writeUDP("wrong file part received.", LogLevel.Error); - return true; - } - try { - synchronized(this) { - while(tasksListsLock) { - this.wait(); - } - tasksListsLock = true; - pendingTasks.remove(offset); - tasksDone.add(offset); - tasksListsLock = false; - this.notifyAll(); - } - } catch(InterruptedException e) { - System.err.println("Error: DownloadPart Interrupted exception"); - logger.writeUDP("DownloadPart Interrupted exception", LogLevel.Error); - return true; - } - } - } catch (EmptyDirectory e) { - System.err.println("Error: empty directory."); - logger.writeUDP("empty directory.", LogLevel.Error); - return true; - } catch (EmptyFile e) { - System.err.println("Error: downloadPart emptyFile"); - logger.writeUDP("downloadPart emptyFile", LogLevel.Error); - // TODO: use more specific errors - return true; - } catch (ProtocolError e) { - System.err.println("Error: downloadPart protocolError"); - logger.writeUDP("downloadPart protocolError", LogLevel.Error); - return true; - } catch (InternalRemoteError e) { - System.err.println("Error: downloadPart internalRemoteError"); - logger.writeUDP("downloadPart internalRemoteError", LogLevel.Error); - return true; - } catch (VersionRemoteError e) { - System.err.println("Error: downloadPart versionRemoteError"); - logger.writeUDP("downloadPart versionRemoteError", LogLevel.Error); - return true; - } catch (ProtocolRemoteError e) { - System.err.println("Error: downloadPart protocolRemoteError"); - logger.writeUDP("downloadPart protocolRemoteError", LogLevel.Error); - return true; - } catch (TransmissionError e) { - System.err.println("Error: downloadPart transmissionError"); - logger.writeUDP("downloadPart transmissionError", LogLevel.Error); - return true; - } catch (VersionError e) { - System.err.println("Error: downloadPart versionError"); - logger.writeUDP("downloadPart versionError", LogLevel.Error); - return true; - } catch (SizeError e) { - System.err.println("Error: downloadPart sizeError"); - logger.writeUDP("downloadPart sizeError", LogLevel.Error); - return true; - } catch (NotFound e) { - System.err.println("Error: downloadPart notFound"); - logger.writeUDP("downloadPart notFound", LogLevel.Error); - return true; - } catch (IOException e) { - System.err.println("Error: downloadPart ioexception"); - logger.writeUDP("downloadPart ioexception", LogLevel.Error); - return true; - } catch (InternalError e) { - System.err.println("Error: downloadPart internalError"); - logger.writeUDP("downloadPart internalError", LogLevel.Error); - return true; - } catch (NotATracker e) { - System.err.println("Error: downloadPart notATracker"); - logger.writeUDP("downloadPart notATracker", LogLevel.Error); - return true; - } - return false; + protected < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload) { + return (ProtocolP2PPacket)new ProtocolP2PPacketUDP(payload); } - } diff --git a/src/clientP2P/ClientDownloadTCP.java b/src/clientP2P/ClientDownloadTCP.java index 3bc8981..5d32835 100644 --- a/src/clientP2P/ClientDownloadTCP.java +++ b/src/clientP2P/ClientDownloadTCP.java @@ -26,10 +26,12 @@ import protocolP2P.HashAlgorithm; import protocolP2P.HashResponse; import protocolP2P.HashRequest; import protocolP2P.ProtocolP2PPacketTCP; +import protocolP2P.ProtocolP2PPacket; import protocolP2P.Payload; import protocolP2P.FilePart; import protocolP2P.LoadRequest; import clientP2P.ClientDownloadPartTCP; +import clientP2P.ClientDownload; import tools.HostItem; import tools.Logger; import tools.LogLevel; @@ -40,407 +42,61 @@ import tools.LogLevel; * @author JS Auge * @version 1.0 */ -public class ClientDownloadTCP implements Runnable { - - private List hostList; - private String filename; - private byte[] hash512; - private List sockList = new ArrayList(); - private List offsetsToAsk = new ArrayList(); - private List offsetsPending = new ArrayList(); - private boolean stop; - private long size; - private static final long MAX_PARTIAL_SIZE = 4096; - private String partsSubdir; - private String dirStorage; - private boolean success = false; - private Logger logger; +public class ClientDownloadTCP extends ClientDownload { /** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage * @param filename name of file to download * @param hostList list of servers * @param partsSubdir directory to store .part files * @param dirStorage directory to write assembled file + * @param logger Logger */ public ClientDownloadTCP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger) { - this.partsSubdir = partsSubdir; - this.dirStorage = dirStorage; - this.filename = filename; - this.hostList = hostList; - this.logger = logger; - this.stop = false; + super(filename, hostList, partsSubdir, dirStorage, logger); } - /** Asks thread to stop + /** Create a clientDownloadPart + * @param filename name of the file to download + * @param hostItem Hostitem of the server */ - public void setStop() { - stop = true; + protected ClientDownloadPart createDownloadPart(String filename, HostItem hostItem) { + return (ClientDownloadPart)new ClientDownloadPartTCP((ClientDownload)this, filename, hostItem.getTCPSocket(), partsSubdir, logger); } - - /** Runnable implementation + + /** Close HostItem socket + * @param hostItem HostItem */ - public void run() { - try { - init(); - if (stop) { - System.err.println("File is smaller than part max size."); - logger.writeTCP("File is smaller than part max size.", LogLevel.Info); - hostList.get(0).closeTCPSocket(); - } else { - System.err.println("File is bigger than part max size."); - logger.writeTCP("File is bigger than part max size.", LogLevel.Info); - purgeList(); - initThreads(); - while(!stop) { - assignTasks(); - checkTasksStatus(); - - } - } - System.err.println("Reassembling file parts."); - logger.writeTCP("Reassembling file parts.", LogLevel.Info); - reassembleFile(); - } catch(InternalError e) { - System.err.println("Error while downloading file. Aborting."); - logger.writeTCP("Error while downloading file. Aborting.", LogLevel.Error); - } finally { - stopTasks(); - } + protected void closeHostItemSocket(HostItem hostItem) { + hostItem.closeTCPSocket(); } - /** Starts threads for each server in hostList. + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging */ - private void initThreads() { - for(HostItem hostItem: hostList) { - sockList.add(new ClientDownloadPartTCP(this, filename, hostItem.getTCPSocket(), partsSubdir, logger)); - } - for(ClientDownloadPartTCP c: sockList) { - Thread t = new Thread(c); - t.start(); - } - System.err.println("Threads initialized"); - logger.writeTCP("Threads initialized", LogLevel.Info); - } - - /** Remove tasks from failed threads. Update done status. - * @throws InternalError - */ - private void checkTasksStatus() throws InternalError { - try { - synchronized(this) { - this.wait(); - List sockListCpy = new ArrayList<>(sockList); - for(ClientDownloadPartTCP c: sockListCpy) { - if (c.hasFailed() == true) { - sockList.remove(c); - offsetsPending.removeAll(c.getFailed()); - offsetsToAsk.addAll(c.getFailed()); - } - try { - offsetsPending.removeAll(c.getDone()); - } catch (InterruptedException e) { - throw new InternalError(); - } - } - System.err.println("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending"); - logger.writeTCP("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending", LogLevel.Info); - if (offsetsToAsk.isEmpty() && offsetsPending.isEmpty()) { - stop = true; - } - if (sockList.size() == 0) { - System.err.println("No thread working"); - logger.writeTCP("No thread working", LogLevel.Error); - throw new InternalError(); - } - } - } catch (InterruptedException e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } - } - - /** Assign tasks randomly to threads. - * @throws InternalError - */ - private void assignTasks() throws InternalError { - Random rand = new Random(); - for(long offset : offsetsToAsk) { - try { - sockList.get(rand.nextInt(sockList.size())).assignTask(offset); - offsetsPending.add(offset); - System.err.println("Assigned task "+ offset); - } catch(InterruptedException e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } - } - offsetsToAsk.removeAll(offsetsPending); - } - - /** Stop threads */ - private void stopTasks() { - for(ClientDownloadPartTCP c : sockList) { - try { - c.setStop(); - } catch (InterruptedException e) { - logger.writeTCP(e, LogLevel.Error); - } - } - } - - /** Get hashsum from server. - * @param hostItem server to ask hash - * @return hash512sum - * @throws InternalError - */ - private byte[] getHashSum512(HostItem hostItem) throws InternalError { - byte[] hash; - HashAlgorithm[] hashesAlgo = new HashAlgorithm[1]; - hashesAlgo[0] = HashAlgorithm.SHA512; - ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP<>(new HashRequest(filename, hashesAlgo)); - try { - d.sendRequest((Object)hostItem.getTCPSocket()); - try { - Payload pHash = d.receiveResponse().getPayload(); - assert pHash instanceof HashResponse : "This payload must be instance of HashResponse"; - if (!(pHash instanceof HashResponse)) { - throw new InternalError(); - } else { - hash = ((HashResponse)pHash).getHash(HashAlgorithm.SHA512); - } - } catch (EmptyDirectory e) { - logger.writeTCP(e, LogLevel.Error); - hash = new byte[0]; - } catch (NotFound e) { - logger.writeTCP(e, LogLevel.Error); - hash = new byte[0]; - // TODO: use more specific errors - } catch (EmptyFile e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (ProtocolError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (InternalRemoteError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (VersionRemoteError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (ProtocolRemoteError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (TransmissionError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (VersionError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (SizeError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (NotATracker e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } - return hash; - } catch (IOException e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (SocketClosed e){ - System.err.println("getHashSum512 : SocketClosed"); - logger.writeTCP("getHashSum512 : SocketClosed", LogLevel.Error); - throw new InternalError(); - } - } - - /** Removes servers not owning the correct file to download from list. - * This is done by comparing hash512sum. - * @throws InternalError - */ - private void purgeList() throws InternalError { - List blackList = new ArrayList(); - boolean first = false; - byte[] hashsum; - for(HostItem host: hostList) { - // already have hashsum from 1st server - if (!first) { - first = true; - continue; - } - // ask hashsum - hashsum = getHashSum512(host); - if (!Arrays.equals(hash512, hashsum)) { - blackList.add(host); - } - } - // purge list - for(HostItem host: blackList) { - hostList.remove(host); - } - System.err.println("Host list purge: done"); - logger.writeTCP("Host list purge: done", LogLevel.Info); - } - - /** Getter for hash512sum - * @return hash512sum - */ - public byte[] getHashSum512() { - return hash512; - } - - /** Initialize infos about file to download (size, hash512sum, partslist to dl). - * Also download first partfile (to get size). - * @throws InternalError - */ - private void init() throws InternalError { - // get size - setSize(); - - // get hashsum from 1st server in list - hash512 = getHashSum512(hostList.get(0)); - if (hash512.length == 0) { - System.err.println("Error: no hash512sum support."); - logger.writeTCP("no hash512sum support.", LogLevel.Error); - throw new InternalError(); - } - - // Add tasks - if (!stop) { - for(long i=MAX_PARTIAL_SIZE; i d = new ProtocolP2PPacketTCP<>(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE)); - try { - d.sendRequest((Object)hostList.get(0).getTCPSocket()); - 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."); - logger.writeTCP("cannot get size.", LogLevel.Error); - throw new InternalError(); - } else { - FilePart fp = (FilePart)p; - if (!fp.getFilename().equals(filename)) { - System.err.println("Error: wrong file received: `" + fp.getFilename() + "`"); - logger.writeTCP("wrong file 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)"); - logger.writeTCP("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."); - logger.writeTCP("wrong file part received.", LogLevel.Error); - throw new InternalError(); - } - } - } catch (EmptyDirectory e) { - System.err.println("Error: empty directory."); - logger.writeTCP("empty directory.", LogLevel.Error); - throw new InternalError(); - } catch (EmptyFile e) { - logger.writeTCP(e, LogLevel.Error); - // TODO: use more specific errors - throw new InternalError(); - } catch (ProtocolError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (InternalRemoteError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (VersionRemoteError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (ProtocolRemoteError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (TransmissionError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (VersionError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (SizeError e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (NotFound e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (NotATracker e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } - } catch (IOException e) { - logger.writeTCP(e, LogLevel.Error); - throw new InternalError(); - } catch (SocketClosed e){ - System.err.println("setSize : SocketClosed"); - logger.writeTCP("setSize : SocketClosed", LogLevel.Error); - } + protected void writeLog(Exception e, LogLevel logLevel) { + logger.writeTCP(e, logLevel); } - /** Success getter. - * @return true when file have successfully been reassembled. + /** Create packets + * @param payload Payload */ - public boolean getSuccess() { - return success; + protected < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload) { + return (ProtocolP2PPacket)new ProtocolP2PPacketTCP(payload); } - /** Reassemble file from file parts. - * Set success to true if file is reassembled successfully. + /** Getter for HostItem socket + * @param hostItem HostItem */ - private void reassembleFile() { - boolean firstPart = true; - boolean abort = false; - long nextOffset = 0; - do { - if (firstPart) { - System.err.println("Reassembling: First part"); - logger.writeTCP("Reassembling: First part", LogLevel.Info); - try { - // create file - Files.copy(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath(), new File(dirStorage + filename).toPath(), StandardCopyOption.REPLACE_EXISTING); - nextOffset = (new File(dirStorage + filename)).length(); - firstPart = false; - } catch (IOException e) { - System.err.println("Reassembling: aborting on first part"); - logger.writeTCP("Reassembling: aborting on first part", LogLevel.Error); - abort = true; - } - } else if (nextOffset >= size) { - success = true; - System.err.println("Reassembling: success"); - logger.writeTCP("Reassembling: success", LogLevel.Info); - } else { - // append to file - try { - Files.write(new File(dirStorage + filename).toPath(), Files.readAllBytes(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath()), StandardOpenOption.APPEND); - nextOffset = (new File(dirStorage + filename)).length(); - } catch (IOException e) { - abort = true; - System.err.println("Aborting: bad number " + nextOffset); - logger.writeTCP("Aborting: bad number " + nextOffset, LogLevel.Error); - } - } - } while((!success) && (!abort)); + protected Object getHostItemSocket(HostItem hostItem) { + return (Object)hostItem.getTCPSocket(); } } diff --git a/src/clientP2P/ClientDownloadUDP.java b/src/clientP2P/ClientDownloadUDP.java index 9fa14d2..008caaf 100644 --- a/src/clientP2P/ClientDownloadUDP.java +++ b/src/clientP2P/ClientDownloadUDP.java @@ -25,10 +25,12 @@ import protocolP2P.HashAlgorithm; import protocolP2P.HashResponse; import protocolP2P.HashRequest; import protocolP2P.ProtocolP2PPacketUDP; +import protocolP2P.ProtocolP2PPacket; import protocolP2P.Payload; import protocolP2P.FilePart; import protocolP2P.LoadRequest; import clientP2P.ClientDownloadPartUDP; +import clientP2P.ClientDownload; import tools.HostItem; import tools.Logger; import tools.LogLevel; @@ -40,400 +42,61 @@ import tools.LogLevel; * @author JS Auge * @version 1.0 */ -public class ClientDownloadUDP implements Runnable { - - private List hostList; - private String filename; - private byte[] hash512; - private List sockList = new ArrayList(); - private List offsetsToAsk = new ArrayList(); - private List offsetsPending = new ArrayList(); - private boolean stop; - private long size; - private static final long MAX_PARTIAL_SIZE = 4096; - private String partsSubdir; - private String dirStorage; - private boolean success = false; - private Logger logger; +public class ClientDownloadUDP extends ClientDownload { /** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage * @param filename name of file to download * @param hostList list of servers * @param partsSubdir directory to store .part files * @param dirStorage directory to write assembled file + * @param logger Logger */ public ClientDownloadUDP(String filename, List hostList, String partsSubdir, String dirStorage, Logger logger) { - this.partsSubdir = partsSubdir; - this.dirStorage = dirStorage; - this.filename = filename; - this.hostList = hostList; - this.logger = logger; - this.stop = false; - } - - /** Asks thread to stop - */ - public void setStop() { - stop = true; - } - - /** Runnable implementation - */ - public void run() { - try { - init(); - if (stop) { - System.err.println("File is smaller than part max size."); - logger.writeUDP("File is smaller than part max size.", LogLevel.Info); - hostList.get(0).closeUDPSocket(); - } else { - System.err.println("File is bigger than part max size."); - logger.writeUDP("File is bigger than part max size.", LogLevel.Info); - purgeList(); - initThreads(); - while(!stop) { - assignTasks(); - checkTasksStatus(); - - } - } - System.err.println("Reassembling file parts."); - logger.writeUDP("Reassembling file parts.", LogLevel.Info); - reassembleFile(); - } catch(InternalError e) { - System.err.println("Error while downloading file. Aborting."); - logger.writeUDP("Error while downloading file. Aborting.", LogLevel.Error); - } finally { - stopTasks(); - } - } - - /** Starts threads for each server in hostList. - */ - private void initThreads() { - for(HostItem hostItem: hostList) { - sockList.add(new ClientDownloadPartUDP(this, filename, hostItem.getUDPSocket(), partsSubdir, logger)); - } - for(ClientDownloadPartUDP c: sockList) { - Thread t = new Thread(c); - t.start(); - } - System.err.println("Threads initialized"); - logger.writeUDP("Threads initialized", LogLevel.Error); - } - - /** Remove tasks from failed threads. Update done status. - * @throws InternalError - */ - private void checkTasksStatus() throws InternalError { - try { - synchronized(this) { - this.wait(); - List sockListCpy = new ArrayList<>(sockList); - for(ClientDownloadPartUDP c: sockListCpy) { - if (c.hasFailed() == true) { - sockList.remove(c); - offsetsPending.removeAll(c.getFailed()); - offsetsToAsk.addAll(c.getFailed()); - } - try { - offsetsPending.removeAll(c.getDone()); - } catch (InterruptedException e) { - throw new InternalError(); - } - } - System.err.println("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending"); - logger.writeUDP("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending", LogLevel.Info); - if (offsetsToAsk.isEmpty() && offsetsPending.isEmpty()) { - stop = true; - } - if (sockList.size() == 0) { - System.err.println("No thread working"); - logger.writeUDP("No thread working", LogLevel.Error); - throw new InternalError(); - } - } - } catch (InterruptedException e) { - throw new InternalError(); - } - } - - /** Assign tasks randomly to threads. - * @throws InternalError - */ - private void assignTasks() throws InternalError { - Random rand = new Random(); - for(long offset : offsetsToAsk) { - try { - sockList.get(rand.nextInt(sockList.size())).assignTask(offset); - offsetsPending.add(offset); - System.err.println("Assigned task "+ offset); - logger.writeUDP("Assigned task "+ offset, LogLevel.Info); - } catch(InterruptedException e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } - } - offsetsToAsk.removeAll(offsetsPending); - } - - /** Stop threads */ - private void stopTasks() { - for(ClientDownloadPartUDP c : sockList) { - try { - c.setStop(); - } catch (InterruptedException e) { - logger.writeUDP(e, LogLevel.Error); - } - } - } - - /** Get hashsum from server. - * @param hostItem server to ask hash - * @return hash512sum - * @throws InternalError - */ - private byte[] getHashSum512(HostItem hostItem) throws InternalError { - byte[] hash; - HashAlgorithm[] hashesAlgo = new HashAlgorithm[1]; - hashesAlgo[0] = HashAlgorithm.SHA512; - ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP<>(new HashRequest(filename, hashesAlgo)); - try { - d.sendRequest((Object)hostItem.getUDPSocket()); - try { - Payload pHash = d.receiveResponse().getPayload(); - assert pHash instanceof HashResponse : "This payload must be instance of HashResponse"; - if (!(pHash instanceof HashResponse)) { - throw new InternalError(); - } else { - hash = ((HashResponse)pHash).getHash(HashAlgorithm.SHA512); - } - } catch (EmptyDirectory e) { - logger.writeUDP(e, LogLevel.Error); - hash = new byte[0]; - } catch (NotFound e) { - logger.writeUDP(e, LogLevel.Error); - hash = new byte[0]; - // TODO: use more specific errors - } catch (EmptyFile e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (ProtocolError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (InternalRemoteError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (VersionRemoteError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (ProtocolRemoteError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (TransmissionError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (VersionError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (SizeError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (NotATracker e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } - return hash; - } catch (IOException e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } + super(filename, hostList, partsSubdir, dirStorage, logger); } - /** Removes servers not owning the correct file to download from list. - * This is done by comparing hash512sum. - * @throws InternalError + /** Create a clientDownloadPart + * @param filename name of the file to download + * @param hostItem Hostitem of the server */ - private void purgeList() throws InternalError { - List blackList = new ArrayList(); - boolean first = false; - byte[] hashsum; - for(HostItem host: hostList) { - // already have hashsum from 1st server - if (!first) { - first = true; - continue; - } - // ask hashsum - hashsum = getHashSum512(host); - if (!Arrays.equals(hash512, hashsum)) { - blackList.add(host); - } - } - // purge list - for(HostItem host: blackList) { - hostList.remove(host); - } - System.err.println("Host list purge: done"); - logger.writeUDP("Host list purge: done", LogLevel.Info); + protected ClientDownloadPart createDownloadPart(String filename, HostItem hostItem) { + return (ClientDownloadPart)new ClientDownloadPartUDP((ClientDownload)this, filename, hostItem.getUDPSocket(), partsSubdir, logger); } - /** Getter for hash512sum - * @return hash512sum + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging */ - public byte[] getHashSum512() { - return hash512; + protected void writeLog(String text, LogLevel logLevel) { + logger.writeUDP(text, logLevel); } - /** Initialize infos about file to download (size, hash512sum, partslist to dl). - * Also download first partfile (to get size). - * @throws InternalError + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging */ - private void init() throws InternalError { - // get size - setSize(); - - // get hashsum from 1st server in list - hash512 = getHashSum512(hostList.get(0)); - if (hash512.length == 0) { - System.err.println("Error: no hash512sum support."); - logger.writeUDP("no hash512sum support.", LogLevel.Error); - throw new InternalError(); - } - - // Add tasks - if (!stop) { - for(long i=MAX_PARTIAL_SIZE; i d = new ProtocolP2PPacketUDP<>(new LoadRequest(filename, 0, MAX_PARTIAL_SIZE)); - try { - d.sendRequest((Object)hostList.get(0).getUDPSocket()); - 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."); - logger.writeUDP("cannot get size.", LogLevel.Error); - throw new InternalError(); - } else { - FilePart fp = (FilePart)p; - if (!fp.getFilename().equals(filename)) { - System.err.println("Error: wrong file received: `" + fp.getFilename() + "`"); - logger.writeUDP("wrong file 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)"); - logger.writeUDP("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."); - logger.writeUDP("wrong file part received.", LogLevel.Error); - throw new InternalError(); - } - } - } catch (EmptyDirectory e) { - System.err.println("Error: empty directory."); - logger.writeUDP("empty directory.", LogLevel.Error); - throw new InternalError(); - } catch (EmptyFile e) { - logger.writeUDP(e, LogLevel.Error); - // TODO: use more specific errors - throw new InternalError(); - } catch (ProtocolError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (InternalRemoteError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (VersionRemoteError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (ProtocolRemoteError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (TransmissionError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (VersionError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (SizeError e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (NotFound e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } catch (NotATracker e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } - } catch (IOException e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } + protected < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload) { + return (ProtocolP2PPacket)new ProtocolP2PPacketUDP(payload); } - /** Success getter. - * @return true when file have successfully been reassembled. + /** Getter for HostItem socket + * @param hostItem HostItem */ - public boolean getSuccess() { - return success; + protected Object getHostItemSocket(HostItem hostItem) { + return (Object)hostItem.getUDPSocket(); } - /** Reassemble file from file parts. - * Set success to true if file is reassembled successfully. + /** Close HostItem socket + * @param hostItem HostItem */ - private void reassembleFile() { - boolean firstPart = true; - boolean abort = false; - long nextOffset = 0; - do { - if (firstPart) { - System.err.println("Reassembling: First part"); - logger.writeUDP("Reassembling: First part", LogLevel.Info); - try { - // create file - Files.copy(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath(), new File(dirStorage + filename).toPath(), StandardCopyOption.REPLACE_EXISTING); - nextOffset = (new File(dirStorage + filename)).length(); - firstPart = false; - } catch (IOException e) { - System.err.println("Reassembling: aborting on first part"); - logger.writeUDP("Reassembling: aborting on first part", LogLevel.Warning); - abort = true; - } - } else if (nextOffset >= size) { - success = true; - System.err.println("Reassembling: success"); - logger.writeUDP("Reassembling: success", LogLevel.Info); - } else { - // append to file - try { - Files.write(new File(dirStorage + filename).toPath(), Files.readAllBytes(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath()), StandardOpenOption.APPEND); - nextOffset = (new File(dirStorage + filename)).length(); - } catch (IOException e) { - abort = true; - System.err.println("Aborting: bad number " + nextOffset); - logger.writeUDP("Aborting: bad number " + nextOffset, LogLevel.Error); - } - } - } while((!success) && (!abort)); + protected void closeHostItemSocket(HostItem hostItem) { + hostItem.closeUDPSocket(); } } diff --git a/src/clientP2P/ClientManagement.java b/src/clientP2P/ClientManagement.java new file mode 100644 index 0000000..cf1dad8 --- /dev/null +++ b/src/clientP2P/ClientManagement.java @@ -0,0 +1,262 @@ +package clientP2P; +import tools.HostItem; +import tools.Logger; +import tools.LogLevel; +import java.util.Scanner; +import java.util.List; +import localException.ProtocolError; +import tools.ServeErrors; +import protocolP2P.RequestResponseCode; +import protocolP2P.FileList; +import protocolP2P.ProtocolP2PPacket; +import protocolP2P.DiscoverRequest; +import protocolP2P.DiscoverResponse; +import protocolP2P.Payload; +import protocolP2P.HashAlgorithm; +import localException.InternalError; +import localException.ProtocolError; +import localException.SizeError; +import localException.TransmissionError; +import localException.VersionError; +import localException.SocketClosed; +import remoteException.EmptyFile; +import remoteException.EmptyDirectory; +import remoteException.InternalRemoteError; +import remoteException.NotFound; +import remoteException.ProtocolRemoteError; +import remoteException.VersionRemoteError; +import remoteException.NotATracker; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; + + +/** Implementation of P2P-JAVA-PROJECT CLIENT + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public abstract class ClientManagement extends ServeErrors implements Runnable { + protected String baseDirectory; + protected String partsSubdir; + protected List hostList; + protected HostItem tracker; + protected Logger logger; + protected Scanner scanner; + protected ClientDownload downLoader; + + /** Constructor with baseDirectory, tracker, partsSubdir, logger, and scanner parameters. + * @param baseDirectory the root directory where files are stored + * @param tracker Tracker hostItem + * @param partsSubdir subdirectory to store file parts + * @param logger Loggger + * @param scanner Scanner used to read input + */ + public ClientManagement(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { + this.scanner = scanner; + this.baseDirectory = baseDirectory; + this.tracker = tracker; + this.partsSubdir = partsSubdir; + this.logger = logger; + try { + initHostList(); + } catch (InternalError e) { + System.exit(-1); + } catch (ProtocolError e) { + System.exit(-2); + } + } + + /** Getter for tracker socket + */ + protected abstract Object getTrackerSocket(); + + + /** Initialize hostList from tracker + * @throws ProtocolError + * @throws InternalError + */ + private void initHostList() throws ProtocolError, InternalError { + ProtocolP2PPacket d = createProtocolP2PPacket(new DiscoverRequest(null)); + try { + d.sendRequest(getTrackerSocket()); + 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){ + writeLog("listDirectory : SocketClosed", LogLevel.Error); + throw new ProtocolError(); + } catch (NotATracker e) { + writeLog(e, LogLevel.Error); + throw new ProtocolError(); + } catch (Exception e) { + writeLog(e, LogLevel.Error); + throw new ProtocolError(); + } + } + + /** Compute Hashsum of a file. + * @param filename + * @return hashsum + */ + protected byte[] computeHashsum(String filename, HashAlgorithm h) { + try { + MessageDigest md = MessageDigest.getInstance(HashAlgorithm.SHA512.getName()); + return md.digest(Files.readAllBytes(Paths.get(baseDirectory + filename))); + } catch (NoSuchAlgorithmException e) { + writeLog(h.getName() + " not supported", LogLevel.Error); + } catch (IOException e) { + writeLog("cannot read " + filename, LogLevel.Error); + } + return new byte[0]; + } + + /** Getter for HostItem socket + * @param hostItem HostItem + */ + protected abstract Object getHostItemSocket(HostItem hostItem); + + /** list server’s directory content + * @return list of files + * @throws InternalError + * @throws UnknowHostException + * @throws IOException + * @throws TransmissionError + * @throws ProtocolError + * @throws VersionError + * @throws SizeError + * @throws EmptyDirectory + * @throws InternalRemoteError + * @throws ProtocolRemoteError + * @throws VersionRemoteError + */ + protected String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { + ProtocolP2PPacket d = createProtocolP2PPacket(new Payload(RequestResponseCode.LIST_REQUEST)); + try { + d.sendRequest(getHostItemSocket(hostList.get(0))); + Payload p = d.receiveResponse().getPayload(); + assert p instanceof FileList : "This payload must be instance of Filelist"; + if (!(p instanceof FileList)) { + throw new InternalError(); + } else { + return ((FileList)p).getFileList(); + } + } catch (NotFound e) { + writeLog(e, LogLevel.Error); + throw new ProtocolError(); + } catch (EmptyFile e) { + writeLog(e, LogLevel.Error); + throw new ProtocolError(); + } catch (SocketClosed e){ + writeLog("listDirectory : SocketClosed", LogLevel.Error); + throw new ProtocolError(); + } catch (NotATracker e) { + writeLog(e, LogLevel.Error); + throw new ProtocolError(); + } + } + + /** Initialize downloader + * @param filename Name of the file to download + */ + protected abstract void initDownloader(String filename); + + /** Try to download a file + * @param filename name of the file to download + * @throws NotFound + * @throws InternalError + * @throws UnknownHostException + * @throws IOException + * @throws TransmissionError + * @throws ProtocolError + * @throws VersionError + * @throws SizeError + * @throws InternalRemoteError + * @throws ProtocolRemoteError + * @throws VersionRemoteError + * @throws EmptyFile + */ + private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { + initDownloader(filename); + Thread t = new Thread(downLoader); + t.start(); + try { + t.join(); + if (downLoader.getSuccess()) { + byte[] hash512 = downLoader.getHashSum512(); + if (!Arrays.equals(hash512, computeHashsum(filename, HashAlgorithm.SHA512))) { + writeLog("Hashsum does not match", LogLevel.Error); + String line = "Computed checksum:\n"; + byte[] c = computeHashsum(filename, HashAlgorithm.SHA512); + for (byte b: c) { + line += String.format("%02X", b); + } + line += "\nReceived checksum:\n"; + for (byte b: hash512) { + line += String.format("%02X", b); + } + line += "\n"; + writeLog(line, LogLevel.Info); + throw new InternalError(); + } + } else { + throw new InternalError(); + } + } catch (InterruptedException e) { + throw new InternalError(); + } + } + + /** Implementation of Runnable + */ + public void run() { + try { + String[] list = listDirectory(); + System.out.println("Files present on the server:"); + for(String listItem: list) { + System.out.println(listItem); + } + System.out.println("Name of the file to download:"); + String f = scanner.nextLine(); + download(f); + System.out.println("File " + f + " sucessfully downloaded"); + writeLog("File " + f + " sucessfully downloaded", LogLevel.Info); + } catch (EmptyDirectory e) { + writeLog("Server has no file in directory", LogLevel.Error); + } catch (InternalError e) { + writeLog("Client internal error", LogLevel.Error); + } catch (UnknownHostException e) { + writeLog("Server host is unknown", LogLevel.Error); + } catch (IOException e) { + writeLog("Request cannot be send or response cannot be received", LogLevel.Error); + } catch (TransmissionError e) { + writeLog("Message received is too big", LogLevel.Error); + } catch (ProtocolError e) { + writeLog("Cannot decode server’s response", LogLevel.Error); + } catch (VersionError e) { + writeLog("Server’s response use bad version of the protocol", LogLevel.Error); + } catch (SizeError e) { + writeLog("Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error); + } catch (InternalRemoteError e) { + writeLog("Server internal error", LogLevel.Error); + } catch (ProtocolRemoteError e) { + writeLog("Server cannot decode client’s request", LogLevel.Error); + } catch (VersionRemoteError e) { + writeLog("Server cannot decode this version of the protocol", LogLevel.Error); + } catch (NotFound e) { + writeLog("Server has not this file in directory", LogLevel.Error); + } catch (EmptyFile e) { + writeLog("File is empty", LogLevel.Error); + } + } + +} diff --git a/src/clientP2P/ClientManagementTCP.java b/src/clientP2P/ClientManagementTCP.java index b5263ec..559fd71 100644 --- a/src/clientP2P/ClientManagementTCP.java +++ b/src/clientP2P/ClientManagementTCP.java @@ -1,38 +1,15 @@ package clientP2P; -import java.net.UnknownHostException; import java.util.Scanner; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import localException.InternalError; -import localException.ProtocolError; -import localException.SizeError; -import localException.TransmissionError; -import localException.VersionError; -import localException.SocketClosed; -import remoteException.EmptyFile; -import remoteException.EmptyDirectory; -import remoteException.InternalRemoteError; -import remoteException.NotFound; -import remoteException.ProtocolRemoteError; -import remoteException.VersionRemoteError; -import remoteException.NotATracker; -import protocolP2P.ProtocolP2PPacketTCP; import protocolP2P.Payload; -import protocolP2P.RequestResponseCode; -import protocolP2P.FileList; -import protocolP2P.HashAlgorithm; -import clientP2P.ClientDownloadTCP; +import protocolP2P.ProtocolP2PPacket; +import protocolP2P.ProtocolP2PPacketTCP; import tools.HostItem; import tools.Logger; import tools.LogLevel; -import protocolP2P.DiscoverRequest; -import protocolP2P.DiscoverResponse; +import clientP2P.ClientDownloadTCP; +import clientP2P.ClientManagement; + /** Implementation of P2P-JAVA-PROJECT CLIENT * @author Louis Royer @@ -40,14 +17,7 @@ import protocolP2P.DiscoverResponse; * @author JS Auge * @version 1.0 */ -public class ClientManagementTCP implements Runnable { - private String baseDirectory; - private String partsSubdir; - private List hostList; - private HostItem tracker; - private Logger logger; - private Scanner scanner; - +public class ClientManagementTCP extends ClientManagement { /** Constructor for TCP implementation, with baseDirectory, tracker, partsSubdir, logger, and scanner parameters. * @param baseDirectory the root directory where files are stored * @param tracker Tracker hostItem @@ -56,189 +26,51 @@ public class ClientManagementTCP implements Runnable { * @param scanner Scanner used to read input */ public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { - this.scanner = scanner; - this.baseDirectory = baseDirectory; - this.tracker = tracker; - this.partsSubdir = partsSubdir; - this.logger = logger; - try { - initHostList(); - } catch (InternalError e) { - System.exit(-1); - } catch (ProtocolError e) { - System.exit(-2); - } + super(baseDirectory, tracker, partsSubdir, logger, scanner); } - /** Implementation of Runnable + /** Initialize downloader + * @param filename Name of the file to download + */ + protected void initDownloader(String filename) { + downLoader = (ClientDownload) new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger); + } + + + + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging */ - public void run() { - try { - String[] list = listDirectory(); - System.out.println("Files present on the server:"); - for(String listItem: list) { - System.out.println(listItem); - } - System.out.println("Name of the file to download:"); - String f = scanner.nextLine(); - download(f); - System.out.println("File " + f + " sucessfully downloaded"); - logger.writeTCP("File " + f + " sucessfully downloaded", LogLevel.Info); - } catch (EmptyDirectory e) { - logger.writeTCP("Server has no file in directory", LogLevel.Error); - } catch (InternalError e) { - logger.writeTCP("Client internal error", LogLevel.Error); - } catch (UnknownHostException e) { - logger.writeTCP("Server host is unknown", LogLevel.Error); - } catch (IOException e) { - logger.writeTCP("Request cannot be send or response cannot be received", LogLevel.Error); - } catch (TransmissionError e) { - logger.writeTCP("Message received is too big", LogLevel.Error); - } catch (ProtocolError e) { - logger.writeTCP("Cannot decode server’s response", LogLevel.Error); - } catch (VersionError e) { - logger.writeTCP("Server’s response use bad version of the protocol", LogLevel.Error); - } catch (SizeError e) { - logger.writeTCP("Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error); - } catch (InternalRemoteError e) { - logger.writeTCP("Server internal error", LogLevel.Error); - } catch (ProtocolRemoteError e) { - logger.writeTCP("Server cannot decode client’s request", LogLevel.Error); - } catch (VersionRemoteError e) { - logger.writeTCP("Server cannot decode this version of the protocol", LogLevel.Error); - } catch (NotFound e) { - logger.writeTCP("Server has not this file in directory", LogLevel.Error); - } catch (EmptyFile e) { - logger.writeTCP("File is empty", LogLevel.Error); - } + protected void writeLog(String text, LogLevel logLevel) { + logger.writeTCP(text, logLevel); } - /** Try to download a file - * @param filename name of the file to download - * @throws NotFound - * @throws InternalError - * @throws UnknownHostException - * @throws IOException - * @throws TransmissionError - * @throws ProtocolError - * @throws VersionError - * @throws SizeError - * @throws InternalRemoteError - * @throws ProtocolRemoteError - * @throws VersionRemoteError - * @throws EmptyFile + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging */ - private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { - ClientDownloadTCP downLoader = new ClientDownloadTCP(filename, hostList, partsSubdir, baseDirectory, logger); - Thread t = new Thread(downLoader); - t.start(); - try { - t.join(); - if (downLoader.getSuccess()) { - byte[] hash512 = downLoader.getHashSum512(); - if (!Arrays.equals(hash512, computeHashsum(filename, HashAlgorithm.SHA512))) { - logger.writeTCP("Hashsum does not match", LogLevel.Error); - String line = "Computed checksum:\n"; - byte[] c = computeHashsum(filename, HashAlgorithm.SHA512); - for (byte b: c) { - line += String.format("%02X", b); - } - line += "\nReceived checksum:\n"; - for (byte b: hash512) { - line += String.format("%02X", b); - } - line += "\n"; - logger.writeTCP(line, LogLevel.Info); - throw new InternalError(); - } - } else { - throw new InternalError(); - } - } catch (InterruptedException e) { - throw new InternalError(); - } + protected void writeLog(Exception e, LogLevel logLevel) { + logger.writeTCP(e, logLevel); } - /** list server’s directory content - * @return list of files - * @throws InternalError - * @throws UnknowHostException - * @throws IOException - * @throws TransmissionError - * @throws ProtocolError - * @throws VersionError - * @throws SizeError - * @throws EmptyDirectory - * @throws InternalRemoteError - * @throws ProtocolRemoteError - * @throws VersionRemoteError + /** Create packets + * @param payload Payload */ - private String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { - ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP<>(new Payload(RequestResponseCode.LIST_REQUEST)); - try { - d.sendRequest((Object)hostList.get(0).getTCPSocket()); - Payload p = d.receiveResponse().getPayload(); - assert p instanceof FileList : "This payload must be instance of Filelist"; - if (!(p instanceof FileList)) { - throw new InternalError(); - } else { - return ((FileList)p).getFileList(); - } - } catch (NotFound e) { - logger.writeTCP(e, LogLevel.Error); - throw new ProtocolError(); - } catch (EmptyFile e) { - logger.writeTCP(e, LogLevel.Error); - throw new ProtocolError(); - } catch (SocketClosed e){ - logger.writeTCP("listDirectory : SocketClosed", LogLevel.Error); - throw new ProtocolError(); - } catch (NotATracker e) { - logger.writeTCP(e, LogLevel.Error); - throw new ProtocolError(); - } + protected < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload) { + return (ProtocolP2PPacket)new ProtocolP2PPacketTCP(payload); } - /** Compute Hashsum of a file. - * @param filename - * @return hashsum + /** Getter for tracker socket */ - private byte[] computeHashsum(String filename, HashAlgorithm h) { - try { - MessageDigest md = MessageDigest.getInstance(HashAlgorithm.SHA512.getName()); - return md.digest(Files.readAllBytes(Paths.get(baseDirectory + filename))); - } catch (NoSuchAlgorithmException e) { - logger.writeTCP(h.getName() + " not supported", LogLevel.Error); - } catch (IOException e) { - logger.writeTCP("cannot read " + filename, LogLevel.Error); - } - return new byte[0]; + protected Object getTrackerSocket() { + return (Object)tracker.getTCPSocket(); } - /** Initialize hostList from tracker - * @throws ProtocolError - * @throws InternalError + /** Getter for HostItem socket + * @param hostItem HostItem */ - private void initHostList() throws ProtocolError, InternalError { - ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP<>(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(); - } + protected Object getHostItemSocket(HostItem hostItem) { + return (Object)hostItem.getTCPSocket(); } } diff --git a/src/clientP2P/ClientManagementUDP.java b/src/clientP2P/ClientManagementUDP.java index 1f20484..19e7a0b 100644 --- a/src/clientP2P/ClientManagementUDP.java +++ b/src/clientP2P/ClientManagementUDP.java @@ -1,37 +1,14 @@ package clientP2P; import java.util.Scanner; -import java.util.Arrays; -import java.util.List; -import java.io.IOException; -import java.net.UnknownHostException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import localException.InternalError; -import localException.ProtocolError; -import localException.SizeError; -import localException.TransmissionError; -import localException.VersionError; -import remoteException.EmptyFile; -import remoteException.EmptyDirectory; -import remoteException.InternalRemoteError; -import remoteException.NotFound; -import remoteException.ProtocolRemoteError; -import remoteException.VersionRemoteError; -import remoteException.NotATracker; -import protocolP2P.ProtocolP2PPacketUDP; import protocolP2P.Payload; -import protocolP2P.RequestResponseCode; -import protocolP2P.FileList; -import protocolP2P.HashAlgorithm; -import protocolP2P.DiscoverRequest; -import protocolP2P.DiscoverResponse; +import protocolP2P.ProtocolP2PPacket; +import protocolP2P.ProtocolP2PPacketUDP; import tools.HostItem; import tools.Logger; import tools.LogLevel; import clientP2P.ClientDownloadUDP; +import clientP2P.ClientManagement; /** Implementation of P2P-JAVA-PROJECT CLIENT * @author Louis Royer @@ -39,14 +16,7 @@ import clientP2P.ClientDownloadUDP; * @author JS Auge * @version 1.0 */ -public class ClientManagementUDP implements Runnable { - private String baseDirectory; - private String partsSubdir; - private List hostList; - private HostItem tracker; - private Logger logger; - private Scanner scanner; - +public class ClientManagementUDP extends ClientManagement { /** Constructor for UDP implementation, with baseDirectory, tracker, partsSubdir, logger and scanner parameters. * @param baseDirectory the root directory where files are stored * @param tracker tracker HostItem @@ -55,201 +25,56 @@ public class ClientManagementUDP implements Runnable { * @param scanner Scanner used to read input */ public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner) { - this.scanner = scanner; - this.baseDirectory = baseDirectory; - this.tracker = tracker; - this.partsSubdir = partsSubdir; - this.logger = logger; - try { - initHostList(); - } catch (InternalError e) { - System.exit(-1); - } catch (ProtocolError e) { - System.exit(-2); - } + super(baseDirectory, tracker, partsSubdir, logger, scanner); + } + + /** Initialize downloader + * @param filename Name of the file to download + */ + protected void initDownloader(String filename) { + downLoader = (ClientDownload) new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger); + } + + /** 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 Runnable + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging */ - public void run() { - try { - String[] list = listDirectory(); - System.out.println("Files present on the server:"); - for(String listItem: list) { - System.out.println(listItem); - } - System.out.println("Name of the file to download:"); - String f = scanner.nextLine(); - download(f); - System.out.println("File " + f + " sucessfully downloaded"); - logger.writeUDP("File " + f + " sucessfully downloaded", LogLevel.Info); - } catch (EmptyDirectory e) { - System.err.println("Error: Server has no file in directory"); - logger.writeUDP("Error: Server has no file in directory", LogLevel.Error); - } catch (InternalError e) { - System.err.println("Error: Client internal error"); - logger.writeUDP("Error: Client internal error", LogLevel.Error); - } catch (UnknownHostException e) { - System.err.println("Error: Server host is unknown"); - logger.writeUDP("Error: Server host is unknown", LogLevel.Error); - } catch (IOException e) { - System.err.println("Error: Request cannot be send or response cannot be received"); - logger.writeUDP("Error: Request cannot be send or response cannot be received", LogLevel.Error); - } catch (TransmissionError e) { - System.err.println("Error: Message received is too big"); - logger.writeUDP("Error: Message received is too big", LogLevel.Error); - } catch (ProtocolError e) { - System.err.println("Error: Cannot decode server’s response"); - logger.writeUDP("Error: Cannot decode server’s response", LogLevel.Error); - } catch (VersionError e) { - System.err.println("Error: Server’s response use bad version of the protocol"); - logger.writeUDP("Error: 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.writeUDP("Error: 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.writeUDP("Error: Server internal error", LogLevel.Error); - } catch (ProtocolRemoteError e) { - System.err.println("Error: Server cannot decode client’s request"); - logger.writeUDP("Error: Server cannot decode client’s request", LogLevel.Error); - } catch (VersionRemoteError e) { - System.err.println("Error: Server cannot decode this version of the protocol"); - logger.writeUDP("Error: 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.writeUDP("Error: Server has not this file in directory", LogLevel.Error); - } catch (EmptyFile e) { - System.err.println("Error: File is empty"); - logger.writeUDP("Error: File is empty", LogLevel.Error); - } + protected void writeLog(Exception e, LogLevel logLevel) { + logger.writeUDP(e, logLevel); } - /** Try to download a file - * @param filename name of the file to download - * @throws NotFound - * @throws InternalError - * @throws UnknownHostException - * @throws IOException - * @throws TransmissionError - * @throws ProtocolError - * @throws VersionError - * @throws SizeError - * @throws InternalRemoteError - * @throws ProtocolRemoteError - * @throws VersionRemoteError - * @throws EmptyFile + /** Create packets + * @param payload Payload */ - private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { - ClientDownloadUDP downLoader = new ClientDownloadUDP(filename, hostList, partsSubdir, baseDirectory, logger); - Thread t = new Thread(downLoader); - t.start(); - try { - t.join(); - if (downLoader.getSuccess()) { - byte[] hash512 = downLoader.getHashSum512(); - if (!Arrays.equals(hash512, computeHashsum(filename, HashAlgorithm.SHA512))) { - System.err.println("Error: Hashsum does not match"); - System.err.println("Computed checksum:"); - byte[] c = computeHashsum(filename, HashAlgorithm.SHA512); - for (byte b: c) { - System.err.print(String.format("%02X", b)); - logger.writeUDP("Computed checksum:" + String.format("%02X", b), LogLevel.Info); - } - System.err.println(""); - System.err.println("Received checksum:"); - for (byte b: hash512) { - System.err.print(String.format("%02X", b)); - logger.writeUDP("Received checksum:" + String.format("%02X", b), LogLevel.Info); - } - System.err.println(""); - throw new InternalError(); - } - } else { - throw new InternalError(); - } - } catch (InterruptedException e) { - logger.writeUDP(e, LogLevel.Error); - throw new InternalError(); - } + protected < T extends Payload > ProtocolP2PPacket createProtocolP2PPacket(T payload) { + return (ProtocolP2PPacket)new ProtocolP2PPacketUDP(payload); } - /** list server’s directory content - * @return list of files - * @throws InternalError - * @throws UnknowHostException - * @throws IOException - * @throws TransmissionError - * @throws ProtocolError - * @throws VersionError - * @throws SizeError - * @throws EmptyDirectory - * @throws InternalRemoteError - * @throws ProtocolRemoteError - * @throws VersionRemoteError + /** Getter for tracker socket */ - private String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { - ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP<>(new Payload(RequestResponseCode.LIST_REQUEST)); - d.sendRequest((Object)hostList.get(0).getUDPSocket()); - try { - Payload p = d.receiveResponse().getPayload(); - assert p instanceof FileList : "This payload must be instance of Filelist"; - if (!(p instanceof FileList)) { - throw new InternalError(); - } else { - return ((FileList)p).getFileList(); - } - } catch (NotFound e) { - logger.writeUDP(e, LogLevel.Error); - throw new ProtocolError(); - } catch (EmptyFile e) { - logger.writeUDP(e, LogLevel.Error); - throw new ProtocolError(); - } catch (NotATracker e) { - logger.writeUDP(e, LogLevel.Error); - throw new ProtocolError(); - } + protected Object getTrackerSocket() { + return (Object)tracker.getUDPSocket(); } - /** Compute Hashsum of a file. - * @param filename - * @return hashsum + /** Getter for HostItem socket + * @param hostItem HostItem */ - private byte[] computeHashsum(String filename, HashAlgorithm h) { - try { - 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.writeUDP("Error: " + h.getName() + " not supported", LogLevel.Error); - } catch (IOException e) { - System.out.println("Error: cannot read " + filename); - logger.writeUDP("Error: cannot read " + filename, LogLevel.Error); - } - return new byte[0]; + protected Object getHostItemSocket(HostItem hostItem) { + return (Object)hostItem.getUDPSocket(); } - /** Initialize hostList from tracker - * @throws ProtocolError - * @throws InternalError + /** Close HostItem socket + * @param hostItem HostItem */ - private void initHostList() throws ProtocolError, InternalError { - ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP<>(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(); - } + protected void closeHostItemSocket(HostItem hostItem) { + hostItem.closeUDPSocket(); } } diff --git a/src/serverP2P/ServerManagementTCP.java b/src/serverP2P/ServerManagementTCP.java index 455cbd3..d44b79a 100644 --- a/src/serverP2P/ServerManagementTCP.java +++ b/src/serverP2P/ServerManagementTCP.java @@ -65,10 +65,10 @@ public class ServerManagementTCP extends ServerManagement { try { socket = new ServerSocket(server.getPort(), 10, server.getInetAddress()); } catch (SocketException e) { - logger.writeTCP("Error: cannot listen on " + server, LogLevel.Error); + writeLog("Error: cannot listen on " + server, LogLevel.Error); System.exit(-1); } catch (IOException e) { - logger.writeTCP("Error: cannot openning socket", LogLevel.Error); + writeLog("Error: cannot openning socket", LogLevel.Error); System.exit(-2); } } @@ -77,7 +77,7 @@ public class ServerManagementTCP extends ServerManagement { /** Implementation of runnable. This methods allows to run the server. */ public void run() { - logger.writeTCP("Server sucessfully started", LogLevel.Info); + writeLog("Server sucessfully started", LogLevel.Info); fileListWatcher = (FileWatcher)new FileWatcherTCP(logger, 10000, server, tracker, baseDirectory); // checking every 10 seconds (new Thread(fileListWatcher)).start(); while(!stop) { @@ -86,7 +86,7 @@ public class ServerManagementTCP extends ServerManagement { ClientHandler c = new ClientHandler(s); (new Thread(c)).start(); } catch (IOException e) { - logger.writeTCP("Error while accepting new connection", LogLevel.Warning); + writeLog("Error while accepting new connection", LogLevel.Warning); } } fileListWatcher.setStop(); @@ -109,11 +109,11 @@ public class ServerManagementTCP extends ServerManagement { public void run() { boolean end = false; - logger.writeTCP("[" + addr + "] New connection", LogLevel.Action); + writeLog("[" + addr + "] New connection", LogLevel.Action); do { end = handleClientRequest(); } while(!end); - logger.writeTCP("[" + addr + "] End of connection", LogLevel.Action); + writeLog("[" + addr + "] End of connection", LogLevel.Action); } /** Respond to next request incomming on socket s. diff --git a/src/tracker/TrackerManagement.java b/src/tracker/TrackerManagement.java index e28790d..37c3cbc 100644 --- a/src/tracker/TrackerManagement.java +++ b/src/tracker/TrackerManagement.java @@ -19,6 +19,13 @@ import localException.InternalError; import remoteException.EmptyDirectory; import exception.LocalException; + +/** Tracker management implementation + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ public abstract class TrackerManagement extends ServeErrors implements Runnable { protected HostItem tracker; protected Logger logger; diff --git a/src/tracker/TrackerManagementTCP.java b/src/tracker/TrackerManagementTCP.java index bf659f3..d124297 100644 --- a/src/tracker/TrackerManagementTCP.java +++ b/src/tracker/TrackerManagementTCP.java @@ -46,10 +46,10 @@ public class TrackerManagementTCP extends TrackerManagement { try { socket = new ServerSocket(tracker.getPort(), 10, tracker.getInetAddress()); } catch (SocketException e) { - logger.writeTCP("Error: cannot listen on" + tracker, LogLevel.Error); + writeLog("Error: cannot listen on" + tracker, LogLevel.Error); System.exit(-1); } catch (IOException e) { - logger.writeTCP("Error: cannot open socket", LogLevel.Error); + writeLog("Error: cannot open socket", LogLevel.Error); System.exit(-2); } } @@ -57,14 +57,14 @@ public class TrackerManagementTCP extends TrackerManagement { /** Implementation of runnable. This methods allows to run the server. */ public void run() { - logger.writeTCP("Tracker sucessfully started", LogLevel.Info); + writeLog("Tracker sucessfully started", LogLevel.Info); while (!stop) { try { Socket s = socket.accept(); ClientHandler c = new ClientHandler(s); (new Thread(c)).start(); } catch (IOException e) { - logger.writeTCP("Error while accepting new connection", LogLevel.Warning); + writeLog("Error while accepting new connection", LogLevel.Warning); } } } @@ -86,11 +86,11 @@ public class TrackerManagementTCP extends TrackerManagement { public void run() { boolean end = false; - logger.writeTCP("[ " + addr + "] New connection", LogLevel.Action); + writeLog("[ " + addr + "] New connection", LogLevel.Action); do { end = handleClientRequest(); } while(!end); - logger.writeTCP("[ " + addr + "] End of connection", LogLevel.Action); + writeLog("[ " + addr + "] End of connection", LogLevel.Action); } /** Respond to next request incomming on socket s. @@ -102,12 +102,12 @@ public class TrackerManagementTCP extends TrackerManagement { ProtocolP2PPacketTCP pd = new ProtocolP2PPacketTCP<>((Object)addr.getTCPSocket()); handleRequest(pd); } catch (IOException e) { - logger.writeTCP(e, LogLevel.Warning); + writeLog(e, LogLevel.Warning); return true; } catch (SocketClosed e) { return true; } catch (LocalException e) { - logger.writeTCP(e, LogLevel.Warning); + writeLog(e, LogLevel.Warning); return true; } return false;