You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Projet_JAVA_P2P_STRI2A/src/clientP2P/ClientManagementUDP.java

282 lines
10 KiB
Java

package clientP2P;
import exception.InternalError;
import exception.ProtocolError;
import exception.SizeError;
import exception.TransmissionError;
import exception.VersionError;
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.DatagramSocket;
import java.net.SocketException;
import java.io.IOException;
import java.nio.file.Files;
import java.io.File;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
5 years ago
import java.util.Arrays;
import protocolP2P.ProtocolP2PPacketUDP;
import protocolP2P.Payload;
import protocolP2P.RequestResponseCode;
import protocolP2P.FileList;
import protocolP2P.FilePart;
import protocolP2P.LoadRequest;
5 years ago
import protocolP2P.HashAlgorithm;
import protocolP2P.HashRequest;
import protocolP2P.HashResponse;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/** Implementation of P2P-JAVA-PROJECT CLIENT
* @author Louis Royer
* @author Flavien Haas
* @author JS Auge
* @version 1.0
*/
public class ClientManagementUDP implements Runnable {
private String baseDirectory;
private int UDPPort;
private String host;
private DatagramSocket socket;
/** Constructor for UDP implementation, with baseDirectory and UDPPort parameters.
* @param baseDirectory the root directory where files are stored
* @param host hostname of the server
* @param UDPPort the server will listen on this port
*/
public ClientManagementUDP(String baseDirectory, String host, int UDPPort) {
this.baseDirectory = baseDirectory;
this.host = host;
this.UDPPort = UDPPort;
try {
socket = new DatagramSocket();
socket.connect(InetAddress.getByName(host), UDPPort);
} catch (SocketException e) {
System.err.println("Error: No UDP socket available.");
System.exit(-1);
} catch (UnknownHostException e) {
System.err.println("Error: Unknown host.");
System.exit(-1);
}
}
/** 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 (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");
}
}
/** Try to download a file
* @param filename name of the file to download
* @throws NotFound
* @throws InternalError
* @throws UnknownHostException
* @throws IOException
* @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, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
5 years ago
byte[] hash512;
final long MAX_PARTIAL_SIZE = 4096;
5 years ago
HashAlgorithm[] hashesAlgo = new HashAlgorithm[1];
hashesAlgo[0] = HashAlgorithm.SHA512;
ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP((Payload) new HashRequest(filename, hashesAlgo));
d.sendRequest((Object)socket);
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 ProtocolP2PPacketUDP((Payload) new LoadRequest(filename, 0, MAX_PARTIAL_SIZE));
d.sendRequest((Object)socket);
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 ProtocolP2PPacketUDP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
d.sendRequest((Object)socket);
} 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 ProtocolP2PPacketUDP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
d.sendRequest((Object)socket);
}
} 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);
5 years ago
if (!Arrays.equals(hash512, computeHashsum(filename, HashAlgorithm.SHA512))) {
System.err.println("Error: Hashsum does not match");
5 years ago
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("");
5 years ago
throw new InternalError();
}
}
/** list servers directory content
* @return list of files
* @throws InternalError
* @throws UnknowHostException
* @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, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
ProtocolP2PPacketUDP d = new ProtocolP2PPacketUDP(new Payload(RequestResponseCode.LIST_REQUEST));
d.sendRequest((Object)socket);
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();
}
}
5 years ago
/** 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];
}
}