|
|
|
@ -1,35 +1,38 @@
|
|
|
|
|
package clientP2P;
|
|
|
|
|
import clientP2P.ClientDownloadPartTCP;
|
|
|
|
|
import tools.HostItem;
|
|
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.Random;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.nio.file.Files;
|
|
|
|
|
import java.nio.file.Paths;
|
|
|
|
|
import java.nio.file.StandardOpenOption;
|
|
|
|
|
import java.nio.file.StandardCopyOption;
|
|
|
|
|
import remoteException.EmptyDirectory;
|
|
|
|
|
import remoteException.EmptyFile;
|
|
|
|
|
import remoteException.VersionRemoteError;
|
|
|
|
|
import remoteException.ProtocolRemoteError;
|
|
|
|
|
import remoteException.NotFound;
|
|
|
|
|
import remoteException.InternalRemoteError;
|
|
|
|
|
import protocolP2P.HashAlgorithm;
|
|
|
|
|
import protocolP2P.HashResponse;
|
|
|
|
|
import protocolP2P.HashRequest;
|
|
|
|
|
import protocolP2P.ProtocolP2PPacketTCP;
|
|
|
|
|
import protocolP2P.Payload;
|
|
|
|
|
import localException.ProtocolError;
|
|
|
|
|
import localException.InternalError;
|
|
|
|
|
import localException.TransmissionError;
|
|
|
|
|
import localException.SizeError;
|
|
|
|
|
import localException.VersionError;
|
|
|
|
|
import localException.SocketClosed;
|
|
|
|
|
import protocolP2P.HashAlgorithm;
|
|
|
|
|
import protocolP2P.HashResponse;
|
|
|
|
|
import protocolP2P.HashRequest;
|
|
|
|
|
import protocolP2P.ProtocolP2PPacketTCP;
|
|
|
|
|
import protocolP2P.Payload;
|
|
|
|
|
import protocolP2P.FilePart;
|
|
|
|
|
import protocolP2P.LoadRequest;
|
|
|
|
|
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.nio.file.StandardCopyOption;
|
|
|
|
|
import localException.SocketClosed;
|
|
|
|
|
import clientP2P.ClientDownloadPartTCP;
|
|
|
|
|
import tools.HostItem;
|
|
|
|
|
import tools.Logger;
|
|
|
|
|
import tools.LogLevel;
|
|
|
|
|
|
|
|
|
|
/** Class to download file from tcp
|
|
|
|
|
* @author Louis Royer
|
|
|
|
@ -51,6 +54,7 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
private String partsSubdir;
|
|
|
|
|
private String dirStorage;
|
|
|
|
|
private boolean success = false;
|
|
|
|
|
private Logger logger;
|
|
|
|
|
|
|
|
|
|
/** Constructor with parameters: filename, list of hosts, parts subdirectory and dirStorage
|
|
|
|
|
* @param filename name of file to download
|
|
|
|
@ -58,11 +62,12 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
* @param partsSubdir directory to store .part files
|
|
|
|
|
* @param dirStorage directory to write assembled file
|
|
|
|
|
*/
|
|
|
|
|
public ClientDownloadTCP(String filename, List<HostItem> hostList, String partsSubdir, String dirStorage) {
|
|
|
|
|
public ClientDownloadTCP(String filename, List<HostItem> hostList, String partsSubdir, String dirStorage, Logger logger) {
|
|
|
|
|
this.partsSubdir = partsSubdir;
|
|
|
|
|
this.dirStorage = dirStorage;
|
|
|
|
|
this.filename = filename;
|
|
|
|
|
this.hostList = hostList;
|
|
|
|
|
this.logger = logger;
|
|
|
|
|
this.stop = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -79,9 +84,11 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
init();
|
|
|
|
|
if (stop) {
|
|
|
|
|
System.err.println("File is smaller than part max size.");
|
|
|
|
|
logger.writeTCP("File is smaller than part max size.", LogLevel.Info);
|
|
|
|
|
hostList.get(0).closeTCPSocket();
|
|
|
|
|
} else {
|
|
|
|
|
System.err.println("File is bigger than part max size.");
|
|
|
|
|
logger.writeTCP("File is bigger than part max size.", LogLevel.Info);
|
|
|
|
|
purgeList();
|
|
|
|
|
initThreads();
|
|
|
|
|
while(!stop) {
|
|
|
|
@ -91,9 +98,11 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
System.err.println("Reassembling file parts.");
|
|
|
|
|
logger.writeTCP("Reassembling file parts.", LogLevel.Info);
|
|
|
|
|
reassembleFile();
|
|
|
|
|
} catch(InternalError e) {
|
|
|
|
|
System.err.println("Error while downloading file. Aborting.");
|
|
|
|
|
logger.writeTCP("Error while downloading file. Aborting.", LogLevel.Error);
|
|
|
|
|
} finally {
|
|
|
|
|
stopTasks();
|
|
|
|
|
}
|
|
|
|
@ -103,13 +112,14 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
*/
|
|
|
|
|
private void initThreads() {
|
|
|
|
|
for(HostItem hostItem: hostList) {
|
|
|
|
|
sockList.add(new ClientDownloadPartTCP(this, filename, hostItem.getTCPSocket(), partsSubdir));
|
|
|
|
|
sockList.add(new ClientDownloadPartTCP(this, filename, hostItem.getTCPSocket(), partsSubdir, logger));
|
|
|
|
|
}
|
|
|
|
|
for(ClientDownloadPartTCP c: sockList) {
|
|
|
|
|
Thread t = new Thread(c);
|
|
|
|
|
t.start();
|
|
|
|
|
}
|
|
|
|
|
System.err.println("Threads initialized");
|
|
|
|
|
logger.writeTCP("Threads initialized", LogLevel.Info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Remove tasks from failed threads. Update done status.
|
|
|
|
@ -133,15 +143,18 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
System.err.println("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending");
|
|
|
|
|
logger.writeTCP("Task check status: " + offsetsToAsk.size() + " to asks, " + offsetsPending.size() + " pending", LogLevel.Info);
|
|
|
|
|
if (offsetsToAsk.isEmpty() && offsetsPending.isEmpty()) {
|
|
|
|
|
stop = true;
|
|
|
|
|
}
|
|
|
|
|
if (sockList.size() == 0) {
|
|
|
|
|
System.err.println("No thread working");
|
|
|
|
|
logger.writeTCP("No thread working", LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -157,6 +170,7 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
offsetsPending.add(offset);
|
|
|
|
|
System.err.println("Assigned task "+ offset);
|
|
|
|
|
} catch(InterruptedException e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -168,7 +182,9 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
for(ClientDownloadPartTCP c : sockList) {
|
|
|
|
|
try {
|
|
|
|
|
c.setStop();
|
|
|
|
|
} catch (InterruptedException e) {}
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -193,32 +209,44 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
hash = ((HashResponse)pHash).getHash(HashAlgorithm.SHA512);
|
|
|
|
|
}
|
|
|
|
|
} catch (EmptyDirectory e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
hash = new byte[0];
|
|
|
|
|
} catch (NotFound e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
hash = new byte[0];
|
|
|
|
|
// TODO: use more specific errors
|
|
|
|
|
} catch (EmptyFile e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (ProtocolError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (InternalRemoteError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (VersionRemoteError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (ProtocolRemoteError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (TransmissionError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (VersionError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (SizeError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
}
|
|
|
|
|
return hash;
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (SocketClosed e){
|
|
|
|
|
System.err.println("getHashSum512 : SocketClosed");
|
|
|
|
|
logger.writeTCP("getHashSum512 : SocketClosed", LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -248,6 +276,7 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
hostList.remove(host);
|
|
|
|
|
}
|
|
|
|
|
System.err.println("Host list purge: done");
|
|
|
|
|
logger.writeTCP("Host list purge: done", LogLevel.Info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Getter for hash512sum
|
|
|
|
@ -269,6 +298,7 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
hash512 = getHashSum512(hostList.get(0));
|
|
|
|
|
if (hash512.length == 0) {
|
|
|
|
|
System.err.println("Error: no hash512sum support.");
|
|
|
|
|
logger.writeTCP("no hash512sum support.", LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -278,6 +308,7 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
offsetsToAsk.add(Long.valueOf(i));
|
|
|
|
|
}
|
|
|
|
|
System.err.println("Adding tasks: done");
|
|
|
|
|
logger.writeTCP("Adding tasks: done", LogLevel.Info);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -293,11 +324,13 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
assert p instanceof FilePart : "This payload must be instance of FilePart";
|
|
|
|
|
if (!(p instanceof FilePart)) {
|
|
|
|
|
System.err.println("Error: cannot get size.");
|
|
|
|
|
logger.writeTCP("cannot get size.", LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} else {
|
|
|
|
|
FilePart fp = (FilePart)p;
|
|
|
|
|
if (!fp.getFilename().equals(filename)) {
|
|
|
|
|
System.err.println("Error: wrong file received: `" + fp.getFilename() + "`");
|
|
|
|
|
logger.writeTCP("wrong file received: `" + fp.getFilename() + "`", LogLevel.Error);
|
|
|
|
|
throw new ProtocolError();
|
|
|
|
|
}
|
|
|
|
|
if (fp.getOffset() == 0) {
|
|
|
|
@ -305,6 +338,7 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
Files.write(new File(partsSubdir + filename + "_0.part").toPath(), fp.getPartialContent());
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
System.err.println("Error: cannot write file (" + partsSubdir + filename + "_0.part)");
|
|
|
|
|
logger.writeTCP("cannot write file (" + partsSubdir + filename + "_0.part)", LogLevel.Error);
|
|
|
|
|
}
|
|
|
|
|
size = fp.getTotalSize();
|
|
|
|
|
if (fp.getPartialContent().length == size) {
|
|
|
|
@ -312,36 +346,49 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
System.err.println("Error: wrong file part received.");
|
|
|
|
|
logger.writeTCP("wrong file part received.", LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (EmptyDirectory e) {
|
|
|
|
|
System.err.println("Error: empty directory.");
|
|
|
|
|
logger.writeTCP("empty directory.", LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (EmptyFile e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
// TODO: use more specific errors
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (ProtocolError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (InternalRemoteError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (VersionRemoteError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (ProtocolRemoteError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (TransmissionError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (VersionError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (SizeError e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (NotFound e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
logger.writeTCP(e, LogLevel.Error);
|
|
|
|
|
throw new InternalError();
|
|
|
|
|
} catch (SocketClosed e){
|
|
|
|
|
System.err.println("setSize : SocketClosed");
|
|
|
|
|
logger.writeTCP("setSize : SocketClosed", LogLevel.Error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -362,6 +409,7 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
do {
|
|
|
|
|
if (firstPart) {
|
|
|
|
|
System.err.println("Reassembling: First part");
|
|
|
|
|
logger.writeTCP("Reassembling: First part", LogLevel.Info);
|
|
|
|
|
try {
|
|
|
|
|
// create file
|
|
|
|
|
Files.copy(new File(partsSubdir + filename + "_" + nextOffset + ".part").toPath(), new File(dirStorage + filename).toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
|
|
@ -369,11 +417,13 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
firstPart = false;
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
System.err.println("Reassembling: aborting on first part");
|
|
|
|
|
logger.writeTCP("Reassembling: aborting on first part", LogLevel.Error);
|
|
|
|
|
abort = true;
|
|
|
|
|
}
|
|
|
|
|
} else if (nextOffset >= size) {
|
|
|
|
|
success = true;
|
|
|
|
|
System.err.println("Reassembling: success");
|
|
|
|
|
logger.writeTCP("Reassembling: success", LogLevel.Info);
|
|
|
|
|
} else {
|
|
|
|
|
// append to file
|
|
|
|
|
try {
|
|
|
|
@ -382,6 +432,7 @@ public class ClientDownloadTCP implements Runnable {
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
abort = true;
|
|
|
|
|
System.err.println("Aborting: bad number " + nextOffset);
|
|
|
|
|
logger.writeTCP("Aborting: bad number " + nextOffset, LogLevel.Error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while((!success) && (!abort));
|
|
|
|
|