Projet_JAVA_P2P_STRI2A/src/clientP2P/ClientManagementTCP.java
Louis f88f5b1d40
All checks were successful
flavien's git/Projet_JAVA_P2P_STRI2A/pipeline/pr-master This commit looks good
Add multiple servers choice, but dl only from one
Je suis en train de faire en sorte qu’on télécharge depuis plusieurs
2020-03-11 20:31:13 +01:00

280 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package clientP2P;
import exception.InternalError;
import exception.ProtocolError;
import exception.SizeError;
import exception.TransmissionError;
import exception.VersionError;
import exception.SocketClosed;
import remoteException.EmptyFile;
import remoteException.EmptyDirectory;
import remoteException.InternalRemoteError;
import remoteException.NotFound;
import remoteException.ProtocolRemoteError;
import remoteException.VersionRemoteError;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.Socket;
import java.io.IOException;
import java.nio.file.Files;
import java.io.File;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import protocolP2P.ProtocolP2PPacketTCP;
import protocolP2P.Payload;
import protocolP2P.RequestResponseCode;
import protocolP2P.FileList;
import protocolP2P.FilePart;
import protocolP2P.LoadRequest;
import protocolP2P.HashAlgorithm;
import protocolP2P.HashRequest;
import protocolP2P.HashResponse;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import tools.HostItem;
import java.util.List;
/** Implementation of P2P-JAVA-PROJECT CLIENT
* @author Louis Royer
* @author Flavien Haas
* @author JS Auge
* @version 1.0
*/
public class ClientManagementTCP implements Runnable {
private String baseDirectory;
private List<HostItem> hostList;
/** Constructor for TCP implementation, with baseDirectory and TCPPort parameters.
* @param baseDirectory the root directory where files are stored
* @param host hostname of the server
* @param TCPPort the server will listen on this port
*/
public ClientManagementTCP(String baseDirectory, List<HostItem> hostList) {
this.baseDirectory = baseDirectory;
this.hostList = hostList;
}
/** 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:");
Scanner scanner = new Scanner(System.in);
String f = scanner.nextLine();
download(f);
System.out.println("File sucessfully downloaded");
} catch (EmptyDirectory e) {
System.err.println("Error: Server has no file in directory");
} catch (InternalError e) {
System.err.println("Error: Client internal error");
} catch (UnknownHostException e) {
System.err.println("Error: Server host is unknown");
} catch (SocketClosed e) {
System.err.println("Error: Request cannot be send or response cannot be received");
} catch (IOException e) {
System.err.println("Error: Request cannot be send or response cannot be received");
} catch (TransmissionError e) {
System.err.println("Error: Message received is too big");
} catch (ProtocolError e) {
System.err.println("Error: Cannot decode servers response");
} catch (VersionError e) {
System.err.println("Error: Servers response use bad version of the protocol");
} catch (SizeError e) {
System.err.println("Error: Cannot handle this packets because of internal representation limitations of numbers on the client");
} catch (InternalRemoteError e) {
System.err.println("Error: Server internal error");
} catch (ProtocolRemoteError e) {
System.err.println("Error: Server cannot decode clients request");
} catch (VersionRemoteError e) {
System.err.println("Error: Server cannot decode this version of the protocol");
} catch (NotFound e) {
System.err.println("Error: Server has not this file in directory");
} catch (EmptyFile e) {
System.err.println("Error: File is empty");
} finally {
for (HostItem h: hostList) {
h.closeTCPSocket();
}
}
}
/** Try to download a file
* @param filename name of the file to download
* @throws NotFound
* @throws InternalError
* @throws UnknownHostException
* @throws IOException
* @throws SocketClosed
* @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, SocketClosed, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
byte [] hash512;
final long MAX_PARTIAL_SIZE = 4096;
HashAlgorithm[] hashesAlgo = new HashAlgorithm[1];
hashesAlgo[0] = HashAlgorithm.SHA512;
ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP((Payload) new HashRequest(filename, hashesAlgo));
d.sendRequest((Object)hostList.get(0).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 {
hash512 = ((HashResponse)pHash).getHash(HashAlgorithm.SHA512);
if (hash512.length == 0) {
System.err.println("Error: server do not support sha512 hashes");
throw new InternalError();
}
}
} catch (EmptyDirectory e) {
System.err.println("Error: empty directory, but request was not LIST_REQUEST");
throw new ProtocolError();
}
d = new ProtocolP2PPacketTCP((Payload) new LoadRequest(filename, 0, MAX_PARTIAL_SIZE));
d.sendRequest((Object)hostList.get(0).getTCPSocket());
boolean fileFullyWritten = false;
long offset = 0;
do {
try {
Payload p = d.receiveResponse().getPayload();
assert p instanceof FilePart : "This payload must be instance of FilePart";
if (!(p instanceof FilePart)) {
throw new InternalError();
} else {
FilePart fp = (FilePart)p;
if (!fp.getFilename().equals(filename)) {
System.err.println("Error: wrong file received: `" + fp.getFilename() + "`");
throw new ProtocolError();
}
if (fp.getOffset() == 0) {
System.err.println("Receiving first partialContent");
// first partialContent
// increment offset
offset = fp.getPartialContent().length;
/* write first partialContent */
try {
Files.write(new File(baseDirectory + filename).toPath(), fp.getPartialContent());
} catch (IOException e) {
System.err.println("Error: cannot write file (" + baseDirectory + filename + ")");
}
// next partialContentRequest
if (offset != fp.getTotalSize()) {
System.err.println("Sending following request with offset: " + offset + " maxpartialsize: " + MAX_PARTIAL_SIZE);
d = new ProtocolP2PPacketTCP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
d.sendRequest((Object)hostList.get(0).getTCPSocket());
} else {
fileFullyWritten = true;
}
} else if (offset == fp.getOffset()){
System.err.println("Receiving following partialContent (offset: " + offset + ")");
// following
// increment offset
offset += fp.getPartialContent().length;
/* write following partialContent at end of file*/
try {
Files.write(Paths.get(baseDirectory + filename), fp.getPartialContent(), StandardOpenOption.APPEND);
} catch (IOException e) {
System.err.println("Error: cannot write file (" + baseDirectory + filename + ")");
}
if (offset >= fp.getTotalSize()) {
fileFullyWritten = true;
} else {
// next partialContentRequest
d = new ProtocolP2PPacketTCP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
d.sendRequest((Object)hostList.get(0).getTCPSocket());
}
} else {
System.err.println("offset: " + fp.getOffset() + " ; content.length: " + fp.getPartialContent().length + " ; totalSize: " + fp.getTotalSize());
System.err.println("Error: cannot handle non-consecutive partial files (not implemented)");
throw new InternalError();
}
}
} catch (EmptyDirectory e) {
throw new ProtocolError();
}
} while(!fileFullyWritten);
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));
}
System.err.println("");
System.err.println("Received checksum:");
for (byte b: hash512) {
System.err.print(String.format("%02X", b));
}
System.err.println("");
throw new InternalError();
}
hostList.get(0).closeTCPSocket();
}
/** list servers directory content
* @return list of files
* @throws InternalError
* @throws UnknowHostException
* @throws SocketClosed
* @throws IOException
* @throws TransmissionError
* @throws ProtocolError
* @throws VersionError
* @throws SizeError
* @throws EmptyDirectory
* @throws InternalRemoteError
* @throws ProtocolRemoteError
* @throws VersionRemoteError
*/
private String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, SocketClosed, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP(new Payload(RequestResponseCode.LIST_REQUEST));
d.sendRequest((Object)hostList.get(0).getTCPSocket());
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) {
throw new ProtocolError();
} catch (EmptyFile e) {
throw new ProtocolError();
}
}
/** Compute Hashsum of a file.
* @param filename
* @return hashsum
*/
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");
} catch (IOException e) {
System.out.println("Error: cannot read " + filename);
}
return new byte[0];
}
}