Fix #27
- [x] Faire un thread qui tous les X secondes (configurable) va comparer les fichiers dispo avec la liste et mettre à jour (penser à le logger). La mise à jour peut s’effectuer en faisant juste une REGISTER REQUEST.
- [x] Télécharger dans le même dossier que celui où on seed
- [x] Mettre les logs dans un dossier pas partagé

Co-authored-by: Louis <louis.royer@univ-tlse3.fr>
This commit is contained in:
Louis Royer 2020-03-21 22:30:42 +01:00
parent e0dca481fb
commit 5f48c9cbc1
7 changed files with 250 additions and 111 deletions

View File

@ -19,8 +19,8 @@ import tools.HostItem;
*/
public class ClientP2P {
private String subdir = "seeded/";
private String parts = ".parts";
private String logDir = "logs/";
private String partsDir = ".parts/";
private Logger loggerServer;
private Logger loggerClient;
private String host;
@ -34,11 +34,13 @@ public class ClientP2P {
/** Initialize loggers if directories and logger are null,
* else fail silently.
*/
public void initLogger() {
public void initDirectoriesAndLoggers() {
if (directories == null && loggerServer == null && loggerClient == null) {
directories = new Directories("P2P_JAVA_PROJECT_" + port);
loggerServer = new Logger(directories.getDataHomeDirectory() + "server.log");
loggerClient = new Logger(directories.getDataHomeDirectory() + "client.log");
directories.createSubdir(logDir);
loggerServer = new Logger(directories.getDataHomeDirectory() + logDir + "server.log");
loggerClient = new Logger(directories.getDataHomeDirectory() + logDir + "client.log");
directories.createSubdir(partsDir);
}
}
@ -53,16 +55,14 @@ public class ClientP2P {
} catch (NumberFormatException e){
int oldPort = port;
port = defaultPort;
initLogger();
initDirectoriesAndLoggers();
System.err.println("Error incorrect port " + oldPort + " using default port " + defaultPort);
loggerServer.write("incorrect port " + oldPort + " using default port " + defaultPort, LogLevel.Info);
}
initLogger();
directories.createSubdir(subdir);
directories.createSubdir(parts);
initDirectoriesAndLoggers();
host = "localhost";
System.out.println("Server will listen on port " + port + " and serve files from " + directories.getDataHomeDirectory() + subdir);
directories.askOpenDataHomeDirectory(subdir, scanner);
System.out.println("Server will listen on port " + port + " and serve files from " + directories.getDataHomeDirectory());
directories.askOpenDataHomeDirectory(null, scanner);
System.out.println("Please enter list of servers to use; first one will be used to ask list of files");
}
@ -84,8 +84,8 @@ public class ClientP2P {
}
// Server threads
ServerManagementUDP smudp = new ServerManagementUDP(c.directories.getDataHomeDirectory() + c.subdir, "localhost", c.port, c.loggerServer, c.tracker);
ServerManagementTCP smtcp = new ServerManagementTCP(c.directories.getDataHomeDirectory() + c.subdir, "localhost", c.port, c.loggerServer, c.tracker);
ServerManagementUDP smudp = new ServerManagementUDP(c.directories.getDataHomeDirectory(), "localhost", c.port, c.loggerServer, c.tracker);
ServerManagementTCP smtcp = new ServerManagementTCP(c.directories.getDataHomeDirectory(), "localhost", c.port, c.loggerServer, c.tracker);
Thread tudp = new Thread(smudp);
tudp.setName("server UDP P2P-JAVA-PROJECT (port: " + c.port + ")");
tudp.start();
@ -96,7 +96,7 @@ public class ClientP2P {
// Wait a bit before printing client interface
// This is not required, but allow to have a cleaner interface
try {
Thread.sleep(100);
Thread.sleep(200);
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
@ -112,7 +112,7 @@ public class ClientP2P {
case "upd": // alias typo
case "2" :
System.out.println("Starting with UDP");
ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient, c.scanner);
ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner);
t = new Thread(cmudp);
break;
case "TCP":
@ -120,7 +120,7 @@ public class ClientP2P {
case "1":
default:
System.out.println("Starting with TCP");
ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.parts + "/", c.loggerClient, c.scanner);
ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner);
t = new Thread(cmtcp);
break;
}

View File

@ -1,5 +1,5 @@
package exception;
public class LocalException extends Exception {
public abstract class LocalException extends Exception {
private static final long serialVersionUID = 12L;
}

View File

@ -1,5 +1,5 @@
package exception;
public class RemoteException extends Exception {
public abstract class RemoteException extends Exception {
private static final long serialVersionUID = 12L;
}

View File

@ -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<String> v = new Vector<String>();
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,40 +343,90 @@ public class ServerManagementTCP implements Runnable {
}
}
/** Private runnable class allowing to initialize tracker while initializing server. */
private class TrackerRegisterer implements Runnable {
/** 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 {
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) {
// error, trying again at next iteration
force = true;
logger.writeTCP("Cannot contact tracker, trying again at next iteration (" + time + " milliseconds).", LogLevel.Error);
}
}
/** Update fileList and returns true if different than old list.
* @return true if changed
*/
private boolean updateFileList() {
File folder = new File(baseDirectory);
Vector<String> v = new Vector<String>();
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() {
try {
registerTracker();
} catch (Exception e) {
logger.writeTCP(e, LogLevel.Error);
System.exit(-4);
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();
}
}
}
/** Register server on tracker
* @throws InternalError
* @throws IOException
* @throws SocketClosed
*/
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();
}
}
}

View File

@ -43,13 +43,15 @@ import java.net.UnknownHostException;
*/
public class ServerManagementUDP implements Runnable {
private String[] fileList;
private String[] fileList = new String[0];
private Map<String, byte[]> 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<String> v = new Vector<String>();
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 {
/** 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 {
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) {
force = true;
logger.writeUDP("Cannot contact tracker, trying again at next iteration (" + time + " milliseconds).", LogLevel.Error);
}
}
/** Update fileList and returns true if different than old list.
* @return true if changed
*/
private boolean updateFileList() {
File folder = new File(baseDirectory);
Vector<String> v = new Vector<String>();
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() {
try {
registerTracker();
} catch (Exception e) {
logger.writeUDP(e, LogLevel.Error);
System.exit(-4);
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();
}
}
}
/** Register server on tracker
* @throws InternalError
* @throws IOException
* @throws SocketClosed
*/
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();
}
}
}

View File

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

View File

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