All checks were successful
flavien's git/Projet_JAVA_P2P_STRI2A/pipeline/pr-etape5 This commit looks good
313 lines
9.4 KiB
Java
313 lines
9.4 KiB
Java
package serverP2P;
|
|
import serverP2P.FileWatcher;
|
|
import serverP2P.RatioWatcher;
|
|
import tools.Logger;
|
|
import tools.LogLevel;
|
|
import tools.HostItem;
|
|
import tools.ServeErrors;
|
|
import protocolP2P.ProtocolP2PPacket;
|
|
import protocolP2P.Payload;
|
|
import protocolP2P.RequestResponseCode;
|
|
import protocolP2P.FileList;
|
|
import protocolP2P.FilePart;
|
|
import protocolP2P.LoadRequest;
|
|
import protocolP2P.HashRequest;
|
|
import protocolP2P.HashResponse;
|
|
import protocolP2P.HashAlgorithm;
|
|
import protocolP2P.Unregister;
|
|
import protocolP2P.SizeRequest;
|
|
import protocolP2P.SizeResponse;
|
|
import protocolP2P.Denied;
|
|
import java.nio.file.Paths;
|
|
import java.nio.file.Files;
|
|
import java.io.File;
|
|
import java.util.Arrays;
|
|
import java.util.Map;
|
|
import java.util.HashMap;
|
|
import java.util.Random;
|
|
import java.io.IOException;
|
|
import exception.LocalException;
|
|
import localException.InternalError;
|
|
import remoteException.UnknownHost;
|
|
|
|
/** Implementation of P2P-JAVA-PROJECT VERSION 1.0 protocol.
|
|
* @author Louis Royer
|
|
* @author Flavien Haas
|
|
* @author JS Auge
|
|
* @version 1.0
|
|
*/
|
|
public abstract class ServerManagement extends ServeErrors implements Runnable {
|
|
|
|
protected volatile boolean stop;
|
|
protected FileWatcher fileListWatcher;
|
|
protected Logger logger;
|
|
protected String baseDirectory;
|
|
protected HostItem server;
|
|
protected HostItem tracker;
|
|
protected Random punisher = new Random();
|
|
protected RatioWatcher ratioWatcher;
|
|
|
|
/** Constructor */
|
|
public ServerManagement(String baseDirectory, HostItem server, HostItem tracker, Logger logger) {
|
|
super();
|
|
assert baseDirectory != null : "baseDirectory is null";
|
|
assert server != null : "server is null";
|
|
assert tracker != null : "tracker is null";
|
|
assert logger != null : "logger is null";
|
|
stop = false;
|
|
this.baseDirectory = baseDirectory;
|
|
this.server = server;
|
|
this.tracker = tracker;
|
|
this.logger = logger;
|
|
}
|
|
|
|
/** Stop the thread */
|
|
public void setStop() {
|
|
stop = true;
|
|
fileListWatcher.setStop();
|
|
ratioWatcher.setStop();
|
|
sendUnregisterRequest();
|
|
closeSocket();
|
|
}
|
|
|
|
/** Closes socket */
|
|
protected abstract void closeSocket();
|
|
|
|
/** Trigger a manual check of the file list
|
|
*/
|
|
public void updateFileList() {
|
|
if (fileListWatcher != null) {
|
|
fileListWatcher.trigger();
|
|
}
|
|
}
|
|
|
|
/** Send response to list request
|
|
* @param pd Request received
|
|
*/
|
|
protected < T extends ProtocolP2PPacket<?> > void sendListResponse(T pd) {
|
|
try {
|
|
String[] fileList = fileListWatcher.getFileList();
|
|
if (fileList.length == 0) {
|
|
writeLog("Sending EMPTY_DIRECTORY to host " + pd.getHostItem(), LogLevel.Action);
|
|
sendEmptyDirectory(pd);
|
|
} else {
|
|
writeLog("Sending LIST_RESPONSE to host " + pd.getHostItem(), LogLevel.Action);
|
|
pd.sendResponse(createProtocolP2PPacket((Payload)(new FileList(fileList))));
|
|
}
|
|
} catch (Exception e2) {
|
|
writeLog(e2, LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** Send hash response to hash request
|
|
* @param pd Request received
|
|
*/
|
|
protected < T extends ProtocolP2PPacket<?> > void sendHashResponse(T pd) {
|
|
Payload p = pd.getPayload();
|
|
assert p instanceof HashRequest : "payload must be an instance of HashRequest";
|
|
if (!(p instanceof HashRequest)) {
|
|
sendInternalError(pd);
|
|
} else {
|
|
String filename = ((HashRequest)p).getFilename();
|
|
if (Arrays.binarySearch(fileListWatcher.getFileList(), filename) >= 0) {
|
|
Map<HashAlgorithm, byte[]> hashes = new HashMap<>();
|
|
for (HashAlgorithm h : ((HashRequest)p).getAlgoList()) {
|
|
switch (h) {
|
|
case SHA512:
|
|
hashes.put(h, fileListWatcher.getSha512Map().get(filename));
|
|
break;
|
|
case MD5:
|
|
default:
|
|
hashes.put(h, new byte[0]);
|
|
break;
|
|
}
|
|
}
|
|
try {
|
|
pd.sendResponse(createProtocolP2PPacket((Payload)(new HashResponse(filename, hashes))));
|
|
} catch (Exception e) {
|
|
writeLog(e, LogLevel.Error);
|
|
}
|
|
} else {
|
|
// file not found
|
|
try {
|
|
sendNotFound(pd);
|
|
} catch (Exception e) {
|
|
writeLog(e, LogLevel.Error);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Send response to load request
|
|
* @param pd Request received
|
|
*/
|
|
protected < T extends ProtocolP2PPacket<?> > void sendLoadResponse(T pd) {
|
|
Payload p = pd.getPayload();
|
|
assert p instanceof LoadRequest : "payload must be an instance of LoadRequest";
|
|
if (!(p instanceof LoadRequest)) {
|
|
sendInternalError(pd);
|
|
} else {
|
|
String filename = ((LoadRequest)p).getFilename();
|
|
long offset = ((LoadRequest)p).getOffset();
|
|
long maxSizePartialContent = ((LoadRequest)p).getMaxSizePartialContent();
|
|
try {
|
|
String[] fileList = fileListWatcher.getFileList();
|
|
if (Arrays.binarySearch(fileList, filename) >= 0) {
|
|
try {
|
|
double proba = ratioWatcher.getPunishmentProbability(((LoadRequest)p).getHostItem());
|
|
if (punisher.nextDouble() <= proba) {
|
|
writeLog("Sending punishment", LogLevel.Debug);
|
|
pd.sendResponse(createProtocolP2PPacket(new Denied(filename, offset)));
|
|
} else {
|
|
byte[] fullLoad = Files.readAllBytes(Paths.get(baseDirectory + filename));
|
|
long sizeToSend = 0;
|
|
if (fullLoad.length - offset < maxSizePartialContent) {
|
|
writeLog("Sending last partialContent", LogLevel.Debug);
|
|
sizeToSend = fullLoad.length - offset;
|
|
} else {
|
|
sizeToSend = maxSizePartialContent;
|
|
}
|
|
writeLog("maxSizePartialContent: " + maxSizePartialContent, LogLevel.Debug);
|
|
writeLog("Sending " + filename + " from " + offset + " to " + (offset + sizeToSend), LogLevel.Debug);
|
|
byte[] load = Arrays.copyOfRange(fullLoad, (int)offset, (int)(offset + sizeToSend));
|
|
try {
|
|
if (load.length == 0) {
|
|
sendEmptyFile(pd);
|
|
} else {
|
|
pd.sendResponse(createProtocolP2PPacket((Payload)(new FilePart(filename, offset, load))));
|
|
}
|
|
} catch (Exception e2) {
|
|
writeLog(e2, LogLevel.Error);
|
|
}
|
|
}
|
|
} catch (InternalError e) {
|
|
writeLog("InternalError", LogLevel.Debug);
|
|
writeLog(e, LogLevel.Debug);
|
|
sendInternalError(pd);
|
|
return;
|
|
} catch (UnknownHost e) {
|
|
writeLog("Unknown host: " + ((LoadRequest)p).getHostItem(), LogLevel.Debug);
|
|
writeLog(e, LogLevel.Debug);
|
|
sendInternalError(pd);
|
|
return;
|
|
} catch(LocalException e) {
|
|
sendInternalError(pd);
|
|
return;
|
|
}
|
|
} else {
|
|
writeLog("File requested not found: `" + filename + "` " + Arrays.binarySearch(fileList, filename), LogLevel.Debug);
|
|
writeLog("File list:", LogLevel.Debug);
|
|
for (String f: fileList) {
|
|
writeLog("- " + f, LogLevel.Debug);
|
|
}
|
|
|
|
throw new IOException(); // to send a NOT_FOUND in the catch block
|
|
}
|
|
} catch (IOException e) {
|
|
try {
|
|
sendNotFound(pd);
|
|
} catch (Exception e2) {
|
|
writeLog(e2, LogLevel.Debug);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Send response to size request
|
|
* @param pd Request received
|
|
*/
|
|
protected < T extends ProtocolP2PPacket<?> > void sendSizeResponse(T pd) {
|
|
Payload p = pd.getPayload();
|
|
assert p instanceof SizeRequest : "payload must be an instance of SizeRequest";
|
|
if (!(p instanceof SizeRequest)) {
|
|
sendInternalError(pd);
|
|
} else {
|
|
String filename = ((SizeRequest)p).getFilename();
|
|
try {
|
|
long size = (new File(baseDirectory + filename)).length();
|
|
String[] fileList = fileListWatcher.getFileList();
|
|
if (Arrays.binarySearch(fileList, filename) >= 0) {
|
|
try {
|
|
if (size == 0) {
|
|
sendEmptyFile(pd);
|
|
} else {
|
|
pd.sendResponse(createProtocolP2PPacket((new SizeResponse(filename, size))));
|
|
}
|
|
} catch (Exception e2) {
|
|
writeLog(e2, LogLevel.Error);
|
|
}
|
|
} else {
|
|
throw new IOException(); // to send a NOT_FOUND in the catch block
|
|
}
|
|
} catch (IOException e) {
|
|
try {
|
|
sendNotFound(pd);
|
|
} catch (Exception e2) {
|
|
writeLog(e2, LogLevel.Debug);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/** Getter for tracker socket
|
|
*/
|
|
protected abstract Object getTrackerSocket();
|
|
|
|
/** Send unregister request to tracker
|
|
*/
|
|
protected void sendUnregisterRequest() {
|
|
// unregistering from tracker
|
|
try {
|
|
writeLog("Unregistering from tracker", LogLevel.Info);
|
|
createProtocolP2PPacket(new Unregister(server)).sendRequest(getTrackerSocket());
|
|
} catch (Exception e) {
|
|
writeLog("Cannot unregister from tracker", LogLevel.Error);
|
|
writeLog(e, LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
/** Handle request.
|
|
* @throws LocalException
|
|
*/
|
|
protected < T extends ProtocolP2PPacket<?> > void handleRequest(T pd) throws LocalException {
|
|
Payload p = pd.getPayload();
|
|
switch (p.getRequestResponseCode()) {
|
|
case LOAD_REQUEST:
|
|
writeLog("Received LOAD_REQUEST from host " + pd.getHostItem(), LogLevel.Action);
|
|
sendLoadResponse(pd);
|
|
break;
|
|
case SIZE_REQUEST:
|
|
writeLog("Received SIZE_REQUEST from host " + pd.getHostItem(), LogLevel.Action);
|
|
sendSizeResponse(pd);
|
|
break;
|
|
case LIST_REQUEST:
|
|
writeLog("Received LIST_REQUEST from host " + pd.getHostItem(), LogLevel.Action);
|
|
sendListResponse(pd);
|
|
break;
|
|
case HASH_REQUEST:
|
|
writeLog("Received HASH_REQUEST from host " + pd.getHostItem(), LogLevel.Action);
|
|
sendHashResponse(pd);
|
|
break;
|
|
case DISCOVER_REQUEST:
|
|
writeLog("Received DISCOVER_REQUEST from host " + pd.getHostItem(), LogLevel.Action);
|
|
sendNotATracker(pd);
|
|
break;
|
|
case UNREGISTER:
|
|
writeLog("Received UNREGISTER from host " + pd.getHostItem(), LogLevel.Action);
|
|
sendNotATracker(pd);
|
|
break;
|
|
case REGISTER:
|
|
writeLog("Received REGISTER from host " + pd.getHostItem(), LogLevel.Action);
|
|
sendNotATracker(pd);
|
|
break;
|
|
default:
|
|
writeLog("Received grabbage from host " + pd.getHostItem(), LogLevel.Action);
|
|
sendInternalError(pd);
|
|
}
|
|
}
|
|
|
|
}
|