249 lines
8.2 KiB
Java
249 lines
8.2 KiB
Java
package serverP2P;
|
|
import java.util.Vector;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.net.DatagramSocket;
|
|
import java.net.InetAddress;
|
|
import java.net.SocketException;
|
|
import java.nio.file.Paths;
|
|
import java.nio.file.Files;
|
|
import java.security.MessageDigest;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import protocolP2P.ProtocolP2PPacketUDP;
|
|
import protocolP2P.ProtocolP2PPacket;
|
|
import protocolP2P.RequestResponseCode;
|
|
import protocolP2P.Payload;
|
|
import protocolP2P.LoadRequest;
|
|
import protocolP2P.FileList;
|
|
import protocolP2P.FilePart;
|
|
import exception.InternalError;
|
|
import exception.ProtocolError;
|
|
import exception.SizeError;
|
|
import exception.TransmissionError;
|
|
import exception.VersionError;
|
|
import exception.SocketClosed;
|
|
import remoteException.EmptyDirectory;
|
|
import remoteException.InternalRemoteError;
|
|
import remoteException.NotFound;
|
|
import remoteException.ProtocolRemoteError;
|
|
import remoteException.VersionRemoteError;
|
|
import remoteException.EmptyFile;
|
|
import java.util.Arrays;
|
|
import tools.Logger;
|
|
import tools.LogLevel;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import protocolP2P.HashAlgorithm;
|
|
import protocolP2P.HashRequest;
|
|
import protocolP2P.HashResponse;
|
|
|
|
/** Implementation of P2P-JAVA-PROJECT VERSION 1.0 protocol for UDP.
|
|
* @author Louis Royer
|
|
* @author Flavien Haas
|
|
* @author JS Auge
|
|
* @version 1.0
|
|
*/
|
|
public class ServerManagementUDP implements Runnable {
|
|
|
|
private String[] fileList;
|
|
private Map<String, byte[]> sha512 = new HashMap<>();
|
|
private String baseDirectory;
|
|
private int UDPPort;
|
|
private DatagramSocket socket;
|
|
private Logger logger;
|
|
|
|
/** Constructor for UDP implementation, with baseDirectory and UDPPort parameters.
|
|
* @param baseDirectory the root directory where files are stored
|
|
* @param UDPPort the server will listen on this port
|
|
*/
|
|
public ServerManagementUDP(String baseDirectory, int UDPPort, Logger logger) {
|
|
this.logger = logger;
|
|
this.baseDirectory = baseDirectory;
|
|
this.UDPPort = UDPPort;
|
|
initFileList();
|
|
initSha512();
|
|
try {
|
|
socket = new DatagramSocket(UDPPort);
|
|
} catch (SocketException e) {
|
|
logger.writeUDP("Error: cannot listen on port " + UDPPort, LogLevel.Error);
|
|
System.exit(-1);
|
|
}
|
|
}
|
|
|
|
/** Implementation of runnable. This methods allows to run the server.
|
|
*/
|
|
public void run() {
|
|
logger.writeUDP("Server sucessfully started", LogLevel.Info);
|
|
while(true) {
|
|
try {
|
|
ProtocolP2PPacketUDP pd = new ProtocolP2PPacketUDP((Object)socket);
|
|
Payload p = pd.getPayload();
|
|
switch (p.getRequestResponseCode()) {
|
|
case LOAD_REQUEST:
|
|
logger.writeUDP("Received LOAD_REQUEST", LogLevel.Action);
|
|
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 {
|
|
byte[] fullLoad = Files.readAllBytes(Paths.get(baseDirectory + filename));
|
|
long sizeToSend = 0;
|
|
if (fullLoad.length - offset < maxSizePartialContent) {
|
|
logger.writeUDP("Sending last partialContent", LogLevel.Debug);
|
|
sizeToSend = fullLoad.length - offset;
|
|
} else {
|
|
sizeToSend = maxSizePartialContent;
|
|
}
|
|
logger.writeUDP("maxSizePartialContent: " + maxSizePartialContent, LogLevel.Debug);
|
|
logger.writeUDP("Sending " + filename + " from " + offset + " to " + (offset + sizeToSend), LogLevel.Debug);
|
|
byte[] load = Arrays.copyOfRange(fullLoad, (int)offset, (int)(offset + sizeToSend));
|
|
if (Arrays.binarySearch(fileList, filename) >= 0) {
|
|
try {
|
|
if (load.length == 0) {
|
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.EMPTY_FILE)));
|
|
} else {
|
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)(new FilePart(filename, fullLoad.length, offset, load))));
|
|
}
|
|
} catch (Exception e2) {
|
|
logger.writeUDP(e2, LogLevel.Error);
|
|
}
|
|
} else {
|
|
logger.writeUDP("File requested not found: `" + filename + "` " + Arrays.binarySearch(fileList, filename), LogLevel.Debug);
|
|
logger.writeUDP("File list:", LogLevel.Debug);
|
|
for (String f: fileList) {
|
|
logger.writeUDP("- " + f, LogLevel.Debug);
|
|
}
|
|
|
|
throw new IOException(); // to send a NOT_FOUND in the catch block
|
|
}
|
|
} catch (IOException e) {
|
|
try {
|
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.NOT_FOUND)));
|
|
} catch (Exception e2) {
|
|
logger.writeUDP(e2, LogLevel.Error);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case LIST_REQUEST:
|
|
logger.writeUDP("Received LIST_REQUEST", LogLevel.Action);
|
|
try {
|
|
if (fileList.length == 0) {
|
|
logger.writeUDP("Sending EMPTY_DIRECTORY", LogLevel.Action);
|
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.EMPTY_DIRECTORY)));
|
|
} else {
|
|
logger.writeUDP("Sending LIST_RESPONSE", LogLevel.Action);
|
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)(new FileList(fileList))));
|
|
}
|
|
} catch (Exception e2) {
|
|
logger.writeUDP(e2, LogLevel.Error);
|
|
}
|
|
break;
|
|
case HASH_REQUEST:
|
|
logger.writeUDP("Received HASH_REQUEST", LogLevel.Action);
|
|
sendHashResponse(pd);
|
|
break;
|
|
default:
|
|
sendInternalError(pd);
|
|
}
|
|
} catch (IOException e) {
|
|
} catch (SocketClosed e) {
|
|
} catch (TransmissionError e) {
|
|
} catch (ProtocolError e) {
|
|
} catch (VersionError e) {
|
|
} catch (InternalError e) {
|
|
} 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());
|
|
}
|
|
}
|
|
fileList = new String[v.size()];
|
|
v.toArray(fileList);
|
|
Arrays.sort(fileList);
|
|
}
|
|
|
|
/** Init sha512 map.
|
|
*/
|
|
private void initSha512() {
|
|
for(String f: fileList) {
|
|
try {
|
|
MessageDigest md = MessageDigest.getInstance(HashAlgorithm.SHA512.getName());
|
|
sha512.put(f, md.digest(Files.readAllBytes(Paths.get(baseDirectory + f))));
|
|
md.reset();
|
|
} catch (NoSuchAlgorithmException e) {
|
|
logger.writeUDP("sha512 not supported", LogLevel.Error);
|
|
} catch (IOException e) {
|
|
logger.writeUDP("cannot read " + f, LogLevel.Warning);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Send an internal error message.
|
|
* @param pd ProtocolP2PPacketUDP to respond
|
|
*/
|
|
private void sendInternalError(ProtocolP2PPacketUDP pd) {
|
|
logger.writeUDP("Internal Error", LogLevel.Warning);
|
|
try {
|
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.INTERNAL_ERROR)));
|
|
} catch (Exception e) {
|
|
logger.writeUDP(e, LogLevel.Error);
|
|
}
|
|
}
|
|
|
|
/** Send hash response to hash request
|
|
* @param pd Request received
|
|
*/
|
|
private void sendHashResponse(ProtocolP2PPacketUDP 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(fileList, filename) >= 0) {
|
|
Map<HashAlgorithm, byte[]> hashes = new HashMap<>();
|
|
for (HashAlgorithm h : ((HashRequest)p).getAlgoList()) {
|
|
switch (h) {
|
|
case SHA512:
|
|
hashes.put(h, sha512.get(filename));
|
|
break;
|
|
case MD5:
|
|
default:
|
|
hashes.put(h, new byte[0]);
|
|
break;
|
|
}
|
|
}
|
|
try {
|
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP((Payload)(new HashResponse(filename, hashes))));
|
|
} catch (Exception e) {
|
|
logger.writeUDP(e, LogLevel.Error);
|
|
}
|
|
} else {
|
|
// file not found
|
|
try {
|
|
pd.sendResponse((ProtocolP2PPacket)new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.NOT_FOUND)));
|
|
} catch (Exception e) {
|
|
logger.writeUDP(e, LogLevel.Error);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|