2020-02-29 16:57:19 +01:00
|
|
|
|
package clientP2P;
|
|
|
|
|
import exception.InternalError;
|
|
|
|
|
import exception.ProtocolError;
|
|
|
|
|
import exception.SizeError;
|
|
|
|
|
import exception.TransmissionError;
|
|
|
|
|
import exception.VersionError;
|
2020-03-03 16:39:19 +01:00
|
|
|
|
import exception.SocketClosed;
|
2020-02-29 16:57:19 +01:00
|
|
|
|
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 protocolP2P.ProtocolP2PPacketTCP;
|
|
|
|
|
import protocolP2P.Payload;
|
|
|
|
|
import protocolP2P.RequestResponseCode;
|
|
|
|
|
import protocolP2P.FileList;
|
|
|
|
|
import protocolP2P.FilePart;
|
|
|
|
|
import protocolP2P.LoadRequest;
|
|
|
|
|
|
|
|
|
|
/** 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 int TCPPort;
|
|
|
|
|
private String host;
|
|
|
|
|
private Socket socket;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 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, String host, int TCPPort) {
|
|
|
|
|
this.baseDirectory = baseDirectory;
|
|
|
|
|
this.host = host;
|
|
|
|
|
this.TCPPort = TCPPort;
|
|
|
|
|
try {
|
|
|
|
|
socket = new Socket(InetAddress.getByName(host), TCPPort);
|
|
|
|
|
} catch (SocketException e) {
|
|
|
|
|
System.err.println("Error: No TCP socket available.");
|
|
|
|
|
System.exit(-1);
|
|
|
|
|
} catch (UnknownHostException e) {
|
|
|
|
|
System.err.println("Error: Unknown host.");
|
|
|
|
|
System.exit(-1);
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
System.err.println("Error: Cannot create TCP socket");
|
|
|
|
|
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");
|
2020-03-03 16:39:19 +01:00
|
|
|
|
} catch (SocketClosed e) {
|
|
|
|
|
System.err.println("Error: Request cannot be send or response cannot be received");
|
2020-02-29 16:57:19 +01:00
|
|
|
|
} 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 server’s response");
|
|
|
|
|
} catch (VersionError e) {
|
|
|
|
|
System.err.println("Error: Server’s 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 client’s 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");
|
2020-03-03 16:39:19 +01:00
|
|
|
|
} finally {
|
|
|
|
|
try {
|
|
|
|
|
System.err.println("Closing socket");
|
|
|
|
|
socket.close();
|
|
|
|
|
} catch (IOException e2) {
|
|
|
|
|
System.err.println("Error: cannot close socket");
|
|
|
|
|
}
|
2020-02-29 16:57:19 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Try to download a file
|
|
|
|
|
* @param filename name of the file to download
|
|
|
|
|
* @throws NotFound
|
|
|
|
|
* @throws InternalError
|
|
|
|
|
* @throws UnknownHostException
|
|
|
|
|
* @throws IOException
|
2020-03-03 16:39:19 +01:00
|
|
|
|
* @throws SocketClosed
|
2020-02-29 16:57:19 +01:00
|
|
|
|
* @throws TransmissionError
|
|
|
|
|
* @throws ProtocolError
|
|
|
|
|
* @throws VersionError
|
|
|
|
|
* @throws SizeError
|
|
|
|
|
* @throws InternalRemoteError
|
|
|
|
|
* @throws ProtocolRemoteError
|
|
|
|
|
* @throws VersionRemoteError
|
|
|
|
|
* @throws EmptyFile
|
|
|
|
|
*/
|
2020-03-03 16:39:19 +01:00
|
|
|
|
private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, SocketClosed, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
|
2020-03-02 15:31:37 +01:00
|
|
|
|
final long MAX_PARTIAL_SIZE = 4096;
|
2020-02-29 16:57:19 +01:00
|
|
|
|
ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP((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 ProtocolP2PPacketTCP((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 ProtocolP2PPacketTCP((Payload) new LoadRequest(filename, offset, MAX_PARTIAL_SIZE));
|
|
|
|
|
d.sendRequest((Object)socket);
|
|
|
|
|
}
|
2020-03-02 15:31:37 +01:00
|
|
|
|
|
2020-02-29 16:57:19 +01:00
|
|
|
|
} 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);
|
2020-03-02 15:31:37 +01:00
|
|
|
|
socket.close();
|
2020-02-29 16:57:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** list server’s directory content
|
|
|
|
|
* @return list of files
|
|
|
|
|
* @throws InternalError
|
|
|
|
|
* @throws UnknowHostException
|
2020-03-03 16:39:19 +01:00
|
|
|
|
* @throws SocketClosed
|
2020-02-29 16:57:19 +01:00
|
|
|
|
* @throws IOException
|
|
|
|
|
* @throws TransmissionError
|
|
|
|
|
* @throws ProtocolError
|
|
|
|
|
* @throws VersionError
|
|
|
|
|
* @throws SizeError
|
|
|
|
|
* @throws EmptyDirectory
|
|
|
|
|
* @throws InternalRemoteError
|
|
|
|
|
* @throws ProtocolRemoteError
|
|
|
|
|
* @throws VersionRemoteError
|
|
|
|
|
*/
|
2020-03-03 16:39:19 +01:00
|
|
|
|
private String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, SocketClosed, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError {
|
2020-02-29 16:57:19 +01:00
|
|
|
|
ProtocolP2PPacketTCP d = new ProtocolP2PPacketTCP(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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|