From 0c10752e9b2567ec669f1a7ddf2d098929abc873 Mon Sep 17 00:00:00 2001 From: Louis Date: Sat, 21 Mar 2020 22:28:19 +0100 Subject: [PATCH] =?UTF-8?q?Fix=20#27=20-=20[x]=20Faire=20un=20thread=20qui?= =?UTF-8?q?=20tous=20les=20X=20secondes=20(configurable)=20va=20comparer?= =?UTF-8?q?=20les=20fichiers=20dispo=20avec=20la=20liste=20et=20mettre=20?= =?UTF-8?q?=C3=A0=20jour=20(penser=20=C3=A0=20le=20logger).=20La=20mise=20?= =?UTF-8?q?=C3=A0=20jour=20peut=20s=E2=80=99effectuer=20en=20faisant=20jus?= =?UTF-8?q?te=20une=20REGISTER=20REQUEST.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/exception/LocalException.java | 2 +- src/exception/RemoteException.java | 2 +- src/serverP2P/ServerManagementTCP.java | 158 +++++++++++++++++-------- src/serverP2P/ServerManagementUDP.java | 148 ++++++++++++++++------- src/tools/HostItem.java | 13 ++ src/tracker/TrackerManagementUDP.java | 2 + 6 files changed, 232 insertions(+), 93 deletions(-) diff --git a/src/exception/LocalException.java b/src/exception/LocalException.java index 5c115d5..2fbc0f2 100644 --- a/src/exception/LocalException.java +++ b/src/exception/LocalException.java @@ -1,5 +1,5 @@ package exception; -public class LocalException extends Exception { +public abstract class LocalException extends Exception { private static final long serialVersionUID = 12L; } diff --git a/src/exception/RemoteException.java b/src/exception/RemoteException.java index cfb2cd7..968c8db 100644 --- a/src/exception/RemoteException.java +++ b/src/exception/RemoteException.java @@ -1,5 +1,5 @@ package exception; -public class RemoteException extends Exception { +public abstract class RemoteException extends Exception { private static final long serialVersionUID = 12L; } diff --git a/src/serverP2P/ServerManagementTCP.java b/src/serverP2P/ServerManagementTCP.java index 359d616..5cbe8af 100644 --- a/src/serverP2P/ServerManagementTCP.java +++ b/src/serverP2P/ServerManagementTCP.java @@ -51,6 +51,8 @@ public class ServerManagementTCP implements Runnable { private Logger logger; private HostItem tracker; private HostItem server; + private FileListWatcher fileListWatcher; + private volatile boolean stop; /** Constructor for TCP implementation, with baseDirectory and TCPPort parameters. * @param baseDirectory the root directory where files are stored @@ -60,12 +62,12 @@ public class ServerManagementTCP implements Runnable { * @param tracker Tracker */ public ServerManagementTCP(String baseDirectory, String hostName, int port, Logger logger, HostItem tracker) { + stop = false; server = new HostItem(hostName, port); + fileList = new String[0]; this.tracker = tracker; this.logger = logger; this.baseDirectory = baseDirectory; - initFileList(); - initSha512(); try { socket = new ServerSocket(server.getPort(), 10, server.getInetAddress()); } catch (SocketException e) { @@ -77,12 +79,26 @@ public class ServerManagementTCP implements Runnable { } } + /** Stop the thread */ + public void setStop() { + stop = true; + } + + /** Trigger a manual check of the file list + */ + public void updateFileList() { + if (fileListWatcher != null) { + fileListWatcher.trigger(); + } + } + /** Implementation of runnable. This methods allows to run the server. */ public void run() { logger.writeTCP("Server sucessfully started", LogLevel.Info); - (new Thread(new TrackerRegisterer())).start(); - do { + fileListWatcher = new FileListWatcher(10000); // checking every 10 seconds + (new Thread(fileListWatcher)).start(); + while(!stop) { try { Socket s = socket.accept(); ClientHandler c = new ClientHandler(s); @@ -90,7 +106,17 @@ public class ServerManagementTCP implements Runnable { } catch (IOException e) { logger.writeTCP("Error while accepting new connection", LogLevel.Warning); } - } while(true); + } + fileListWatcher.setStop(); + // unregistering from tracker + try { + logger.writeTCP("Unregistering from tracker", LogLevel.Info); + ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new Unregister(server)); + p.sendRequest((Object)tracker.getTCPSocket()); + } catch (Exception e) { + logger.writeTCP("Cannot unregister from tracker", LogLevel.Error); + logger.writeTCP(e, LogLevel.Error); + } } /** Private runnable class allowing to serve one client. @@ -167,22 +193,6 @@ public class ServerManagementTCP implements Runnable { } } - /** Initialize local list of all files allowed to be shared. - */ - private void initFileList() { - File folder = new File(baseDirectory); - Vector v = new Vector(); - File[] files = folder.listFiles(); - /* Add non-recursively files's names to fileList */ - for (File f : files) { - if (f.isFile()) { - v.add(f.getName()); - } - } - fileList = new String[v.size()]; - v.toArray(fileList); - Arrays.sort(fileList); - } /** Init sha512 map. */ @@ -333,39 +343,89 @@ public class ServerManagementTCP implements Runnable { } } - /** Private runnable class allowing to initialize tracker while initializing server. */ - private class TrackerRegisterer implements Runnable { - - /** Runnable implementation */ - public void run() { + /** Private runnable class allowing to keep the tracker informed about file list. */ + private class FileListWatcher implements Runnable { + private volatile boolean stop; + private long time; + private boolean force; + + /** Register server on tracker + */ + private void registerTracker() { try { - registerTracker(); + logger.writeTCP("Trying to into tracker", LogLevel.Info); + ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new Register(server)); + p.sendRequest((Object)tracker.tryGetTCPSocket()); + logger.writeTCP("Register request sent.", LogLevel.Debug); + tracker.closeTCPSocket(); } catch (Exception e) { - logger.writeTCP(e, LogLevel.Error); - System.exit(-4); + // error, trying again at next iteration + force = true; + logger.writeTCP("Cannot contact tracker, trying again at next iteration (" + time + " milliseconds).", LogLevel.Error); } } - /** Register server on tracker - * @throws InternalError - * @throws IOException - * @throws SocketClosed + + /** Update fileList and returns true if different than old list. + * @return true if changed */ - private void registerTracker() throws InternalError, IOException, SocketClosed { - logger.writeTCP("Unregistering from tracker", LogLevel.Info); - ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new Unregister(server)); - p.sendRequest((Object)tracker.getTCPSocket()); - // FIXME: this is a hack - // ProtocolP2PPacketTCP reads 1024 bytes but if 2 request comes at the same time InputStream is cleared fully - // and we keep waiting forever on the other side - // a fix could be to read only the header first, and read the required size after - try { - Thread.sleep(100); - } catch (InterruptedException e) {} - logger.writeTCP("Registering into tracker", LogLevel.Info); - p = (ProtocolP2PPacket)new ProtocolP2PPacketTCP((Payload)new Register(server)); - p.sendRequest((Object)tracker.getTCPSocket()); - logger.writeTCP("Registering completed", LogLevel.Debug); - tracker.closeTCPSocket(); + private boolean updateFileList() { + File folder = new File(baseDirectory); + Vector v = new Vector(); + File[] files = folder.listFiles(); + /* Add non-recursively files's names to fileList */ + for (File f : files) { + if (f.isFile()) { + v.add(f.getName()); + } + } + String[] newFileList = new String[v.size()]; + v.toArray(newFileList); + Arrays.sort(newFileList); + if (!Arrays.equals(newFileList, fileList)) { + fileList = newFileList; + initSha512(); + return true; + } else { + return false; + } + } + + /** Constructor with millis parameter + * @param millis interval of time between checks + */ + public FileListWatcher(long millis) { + this.stop = false; + this.time = millis; + } + + /** Ask the thread to stop + */ + public void setStop() { + stop = true; + } + + /** Allow a manual check + */ + public void trigger() { + if (updateFileList() || force) { + force = false; + logger.writeTCP("File list watcher detected changes. Informing tracker.", LogLevel.Info); + registerTracker(); + } + } + + /** Runnable implementation */ + public void run() { + logger.writeTCP("File list watcher started : delay " + time + " milliseconds.", LogLevel.Info); + while(!stop) { + trigger(); + try { + Thread.sleep(time); + } catch(InterruptedException e) { + logger.writeTCP("File list watcher interrupted", LogLevel.Error); + setStop(); + } + } } } diff --git a/src/serverP2P/ServerManagementUDP.java b/src/serverP2P/ServerManagementUDP.java index fbc0795..25a988a 100644 --- a/src/serverP2P/ServerManagementUDP.java +++ b/src/serverP2P/ServerManagementUDP.java @@ -43,13 +43,15 @@ import java.net.UnknownHostException; */ public class ServerManagementUDP implements Runnable { - private String[] fileList; + private String[] fileList = new String[0]; private Map sha512 = new HashMap<>(); private String baseDirectory; private DatagramSocket socket; private Logger logger; private HostItem tracker; private HostItem server; + private FileListWatcher fileListWatcher; + private volatile boolean stop; /** Constructor for UDP implementation, with baseDirectory and UDPPort parameters. * @param baseDirectory the root directory where files are stored @@ -59,12 +61,11 @@ public class ServerManagementUDP implements Runnable { * @param tracker Tracker */ public ServerManagementUDP(String baseDirectory, String hostName, int port, Logger logger, HostItem tracker) { + stop = false; server = new HostItem(hostName, port); this.logger = logger; this.baseDirectory = baseDirectory; this.tracker = tracker; - initFileList(); - initSha512(); try { socket = new DatagramSocket(server.getPort(), server.getInetAddress()); } catch (SocketException e) { @@ -73,12 +74,26 @@ public class ServerManagementUDP implements Runnable { } } + /** Stop the thread */ + public void setStop() { + stop = true; + } + + /** Trigger a manual check of the file list + */ + public void updateFileList() { + if (fileListWatcher != null) { + fileListWatcher.trigger(); + } + } + /** Implementation of runnable. This methods allows to run the server. */ public void run() { logger.writeUDP("Server sucessfully started", LogLevel.Info); - (new Thread(new TrackerRegisterer())).start(); - while(true) { + fileListWatcher = new FileListWatcher(10000); // checking every 10 seconds + (new Thread(fileListWatcher)).start(); + while(!stop) { try { ProtocolP2PPacketUDP pd = new ProtocolP2PPacketUDP((Object)socket); Payload p = pd.getPayload(); @@ -111,23 +126,15 @@ public class ServerManagementUDP implements Runnable { } catch (SizeError e) { } } - } - - /** Initialize local list of all files allowed to be shared. - */ - private void initFileList() { - File folder = new File(baseDirectory); - Vector v = new Vector(); - File[] files = folder.listFiles(); - /* Add non-recursively files's names to fileList */ - for (File f : files) { - if (f.isFile()) { - v.add(f.getName()); - } + fileListWatcher.setStop(); + // unregistering from tracker + try { + logger.writeUDP("Unregistering from tracker", LogLevel.Info); + ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new Unregister(server)); + p.sendRequest((Object)tracker.getUDPSocket()); + } catch (Exception e) { + logger.writeUDP(e, LogLevel.Error); } - fileList = new String[v.size()]; - v.toArray(fileList); - Arrays.sort(fileList); } /** Init sha512 map. @@ -280,32 +287,89 @@ public class ServerManagementUDP implements Runnable { } } -/** Private runnable class allowing to initialize tracker while initializing server. */ - private class TrackerRegisterer implements Runnable { - - /** Runnable implementation */ - public void run() { + /** Private runnable class allowing to keep the tracker informed about file list. */ + private class FileListWatcher implements Runnable { + private volatile boolean stop; + private long time; + private boolean force; + + /** Register server on tracker + */ + private void registerTracker() { try { - registerTracker(); + logger.writeUDP("Trying to register into tracker", LogLevel.Info); + ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new Register(server)); + p.sendRequest((Object)tracker.getUDPSocket()); + logger.writeUDP("Register request sent (but cannot ensure reception).", LogLevel.Debug); + tracker.closeUDPSocket(); } catch (Exception e) { - logger.writeUDP(e, LogLevel.Error); - System.exit(-4); + force = true; + logger.writeUDP("Cannot contact tracker, trying again at next iteration (" + time + " milliseconds).", LogLevel.Error); } } - /** Register server on tracker - * @throws InternalError - * @throws IOException - * @throws SocketClosed + + /** Update fileList and returns true if different than old list. + * @return true if changed */ - private void registerTracker() throws InternalError, IOException, SocketClosed { - logger.writeUDP("Unregistering from tracker", LogLevel.Info); - ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new Unregister(server)); - p.sendRequest((Object)tracker.getUDPSocket()); - logger.writeUDP("Registering into tracker", LogLevel.Info); - p = (ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)new Register(server)); - p.sendRequest((Object)tracker.getUDPSocket()); - logger.writeUDP("Registering completed", LogLevel.Debug); - tracker.closeUDPSocket(); + private boolean updateFileList() { + File folder = new File(baseDirectory); + Vector v = new Vector(); + File[] files = folder.listFiles(); + /* Add non-recursively files's names to fileList */ + for (File f : files) { + if (f.isFile()) { + v.add(f.getName()); + } + } + String[] newFileList = new String[v.size()]; + v.toArray(newFileList); + Arrays.sort(newFileList); + if (!Arrays.equals(newFileList, fileList)) { + fileList = newFileList; + initSha512(); + return true; + } else { + return false; + } + } + + /** Constructor with millis parameter + * @param millis interval of time between checks + */ + public FileListWatcher(long millis) { + this.force = true; + this.stop = false; + this.time = millis; + } + + /** Ask the thread to stop + */ + public void setStop() { + stop = true; + } + + /** Allow a manual check + */ + public void trigger() { + if (updateFileList() || force) { + force = false; + logger.writeUDP("File list watcher detected changes. Informing tracker.", LogLevel.Info); + registerTracker(); + } + } + + /** Runnable implementation */ + public void run() { + logger.writeUDP("File list watcher started : delay " + time + " milliseconds.", LogLevel.Info); + while(!stop) { + trigger(); + try { + Thread.sleep(time); + } catch(InterruptedException e) { + logger.writeUDP("File list watcher interrupted", LogLevel.Error); + setStop(); + } + } } } } diff --git a/src/tools/HostItem.java b/src/tools/HostItem.java index 231e6b7..95960af 100644 --- a/src/tools/HostItem.java +++ b/src/tools/HostItem.java @@ -49,6 +49,19 @@ public class HostItem { return tcpSocket; } + /** Get TCP Socket. + * @return TCP Socket + * @throws SocketException + * @throws UnknownHostException + * @throws IOException + */ + public Socket tryGetTCPSocket() throws SocketException, UnknownHostException, IOException { + if (tcpSocket == null) { + tcpSocket = new Socket(InetAddress.getByName(hostname), port); + } + return tcpSocket; + } + /** Closes tcp socket */ public void closeTCPSocket() { diff --git a/src/tracker/TrackerManagementUDP.java b/src/tracker/TrackerManagementUDP.java index 4d31c2f..42d6445 100644 --- a/src/tracker/TrackerManagementUDP.java +++ b/src/tracker/TrackerManagementUDP.java @@ -75,9 +75,11 @@ public class TrackerManagementUDP implements Runnable { sendNotFound(pd); break; case REGISTER: + logger.writeUDP("Received REGISTER from host " + pd.getHostItem(), LogLevel.Debug); handleRegister(pd); break; case UNREGISTER: + logger.writeUDP("Received UNREGISTER from host " + pd.getHostItem(), LogLevel.Debug); handleUnregister(pd); break; case DISCOVER_REQUEST: